先前已经讲述了绑定的一个基本流程,然后我们尝试将guice黑盒后,注入和绑定是分开的。在绑定的时候,我们可以有很多非常灵活的结构、语法和概念来需要掌握。
module是可以互相嵌套与并列的,嵌套的话可以install引入,当然还有覆盖。
一、常用的绑定方法:
(1)类名绑定 (把一个需要的东西绑定到具体实现的类上)
eg: bind(PriceService.class).to(PriceServiceImpl.class);
(2)实例绑定(可以new一个对象绑定上去)
eg: bind(PriceService.class).toInstance(new PriceServiceImpl());
(3)连接绑定(对已有的目标,我们还可以进行新的绑定,一级级连下去找真正实例)
一般我们通过测试的时候,可以在测试类后面再加入一个Module来具现化连接绑定测试。
bind(PriceService.class).to(PriceServiceImpl.class); bind(PriceServiceImpl.class).toInstance(new PriceServiceImpl(){ @Override public long getPrice(long orderId) { return 766L; } });
(4)Provider绑定(很多种,其中特别关键是注释的函数)
@Provides Long generateSessionId(){//方式三,名字可以随便起,当且仅当仅一个类型时 return System.currentTimeMillis(); }
当然也可以传入参数,但是参数需要之前已经注入的,guice就会帮我自动注入,然而在具体的Provider的get()方法的时候依然不需要输入参数,因为guice已经帮我们做了
@Provides Long generateSessionId(PriceService priceService){ return priceService.getMoney(); }
(5)命名绑定(对@Named绑定的函数,或者自定义的注释)
@Provides @SessionId Long generateSessionId() {// 参考注入(一)多出一个@SesssionId return System.currentTimeMillis(); }
或者可以给他一个名字,只关注命名和类型,匹配的时候
ServerModule.class
@Provides @Named("getCurrentTimes") Long generateSessionId() {// 方式三,名字可以随便起,当且仅当仅一个类型时 return System.currentTimeMillis(); }
SessionManager.class
@Inject public SessionManager(@Named("getCurrentTimes") Provider<Long> SessionIdProvider) { super(); this.SessionIdProvider = SessionIdProvider; }
(6)泛型绑定(new TypeLiteral加上我们需要的泛型类型)
bind(new TypeLiteral<List<String>>(){}) .toInstance(Arrays.asList("CNY","ENR","USD"));当然也可以通过其他来实现,可以重新new TypeLiteral 来传入一个新的实现,也可以引入其他注释实现都可以。
eg:
bind(new TypeLiteral<List<String>>(){}) .annotatedWith(Names.named("getCurrentTimes")) .toInstance(Arrays.asList("CNY","ENR","USD"));
(7)集合绑定(可在不同的Module内向同一个集合分别去绑定自己所要支持的内容)
<1>Set绑定
假设输出一个Set集合,包含币种
public class ChinaModule extends AbstractModule{ @Override public void configure() { // TODO suit China Yuan Multibinder.newSetBinder(binder(), String.class) .addBinding().toInstance("CNY"); } }
public class GlobalModule extends AbstractModule{ @Override public void configure() { // TODO USD,ENY Multibinder<String> multibinder = Multibinder.newSetBinder(binder(), String.class); multibinder.addBinding().toInstance("USD"); multibinder.addBinding().toInstance("ENY"); } }
ServerModule.class
public class ServerModule extends AbstractModule { @Override protected void configure() { //套入其他Module install(new ChinaModule()); install(new GlobalModule()); bind(OrderService.class).to(OrderServerImpl.class); bind(PaymentService.class).to(PaymentServiceImpl.class); bind(PriceService.class).to(PriceServiceImpl.class); }
OrderServiceImpl.class
private final Set<String> supportedCurrenties; @Inject private PriceServiceImpl(Set<String> supportedCurrenties) { super(); this.supportedCurrenties = supportedCurrenties; } @Override public Set<String> getSupportCurrenties() { return supportedCurrenties; }
<2> Map绑定
MapBinder.newMapBinder(binder(), keyType, valueType) //用法与Set相似,前者是Key,后者是Value
二、Module的关系
(一)并列
eg: Guice.createInjector(new ServerModule(),........... ).injectMembers(this);; //后面可以接一堆Moudule
(二)嵌套
eg: insall(new ChinaModule());//大Module下可以套小Module,一直套if you want it。。。,一般最终有一个Master存在
(三)覆盖(如果有冲突的语句就应用覆盖的,没有的话都是有效的)
eg: Modules.override(new ChinaModule()).with(new GlobalModule()); //用后者覆盖前者
三、初始化
Module内存放了很多表达式,比如Bind().to..\install ,只是相当存放于一个map中,记录下来,它并不会被运行。整个流程花时间在于getInstance(),这是会将所有的依赖、注入建立出来。