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
|求賢若渴