xylz,imxylz

          關(guān)注后端架構(gòu)、中間件、分布式和并發(fā)編程

             :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            111 隨筆 :: 10 文章 :: 2680 評(píng)論 :: 0 Trackbacks


          1. 依賴注入

          1.1 類依賴注入

          所謂的綁定就是將一個(gè)接口綁定到具體的類中,這樣客戶端不用關(guān)心具體的實(shí)現(xiàn),而只需要獲取相應(yīng)的接口完成其服務(wù)即可。

          HelloWorld.java


          1     public interface HelloWorld {
          2 
          3         String sayHello();
          4     }
          5 

          然后是具體的實(shí)現(xiàn),HelloWorldImpl.java


          1     public class HelloWorldImpl implements HelloWorld {
          2 
          3         @Override
          4         public String sayHello() {
          5             return "Hello, world!";
          6         }
          7     }
          8 

          寫一個(gè)測(cè)試?yán)涌纯矗?em>HelleWorldTest.java


           1     public class HelleWorldTest {
           2 
           3         @Test
           4         public void testSayHello() {
           5           Injector inj=  Guice.createInjector(new Module() {
           6                 @Override
           7                 public void configure(Binder binder) {
           8                     binder.bind(HelloWorld.class).to(HelloWorldImpl.class);
           9                 }
          10             });
          11           HelloWorld hw = inj.getInstance(HelloWorld.class);
          12           Assert.assertEquals(hw.sayHello(), "Hello, world!");
          13         }
          14     }
          15 

          這個(gè)例子非常簡(jiǎn)單,通俗的將就是將一個(gè)HelloWorldImpl的實(shí)例與HelloWorld關(guān)聯(lián)起來,當(dāng)想Guice獲取一個(gè)HelloWorld實(shí)例的時(shí)候,Guice就返回一個(gè)HelloWorldImpl的實(shí)例,然后我們就可以調(diào)用HelloWorld服務(wù)的方法了。

          問題(1)HelloWorld是單例的么?測(cè)試下。


          1 HelloWorld hw = inj.getInstance(HelloWorld.class); 
          2 Assert.assertEquals(hw.sayHello(), "Hello, world!");
          3 HelloWorld hw2 = inj.getInstance(HelloWorld.class);
          4 System.out.println(hw.hashCode()+"->"+hw2.hashCode());
          5 Assert.assertEquals(hw.hashCode(), hw2.hashCode());

          解答(1)測(cè)試結(jié)果告訴我們,HelloWorld不是單例的,每次都會(huì)返回一個(gè)新的實(shí)例。

          問題(2)HelloWorld的實(shí)例是HelloWorldImpl么?可以強(qiáng)制轉(zhuǎn)型么?

          HelloWorld hw = inj.getInstance(HelloWorld.class);
          System.out.println(hw.getClass().getName());

           

          解答(2),結(jié)果輸出cn.imxylz.study.guice.helloworld.HelloWorldImpl,看來確實(shí)只是返回了一個(gè)正常的實(shí)例,并沒有做過多的轉(zhuǎn)換和代理。

          問題(3),如果綁定多個(gè)實(shí)現(xiàn)到同一個(gè)接口上會(huì)出現(xiàn)什么情況?


          1 public class HelloWorldImplAgain implements HelloWorld {
          2     @Override
          3     public String sayHello() {
          4         return "Hello world again.";
          5     }
          6 }

          binder.bind(HelloWorld.class).to(HelloWorldImpl.class);
          binder.bind(HelloWorld.
          class).to(HelloWorldImplAgain.class);

          解答(3),很不幸,Guice目前看起來不允許多個(gè)實(shí)例綁定到同一個(gè)接口上了。

          com.google.inject.CreationException: Guice creation errors:

          1) A binding to cn.imxylz.study.guice.helloworld.HelloWorld was already configured at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:28).
            at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:29)

          問題(4),可以綁定一個(gè)實(shí)現(xiàn)類到實(shí)現(xiàn)類么?

          1 Injector inj=  Guice.createInjector(new Module() {
          2       @Override
          3       public void configure(Binder binder) {
          4           binder.bind(HelloWorldImpl.class).to(HelloWorldImpl.class);
          5       }
          6   });
          7 HelloWorld hw = inj.getInstance(HelloWorldImpl.class);
          8 System.out.println(hw.sayHello());

           

          非常不幸,不可以自己綁定到自己。

          1) Binding points to itself.
            at cn.imxylz.study.guice.helloworld.HelleWorldTest$1.configure(HelleWorldTest.java:28)

          我們來看看bind的語法。

          <T> AnnotatedBindingBuilder<T> bind(Class<T> type);


          ScopedBindingBuilder to(Class<? extends T> implementation);

          也就是說只能綁定一個(gè)類的子類到其本身。改造下,改用子類替代。


          1     public class HelloWorldSubImpl extends HelloWorldImpl {
          2 
          3         @Override
          4         public String sayHello() {
          5             return "@HelloWorldSubImpl";
          6         }
          7     }
          8 

          1 Injector inj=  Guice.createInjector(new Module() {
          2             @Override
          3             public void configure(Binder binder) {
          4                 binder.bind(HelloWorldImpl.class).to(HelloWorldSubImpl.class);
          5             }
          6         });
          7       HelloWorldImpl hw = inj.getInstance(HelloWorldImpl.class);
          8       System.out.println(hw.sayHello());

          太好了,支持子類綁定,這樣即使我們將一個(gè)實(shí)現(xiàn)類發(fā)布出去了(盡管不推薦這么做),我們?cè)诤笃谌匀挥修k法替換實(shí)現(xiàn)類。

          使用bind有一個(gè)好處,由于JAVA 5以上的泛型在編譯器就確定了,所以可以幫我們檢測(cè)出綁定錯(cuò)誤的問題,而這個(gè)在配置文件中是無法檢測(cè)出來的。

          這樣看起來Module像是一個(gè)Map,根據(jù)一個(gè)Key獲取其Value,非常簡(jiǎn)單的邏輯。

          問題(5),可以綁定到我們自己構(gòu)造出來的實(shí)例么?

          解答(5)當(dāng)然可以!看下面的例子。


          1 Injector inj=  Guice.createInjector(new Module() {
          2             @Override
          3             public void configure(Binder binder) {
          4                 binder.bind(HelloWorld.class).toInstance(new HelloWorldImpl());
          5             }
          6         });
          7       HelloWorld hw = inj.getInstance(HelloWorld.class);
          8       System.out.println(hw.sayHello());

          問題(6),我不想自己提供邏輯來構(gòu)造一個(gè)對(duì)象可以么?

          解答(6),可以Guice提供了一個(gè)方式(Provider<T>),允許自己提供構(gòu)造對(duì)象的方式。


           1 Injector inj=  Guice.createInjector(new Module() {
           2       @Override
           3       public void configure(Binder binder) {
           4           binder.bind(HelloWorld.class).toProvider(new Provider<HelloWorld>() {
           5               @Override
           6               public HelloWorld get() {
           7                   return new HelloWorldImpl();
           8               }
           9           });
          10       }
          11   });
          12 HelloWorld hw = inj.getInstance(HelloWorld.class);
          13 System.out.println(hw.sayHello());

          問題(7),實(shí)現(xiàn)類可以不經(jīng)過綁定就獲取么?比如我想獲取HelloWorldImpl的實(shí)例而不通過Module綁定么?

          解答(7),可以,實(shí)際上Guice能夠自動(dòng)尋找實(shí)現(xiàn)類。


          Injector inj=  Guice.createInjector();
          HelloWorld hw 
          = inj.getInstance(HelloWorldImpl.class);
          System.out.println(hw.sayHello());

          問題(8),可以使用注解方式完成注入么?不想手動(dòng)關(guān)聯(lián)實(shí)現(xiàn)類。

          解答(8),好,Guice提供了注解的方式完成關(guān)聯(lián)。我們需要在接口上指明此接口被哪個(gè)實(shí)現(xiàn)類關(guān)聯(lián)了。


          1     @ImplementedBy(HelloWorldImpl.class)
          2     public interface HelloWorld {
          3 
          4         String sayHello();
          5     }
          6 

          Injector inj=  Guice.createInjector();
          HelloWorld hw 
          = inj.getInstance(HelloWorld.class);
          System.out.println(hw.sayHello());


          事實(shí)上對(duì)于一個(gè)已經(jīng)被注解的接口我們?nèi)匀豢梢允褂肕odule來關(guān)聯(lián),這樣獲取的實(shí)例將是Module關(guān)聯(lián)的實(shí)例,而不是@ImplementedBy注解關(guān)聯(lián)的實(shí)例。這樣仍然遵循一個(gè)原則,手動(dòng)優(yōu)于自動(dòng)。

          問題(9)再回頭看問題(1)怎么綁定一個(gè)單例?

           1     Injector inj = Guice.createInjector(new Module() {
           2 
           3         @Override
           4         public void configure(Binder binder) {
           5             binder.bind(HelloWorld.class).to(HelloWorldImplAgain.class).in(Scopes.SINGLETON);
           6         }
           7     });
           8     HelloWorld hw = inj.getInstance(HelloWorld.class);
           9     HelloWorld hw2 = inj.getInstance(HelloWorld.class);
          10     System.out.println(hw.hashCode() + "->" + hw2.hashCode());
          11 

          可以看到現(xiàn)在獲取的實(shí)例已經(jīng)是單例的,不再每次請(qǐng)求生成一個(gè)新的實(shí)例。事實(shí)上Guice提供兩種Scope,com.google.inject.Scopes.SINGLETON和com.google.inject.Scopes.NO_SCOPE,所謂沒有scope即是每次生成一個(gè)新的實(shí)例。

          對(duì)于自動(dòng)注入就非常簡(jiǎn)單了,只需要在實(shí)現(xiàn)類加一個(gè)Singleton注解即可。

          1     @Singleton
          2     public class HelloWorldImpl implements HelloWorld {
          3 
          4         @Override
          5         public String sayHello() {
          6             return "Hello, world!";
          7         }
          8     }
          9
          附:【前沿】本教程的依賴注入部分基于老菜鳥叮咚的教程,原文在此http://www.family168.com/tutorial/guice/html/。原文主要基于Google Guice 1.0版本的,本文基于Google Guice 2.0版本進(jìn)行學(xué)習(xí)和討論。

          下一篇:Google Guice 入門教程02 - 依賴注入(2)


          ©2009-2014 IMXYLZ |求賢若渴
          posted on 2009-12-22 23:28 imxylz 閱讀(35762) 評(píng)論(5)  編輯  收藏 所屬分類: J2EE 、Google Guice

          評(píng)論

          # re: Google Guice 入門教程01 - 依賴注入 2009-12-23 09:49 字典
          不錯(cuò)  回復(fù)  更多評(píng)論
            

          # re: Google Guice 入門教程01 - 依賴注入(1)[未登錄] 2010-07-01 09:57 Sam
          Very Nice!  回復(fù)  更多評(píng)論
            

          # re: Google Guice 入門教程01 - 依賴注入(1) 2011-06-15 23:32 RunCode
          不錯(cuò)  回復(fù)  更多評(píng)論
            

          # re: Google Guice 入門教程01 - 依賴注入(1) 2012-07-25 19:00 怒破
          博主小哥,你認(rèn)識(shí)張民松嗎  回復(fù)  更多評(píng)論
            

          # re: Google Guice 入門教程01 - 依賴注入(1)[未登錄] 2016-03-05 14:12 yong
          Guice的實(shí)現(xiàn)方式不太優(yōu)雅,在配置的繼承重用和annotation侵入性上有問題,我最近做了一個(gè)小項(xiàng)目叫jBeanBox (不能發(fā)鏈接,請(qǐng)Google之) 。特點(diǎn):1.只用單個(gè)Java文件350行源碼實(shí)現(xiàn)完整IOC/AOP 2.用Java類代替XML作為配置,支持IDE重構(gòu),無侵入性(沒用annotation),敬請(qǐng)?jiān)u價(jià)。  回復(fù)  更多評(píng)論
            


          ©2009-2014 IMXYLZ
          主站蜘蛛池模板: 深水埗区| 井研县| 交城县| 韩城市| 邯郸县| 偏关县| 南昌县| 岳普湖县| 乌鲁木齐县| 绥滨县| 罗田县| 阿图什市| 新和县| 汶川县| 调兵山市| 郧西县| 秦安县| 寻甸| 托克逊县| 麟游县| 同仁县| 新竹市| 雅安市| 海宁市| 上思县| 林西县| 堆龙德庆县| 清徐县| 吴堡县| 淮南市| 容城县| 汕头市| 米泉市| 峡江县| 鲜城| 大竹县| 成安县| 金山区| 成武县| 邓州市| 林周县|