01.CDI(上下文與依賴注入)

CDI(Context and Dependency Injection)
  1. JSR #346, CDI 1.1, JEE 7, http://jcp.org/en/jsr/detail?id=346
    1. JSR 299 (JEE 6)

打破不同 JEE 框架間的模組鴻溝...


用於依賴注入的標準化註釋(@Annotation)
該規範的目標在於為依賴注入提供標準化、可擴展的API。JSR 330 所定義的一套註解, 使得被注入的類別能夠在各種框架(Framework)間移植,這樣開發者就不會再深陷於特定於某個廠商的@Annotation了,比如 Spring 和 Google Guice ...等框架。CDI是由JSR 299定義的新的Java Ee的類型安全的依賴注入解決方案。CDI試圖集成其他的依賴注入解決方案例如Seam,Guice和Spring的優點並添加自己新的創新。



發展史


Jave EE 5的一個主要的關注點是通過 POJO,annotations 和『規範優於配置』來實現的易用性。Java EE 5其實已經有了一個依賴注入(Dependency Injection)的基本結構,或者這個結構應該叫做資源注入更好。通過這個結構,我們可以通過 @Resource,@PersistenceContext,@PersistenceUnit 和 @EJB 這些annotation來將容器資源例如JMS連接工廠,數據源(Data Source),隊列,JPA實體管理器,實體管理器工廠和EJB注入到Servlets,JSF backing beans和其他的EJB中。如果你的應用程序只是由JPA領域對象和以EJB,JSF方式提供的服務、DAO組成的,那麼這個模型已經夠用了。
但是,在大多數情況下我們還是需要求助於其他的依賴注入技術(如Seam,Spring或Guice)。例如,我們要將EJB注入到Strust Action中或JUnit測試代碼中,或這我們要注入不是使用EJB方式實現的DAO或幫助類。更為常見的情況是我們要使用第三方的API。這些情況下這個基本的模型就不夠用了。CDI的設計目的就是以一種符合Java理念的高類型安全的、一致的和可移植的方式來解決這些問題。實際上Resin容器的很大的一部分就是使用JSR299來寫的,這對於Java EE 5來說是難以想像的。
如果你熟悉Spring的控制反轉,那麼CDI其實是很相似的,但是更加類型安全,更加未來化,並且是annotation驅動的。Seam的開發人員會發現CDI有很多很好的特性。相比Guice來說,CDI更加適用於企業開發。對於Java EE 5開發人員來說,CDI剛開始看來可能比較複雜,但是大部分的複雜性已經做了調整併且如果不需要使用他們,完全可以忽略。
除了依賴注入相關的特性以外,CDI還以兩種方式增強了Java Ee編程模型,這兩種方式都是來自Seam。首先,它允許以JSF backing bean的方式直接使用EJB。另外,CDI允許我們以聲明的方式來管理對象的範圍、狀態、生命週期和上下文。


CDI 概要


Contexts and Dependency Injection (CDI), specified by JSR-299, is an integral part of Java EE 6 and provides an architecture that allows Java EE components such as servlets, enterprise beans, and JavaBeans to exist within the lifecycle of an application with well-defined scopes. In addition, CDI services allow Java EE components such as EJB session beans and JavaServer Faces (JSF) managed beans to be injected and to interact in a loosely coupled way by firing and observing events.




Apache Deltaspike





相關 JSR



JSR 330: Dependency Injection for Java
FR: 14 Oct, 2009,, http://jcp.org/en/jsr/detail?id=330

JSR 299: Contexts and Dependency Injection for the JavaTM EE platform
FR: 10 Dec, 2009,, http://jcp.org/en/jsr/summary?id=299





JSR-299 特點


CDI是由JSR 299定義的新的Java EE的類型安全的依賴注入解決方案。CDI試圖集成其他的依賴注入解決方案例如Seam,Guice和Spring的優點並添加自己新的創新。
  • 它定義了一套強大的互補型服務(complementaryservices),用以改善應用代碼的結構。
  • 一套良好定義的生命週期,而這套contexts 是可以擴展的。
  • 一種高級的、類型安全的依賴注入(dependency injection)機制,包括無論是在配置還是開發時選擇依賴的能力,而這一切並不需要太多的配置。
  • 支持Java EE 模組化以及Java EE 組件架構(component architecture)。當在Java EE組件間解析依賴時,會考慮一個JavaEE應用的模塊化架構。
  • 與Unified Expression Language (EL)整合, 允許在JSF或者JSP頁面中直接使用任何上下文物件(contextual object)。
  • 修飾注射式物件(injected objects)的能力。
  • 通過安全類型攔截綁定(typesafe interceptor bindings)與攔截器協同。
  • 一個事件通知模型。
  • 一個網絡談話環境(conversation context)以及由Java Servlets specification定義的三個標註的web環境
  • 一個 SPI 便攜擴展用以與容器集成。




beans.xml -> @Annotation


When the application is deployed, the presence of a beans.xml file signals that the module contains CDI managed beans, so the classes on the path are scanned for CDI annotations. In a CDI module, all beans are registered with Weld, and the @Named annotation is used to match beans to injection points.

@javax.inject.Named





JSF 2.0 EL







EJB 3.1



Different EJB types

You can also try using the @Stateful annotation. Alternatively, you could try the new @Singleton annotation for singleton instances. If you do, you may notice that there is are two annotations: javax.ejb.Singleton and javax.inject.Singleton. Why two singletons? The CDI singleton (javax.inject.Singleton) lets you define a singleton instance outside of EJB in case you are using CDI in a non-EJB environment. The EJB singleton (javax.ejb.Singleton) provides all the features of an EJB such as transaction management. Therefore, you have the choice depending on your needs and whether you are working in an EJB environment.





Example



EJB 3.1 + JSF
package org.wisdomfish.ee.cdi;

import javax.inject.Named;
import javax.ejb.Stateless;
import javax.ejb.Singleton;
import javax.ejb.Stateful;


/**
 *
 * @author WisdomFish, Kuo
 */

@Named
@Stateless
@Stateful
@Singelton

public class MessageServiceBean {

    public String getMessage() {
        return "Hello, CDI.";
    }

}

jsf.xhtml
...
<code>Facelet Title</code> Hello from Facelets
Message Service Bean: #{messageServiceBean}
Message: #{messageServiceBean.message}


Page View
//
Message Service Bean: org.wisdomfish.ee.cdi.MessageServiceBean@6e944d75

// EJB - Stateless
Message Service Bean: org.wisdomfish.ee.cdi.__EJB31_Generated__MessageServiceBean__Intf____Bean__@64c5af75

// EJB - Stateful
Message Service Bean: org.wisdomfish.ee.cdi.__EJB31_Generated__MessageServiceBean__Intf____Bean__@2c88652b

// EJB - Singleton
Hello from Facelets
Message Service Bean: org.wisdomfish.ee.cdi.__EJB31_Generated__MessageServiceBean__Intf____Bean__@4a63c87d




PPT
http://www.slideshare.net/mojavelinux/cdi




IDE 的整合



NetBeans 6.9+


Java Web Application optional - Enable CDI


YouTube Video





Eclipse - JBoss Tool




CDI要成为框架的基础,能够扩展、集成其他技术。因此,CDI提供了一组SPI给开发人员构建portable extension。比如CDI的设计者已经考虑的下面这些扩展: 
  • 与BMP(业务流程管理)引擎的集成;
  • 与第三方框架集成,比如spring,seam,GWT或wicket等
  • 与基于CDI编程模型的新技术集成

[译文]Java EE 6中的依赖注入——第1部分(二)

Conversational CRUD in Java EE 6


Reference





Weld中实现ViewScoped, http://www.javaeye.com/topic/567006

Netbeans Tutorial

Contexts and Dependency Injection






Java EE 6里的CDI

Web Beans Users Forum

http://docs.jboss.org/webbeans/reference/snapshot/en-US/html/
http://docs.jboss.org/webbeans/reference/snapshot/zh-TW/html/



http://in.relation.to/Bloggers/Weld101CR2IsAvailableForFinalInspection

http://www.cn-java.com/www1/?action-viewnews-itemid-55539



Web Beans主要目的是串通JSF與EJB3之間的鴻溝
所以稱不上與JSF有區別 因為他是為JSF服務的

Ref






Videos



Google Developer Day Beijing-Guice,Java Dependency Injection






Java on Guice: Dependency Injection, the Java Way









概述


JSR-299 實作參考(reference implementation)即 Weld 的主管Pete Muir。Pete Muir工作於JBoss,還是 Seam 以及 Weld 專案的核心開發者。

Muir說,新的擴展意味著可以更簡單地寫入和添加應用(如excel 電子表格的生成和安全模組等)從而運行在任何支持JSR-299的容器上。之前Java EE中非常困難的一件事情是向內置的功能中構建擴展。在JSR-299之前,Java EE 6的應用循環中非常需要添加功能。Muir說,沒有辦法知道一個應用是開始還是終止;也沒有辦法知道應用中有什麼Beans以及配置了哪些類。現在有了 JSR-299完整的Metadata SPI,開發者可以註冊Lifecycle Listeners,並且當事件發生的時候(比如class processing和bean創建)可以要求通知。Muir說,有了這些擴展許多強大的應用可以植入Java EE平台中。

用於依賴注入的標準化註解

該規範的目標在於為依賴注入提供標準化、可擴展的API。JSR 330所定義的一套註解使得被注入的類能夠在各種框架間移植,這樣開發者就不會再深陷於特定於某個廠商的註解了,比如Spring和Google Guice等框架。

Weld 並不需要完整的應用服務器。它可以運行在Servlet容器內如Jetty 6.1或是Tomcat 6,同時也能用於Java SE 5.0+。
新 的Managed Bean規範是JSR-299的工作成果(在規範的早期草案中我們稱之為「簡單Web Bean」)。簡單Web Bean支持依賴注入、EL名字與攔截器,但卻沒有EJB那些編程約束。

最後的結果是:CDI可以用在普通的Java類 (現在叫做「Managed Bean」)以及EJB上。現在的EJB可以看作是一種特殊的Managed Bean,只不過有一些額外的編程約束和功能。這種編程模型能夠極大地降低新用戶學習EE的曲線。 

我認為EE平台的未來 發展方向是逐漸將EJB特有的功能通用化,將其應用在所有的Managed Bean上。舉個例子,為何不是所有的Managed Bean都支持@TransactionAttribute和@RolesAllowed呢?簡直沒有道理嘛。

然而EJB在為消息傳輸定 義端點、遠程與異步方法調用、定時器等領域還是有一席之地的。在這些情況下,EJB生命週期模型還是非常有意義的。 

CDI來源於Red Hat的開源Seam框架,從廣義上來講,它將Seam的編程模型標準化為Java EE 6的編程模型。CDI實現了Java EE 6的3個主要目的。首先,它提供了聲明的方式來管理綁定到上下文組件的範圍、狀態與生命週期。其次,它為平台提供了標準化、註解驅動、類型安全的依賴注入 框架,方式類似於Google Guice。最後,它為Java EE平台的擴展開發提供了Service Provider Interface(SPI)。


為Java EE環境定義了一套服務,使Java EE的Web應用程序開發更容易。Web Beans層在現有的Java組件上增強了生命週期和互動模式,如JavaBeans和Enterprise Java Beans。作為一個傳統Java EE編程的補充,Web Beans提供的服務為: 
  • 改進生命週期的狀態,為了更好的定義上下文。
  • 為依賴注入提供一個更安全的方法。
  • 通過事件通知來進行互動
  • 一個更好的方法在組件上綁定攔截器,隨著一種新的攔截器-裝飾器(decorator)的誕生,可以輕鬆的解決很多業務上的問題。
Web Beans在Web應用中有著特殊的作用,同樣也適用於多種不同的應用,甚至還可以用在Java SE的背景下,結合EJB嵌入式容器,被定義在EJB 3.1規範中。 

JSR-299即Java Web Beans規範發佈了最終草稿,JSR-299是由JBoss公司的著名的Java領域的專家Gavin King領導的,目標在於制定Java在Web開發方面的規範,Web Beans也是JavaEE6最重要的組成部分。JSR-299的最終版本將於8月份發佈,隨後9月份將正式發佈大家期盼已久的JavaEE6的正式規 範。 

在JSR-299規範當中,有很多值得我們關注的方面: 

1、一個通用的類型安全的依賴注入模型 
2、帶有執行環境的可注入對象的生命週期管理 
3、具有事件通知模型 
4、可以通過用戶自定義的annotation來進行攔截器綁定 
5、定義了伺服器API,便於第三方的web或者組件容器集成 
6、不但可以支持JSF,還可以直接支持Servlet和JSP 
7、針對JSF提供了會話級別的執行環境 

JSR-299定義的web beans組件模型完全不必使用XML配置文件,而是通過簡單清晰的annotations來實現,因此將會比spring簡潔很多。


RIs


  1. JBoss - Weld
  2. Apache - OpenWebBeans, OWB, http://openwebbeans.apache.org/


Videos



YouTube Video





Reference



Gavin King談JSR-299和Weld 1.0對Java EE與JBoss的影響

作者 Charles Humble 譯者 張龍 發佈於 2009年11月23日 下午11時24分