Google Guice 入门教程03 - 依赖注入(3)

Google Guice 入门教程03 - 依赖注入(3)

1.3 更多话题

1.3.1 接口多实现

如果一个接口有多个实现,这样通过@Inject和Module都难以直接实现,但是这种现象确实是存在的,于是Guice提供了其它注入方式来解决此问题。比如下面的自定义注解。


1       public   interface  Service {
2 
3           void  execute();
4      }
5 
6 

1  public   class  HomeService  implements  Service {
2      @Override
3       public   void  execute() {
4          System.out.println( " home.imxylz.cn " );
5      }
6  }

1  public   class  WwwService  implements  Service {
2      @Override
3       public   void  execute() {
4          System.out.println( " www.imxylz.cn " );
5      }
6  }

1  @Retention(RetentionPolicy.RUNTIME)
2  @Target({FIELD,PARAMETER})
3  @BindingAnnotation
4  public  @ interface  Home {
5  }

1  @Retention(RetentionPolicy.RUNTIME)
2  @Target({FIELD,PARAMETER})
3  @BindingAnnotation
4  public  @ interface  Www {
5  }

上面的代码描述的是一个Service服务,有WwwService和HomeService两个实现,同时有Www和Home两个注解(如果对注解各个参数不明白的需要单独去学习JAVA 5注解)。好了下面请出我们的主角。
 1       /**
 2       * $Id: MultiInterfaceServiceDemo.java 82 2009-12-24 06:55:16Z xylz $
 3       * xylz study project (www.imxylz.cn)
 4        */
 5       package  cn.imxylz.study.guice.inject.more;
 6 
 7       import  com.google.inject.Binder;
 8       import  com.google.inject.Guice;
 9       import  com.google.inject.Inject;
10       import  com.google.inject.Module;
11 
12       /**  a demo with multi interfaces
13       *  @author  xylz (www.imxylz.cn)
14       *  @version  $Rev: 82 $
15        */
16       public   class  MultiInterfaceServiceDemo {
17          @Inject
18          @Www
19           private  Service wwwService;
20          @Inject
21          @Home
22           private  Service homeService;
23           public   static   void  main(String[] args) {
24              MultiInterfaceServiceDemo misd  =  Guice.createInjector( new  Module() {
25                  @Override
26                   public   void  configure(Binder binder) {
27                      binder.bind(Service. class ).annotatedWith(Www. class ).to(WwwService. class );
28                      binder.bind(Service. class ).annotatedWith(Home. class ).to(HomeService. class );
29                  }
30              }).getInstance(MultiInterfaceServiceDemo. class );
31              misd.homeService.execute();
32              misd.wwwService.execute();
33          }
34      }
35 
36 

此类的结构是注入两个Service服务,其中wwwService是注入@Www注解关联的WwwService服务,而homeService是注入@Home注解关联的HomeService服务。

同样关于此结构我们要问几个问题。

问题(1)静态注入多个服务怎么写?

其实,参照教程02,我们可以使用下面的例子。


 1  public   class  StaticMultiInterfaceServiceDemo {
 2      @Inject
 3      @Www
 4       private   static  Service wwwService;
 5      @Inject
 6      @Home
 7       private   static  Service homeService;
 8       public   static   void  main(String[] args) {
 9         Guice.createInjector( new  Module() {
10              @Override
11               public   void  configure(Binder binder) {
12                  binder.bind(Service. class ).annotatedWith(Www. class ).to(WwwService. class );
13                  binder.bind(Service. class ).annotatedWith(Home. class ).to(HomeService. class );
14                  binder.requestStaticInjection(StaticMultiInterfaceServiceDemo. class );
15              }
16          });
17          StaticMultiInterfaceServiceDemo.homeService.execute();
18          StaticMultiInterfaceServiceDemo.wwwService.execute();
19      }
20  }

问题(2):如果不小心一个属性绑定了多个接口怎么办?

非常不幸,你将得到类似一下的错误,也就是说不可以绑定多个服务。


1 ) cn.imxylz.study.guice.inject.more.StaticMultiInterfaceServiceDemo.wwwService has more than one annotation annotated with @BindingAnnotation: cn.imxylz.study.guice.inject.more.Www and cn.imxylz.study.guice.inject.more.Home
  at cn.imxylz.study.guice.inject.more.StaticMultiInterfaceServiceDemo.wwwService(StaticMultiInterfaceServiceDemo.java:
17 )

问题(3):我太懒了不想写注解来区分多个服务,怎么办?

程序员都是懒惰的,于是Google帮我们提供了一个Names的模板来生成注解。看下面的例子。


 1  public   class  NoAnnotationMultiInterfaceServiceDemo {
 2      @Inject
 3      @Named( " Www " )
 4       private   static  Service wwwService;
 5      @Inject
 6      @Named( " Home " )
 7       private   static  Service homeService;
 8       public   static   void  main(String[] args) {
 9         Guice.createInjector( new  Module() {
10              @Override
11               public   void  configure(Binder binder) {
12                  binder.bind(Service. class ).annotatedWith(Names.named( " Www " )).to(WwwService. class );
13                  binder.bind(Service. class ).annotatedWith(Names.named( " Home " )).to(HomeService. class );
14                  binder.requestStaticInjection(NoAnnotationMultiInterfaceServiceDemo. class );
15              }
16          });
17          NoAnnotationMultiInterfaceServiceDemo.homeService.execute();
18          NoAnnotationMultiInterfaceServiceDemo.wwwService.execute();
19      }
20  }

上面的例子中我们使用Named来标注我们的服务应该使用什么样的注解,当然前提是我们已经将相应的服务与注解关联起来了。

1.3.2 Provider注入

在教程第一篇中我们提到了可以通过Provider注入一个服务,这里详细说说这种模式。

首先我们需要构造一个Provider<T>出来。


1       public   class  WwwServiceProvider  implements  Provider < Service >  {
2 
3          @Override
4           public  Service get() {
5               return   new  WwwService();
6          }
7      }
8 
9 

上面的Provider的意思很简单,每次新建一个新的WwwService对象出来。

注入的过程看下面的代码。


 1       public   class  ProviderServiceDemo {
 2 
 3          @Inject
 4           private  Service service;
 5 
 6           public   static   void  main(String[] args) {
 7              Injector inj =   Guice.createInjector( new  Module() {
 8                  @Override
 9                   public   void  configure(Binder binder) {
10                      binder.bind(Service. class ).toProvider(WwwServiceProvider. class );
11                  }
12              });
13              ProviderServiceDemo psd  =  inj.getInstance(ProviderServiceDemo. class );
14              psd.service.execute();
15          }
16 
17      }
18 
19 

很显然如果这东西和线程绑定就非常好了,比如我们可以使用ThreadLocal来做线程的对象交换。

当然如果想自动注入(不使用Module手动关联)服务的话,可以使用@ProviderBy注解。


1      @ProvidedBy(WwwServiceProvider. class )
2       public   interface  Service {
3 
4           void  execute();
5      }
6 
7 

这样我们就不必使用Module将Provider绑定到Service上,获取服务就很简单了。


ProviderServiceDemo psd  =  Guice.createInjector().getInstance(ProviderServiceDemo. class );
psd.service.execute();

除了上述两种方式我们还可以注入Provider,而不是注入服务,比如下面的例子例子中,属性不再是Service,而是一个Provider<Service>。


 1       public   class  ProviderServiceDemo {
 2 
 3          @Inject
 4           private  Provider < Service >  provider;
 5 
 6           public   static   void  main(String[] args) {
 7              ProviderServiceDemo psd  =  Guice.createInjector( new  Module() {
 8                  @Override
 9                   public   void  configure(Binder binder) {
10                      binder.bind(Service. class ).toProvider(WwwServiceProvider. class );
11                  }
12              }).getInstance(ProviderServiceDemo. class );
13              psd.provider.get().execute();
14          }
15      }
16 
17 

当然了,由于我们WwwServiceProvider每次都是构造一个新的服务出来,因此在类ProviderServiceDemo中的provider每次获取的服务也是不一样的。

1.3.3 绑定常量

看看下面的例子,演示了一个绑定整数值到实例的例子。


 1       public   class  ConstantInjectDemo {
 2 
 3          @Inject
 4          @Named( " v " )
 5           private   int  v;
 6           public   static   void  main(String[] args) {
 7 
 8              ConstantInjectDemo cid  =  Guice.createInjector( new  Module() {
 9                  @Override
10                   public   void  configure(Binder binder) {
11                      binder.bindConstant().annotatedWith(Names.named( " v " )).to( 12 );
12                  }
13              }).getInstance(ConstantInjectDemo. class );
14              System.out.println(cid.v);
15          }
16      }
17 
18 

当然,既然可以使用Named,也就可以使用自己写注解了。但是看起来好像没有多大作用。除了上述写法,也可以用下面的方式实现。

binder.bind(int.class).annotatedWith(Names.named("v")).toInstance(12);

除了可以绑定int外,在ConstantBindingBuilder类中还可以绑定其它的基本类型。

com.google.inject.binder.ConstantBindingBuilder.to(String)
com.google.inject.binder.ConstantBindingBuilder.to(
long )
com.google.inject.binder.ConstantBindingBuilder.to(
boolean )
com.google.inject.binder.ConstantBindingBuilder.to(
double )
com.google.inject.binder.ConstantBindingBuilder.to(
float )
com.google.inject.binder.ConstantBindingBuilder.to(
short )
com.google.inject.binder.ConstantBindingBuilder.to(
char )

 

1.3.4 绑定Properties

除了可以绑定基本类型外,还可以绑定一个Properties到Guice中,当然了,由于Properties本质上时一个Map<String,String>,因此Guice也允许绑定一个Map<String,String>。


 1      @Inject
 2      @Named( " web " )
 3       private  String web;
 4 
 5       public   static   void  main(String[] args) {
 6 
 7          ConstantInjectDemo cid  =  Guice.createInjector( new  Module() {
 8              @Override
 9               public   void  configure(Binder binder) {
10                  Properties properties =   new  Properties();
11                  properties.setProperty( " web " " www.imxylz.cn " );
12                  Names.bindProperties(binder, properties);
13              }
14          }).getInstance(ConstantInjectDemo. class );
15          System.out.println(cid.web);
16      }
17 
18 
 
上一篇: Google Guice 入门教程02 - 依赖注入(2)
下一篇: Google Guice 入门教程04 - 依赖注入(4)

©2009-2014 IMXYLZ
imxylz.com
| 求贤若渴

你可能感兴趣的:(Google Guice 入门教程03 - 依赖注入(3))