1、关于标注绑定,如若不是属性,是方法上的注入,如下适用标注
@Inject @Www public Service service; //方法上的如下 @Inject void injectService(@Www Service service) { ... }
2、隐式绑定,如果缺少显示绑定(即没有写任何binder),Guice会试图注入并创建一个所依赖的类的新实例,如果依赖于一个接口,Guice会寻找指向具体实现的@ImplementedBy标注,如果是依赖的是一个类,那就实例化此类。
bind(ServiceImpl.class); //自己绑定自己,当然这语句可有可无,对下面毫无影响 ... class Demo{ @Inject Demo(ServiceImpl service){ ... } }
3、定制Provide。
有时候需要手工创建自己的对象,而不是让Guice创建他们,比如,一个来自第三方的实现类需要注入,但我们不能修改源码,不能添加@Inject标注,在这里就需要 自己定制Provider,手工创建对象。
class WidgetProvider implements Provider<Widget> { final Service service; @Inject//这里注入了第三方实现类需要的参数 WidgetProvider(Service service) { this.service = service; } public Widget get() { return new Widget(service);//这里自己手工传入参数,实例化 } }
例子:与JNDI集成,我们需要绑定从JNDI得到的对象。
class JndiProvider<T> implements Provider<T> { @Inject Context context; final String name; final Class<T> type; JndiProvider(Class<T> type, String name) { this.name = name; this.type = type; } public T get() { try { return type.cast(context.lookup(name)); } catch (NamingException e) { throw new RuntimeException(e); } } /** * Creates a JNDI provider for the given * type and name. */ static <T> Provider<T> fromJndi( Class<T> type, String name) { return new JndiProvider<T>(type, name); } }
我们可以使用定制的JndiProvider来将DataSource绑定到来自JNDI的一个对象上。
// Bind Context to the default InitialContext. bind(Context.class).to(InitialContext.class); // Bind to DataSource from JNDI. bind(DataSource.class) .toProvider(JndiProvider.fromJndi(DataSource.class, "..."));
4、绑定的作用域
缺省情况下,Guice为每次注入创建一个新的对象,即“无作用域”
可以在配置绑定时指明作用域
bind(MySingleton.class).in(Scopes.SINGLETON); //或用标注,Guice缺省支持@Singleton; @Singleton class MySingleton { ... } //用in()的优先级高于标注 //可以使用Binder.bindScope()为定制的作用域 指定 标注. //如,对于标注@SessionScoped 和 一个Scope的实现ServletScopes.SESSION; binder.bindScope(SessionScoped.class,ServletScopes.SESSION);
创建作用域标注
标注必须:
/** * Scopes bindings to the current transaction. */ @Retention(RUNTIME) @Target({TYPE}) @ScopeAnnotation public @interface TransactionScoped {}
5、尽早加载绑定(类似Spring的layzload=false)
有时你希望在启动时加载一个对象,可以通过以下方法实现初始化逻辑,通过在Guice必须首先初始化的单件对象上创造依赖关系来控制初始化顺序。
bind(StartupTask.class).asEagerSingleton();
6、在不同作用域间注入
7、开发阶段
Guice 明白你的应用开发需要经历不同的阶段。你可以在创建容器时告诉它应用程序运行在哪一个阶段。Guice 目前支持“开发”和“产品”两个阶段。我们发现测试通常属于其中某一个阶段。
8、拦截方法
Guice 使用 AOP Alliance API 支持简单的方法拦截。可以在模块中使用 Binder 绑定拦截器。例如,对标注有 @Transactional 的方法应用事务拦截器:
import static com.google.inject.matcher.Matchers.*; ... binder.bindInterceptor( any(), // Match classes. annotatedWith(Transactional.class), // Match methods. new TransactionInterceptor() // The interceptor. );
尽量让匹配代码多做些过滤工作,而不是在拦截器中过滤。因为匹配代码只在启动时运行一次。
10、Struts2支持
要在 Struts 2.0.6 或更高版本中安装 Guice Struts 2 插件,只要将 guice-struts2-plugin-1.0.jar 包含在你的 Web 应用的 classpath 中,并在 struts.xml 文件中选择 Guice 作为你的 ObjectFactory 实现即可:
<constant name="struts.objectFactory" value="guice" />
Guice 会注入所有你的 Struts 2 对象,包括动作和拦截器。你甚至可以设置动作类的作用域。你也可以在你的 struts.xml 文件中指定 Guice 的 Module:
<constant name="guice.module" value="mypackage.MyModule"/>
如果你的所有绑定都是隐式的,你就根本不用定义模块了。
9、可选注入
有时你的代码应该在无论绑定是否存在的时候都能工作。在这些情况下,你可以使用 @Inject(optional=true),Guice 会在有绑定可用时,用一个绑定实现覆盖你的缺省实现。例如:
@Inject(optional=true) Formatter formatter = new DefaultFormatter();
如果谁为 Formatter 创建了一个绑定,Guice 会基于该绑定注入实例。否则,如果 Formatter 不能被注入(参见隐式绑定),Guice 会忽略可选成员。
可选注入只能应用于字段和方法,而不能用于构造函数。对于方法,如果一个参数的绑定找不到,Guice 就不会注入该方法,即便其他参数的绑定是可用的。