Google Guice 入門教程03 - 更多話題

openkk 13年前發布 | 4K 次閱讀 OpenJDK

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 
 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!