<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    (翻譯)JavaEE6規范 CDI教程第一部分

    (譯)JavaEE6規范 CDI教程第一部分

    kuuyee  |  2011-06-11  |  JEE   CDI  

    引言

    此教程講述 DI (依賴注入),并且涵蓋了 CDI (上下文依賴注入)的一些特性,比如類型安全注解配置、替換選擇等內容。

    CDI 是依賴注入 (DI) 和攔截 (AOP) 的Java標準規范。DI 和AOP有著很高的知名度,Java需要處理DIAOP以便在此之上構建其它的標準。DIAOP是很多Java框架的基礎。

    CDIJavaEE 6的基礎。它很快就得到了 Caucho’s Resin、 IBM’s WebSphere、 Oracle’s Glassfish、 Red Hat’s JBoss和眾多應用服務器的支持。CDISpringGuice框架非常相似,就像JPA很像ORMCDI簡化了對于DIAOPAPI。如果你使用過Spring或者Guice,你會發現CDI更容易學習和使用。如果你是依賴注入(DI)的新手,那么CDI能讓你迅速理解DICDI更容易學習和使用。

    CDI能夠獨立使用也能嵌入的任何應用中。

    這個教程在發布三年之久的Spring 2.5 DI 教程 (使用Spring “new” DI 注解)之后出現并不奇怪。它將有趣的對比三年前縮寫的Spring DI注解。

    本教程設計目標

    本教程的目標是描述和解讀不包含復雜的EJB3.1和JSF的DI和CDI。

    CDI的優勢是能夠在EJB和JSF之外。本教程只關注CDI。再次聲明在本教程中沒有JSF2和EJB3.1的內容。很多文章和教程都涵蓋如何使用CDI(JEE6規范)。本教程并不是,這里只是CDI。

    本教程有完整的代碼示例,你可以下載試用。

    我們將放緩速度,逐步的從基礎開始。一旦你理解了基本原理,我們會適當的加快腳步。

    所有的示例代碼都以確保能夠運行。我們不會鍵入臨時代碼,如果代碼不能運行,那它就不屬于本教。

    示例代碼都有清晰的標題,所以你可以把教程看做一個菜單,將來你如果想使用CDI DI的某些特性,可以方便的在菜單目錄中查找示例。

    裝飾器、擴展、攔截器、范圍都不在本教程的范圍之內。

    如果這個教程通過google討論組收到足夠的反饋和評論,我將加入CDI AOP(裝飾器和攔截器)綜合教程還有擴展。

    更多的建議和反饋會鼓舞我做的更好。

    依賴注入

    依賴注入(DI)是為軟件組件提供擴展依賴的過程。DI能夠讓你的代碼架構很簡潔。

    它幫助你用測試驅動開發的方式設計接口,提供統一的方式注入依賴。例如,一個數據訪問對象(DAO)可能依賴一個數據庫連接。

    取而代之,使用JNDI查找數據庫連接,你不需要注入它。

    考慮到JNDI是徹底的翻查,DI框架取代對象查找其它準備好的對象(依賴的),一個DI容器能注入這些依賴的對象。這被成為“好萊塢原則”,“不要給我打電話(查找對象),我會打給你(注入對象)”。

    如果你接觸過CRC卡,你能想象出一個依賴就像一個合作者。一個合作者是一個對象,另一個對象需要執行它的角色。例如,就像DAO(數據訪問對象)需要一個JDBC連接對象。

    依賴注入-自動柜員機 不用CDI或Spring或Guice版

    比如說你有一個自動柜員機(ATM,在其它國家也叫自動銀行機)并需要能夠和銀行通話。它需要調用一個傳輸對象來做此事。在這個例子中,傳輸對象掌控對銀行的底層通訊。

    這個例子可以用下面兩個接口來描述:

    // AutomatedTellerMachine接口 
    package org.cdi.advocacy;

    import java.math.BigDecimal;
    public interface AutomatedTellerMachine {
    public abstract void deposit(BigDecimal bd); //存錢
    public abstract void withdraw(BigDecimal bd); //取錢
    }
    // ATMTransport接口 
    package org.cdi.advocacy;

    public interface ATMTransport {
    public void communicateWithBank(byte[] datapacket);
    }

    現在 AutomatedTellerMachine 需要一個傳輸器來執行它的意圖,也就是存錢和取錢。要執行這個任務,AutomatedTellerMachine 可能會依賴很多對象和與這些依賴合作才能完成工作。

    一個 AutomatedTellerMachine 的實現可能看起來像這樣:

    // AutomatedTellerMachineImpl類 
    package org.cdi.advocacy;
    ...
    public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {
    private ATMTransport transport;
    ...
    public void deposit(BigDecimal bd) {
    System.out.println("deposit called");
    transport.communicateWithBank(...);
    }
    public void withdraw(BigDecimal bd) {
    System.out.println("withdraw called");
    transport.communicateWithBank(...);
    }
    }

    AutomatedTellerMachineImpl 不需要關系傳輸器如何從銀行進行存款和取款操作。這是一個中間層允許我們用不同的傳輸器實現來替換,例如下面的例子:

    三個傳輸器例子:SoapAtmTransport、StandardAtmTransport和JsonAtmTransport

    //StandardAtmTransport 
    package org.cdi.advocacy;

    public class StandardAtmTransport implements ATMTransport {
    public void communicateWithBank(byte[] datapacket) {
    System.out.println("communicating with bank via Standard transport");
    ...
    }
    }
    //SoapAtmTransport 
    package org.cdi.advocacy;

    public class SoapAtmTransport implements ATMTransport {
    public void communicateWithBank(byte[] datapacket) {
    System.out.println("communicating with bank via Soap transport");
    ...
    }
    }
    //JsonRestAtmTransport 
    package org.cdi.advocacy;
    public class JsonRestAtmTransport implements ATMTransport {
    public void communicateWithBank(byte[] datapacket) {
    System.out.println("communicating with bank via JSON REST transport");
    }
    }

    注意 ATMTransport 接口的可能實現。AutomatedTellerMachineImpl 不需要關心使用的是那個傳輸器。并且,對于測試和開發,需要替換通話的真實銀行,你可以容易的通過 Mockito和EasyMock 實現,甚至你能夠編寫一個SimulationAtmTransport模擬實現用來測試。 DI的概念超越 CDI、Guice 和 Spring 。因此,你不用 CDI、Guice 或 Spring就能夠實現 DI,比如下面的例子:

    // AtmMain: 不使用CDI, Spring或Guice的DI實現 
    package org.cdi.advocacy;

    public class AtmMain {
    public void main (String[] args) {
    AutomatedTellerMachine atm = new AutomatedTellerMachineImpl();
    ATMTransport transport = new SoapAtmTransport();
    /* Inject the transport. */
    ((AutomatedTellerMachineImpl)atm).setTransport(transport);
    atm.withdraw(new BigDecimal("10.00"));
    atm.deposit(new BigDecimal("100.00"));
    }
    }

    注入不同的傳輸器只不過是調用了不同的setter方法,如下所示:

    //不使用CDI, Spring或Guice的DI實現 : setTransport 
    ATMTransport transport = new SimulationAtmTransport();
    ((AutomatedTellerMachineImpl)atm).setTransport(transport);

    假定在前面我們為 AutomateTellerMachineImpl 添加了一個 setTransport 方法。注意,你只要使用構造器參數就能替換setter方法。因此,保持 AutomateTellerMachineImpl 的接口簡潔。

    運行例子

    為了馬上能運行例子,我們為你準備了一些pom.xml文件。這里是運行例子的指令說明。

    依賴注入-自動柜員機 使用CDI版

    要使用CDI管理依賴,需要做如下工作:

    • 在META-INF資源目錄下創建一個空的bean.xml

    • 在 AutomatedTellerMachineImpl 內的 setTransport 方法上使用 @Inject 注解

    • 在 StandardAtmTransport 上標注 @Default 注解

    • 在 SoapAtmTransport 和 JsonRestAtmTransport 上標注 @Alternative 注解

    • 在 AutomatedTellerMachineImpl 上標注 @Named 注解一遍其容易被查找;給它一個命名“atm”

    • 使用CDI beanContainer查找atm,執行存款和取款

    在META-INF資源目錄下創建一個空的bean.xml

    CDI 需要有一個 bean.xml 文件放置在 META-INF 內,META-INF 可以是jar文件或classpath或web應用 WEB-INF 下的。這個文件完全可以是空的(大小為0 bytes)。如果你的war或jar內的 META-INF 目錄下沒有這個beans.xml,那么CDI將不會處理它。另外CDI將會檢索jar和war文件內的beans.xml,甚至它為0 bytes。

    META-INF/beans.xml,可能是空文件

    <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    </beans>

    注意,我們在 beans.xml 文件中使用<beans>作為根元素并帶有命名空間。盡管 beans.xml 可以完全是空的,但是加入這個起始元素是個好的習慣。這同樣可以避免IDE對0 byte的 beans.xml 發出警告。(我憎恨IDE警告,它使我分散精力)

    在AutomatedTellerMachineImpl內的setTransport方法上使用@Inject注解

    @Inject 注解用來標記要注入的位置。你可以對構造器參數、實例變量和setter方法的屬性使用此注解。在這個例子中,我們注解在setTransport 方法上(transport屬性的setter方法)。

    // AutomatedTellerMachineImpl使用@Inject注入一個transport 
    package org.cdi.advocacy;
    ...
    import javax.inject.Inject;
    public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {
    private ATMTransport transport;
    @Inject
    public void setTransport(ATMTransport transport) {
    this.transport = transport;
    }
    ...
    }

    默認情況下, CDI 將會尋找 ATMTransport 接口的實現類,一旦找到就會創建一個實例并用setter方法setTransport注入這個實例到 ATMTransport 中。如果我們只有一個 ATMTransport 實例在classpath中,那么我們就不需要注解其它的 ATMTransport 實現。現在我們有三個實現,分別命名為 StandardAtmTransport , SoapAtmTransport 和 JsonAtmTransport ,這就需要我們把其中兩個注解為 @Alternatives ,還有一個注解為 @Default 。

    在StandardAtmTransport上標注@Default注解

    當前的例子里, StandardAtmTransport 是transport的默認實現,所以我們給他加上 @Default 注解,如下:

    //StandardAtmTransport使用注解@Default 
    package org.cdi.advocacy;

    import javax.enterprise.inject.Default;
    @Default
    public class StandardAtmTransport implements ATMTransport {
    ...

    在SoapAtmTransport和JsonRestAtmTransport上標注@Alternative注解

    如果我們沒有給他們使用 @Alternative 注解,那只有等到給他們注解為 @DefaultCDI 才會關注它們。讓我們來給JsonRestAtmTransport 和 SoapRestAtmTransport 加上 @Alternative 注解以便 CDI 不會感到迷惑。

    //JsonRestAtmTransport使用注解@Alternative 
    package org.cdi.advocacy;

    import javax.enterprise.inject.Alternative;
    @Alternative
    public class JsonRestAtmTransport implements ATMTransport { ... }
    // SoapAtmTransport使用注解@Alternative 
    package org.cdi.advocacy;
    import javax.enterprise.inject.Alternative;
    @Alternative
    public class SoapAtmTransport implements ATMTransport { ... }

    在AutomatedTellerMachineImpl上標注@Named注解以便其容易被查找;給它一個命名“atm”

    我們不在 Java EE6 應用中使用 AutomatedTellerMachineImpl ,而只是通過 beanContainer 來查找它。讓我們給它一個容易理解的名字,比如"atm"。使用 @Name 注解來給他命名。在 JavaEE 6 應用中同樣可以使用 @Name 注解來讓bean可以通過統一EL語言(表達式語言標準,用來在JSP和JSF組件中使用)。

    下面是使用 @Named 給 AutomatedTellerMachineImpl 起名為"atm"的代碼:

    //AutomatedTellerMachineImpl使用注解@Name [source,java] package org.cdi.advocacy;  import java.math.BigDecimal;  import javax.inject.Inject; import javax.inject.Named;  @Named("atm") public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {        ...  }

    注意,如果你沒有在 @Name 注解中提供名字,那么默認名字就是類名把第一個字母小寫,如下:

    //名字默認值 @Named public class AutomatedTellerMachineImpl implements AutomatedTellerMachine {        ...  }

    這時候名字默認就是automatedTellerMachineImpl。

    使用CDI beanContainer查找atm,執行存款和取款

    最后我們使用beanContainer查找atm并執行一些存款操作。

    // AtmMain通過名字查找atm 
    package org.cdi.advocacy;
    ...
    public class AtmMain {
    ...
    ...
    public static void main(String[] args) throws Exception {
    AutomatedTellerMachine atm = (AutomatedTellerMachine) beanContainer
    .getBeanByName("atm");
    atm.deposit(new BigDecimal("1.00"));
    }
    }

    如果你在命令行運行它,你將得到如下輸出

    Output

    deposit called             
    communicating with bank via Standard transport

    你同樣可以通過類型查找AtmMain。

    //AtmMain通過類型查找atm 
    package org.cdi.advocacy;
    ...
    public class AtmMain {
    ...
    ...
    public static void main(String[] args) throws Exception {
    AutomatedTellerMachine atm = beanContainer.getBeanByType(AutomatedTellerMachine.class);
    atm.deposit(new BigDecimal("1.00"));
    }
    }

    自從CDI注入是類型安全的,通過名字查找就可能失效。注意我們有一個向下轉型在應用 Java泛型 的時候。

    如果你去掉 StandardATMTransport 上的 @Default 注解,你將會得到同樣的輸出。但是如果你去掉其它兩個 transport JsonATMTransport 和 SoapATMTransport 上的 @Alternative,CDI 將會報出如下錯誤信息:

    Output

    Exception in thread "main" java.lang.ExceptionInInitializerError 
    Caused by: javax.enterprise.inject.AmbiguousResolutionException: org.cdi.advocacy.AutomatedTellerMachineImpl.setTransport:
    Too many beans match, because they all have equal precedence.
    See the @Stereotype and <enable> tags to choose a precedence. Beans:
    ManagedBeanImpl[JsonRestAtmTransport, {@Default(), @Any()}]
    ManagedBeanImpl[SoapAtmTransport, {@Default(), @Any()}]
    ManagedBeanImpl[StandardAtmTransport, {@javax.enterprise.inject.Default(), @Any()}]
    ...

    CDI期望找到一個并且只有一個適合的注入。后面我們將講述如何使用替換選擇(alternative)。

    待續..

    2011-06-11

    posted on 2011-06-16 14:03 kuuyee 閱讀(3774) 評論(1)  編輯  收藏 所屬分類: CDIJEE

    評論

    # re: (翻譯)JavaEE6規范 CDI教程第一部分[未登錄] 2013-03-13 17:39 rainbow

    博主,你好,我在網上看到了您的這篇翻譯的部分內容,找到您的博客后,但發現這幾篇介紹cdi的文章已經不可看了.如果方便的話,希望可以再重新貼出來,謝謝了  回復  更多評論   

    導航

    <2011年6月>
    2930311234
    567891011
    12131415161718
    19202122232425
    262728293012
    3456789

    統計

    隨筆分類(139)

    Linux內核

    搜索

    •  

    積分與排名

    • 積分 - 319346
    • 排名 - 177

    最新評論

    閱讀排行榜

    主站蜘蛛池模板: 成年女人免费视频播放体验区| 蜜桃精品免费久久久久影院| 亚洲成年人电影在线观看| 免费精品国产自产拍在线观看图片 | 2021国内精品久久久久精免费| 亚洲首页国产精品丝袜| 四虎精品亚洲一区二区三区 | 成人爱做日本视频免费| 中文字幕免费视频精品一| 亚洲另类自拍丝袜第1页| 亚洲国产精品综合久久一线| 无码国产精品一区二区免费16| 亚洲日韩国产一区二区三区在线 | 国产精品美女午夜爽爽爽免费| 九九久久国产精品免费热6| 亚洲一区二区成人| 亚洲AV无码成人精品区大在线| 99免费在线观看视频| 猫咪免费人成网站在线观看入口| 亚洲一区二区成人| 久久亚洲精品无码播放| 最新中文字幕免费视频| 小日子的在线观看免费| 亚洲AV无码专区在线厂| 1区1区3区4区产品亚洲| 亚洲综合另类小说色区色噜噜| 99re热免费精品视频观看| 久久精品视频免费| 人妻无码中文字幕免费视频蜜桃| 亚洲香蕉在线观看| 亚洲天天在线日亚洲洲精| 亚洲综合最新无码专区| 女人张腿给男人桶视频免费版| 国内精品久久久久影院免费 | 亚洲专区一路线二| 无码乱人伦一区二区亚洲| jizzjizz亚洲| 韩国二级毛片免费播放| 国产精品爱啪在线线免费观看| 久久WWW免费人成—看片| 精品久久亚洲一级α|