Spring学習資料―注入に依存する(三)


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.teny32.blog.51cto.com");
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 }
上のコードは一つのサービスです.WwServiceとHomeServiceの二つの実装があります.同時にWwwとHomeの二つの注釈があります.はい、次は私たちの主役をお願いします.
1     /**
 2      * $Id: MultiInterfaceServiceDemo.java
 3      * Teny study project (www.teny32.blog.51cto.com)
 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
14      * @version 1.0
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
このような構造は2つのサービスを注入するもので、wServiceは@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を作って出てきます.
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を使ってスレッドのオブジェクト交換ができます.
もちろん自動的にサービスを注入したいなら、@ProviderBy注を使ってもいいです.
1     @ProvidedBy(WwwServiceProvider.class)
2     public interface Service {
3
4         void execute();
5     }
6
7
これでModuleを使ってサービスをServiceにProviderを結びつける必要がなくなります.サービスを受けるのは簡単です.
ProviderServiceDemo psd = Guice.createInjector().getInstance(ProviderServiceDemo.class);
psd.service.execute();
上記の2つの方法以外にも、プロバイダーを注入することができます.例えば、次の例では、属性はServiceではなく、プロバイダー<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は毎回新しいサービスを構築していますので、Provider ServiceDemoの中のプロバイダーは毎回獲得するサービスも違います.
1.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以外にも、コンスタントBindingBuiderクラスで他の基本タイプをバインドすることができます.
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バインディングPropties
基本タイプ以外にも、ProptiesをGuiceに結びつけることができます.もちろん、Proptiesは本質的にはMapであるため、GuiceもMapを一つ縛ることができます.
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.teny32.blog.51cto.com");
12                 Names.bindProperties(binder, properties);
13             }
14         }).getInstance(ConstantInjectDemo.class);
15         System.out.println(cid.web);
16     }
17
18
             51CTO    !http://teny32.blog.51cto.com/ !