xylz,imxylz

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

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

          本章節繼續討論依賴注入的其他話題,包括作用域(scope,這里有一個與線程綁定的作用域例子)、立即初始化(Eagerly Loading Bindings)、運行階段(Stage)、選項注入(Optional Injection)等等。

          1.3.5 Scope(作用域)

          在1.1章節中我們初步了解了對象的單例模式,在Guice中提供了一些常見的作用域,比如對于單例模式有下面兩個作用域。


              com.google.inject.Scopes.SINGLETON

              com.google.inject.Scopes.NO_SCOPE

          在使用上,可以使用Module的bind來實現,看下面的例子。


           1     public class ScopeDemo {
           2         public static void main(String[] args) {
           3 
           4             Service service = Guice.createInjector(new Module() {
           5                 @Override
           6                 public void configure(Binder binder) {
           7                     binder.bind(Service.class).to(WwwService.class).in(Scopes.SINGLETON);
           8                 }
           9             }).getInstance(Service.class);
          10             service.execute();
          11         }
          12     }
          13 
          14 

          當然單例模式還可以似乎用@Singleton注解。

          在com.google.inject.binder.ScopedBindingBuilder.in(Scope)方法中,一個Scope除了可以使上面的SINGLETION和NO_SCOPE外,還可以是自己定義的Scope。下面的例子演示了一個與線程綁定的Scope例子。

           1 /**
           2  * $Id: ThreadScopeDemo.java 90 2009-12-25 08:12:21Z 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.Injector;
          10 import com.google.inject.Key;
          11 import com.google.inject.Module;
          12 import com.google.inject.Provider;
          13 import com.google.inject.Scope;
          14 
          15 /** a demo with thread-scope
          16  * @author xylz (www.imxylz.cn)
          17  * @version $Rev: 90 $
          18  */
          19 public class ThreadScopeDemo {
          20 
          21     static class ThreadServiceScope implements Scope {
          22 
          23         static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();
          24 
          25         @Override
          26         public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
          27             return new Provider<T>() {
          28                 @Override
          29                 public T get() {
          30                     T instance = (T) threadLocal.get();
          31                     if (instance == null) {
          32                         instance = unscoped.get();
          33                         threadLocal.set(instance);
          34                     }
          35                     return instance;
          36                 }
          37             };
          38         }
          39 
          40         @Override
          41         public String toString() {
          42             return "Scopes.ThreadServiceScope";
          43         }
          44     }
          45     
          46     public static void main(String[] args) {
          47         final Injector inj=Guice.createInjector(new Module() {
          48             @Override
          49             public void configure(Binder binder) {
          50                 binder.bind(Service.class).to(WwwService.class).in(new ThreadServiceScope());
          51             }
          52         });
          53         for(int i=0;i<3;i++) {
          54             new Thread("Thread-"+i) {
          55                 public void run() {
          56                     for(int m=0;m<3;m++) {
          57                         System.out.println(String.format("%s-%d:%d",//
          58                                 getName()//
          59                                 ,m//
          60                                 ,inj.getInstance(Service.class).hashCode()));
          61                         try {
          62                             Thread.sleep(50L);
          63                         } catch (Exception e) {
          64                         }
          65                     }
          66                 }
          67             }.start();
          68         }
          69     }
          70 }
          71 

          注意,這里用到了《Google Guice 入門教程03 - 依賴注入》的中的兩個類Service和WwwService。在本例中ThreadServiceScope類是一個與線程綁定的作用域(利用ThreadLocal特性),當當前線程中沒有構造一個對象的時候先構造一個出來,然后放入線程上下文中,以后每次都從線程中獲取對象。第50行是將WwwService服務以ThreadServiceScope的作用域綁定到Service服務上。第57-60行輸出當前對象的hashCode,如果此類是同一對象的話就應該輸出相同的hashCode。為了看到效果,我們使用3個線程,每個線程輸出三次來看結果。

          Thread-0-0:18303751
          Thread-1-0:23473608
          Thread-2-0:21480956
          Thread-1-1:23473608
          Thread-0-1:18303751
          Thread-2-1:21480956
          Thread-1-2:23473608
          Thread-2-2:21480956
          Thread-0-2:18303751

          我們看到對于同一個線程(比如說Thread-0)的三次都輸出了相同的對象(hashCode為18303751),而與線程2和線程3的hashCode不同。

          (特別說明:如果兩個線程輸出了同一個hashCode不必驚慌,那是因為可能前一個線程生成的對象的地址空間被GC釋放了,結果下一個線程使用了上一個線程的相同空間,所以這里使用Thread.sleep來降低這種可能性)

          事實上在guice-servlet-2.0.jar中有與request和session綁定的scope。

          com.google.inject.servlet.ServletScopes.REQUEST
          com.google.inject.servlet.ServletScopes.SESSION

          1.3.6 Eagerly Loading Bindings (立即初始化)

          除了可以綁定scope外,對象默認在第一次調用時被創建,也即所謂的延時加載,Guice也允許對象在注入到Guice容器中時就被創建出來(顯然這是針對單例模式才有效)。

           1 public class EagerSingletonDemo {
           2 
           3     public EagerSingletonDemo() {
           4         System.out.println(" constuctor:"+System.nanoTime());
           5     }
           6     void doit() {
           7         System.out.println("       doit:"+System.nanoTime());
           8     }
           9     public static void main(String[] args) throws Exception{
          10         Injector inj = Guice.createInjector(new Module() {
          11             @Override
          12             public void configure(Binder binder) {
          13                 binder.bind(EagerSingletonDemo.class).asEagerSingleton();
          14             }
          15         });
          16         System.out.println("before call:"+System.nanoTime());
          17         Thread.sleep(100L);
          18         inj.getInstance(EagerSingletonDemo.class).doit();
          19     }
          20 }

          結果輸出如下:

           constuctor:26996967388652
          before call:
          26996967713635
                 doit:
          26997069993702

          可以看到我們的對象在調用getInstance之前就已經被構造出來了。

          1.3.7 Stages (運行階段)

          Guice還有一個特效,可以指定Guice運行模式來控制Guice的加載速度。在com.google.inject.Stage枚舉中提供了TOOL,DEVELOPMENT,PRODUCTION三種模式。

          TOOL描述的是帶有IDE等插件的運行模式;DEVELOPMENT是指在開發階段只加載自己需要的功能(對于非立即初始化單例對象采用延后加載),這樣來降低加載不需要功能的時間;而PRODUCTION模式是指完全加載所有功能(對于單例對象采用立即加載方式),這樣可以更早的發現問題,免得等需要某些功能的時候才發現問題(要知道我們某些功能可能需要特定的條件才能觸發)。

          其實只有比較多的單例對象,并且單例對象構造比較耗時的情況下才能有用。大部分情況下這點性能可能都忽略不計了。

          默認情況下Guice采用DEVELOPMENT模式。


          1.3.8 Optional Injection (選項注入 )

          選項注入描述的是如果不能從Guice容器中注入一個對象,那么可以使用一個默認的對象。看下面的例子。

           1 public class OptionalInjectionDemo {
           2     @Inject(optional=true)
           3     Service service = new WwwService();
           4     public static void main(String[] args) {
           5         Guice.createInjector(new Module() {
           6             public void configure(Binder binder) {
           7                 //binder.bind(Service.class).to(HomeService.class);
           8             }
           9         }).getInstance(OptionalInjectionDemo.class).service.execute();
          10     }
          11 }

          上述例子中第2行描述的是選項注入,如果不能從Guice容器中獲取一個Service服務那么就使用默認的WwwService,否則就是用獲取的服務。如果將第7行注釋去掉我們就可以看到實際上調用的是HomeService服務了。


          到此為止,Guice依賴注入的基本教程就學習完了,下面的章節我們進入經典的AOP教程學習。

          上一篇:Google Guice 入門教程03 - 依賴注入(3)

          下一篇:Google Guice 入門教程05 - AOP(面向切面編程)



          ©2009-2014 IMXYLZ |求賢若渴
          posted on 2009-12-25 18:02 imxylz 閱讀(16634) 評論(1)  編輯  收藏 所屬分類: J2EEGoogle Guice

          評論

          # re: Google Guice 入門教程04 - 依賴注入(4)[未登錄] 2011-03-30 12:28 kevin
          寫得 很好 學習了  回復  更多評論
            


          ©2009-2014 IMXYLZ
          主站蜘蛛池模板: 东乡县| 赤城县| 修武县| 宽甸| 介休市| 宁强县| 玛纳斯县| 大丰市| 佛山市| 昭通市| 泸西县| 延川县| 靖宇县| 博爱县| 云和县| 长乐市| 明水县| 东辽县| 梨树县| 沧源| 德令哈市| 海门市| 黄骅市| 理塘县| 宁都县| 鄂尔多斯市| 新邵县| 临漳县| 镇安县| 高安市| 沙田区| 仙桃市| 萝北县| 名山县| 永昌县| 视频| 岳西县| 仙桃市| 博罗县| 岚皋县| 中西区|