Guice之IOC教程


Guice

在上一篇博客中, 我們講解了Spring中的IOC示例與實現, 本文着重介紹Guice注入以及與Spring中的差異.

Guice是Google開發的, 一個輕量級的依賴注入框架, 跟Spring最大的區別在於脫離xml配置, 

大量使用Annotation來實現注入, 支持屬性, 構造器, setter等多種方式注入對象.

Guice 3.0支持 jdk 1.6, 如果運行報錯ClassNotFoundException: javax.inject.Provider, 則需要導入javax.inject包.

Module容器

Guice中容器即Module, 用於綁定接口 : 實現類, 類似於Spring中的applicationContext.xml.

Module像是一個Map,根據一個Key獲取其Value,清楚明了的邏輯. 

以下代碼實現了一個簡單的注入

1         Injector ij = Guice.createInjector(new Module() {
2             @Override
3             public void configure(Binder binder) {
4                 binder.bind(TestService.class).to(ServiceImpl.class);
5             }
6         });
7         ij.getInstance(TestService.class).test();

 支持繞過Module, 用默認配置, 直接實例化對象, 不過沒啥意義, 除非要用容器做aop

1         Injector ij2 = Guice.createInjector();
2         ij2.getInstance(ServiceImpl.class).test();

 

當然也可以使用注解的方式來聲明接口的實現類, 然后Injector 從接口中獲取對象,

意義也不大, 因為實際業務中, 接口可能在上層包里, 無法直接調用實現類.

 1 @ImplementedBy(ServiceImpl.class)
 2 public interface TestService {
 3 
 4     void test();
 5 }
 6 
 7 ---------------------------------------
 8 
 9 Injector ij3 = Guice.createInjector();
10 ij3.getInstance(TestService.class).test();

@Inject屬性注入

 1 public class GuiceObjectDemo {
 2 
 3  @Inject  4     private TestService service1;
 5  @Inject  6     private TestService service2;
 7 
 8 ---------------------------------------
 9 
10         GuiceObjectDemo demo = Guice.createInjector().getInstance(GuiceObjectDemo.class);
11         System.out.println(demo.getService());
12         System.out.println(demo.getService2());

 

屬性注入的時候, 必須通過Guice.createInjector().getInstance(GuiceObjectDemo.class);來獲取實現類, 如果直接new的話, 會inject失敗, 打印出兩個null.

這是因為如果對象不屬於Guice托管, 那么他也無法得到Guice注入.

如果一定要new GuiceObjectDemo()呢? 沒關系, 還有另外一種寫法可以滿足.

1         GuiceObjectDemo demo1 = new GuiceObjectDemo();
2  Guice.createInjector().injectMembers(demo1); 3         System.out.println(demo1.getService());

靜態屬性注入

調用binder.requestStaticInjection

1         Guice.createInjector(new Module() {
2             @Override
3             public void configure(Binder binder) {
4                 binder.requestStaticInjection(GuiceObjectDemo.class); 5             }
6         });
7         System.out.println(GuiceObjectDemo.getService3());

 

普通屬性也可以通過該方法注入, 只要把binder那邊改成requestInjection即可.

構造函數注入

1  @Inject 2     public GuiceObjectDemo(TestService service1, TestService service2) {
3         this.service1 = service1;
4         this.service2 = service2;
5     }

構造函數會自動注入多個參數, 因此只要寫一個@Inject即可.

如果有多個構造函數, 只能在一個構造函數上加Inject, 不然會報錯

has more than one constructor annotated with @Inject

同理Setter注入, 只要在setXX方法上加上@Inject標簽即可實現賦值.

動態參數注入

這個稍微麻煩一點, 需要引入guice-assistedinject, 利用FactoryModuleBuilder構造一個factory實行注入.

實際業務場景中, 大部分構造函數的參數是動態從外部傳遞進來的, 並不是直接new出來的.

 1 public class ServiceImpl implements TestService{
 2 
 3     private String member;
 4 
 5     @Inject
 6     public ServiceImpl(@Assisted String member) {
 7         // 利用Assisted注解, 動態注入參數
 8         this.member = member;
 9     }
10 
11     public void setMember(String member) {
12         this.member = member;
13     }
14 
15     @Override
16     public String toString() {
17         return "ServiceImpl Memeber: " + member;
18     }
19 }
20 ---------------------------------------
21 public interface TestService {
22 
23 }
24 ---------------------------------------
25 public interface PageFactory {
26 
27     ReportPageProvider createReportPage(ResultReport report);
28 
29 }
30 ---------------------------------------
31 public class IOCDemo {
32 
33     public static void main(String[] args){
34         Module module = new com.fr.third.inject.Module() {
35             @Override
36             public void configure(Binder binder) {
37                 binder.install(new FactoryModuleBuilder() 38                         .implement(TestService.class, ServiceImpl.class) 39                         .build(ImplFactory.class) 40                 );
41             }
42         };
43 
44         Injector injector = Guice.createInjector(module);
45         ImplFactory factory = injector.getInstance(ImplFactory.class);
46         TestService impl = factory.create("neil123");
47         System.out.println(impl);
48     }
49 
50 }

 

有多個實現類的接口

此時通過上文直接寫單個@Inject或者Module都無法實現, 需要引入自定義注解, 或者Names方法.

 1 public class GuiceObjectDemo {
 2 
 3     @Inject
 4     @Named("A")
 5     private TestService service1;
 6     @Inject
 7     @Named("B")
 8     private TestService service2;
 9 
10 ---------------------------------------
11 
12         final GuiceObjectDemo demo1 = new GuiceObjectDemo();
13         Guice.createInjector(new Module() {
14             @Override
15             public void configure(Binder binder) {
16                 binder.bind(TestService.class).annotatedWith(Names.named("A")).to(ServiceImplA.class); 17                 binder.bind(TestService.class).annotatedWith(Names.named("B")).to(ServiceImplB.class); 18  binder.requestInjection(demo1); 19             }
20         });
21         System.out.println(demo1.getService());
22         System.out.println(demo1.getService2());

 如果不用Named注解, 則可以通過自定義注解, 其他寫法都一樣

1                  binder.bind(TestService.class).annotatedWith(ImplA.class).to(ServiceImplA.class);
2                  binder.bind(TestService.class).annotatedWith(ImplB.class).to(ServiceImplB.class);

 

Provider注入 

其實就是類似於工廠注入,  對象不是直接new接口的實現類, 而是由工廠提供. 

 1 public class ServiceFactory implements Provider<TestService> {
 2 
 3     @Override
 4     public TestService get() {
 5         return new ServiceImpl();
 6     }
 7 
 8 }
 9 
10 ---------------------------------------
11 
12 @ProvidedBy(ServiceFactory.class)
13 public interface TestService {
14 
15     void test();
16 }
17 
18 ---------------------------------------
19 
20         GuiceObjectDemo demo = Guice.createInjector().getInstance(GuiceObjectDemo.class);
21         System.out.println(demo.getService());

 

Scope

可以通過在impl類上加@Singleton來實現單例, 也可在module中管理

1  binder.bind(TestService.class).to(ServiceImpl.class).in(Scopes.SINGLETON);

 

默認單例模式的對象, 是在第一次使用的時候才初始化, 也可以通過設置asEagerSingleton, 注入到容器后立刻初始化.

 1         Injector in = Guice.createInjector(new Module() {
 2             @Override
 3             public void configure(Binder binder) {
 4                 // 調用getInstance才初始化impl
 5                 binder.bind(ServiceImpl.class);
 6                 // 注入到容器后立刻初始化impl
 7 //                binder.bind(ServiceImpl.class).asEagerSingleton();
 8             }
 9         });
10         Thread.sleep(3000);
11         in.getInstance(ServiceImpl.class).test();

 到這邊就結束了, 通過上面的案例不難看出, , 相比於Spring IOC, Guice是一個非常輕量靈活的注入實現, 0 xml.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM