欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Guice2.0的变化——第一部分 新的特性(上)

程序员文章站 2022-03-14 08:34:30
...

Guice2 有望于本月发布,但是它并不向下兼容 。很容易让人联想到 Python Python3000 的故事。文章分两部分:“新的特性”和“从 Guice1.0 迁徙到 2.0 ,先睹为快吧。

 

第一部分 新的特性

 

 

Small Features

 

l          Binder.getProvider AbstractModule.requireBinding 允许 module 使用声明式的方式,允许依赖于别的 Module

l          Binder.requestInjection 允许 module 为注册的实例在注入创建时 (Injector-creation time) 进行注入。

l          Providers.of() 方法永远保证返回相同的实例,这一点对测试来说很管用。

l          Scopes.NO_SCOPE 允许显示的设置一个“无作用域”。

l          Matcher.inSubpackage 用于匹配所有指定包下以及其子包下的所有 classes

l          Types 工具类 ( 改用泛型写了 ) 用于创建一个泛型的具体实现。( Guice 的泛型和标注真是用到出神入化的地步了)

l          AbstractModule.requireBinding 允许 module 编程方式的实现依赖。

 

 

Provider Methods

 

创建自定义的 Providers 不需要任何 boilerplate( 模板 ) 。在任意的 module 中,用 @Providers 标注来这样定义一个方法:

 

public class PaymentsModule extends AbstractModule {
	public void configure() {

	}

	@Provides
	@Singleton
	PaymentService providePaymentService(CustomerDb database) {
		DatabasePaymentService result = new DatabasePaymentService();
		result.setDatabase(database);
		result.setReplicationLevel(5);
		return result;
	}
}

 

 

在该方法 providePaymentService 中的所有参数都会被自动注入。当然,你还可配合使用 scoping annotation ,咱们这里用的就是 @Singleton 。最后方法返回的类型也就是咱们要绑定的类型。如果你期望方法返回时返回在一个 annotation 上,可以使用 @Named 来创建这样一个 annotated 类型。

当我看到这里的时候,我把我的理解说出来和大伙分享分享。通常来说,我们会在 Action 中像这样注入一些 Service

public class PaymentAction {

	public static final String SUCCESS = "success";

	@Inject
	private PaymentService paymentService;

	public String execute() {
		paymentService.execute();
		return SUCCESS;
	}
}
 

 

很好,代码简单明了。但是如果这个“ PaymentService ”在使用之前,还需要注入别的东西的话 ( 比如说 DateSource Constant 设置等 ) ,那么以往的做法就是在 PaymentService 中继续使用 @Inject 。不过,既然叫 Guice2.0 ,总得弄点新花样吧。这样 @Provides 就来了。它允许你的“ PaymentService ”在创建 module 的时候,将所需要的参数注入进去,进行相应初始化 ( 调用 providePaymentService 方法 ) ,最后再返回给你一个你真正想要的 paymentService 对象;如果你返回的是一个 annotation ,那么也没问题:

public class PaymentAction {

	public static final String SUCCESS = "success";

	@Inject
	Named foo;

	public String execute() {
		System.out.println(foo.getClass().toString() + " " + foo.value());
		return SUCCESS;
	}
}

 

 

相应的 PaymentsModule 中加入:

 

public class PaymentsModule extends AbstractModule {

	@Named("foo")
	private String foo;

	...

	@Provides
	@Singleton
	Named provideNamed() throws Exception {
		Named name = getClass().getDeclaredField("foo").getAnnotation(
				Named.class);
		return name;
	}
}

 

 

我想看到这里,大家应该明白了吧。继续 ~~~

 

 

Binding Overrides

Module functionalTestModule = Modules.override(new ProductionModule()).with(newOverridesModule());

 

 

顾名思义,允许用新的 module 来复盖原有的 module 。这样的好处在于,你可以开发测试中使用一套 test module ,而在正式的产品中使用另一套 production module

 

 

Multibindings, MapBindings

 

这也是 Guice2 新加入的,先将元素绑定在 Set Map 中,然后注入整个 Collection 。如果多个 module 都有同样的 Collection ,那么 Guice 会帮你合并。

public class SnacksModule extends AbstractModule {
  protected void configure() {
    MapBinder<String, Snack> mapBinder
        = MapBinder.newMapBinder(binder(), String.class, Snack.class);
    mapBinder.addBinding("twix").toInstance(new Twix());
    mapBinder.addBinding("snickers").toProvider(SnickersProvider.class);
    mapBinder.addBinding("skittles").to(Skittles.class);
  }
}
 

 

Private Modules

 

PrivateModules 用于创建并不需要对外可见的绑定对象。当然,这样会使得封装变得更加简单,还避免了冲突。

作者没有写关于 PrivateModules 的内容,有可能还没有更新完吧。我们就简单看一个例子:

public class FooBarBazModule extends PrivateModule {
   protected void configurePrivateBindings() {
     bind(Foo.class).to(RealFoo.class);
     expose(Foo.class); //expose方法用于向外部暴露内部的绑定Foo

     install(new TransactionalBarModule()); //install方法允许将本PrivateModule模块嵌入到TransactionalBarModule模块中去。
     expose(Bar.class).annotatedWith(Transactional.class); //expose方法用于向外部暴露内部的绑定Bar,并令其标注为Transactional

     bind(SomeImplementationDetail.class);
     install(new MoreImplementationDetailsModule());
   }

	//向外部暴露的方法
   @Provides @Exposed
   public Baz provideBaz() {
     return new SuperBaz();
   }
 }