xylz,imxylz

          關注后端架構、中間件、分布式和并發編程

             :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks

          6 Guice的IOC容器

          6.1 注入過程

          在前面的教程中我們講了Guice注入例子,在使用上具體描述了Guice的注入過程。在下面的篇幅中我們從源碼級了解了Guice的注入過程。

          我們從具體到抽象再到具體的深入了解Guice的內部運作機制 。

          下面一張序列圖就是描述了Guice最簡單的一次注入過程。比如下面的例子是我們熟悉的。

           1 public class HelloWorldDemo {
           2     public static void main(String[] args) {
           3         Injector inj = Guice.createInjector(new Module() {
           4             @Override
           5             public void configure(Binder binder) {
           6                 binder.bind(HelloWorld.class).to(HelloWorldImpl.class);
           7             }
           8         });
           9         HelloWorld hw = inj.getInstance(HelloWorld.class);
          10         hw.sayHello();
          11         //
          12     }
          13 }

           

           

          GuiceInject01

          從上面的圖像可以看到我們的核心是Guice如何將我們的實例注入到Injector中的,這樣客戶端才能在Injector查找我們需要的服務。

          我們進入Guice的createInjector方法,看看Guice到底做了什么操作。

          public static Injector createInjector(Module modules) {
              
          return createInjector(Arrays.asList(modules));
            }
             
          public static Injector createInjector(Iterable<? extends Module> modules) {
              
          return createInjector(Stage.DEVELOPMENT, modules);
            }
            
          public static Injector createInjector(Stage stage, Module modules) {
              
          return createInjector(stage, Arrays.asList(modules));
            }
            
          public static Injector createInjector(Stage stage,
                Iterable
          <? extends Module> modules) {
              
          return new InjectorBuilder()
                  .stage(stage)
                  .addModules(modules)
                  .build();
            }

           

          從上面的代碼可以看到我們的Injector是被InjectorBuilder以Builder的模式構造出來的。同時我們也可以注入多個Module,并且默認情況下Guice是以Stage.DEVELOPMENT模式運行的。

          在進入我們最核心的InjectorBuilder之前,我們先簡化下模型。所謂的IOC容器,或者說DI容器,我們可以看做是一個特殊的Map,這個Map能夠將我們的對象按照某種Key(鍵值)的方式存入,然后客戶端能夠根據Key來獲取我們的對象。因此為了了解Guice容器的內部結構,我們先要了解下Guice容器中存放一個對象的Key到底是什么。

          6.2 容器Key

          在Guice中用com.google.inject.Key<T>對象來描述一個實例可以對應的Key。

          我們可以想象,如果我們以某種類型來從Map中獲取結果,那么對于同一種類型每次獲取的結果就一樣。看似滿足需求。但是如果某一種類型對應多種實例怎么辦?這種情況下我們就需要我們的Key不僅支持類型,還附帶另外一點點東西。Guice是完全基于Annotation的,沒有類似spring那樣唯一id的概念,于是在Guice中描述一個Key就是靠類型和注解來完成的。在基礎教程中我們看到了對于同一種類型,加了不同的注解獲取的就是不同的實例。

          在Java中每一個對象都有一個類型的概念,即使私有類型比如int,boolean也是有類型的概念,但是自從Java 5推出泛型以后,一直沒有一種描述泛型的類型。比如說List<String>在Java中使用List類型來描述的。但是盡管JVM有運行時擦除泛型的特點,卻又有能夠獲取編譯前類型的特性,因此實際上List<String>和List<Integer>對于我們來說應該是兩種不同的類型。

          Guice自創造了一種描述類型的方式,包括泛型類型。在Guice中使用com.google.inject.TypeLiteral<T>類描述所有的類型(包括泛型類型)。我們可以寫一個小的例子來看看。

          /**
          * $Id: TypeLiteralDemo.java 110 2010-01-08 03:06:53Z xylz $
          * xylz study project (www.imxylz.cn)
          */
          package cn.imxylz.study.guice.inner;
          import java.lang.reflect.Method;
          import java.util.HashMap;
          import java.util.Map;
          import com.google.inject.TypeLiteral;
          /** a demo for using {@link TypeLiteral}
          @author xylz (www.imxylz.cn)
          @version $Rev: 110 $
          */
          public class TypeLiteralDemo {
              
          public static void main(String[] args) throws Exception{
                  
          //
                  System.out.println(String.format("guice type:%s", TypeLiteral.get(Boolean.class)));
                  System.out.println(String.format(
          "java type:%s", Boolean.class));
                  System.out.println();
                  
          //
                  System.out.println(String.format("guice type:%s", TypeLiteral.get(int.class)));
                  System.out.println(String.format(
          "java type:%s"int.class));
                  System.out.println();
                  
          //
                  System.out.println(String.format("guice type:%s"new TypeLiteral<Map<Integer, String>>(){}));
                  System.out.println(String.format(
          "java type:%s"new HashMap<Integer,String>().getClass()));
                  System.out.println();
                  
          //
                  Method m = Map.class.getMethod("keySet"new Class[0]);
                  System.out.println(String.format(
          "java type:%s", m.getReturnType()));
                  System.out.println(String.format(
          "java generic type:%s", m.getGenericReturnType()));
                  System.out.println(String.format(
          "guice type:%s", TypeLiteral.get(m.getGenericReturnType())));
                  System.out.println();
                  TypeLiteral
          <Map<Integer, String>> mapType = new TypeLiteral<Map<Integer, String>>() {};
                  System.out.println(String.format(
          "guice type:%s", mapType.getReturnType(m)));
              }
          }

           

          下面是一次輸出結果。

          guice type:java.lang.Boolean
          java type:
          class java.lang.Boolean
          guice type:
          int
          java type:
          int
          guice type:java.util.Map
          <java.lang.Integer, java.lang.String>
          java type:
          class java.util.HashMap
          java type:
          interface java.util.Set
          java generic type:java.util.Set
          <K>
          guice type:java.util.Set
          <K>
          guice type:java.util.Set
          <java.lang.Integer>

           

          從上面的結果可以看出,Java通過一些反射機制描述了部分泛型的類型(使用java.lang.reflect.ParameterizedType來描述,其它類型使用java.lang.reflect.Type來描述,注意Class是實現了Type接口的),但是并不完整,因此Guice重寫了這部分。

           

          image

          在上面的類圖中我們可以看到,一個key是包含一個類型描述(TypeLiteral)和一個AnnotationStrategy的。AnnotationStrategy是由Annotation以及Annotation的類型組成。而TypeLiteral包含私有類型Class和對Key的引用的。

          總之在Guice中是通過類型描述和注解(Key)來完整實例描述的,通過一個Key就我們能夠從Guice容器(Injector)中獲取我們需要的實例,至于這個實例是單個實例還是一組實例(Set或者Map類型的實例),后面會繼續探討。

          上一篇:Google Guice 高級教程01 - 源碼目錄

          下一篇:待續



          ©2009-2014 IMXYLZ |求賢若渴
          posted on 2010-01-08 11:46 imxylz 閱讀(28088) 評論(6)  編輯  收藏 所屬分類: Google Guice

          評論

          # re: Google Guice 高級教程02 - Guice的IOC容器(1) 2010-01-08 12:30 凡客誠品官方網站
          順風使舵模仿  回復  更多評論
            

          # re: Google Guice 高級教程02 - Guice的IOC容器(1) 2010-01-12 09:34 ruanchao
          好,多謝,希望有jersey與Guice結合的介紹。  回復  更多評論
            

          # re: Google Guice 高級教程02 - Guice的IOC容器(1) 2011-03-18 17:06 forge
          您覺得Weld和Guice哪個更具優勢  回復  更多評論
            

          # re: Google Guice 高級教程02 - Guice的IOC容器(1) 2011-03-18 17:22 xylz
          @forge
          Weld不熟悉,為了此問題特地去看了官方站點http://seamframework.org/Weld。我感覺從官方態度以及規范、支持力度來看的話Weld可能比較有權威性,畢竟指定此規范JSR299(http://jcp.org/en/jsr/detail?id=299)的人就是RedHat自家的人。另外上面的貢獻者也比較多,說明項目可能比較活躍。
          Guice來說由于是輕量級的,所以可能比較容易使用和受關注,而且開發者也是比較有激情的小伙子,但是官方站點http://code.google.com/p/google-guice/的更新有點慢,活躍度明顯放緩,并且文檔、知識庫、論壇也不全。
          結論是,從使用以及規范角度上講選用Weld(畢竟在Seam中大力推廣,而且Jboss也有一套完整的解決方案)是比較合適的,從流行技術上倒是可以關注Guice。當然也不排除Guice發展壯大了以至于影響整個J2EE,就像當初SPRING對EJB的挑戰一樣。  回復  更多評論
            

          # re: Google Guice 高級教程02 - Guice的IOC容器(1)[未登錄] 2011-03-30 12:36 kevin
          快點更新哦,博主太NB了,偶然看到這個網站,寫得很好,收藏這個網址了。  回復  更多評論
            

          # re: Google Guice 高級教程02 - Guice的IOC容器(1) 2013-07-03 11:00 路過
          求持續更新。。。  回復  更多評論
            


          ©2009-2014 IMXYLZ
          主站蜘蛛池模板: 陆良县| 洛南县| 固安县| 平湖市| 三江| 河南省| 和平区| 霍山县| 铅山县| 榆中县| 沁源县| 邮箱| 宝应县| 济宁市| 延津县| 莆田市| 黄石市| 项城市| 信丰县| 浏阳市| 嘉善县| 岫岩| 聂拉木县| 满洲里市| 伊吾县| 名山县| 新干县| 延庆县| 和平县| 东城区| 宁乡县| 定西市| 兴化市| 广南县| 财经| 唐河县| 三台县| 梁平县| 乃东县| 合水县| 安宁市|