<code id="qf3hh"></code>
  • <menuitem id="qf3hh"></menuitem>
  • <strike id="qf3hh"><label id="qf3hh"></label></strike>

  • ?
      開(kāi)發(fā)技術(shù) / Technology

      Google Guice使用入門(mén)

      日期:2015年1月29日  作者:zhjw  來(lái)源:互聯(lián)網(wǎng)    點(diǎn)擊:960

      下載Google Guice之后,有以下幾個(gè)文件:

      Java代碼
      1. aopalliance.jar   
      2. guice-1.0.jar   
      3. guice-servlet-1.0.jar   
      4. guice-spring-1.0.jar   
      5. guice-struts2-plugin-1.0.jar  

      本例只使用到guice-1.0.jar文件,將其加入到class path中。

      下面簡(jiǎn)單地介紹范例:

      范例1:使用com.google.inject.Module接口實(shí)現(xiàn)類(lèi)
       

       

      文件名
      說(shuō)明
      HelloGuice.java
      業(yè)務(wù)邏輯接口定義文件
      HelloGuiceImpl.java
      業(yè)務(wù)邏輯接口實(shí)現(xiàn)文件
      HelloGuiceModule.java
      該文件必須實(shí)現(xiàn)com.google.inject.Module接口
      TestGuice.java
      測(cè)試文件

       

      HelloGuice.java

      Java代碼
      1. package cn.jcourse.guice;   
      2.   
      3. /**  
      4.  * HelloGuice接口,用于表達(dá)問(wèn)候  
      5.  */  
      6. public interface HelloGuice {   
      7.     public void sayHello();   
      8. }   

      上面接口中,我們定義了一個(gè)方法,sayHello,用于向用戶(hù)問(wèn)候。這里我只是做演示用,在實(shí)際的業(yè)務(wù)中,業(yè)務(wù)邏輯很可能不是這么簡(jiǎn)單。

      HelloGuiceImpl.java
       

      Java代碼
      1. package cn.jcourse.guice.impl;   
      2.   
      3. import cn.jcourse.guice.HelloGuice;   
      4.   
      5. /**    
      6.  * HellGuice實(shí)現(xiàn)類(lèi)  
      7.  */  
      8. public class HelloGuiceImpl implements HelloGuice {   
      9.   
      10.     /* (non-Javadoc)  
      11.      * @see cn.jcourse.guice.HelloGuice#sayHello()  
      12.      */  
      13.     public void sayHello() {   
      14.         System.out.println("Hello Guice!");   
      15.     }   
      16. }  

      該類(lèi)是HelloGuice接口的實(shí)現(xiàn)類(lèi),這里我們僅僅是向控制臺(tái)輸出了一個(gè)Hello Guice!字符串。

      HelloGuiceModule.java
       

      Java代碼
      1. package cn.jcourse.guice;   
      2.   
      3. import cn.jcourse.guice.impl.HelloGuiceImpl;   
      4.   
      5. import com.google.inject.Binder;   
      6. import com.google.inject.Module;   
      7. /**   
      8.  * HelloGuice模塊  
      9.  */  
      10. public class HelloGuiceModule implements Module {   
      11.   
      12.     /*  
      13.      * (non-Javadoc)  
      14.      *   
      15.      * @see com.google.inject.Module#configure(com.google.inject.Binder)  
      16.      */  
      17.     public void configure(Binder binder) {   
      18.         binder.bind(HelloGuice.class).to(HelloGuiceImpl.class);   
      19.     }   
      20. }  

      上面的代碼用于告知Guice將接口和實(shí)現(xiàn)類(lèi)綁定。

      TestGuice.java
       

      Java代碼
      1. package cn.jcourse.guice.test;   
      2.   
      3. import cn.jcourse.guice.HelloGuice;   
      4. import cn.jcourse.guice.HelloGuiceModule;   
      5.   
      6. import com.google.inject.Guice;   
      7. import com.google.inject.Injector;   
      8.   
      9. import junit.framework.TestCase;   
      10.   
      11. /**   
      12.  * 測(cè)試Guice  
      13.  */  
      14. public class TestGuice extends TestCase {   
      15.     public void testHelloGuice() {   
      16.         Injector injector = Guice.createInjector(new HelloGuiceModule());   
      17.         HelloGuice helloGuice = injector.getInstance(HelloGuice.class);   
      18.         helloGuice.sayHello();   
      19.     }   
      20. }  

      上面的代碼我們使用JUnit來(lái)進(jìn)行單元測(cè)試,這里的代碼也相對(duì)比較簡(jiǎn)單。

      在編寫(xiě)完上述代碼后,我們運(yùn)行TestGuice類(lèi),將會(huì)發(fā)現(xiàn)它向控制臺(tái)輸出了Hello Guice!。

      范例2:使用Java Annotation

      范例1中,我們自己手工的去配置了綁定關(guān)系,當(dāng)然我們也可以不用那么做。我們可以直接為HelloGuice加上@ImplementedBy注釋?zhuān)÷缘魧?duì)com.google.inject.Module的實(shí)現(xiàn)。

      HelloGuice.java
       

      Java代碼
      1. package cn.jcourse.guice;   
      2.   
      3. import cn.jcourse.guice.impl.HelloGuiceImpl;   
      4.   
      5. import com.google.inject.ImplementedBy;   
      6.   
      7. /**    
      8.  * HelloGuice接口,用于表達(dá)問(wèn)候  
      9.  */  
      10. @ImplementedBy(HelloGuiceImpl.class)   
      11. public interface HelloGuice {   
      12.     public void sayHello();   
      13. }   

      這里我們使用了Guice提供的注解,ImplementedBy,表示該接口由HelloGuiceImpl類(lèi)實(shí)現(xiàn)。這樣我們就可以不手動(dòng)的去配置依賴(lài)關(guān)系。再看看TestGuice.java。

      TestGuice.java
       

      Java代碼
      1. package cn.jcourse.guice.test;   
      2.   
      3. import junit.framework.TestCase;   
      4. import cn.jcourse.guice.HelloGuice;   
      5.   
      6. import com.google.inject.Guice;   
      7. import com.google.inject.Injector;   
      8.   
      9. /**     
      10.  * 測(cè)試Guice  
      11.  */  
      12. public class TestGuice extends TestCase {   
      13.     public void testHelloGuice() {   
      14.         //Injector injector = Guice.createInjector(new HelloGuiceModule());   
      15.            
      16.         Injector injector = Guice.createInjector();   
      17.            
      18.         HelloGuice helloGuice = injector.getInstance(HelloGuice.class);   
      19.         helloGuice.sayHello();   
      20.     }   
      21. }  

      可以看出,我們不需要自己去new一個(gè)Module了,Guice會(huì)根據(jù)我們提供的注解自己來(lái)配置依賴(lài)關(guān)系。

      我們運(yùn)行例子的時(shí)候可以看出,它也輸出了Hello Guice!到控制臺(tái)。

       

       

       

      通過(guò) Guice 進(jìn)行依賴(lài)項(xiàng)注入(1)

      本教程是轉(zhuǎn)載教程,目的是讓大家了解又一個(gè)很強(qiáng)大的依賴(lài)注入框架Guice.

      Guice 是一個(gè)依賴(lài)項(xiàng)注入(DI)框架。幾年來(lái)我一直建議開(kāi)發(fā)人員使用 DI,因?yàn)樗岣吡丝删S護(hù)性、可測(cè)試性和靈活性。通過(guò)觀察工程師對(duì) Guice 的反饋,我發(fā)現(xiàn)說(shuō)服程序員去采用一種新技術(shù)的最好方法是使這種技術(shù)簡(jiǎn)單易用。Guice 讓 DI 變得很簡(jiǎn)單,因此 Google 采用了這種方法。我希望本文能幫助您輕松學(xué)習(xí) Guice。

      Guice 2.0 beta

      在寫(xiě)這篇文章時(shí),Guice 開(kāi)發(fā)團(tuán)隊(duì)正在奮力編寫(xiě) Guice 2.0,希望能在 2008 年底之前發(fā)布。早期的 beta 發(fā)布在 Google 代碼下載站點(diǎn)。這是一個(gè)好消息,因?yàn)?Guice 團(tuán)隊(duì)添加了一些新功能,使 Guice 代碼的使用和理解變得更簡(jiǎn)單。beta 版沒(méi)有最終版中的一些功能,但是 beta 很穩(wěn)定,質(zhì)量也很好。事實(shí)上,Google 在產(chǎn)品軟件中使用的是 beta 版。我建議您使用 beta 版。這篇文章是專(zhuān)門(mén)為 Guice 2.0 編寫(xiě)的,介紹了 Guice 的一些新功能,但沒(méi)有討論 1.0 中已經(jīng)廢棄的一些功能。Guice 團(tuán)隊(duì)向我保證:這里討論的功能在最終發(fā)行版和當(dāng)前 beta 版中都是一樣的。

      如果您已經(jīng)了解了 DI,而且知道為什么要借助一個(gè)框架來(lái)使用 DI,那么您可以跳到 通過(guò) Guice 進(jìn)行基本注入 小節(jié)。否則,請(qǐng)繼續(xù)閱讀,了解 DI 的好處。

      DI 案例

      我將以一個(gè)例子開(kāi)始。假設(shè)我正在編寫(xiě)一個(gè)超級(jí)英雄(superhero)應(yīng)用程序,同時(shí)實(shí)現(xiàn)一個(gè)名為 Frog Man 的 hero(英雄)。清單 1 是相關(guān)代碼和第一個(gè)測(cè)試(您一定明白編寫(xiě)單元測(cè)試的重要性,這里就不多說(shuō)了)。

      清單 1. 一個(gè)基本 hero 及其測(cè)試

      Java代碼
      1. public class FrogMan {   
      2.   private FrogMobile vehicle = new FrogMobile();   
      3.   public FrogMan() {}   
      4.   // crime fighting logic goes here...   
      5. }   
      6.   
      7. public class FrogManTest extends TestCase {   
      8.  public void testFrogManFightsCrime() {   
      9.     FrogMan hero = new FrogMan();   
      10.     hero.fightCrime();   
      11.     //make some assertions...   
      12.   }   
      13. }  

      似乎一切正常,但在運(yùn)行測(cè)試時(shí)出現(xiàn)了如清單 2 所示的異常:

      清單 2. 依賴(lài)項(xiàng)出現(xiàn)問(wèn)題

      Java代碼
      1. java.lang.RuntimeException: Refinery startup failure.   
      2.   at HeavyWaterRefinery.<init>(HeavyWaterRefinery.java:6)   
      3.   at FrogMobile.<init>(FrogMobile.java:5)   
      4.   at FrogMan.<init>(FrogMan.java:8)   
      5.   at FrogManTest.testFrogManFightsCrime(FrogManTest.java:10)  

      似乎 FrogMobile 構(gòu)建了一個(gè) HeavyWaterRefinery,假設(shè)我不能在測(cè)試中構(gòu)建其中一個(gè)依賴(lài)項(xiàng)。當(dāng)然,我可以在生產(chǎn)環(huán)境中實(shí)現(xiàn)這一點(diǎn),但是不能保證能在測(cè)試中構(gòu)建第二個(gè)提煉廠(refinery)。在現(xiàn)實(shí)生活中,您不可能提煉出氧化氘,但您可以依賴(lài)遠(yuǎn)程服務(wù)器和強(qiáng)大的數(shù)據(jù)庫(kù)。原理是一樣的:這些依賴(lài)項(xiàng)很難啟動(dòng),交互起來(lái)也很慢,這使得測(cè)試比平時(shí)更容易失敗。

      輸入 DI

      為了避免這個(gè)問(wèn)題,您可以創(chuàng)建一個(gè)接口(例如 Vehicle),使 FrogMan 類(lèi)接受 Vehicle 作為一個(gè)構(gòu)造函數(shù)參數(shù),如清單 3 所示:

      清單 3. 依賴(lài)接口并注入它們

      Java代碼
      1. public class FrogMan {   
      2.   private Vehicle vehicle;   
      3.   
      4.   public FrogMan(Vehicle vehicle) {   
      5.     this.vehicle = vehicle;   
      6.   }   
      7.   // crime fighting logic goes here...   
      8. }  

      這種用法就是 DI 的本質(zhì) — 使類(lèi)通過(guò)引用接口而不是構(gòu)建接口(或使用靜態(tài)引用)來(lái)接受它們的依賴(lài)項(xiàng)。清單 4 顯示了 DI 如何使測(cè)試變得更簡(jiǎn)單:

      清單 4. 測(cè)試可以使用 mock 而不是麻煩的依賴(lài)項(xiàng)

      Java代碼
      1. static class MockVehicle implements Vehicle {   
      2.   boolean didZoom;   
      3.   
      4.   public String zoom() {   
      5.     this.didZoom = true;   
      6.     return "Mock Vehicle Zoomed.";   
      7.   }   
      8. }   
      9.   
      10. public void testFrogManFightsCrime() {   
      11.   MockVehicle mockVehicle = new MockVehicle();   
      12.   
      13.   FrogMan hero = new FrogMan(mockVehicle);   
      14.   hero.fightCrime();   
      15.   
      16.   assertTrue(mockVehicle.didZoom);   
      17.   // other assertions   
      18. }  

      這個(gè)測(cè)試使用了一個(gè)手動(dòng)編寫(xiě)的 mock 對(duì)象來(lái)替換 FrogMobile。DI 不僅在測(cè)試中省去了麻煩的 refinery 啟動(dòng)過(guò)程,而且使測(cè)試不用了解 FrogMobile 具體細(xì)節(jié)。需要的僅是一個(gè) Vehicle 接口。除了使測(cè)試變得更簡(jiǎn)單之外,DI 還有助于提高代碼的總體模塊性和可維護(hù)性?,F(xiàn)在,如果想將 FrogMobile 切換為 FrogBarge,可以不修改 FrogMan。所有 FrogMan 都依賴(lài)于 Vehicle 接口。

      不過(guò)這里有一個(gè)陷阱。如果您是第一次閱讀 DI,可能會(huì)想:“這下好了,現(xiàn)在所有 FrogMan 的調(diào)用方 都必須知道 FrogMobile(refinery、refinery 的依賴(lài)項(xiàng),依此類(lèi)推……)”。但如果是這樣,DI 就永遠(yuǎn)不會(huì)這么流行。您可以不增加調(diào)用方的負(fù)擔(dān),而是編寫(xiě)一些工廠 來(lái)管理對(duì)象及其依賴(lài)項(xiàng)的創(chuàng)建。

      工廠是存放框架的地方。工廠需要大量冗長(zhǎng)重復(fù)的代碼。工廠往往會(huì)讓程序員(和讀者)很痛苦,他們甚至?xí)铀闊┒艞壘帉?xiě)。Guice 和其他 DI 框架可作為 “超級(jí)工廠”,您可以通過(guò)配置它們來(lái)構(gòu)建對(duì)象。配置 DI 框架比自己編寫(xiě)工廠容易得多。因此,程序員編寫(xiě)的代碼大部分是 DI 樣式的。測(cè)試越多代碼就越好,程序員以后也就越省事。

      通過(guò) Guice 進(jìn)行基本注入

      我希望在我的介紹之后,您會(huì)相信 DI 能為您的設(shè)計(jì)增加價(jià)值,而且使用框架會(huì)使工作更輕松。現(xiàn)在讓我們從 @Inject 注釋和模塊開(kāi)始深入討論 Guice。

      告訴 Guice 給類(lèi)添加 @Inject

      FrogMan 與 Guice 上的 FrogMan 之間的唯一區(qū)別是 @Inject。清單 5 顯示了 FrogMan 帶有注釋的構(gòu)造函數(shù):

      清單 5. FrogMan 已經(jīng)加上 @Inject

      Java代碼
      1. @Inject  
      2. public FrogMan(Vehicle vehicle) {   
      3.   this.vehicle = vehicle;   
      4. }  

      一些工程師不喜歡給類(lèi)添加 @Inject。他們更喜歡一個(gè)完全忽略 DI 框架的類(lèi)。這種說(shuō)法有一定道理,但是我不大贊同。依賴(lài)項(xiàng)的注入會(huì)使注釋的作用更加明顯。@Inject 標(biāo)記只在您要求 Guice 構(gòu)建類(lèi)時(shí)才有意義。如果不要求 Guice 構(gòu)建 FrogMan,這個(gè)注釋對(duì)代碼行為就沒(méi)有任何影響。這個(gè)注釋恰當(dāng)?shù)刂赋隽?Guice 將參與構(gòu)建類(lèi)。但是,使用它需要源代碼級(jí)別的訪問(wèn)。如果這個(gè)注釋帶來(lái)不便,或者正在使用 Guice 創(chuàng)建無(wú)法控制其源代碼的對(duì)象,那么 Guice 就會(huì)用一個(gè)替代機(jī)制。

      告訴 Guice 您需要哪個(gè)依賴(lài)項(xiàng)

      Guice 知道您的 hero 需要一個(gè) Vehicle 后,它需要知道提供什么 Vehicle。清單 6 包含一個(gè) Module:一個(gè)特殊的類(lèi),用于告訴 Guice 各個(gè)接口對(duì)應(yīng)的實(shí)現(xiàn)。

      清單 6. HeroModule 將 Vehicle 綁定到 FrogMobile

      Java代碼
      1. public class HeroModule implements Module {   
      2.   public void configure(Binder binder) {   
      3.     binder.bind(Vehicle.class).to(FrogMobile.class);   
      4.   }   
      5. }  

      模塊就是一個(gè)具有某種單實(shí)例對(duì)象方法的接口。Guice 傳遞給模塊的 Binder 用于告訴 Guice 您想如何構(gòu)造對(duì)象。綁定程序 API 形成一種 區(qū)域特定語(yǔ)言。這種小語(yǔ)言允許您編寫(xiě)表達(dá)式代碼,比如 bind(X).to(Y).in(Z)。后面將提供更多有關(guān)綁定程序作用的例子。每次調(diào)用 bind 都會(huì)創(chuàng)建一個(gè)綁定,Guice 將使用綁定集解析注入請(qǐng)求。

      使用 Injector 啟動(dòng)

      然后,使用 Injector 類(lèi)啟動(dòng) Guice。通常需要盡早在程序中創(chuàng)建注入器。這樣 Guice 能夠幫助您創(chuàng)建大部分對(duì)象。清單 7 包含一個(gè)以 Injector 開(kāi)始的示例 main 程序:

      清單 7 使用 Injector 啟動(dòng)應(yīng)用程序

      Java代碼
      1. public class Adventure {   
      2.   public static void main(String[] args){   
      3.     Injector injector = Guice.createInjector(new HeroModule());   
      4.     FrogMan hero = injector.getInstance(FrogMan.class);   
      5.     hero.fightCrime();   
      6.   }   
      7. }  

      為了獲取注入器,需要在 Guice 類(lèi)上調(diào)用 createInjector。向 createInjector 傳遞一個(gè)模塊列表,用于配置它本身(本例只有一個(gè),但您可以添加一個(gè)配置 evildoer 的 VillainModule)。擁有注入器后,使用 getInstance 向它請(qǐng)求對(duì)象,傳遞您想返回的 .class(細(xì)心的讀者會(huì)注意到您不需要告訴 Guice 有關(guān) FrogMan 的信息。如果您請(qǐng)求一個(gè)具體類(lèi),而它有一個(gè) @Inject 構(gòu)造函數(shù)或公共非參數(shù)構(gòu)造函數(shù)的話(huà),Guice 就會(huì)創(chuàng)建這個(gè)類(lèi),而無(wú)需調(diào)用 bind)。

      這是 Guice 構(gòu)造對(duì)象的第一種方式:顯式詢(xún)問(wèn)。但是,您不會(huì)希望在啟動(dòng)例程之外使用這個(gè)操作。更好、更簡(jiǎn)單的方式是讓 Guice 注入依賴(lài)項(xiàng)、依賴(lài)項(xiàng)的依賴(lài)項(xiàng),依此類(lèi)推(正如諺語(yǔ)所說(shuō):“背起地球的海龜站在另一個(gè)海龜?shù)谋成?rdquo;)。最初看來(lái),這似乎比較麻煩,但您很快就會(huì)習(xí)慣這種用法。例如,清單 8 顯示了一個(gè)注入了 FuelSource 的 FrogMobile:

      清單 8. FrogMobile 接受一個(gè) FuelSource

      Java代碼
      1. @Inject  
      2. public FrogMobile(FuelSource fuelSource){   
      3.   this.fuelSource = fuelSource;   
      4. }  

      這意味著,當(dāng)您檢索 FrogMan 時(shí),Guice 會(huì)構(gòu)建一個(gè) FuelSource、一個(gè) FrogMobile,最后是一個(gè) FrogMan。即使應(yīng)用程序與注入器只交互一次,也是如此。

      當(dāng)然,您并不總是有機(jī)會(huì)控制應(yīng)用程序的 main 例程。例如,許多 Web 框架自動(dòng)構(gòu)建 “操作”、“模板” 或其他一些初始服務(wù)??偸强梢哉业揭粋€(gè)地方插入 Guice,不管是使用該框架的一個(gè)插件,還是使用一些自己手動(dòng)編寫(xiě)的代碼(例如,Guice 項(xiàng)目發(fā)布了一個(gè) Struts 2 插件,它允許 Guice 配置您的 Strut 操作)。

       

       

      通過(guò) Guice 進(jìn)行依賴(lài)項(xiàng)注入(2)

       

      其他注入形式

      到目前為止,我展示了 @Inject 應(yīng)用于構(gòu)造函數(shù)的用法。當(dāng) Guice 找到注釋時(shí),它會(huì)挑選構(gòu)造函數(shù)參數(shù),并試圖為每個(gè)參數(shù)找到一個(gè)配置綁定。這稱(chēng)為 構(gòu)造函數(shù)注入。根據(jù) Guice 的最佳實(shí)踐指南,構(gòu)造函數(shù)注入是詢(xún)問(wèn)依賴(lài)項(xiàng)的首選方式。但這不是唯一的方式。清單 9 顯示了配置 FrogMan 類(lèi)的另一種方式:

      清單 9. 方法注入

      Java代碼
      1. public class FrogMan{   
      2.   private Vehicle vehicle;   
      3.   
      4.   @Inject  
      5.   public void setVehicle(Vehicle vehicle) {   
      6.     this.vehicle = vehicle;   
      7.   }   
      8. //etc. ...  

      注意,我沒(méi)有使用注入的構(gòu)造函數(shù),而是改用一個(gè)帶有 @Inject 標(biāo)記的方法。Guice 會(huì)在構(gòu)造好 hero 之后立即調(diào)用此方法。Spring 框架的忠實(shí)用戶(hù)可以將此方法視為 “setter 注入”。不過(guò),Guice 只關(guān)心 @Inject;您可以任意命名這個(gè)方法,它可以帶有多個(gè)參數(shù)。此方法可以是包保護(hù)的,也可以是私有方法。

      如果您認(rèn)為 Guice 訪問(wèn)私有方法不是很好,可以參見(jiàn)清單 10,其中 FrogMan 使用了字段注入:

      清單 10. 字段注入

      Java代碼
      1. public class FrogMan {   
      2.   @Inject private Vehicle vehicle;   
      3.   public FrogMan(){}   
      4. //etc. ...  

      同樣,所有 Guice 都只關(guān)心 @Inject 注釋。字段注入查找注釋的所有字段并試圖注入相應(yīng)的依賴(lài)項(xiàng)。

      哪種方法最好

      三個(gè) FrogMan 版本都展示了相同的行為:Guice 在構(gòu)建時(shí)注入相應(yīng)的 Vehicle。不過(guò),像 Guice 的作者一樣,我更喜歡構(gòu)造函數(shù)注入。下面簡(jiǎn)單分析這三種方式:

      • 構(gòu)造函數(shù)注入 很簡(jiǎn)單。因?yàn)?Java 技術(shù)能保證構(gòu)造函數(shù)調(diào)用,您不用擔(dān)心出現(xiàn)未初始化的對(duì)象 — 不管是不是由 Guice 創(chuàng)建的。您還可以將字段標(biāo)記為 final。
      • 字段注入 會(huì)影響可測(cè)試性,特別是將字段標(biāo)記為 private 時(shí)。這破壞了使用 DI 的主要目的。應(yīng)該盡量少使用字段注入。
      • 方法注入 在您不控制類(lèi)的實(shí)例化時(shí)很有用。如果您有一個(gè)需要某些依賴(lài)項(xiàng)的超類(lèi),也可以使用方法注入(構(gòu)造函數(shù)注入會(huì)使這種情況變得很復(fù)雜)。

      選擇實(shí)現(xiàn)

      現(xiàn)在,假設(shè)應(yīng)用程序中有多個(gè) Vehicle。一樣英勇的 Weasel Girl 無(wú)法駕馭 FrogMobile!同時(shí),您不想在 WeaselCopter 上硬編碼依賴(lài)項(xiàng)。清單 11 顯示了 Weasel Girl 請(qǐng)求一種更快的傳輸模式:

      清單 11. 使用注釋請(qǐng)求某種特定的實(shí)現(xiàn)

      Java代碼
      1. @Inject  
      2. public WeaselGirl(@Fast Vehicle vehicle) {   
      3.   this.vehicle = vehicle;   
      4. }  

      在清單 12 中,HeroModule 使用綁定函數(shù)告訴 Guice WeaselCopter 是 “很快” 的:

      清單 12. 告訴 Guice Module 中的相關(guān)注釋

      Java代碼
      1. public class HeroModule implements Module {   
      2.  public void configure(Binder binder) {   
      3.     binder.bind(Vehicle.class).to(FrogMobile.class);   
      4.     binder.bind(Vehicle.class).annotatedWith(Fast.class).to(WeaselCopter.class);   
      5.   }   
      6. }  

      注意,我選擇了一個(gè)注釋?zhuān)枋鑫蚁胍猿橄笮问矫枋龅墓ぞ叻N類(lèi)(@Fast),而不是與實(shí)現(xiàn)太接近的注釋?zhuān)ˊWeaselCopter)。如果您使用的注釋將想要的實(shí)現(xiàn)描述得太精確,就讓讀者覺(jué)得創(chuàng)建一個(gè)隱式依賴(lài)項(xiàng)。如果使用 @WeaselCopter,而且 Weasel Girl 借用了 Wombat Rocket,就會(huì)對(duì)程序員閱讀和調(diào)試代碼造成混淆。

      要?jiǎng)?chuàng)建 @Fast 注釋?zhuān)枰獜?fù)制清單 13 中的模板:

      清單 13. 復(fù)制粘貼這段代碼以創(chuàng)建一個(gè)綁定注釋

      Java代碼
      1. @Retention(RetentionPolicy.RUNTIME)   
      2. @Target({ElementType.FIELD, ElementType.PARAMETER})   
      3. @BindingAnnotation  
      4. public @interface Fast {}  

      如果您編寫(xiě)了大量 BindingAnnotations,就會(huì)得到許多這樣的小文件,每個(gè)文件只是注釋名稱(chēng)不同。如果您覺(jué)得這很繁瑣,或者需要執(zhí)行快速的原型設(shè)計(jì),可以考慮 Guice 的內(nèi)置 @Named 注釋?zhuān)邮芤粋€(gè)字符串屬性。清單 14 展示了這種替代方法:

      清單 14. 使用 @Named 代替自定義注釋

      Java代碼
      1. // in WeaselGirl   
      2. @Inject  
      3. public WeaselGirl(@Named("Fast") Vehicle vehicle) {   
      4.   //...   
      5. }   
      6.   
      7. // in HeroModule   
      8. binder.bind(Vehicle.class)   
      9.   .annotatedWith(Names.named("Fast")).to(WeaselCopter.class);  

      這種方法是可行的,但由于名稱(chēng)只在字符串內(nèi)有效,所以這不能利用編譯時(shí)檢查和自動(dòng)補(bǔ)齊??偟膩?lái)說(shuō),我更愿意自己編寫(xiě)注釋。

      如果您根本不想使用注釋?zhuān)趺崔k?即使添加 @Fast 或 @Named("Fast") 都會(huì)使類(lèi)在某種程度上影響配置本身。如果想知道如何解決這個(gè)問(wèn)題,請(qǐng)接著閱讀。

      provider 方法

      如果每次探險(xiǎn)都派遣 Frog Man,您可能會(huì)厭煩。您喜歡在每個(gè)場(chǎng)景中出現(xiàn)的 hero 是隨機(jī)的。但是,Guice 的默認(rèn)綁定程序 API 不允許出現(xiàn) “每次調(diào)用時(shí)將 Hero 類(lèi)綁定到一個(gè)不同的實(shí)現(xiàn)” 這樣的調(diào)用。不過(guò),您可以 告訴 Guice 使用一種特殊的方法來(lái)創(chuàng)建每個(gè)新的 Hero。清單 15 顯示了將一個(gè)新方法添加到 HeroModule 中,并用特殊的 @Provides 注釋進(jìn)行注釋?zhuān)?/p>

      清單 15. 使用 provider 編寫(xiě)自定義創(chuàng)建邏輯

      Java代碼
      1. @Provides  
      2. private Hero provideHero(FrogMan frogMan, WeaselGirl weaselGirl) {   
      3.   if (Math.random() > .5) {   
      4.     return frogMan;   
      5.   }   
      6.   return weaselGirl;   
      7. }  

      Guice 會(huì)自動(dòng)發(fā)現(xiàn)具有 @Provides 注釋的 Module 中的所有方法。根據(jù) Hero 的返回類(lèi)型,在您請(qǐng)求某個(gè) hero 時(shí),Guice 會(huì)進(jìn)行計(jì)算,它應(yīng)該調(diào)用 provider 方法來(lái)提供 hero。您可以為 provider 方法添加邏輯以構(gòu)建對(duì)象并在緩存中查詢(xún)它,或者通過(guò)其他方式獲得它。provider 方法是將其他庫(kù)集成到 Guice 模塊中的很好方式。它們也是從 Guice 2.0 開(kāi)始提供的新方法(Guice 1.0 中只編寫(xiě)自定義 provider 類(lèi),這比較乏味,而且更加繁瑣。如果您已經(jīng)決定使用 Guice 1.0,用戶(hù)指南中有這種舊方法的文檔,而且在本文隨附的 示例

      国产一级婬片AAA毛,无码中文精品视视在线观看,欧美日韩a人成v在线动漫,五月丁香青草久久
      <code id="qf3hh"></code>
    • <menuitem id="qf3hh"></menuitem>
    • <strike id="qf3hh"><label id="qf3hh"></label></strike>