EJB

企業級JavaBean(Enterprise JavaBean, EJB)是一個用來構築企業級應用的伺服器端可被管理元件。

Java企業版API(Java Enterprise Edition)中提供了對EJB的規範。EJB是一個封裝有某個應用程式之業務邏輯伺服器端元件。EJB最早於1997年由IBM提出,旋即被昇陽電腦採用並形成標準(EJB 1.0 和EJB 1.1)。其後在Java社群行程(Java Community Process)支援下陸續有一些JSR被制訂來定義新的EJB標準,分別是JSR 19 (EJB 2.0), JSR 153 (EJB 2.1) 以及最新的JSR 220 (EJB 3.0)。

EJB規範的目的在於為企業及應用開發人員實現後台業務提供一個標準方式,從而解決一些此前總是在作業過程中總是重複發生的問題。EJB以一個標準方式自動處理了諸如資料持久化,事務整合,安全對策等不同應用的共有問題,使得軟體開發人員可以專注於程式的特定需求而不再飽受那些非業務元素的困擾。

據此,EJB規範明確了一個應用伺服器應當支援的中間管理細目,包括:

  • 資料持久化
  • 事務處理
  • 並行控制
  • 基於JMS的事件驅動
  • 基於JNDI的名字和空間管理
  • 基於JCE和JAAS的安全管理
  • 應用伺服器端的軟體元件部署
  • 使用RMI-IIOP協定的遠端程序呼叫
  • 將業務方法暴露為Web服務

此外,EJB定義文件還指定了EJB容器和各EJB的角色定位,以及如何將EJB部署至EJB容器當中。

EJB的架構

歷史

從擁抱到拋棄

由於IBM和Sun Microsystems等EJB提倡者力推其前景,起初一些大公司紛紛採用EJB部署他們的系統。然而隨後各種問題便接踵而至,對EJB的惡評短時間內激增。對於初學者,EJB的API顯得太過困難;對於許多程式設計師來說,書寫那些必須丟擲特定異常的介面並將bean類作為抽象類實現的做法既不直觀也不正常。當然,EJB所被賦予的使命,如物件關係對映和事務管理確實有其天然複雜性,但其API之複雜還是令開發人員們覺得望而卻步,一些人開始懷疑EJB除了引入了複雜的實現手段以外似乎並未帶來什麼實際好處。

另外,實際運用中被發現,如果使用EJB來封裝業務邏輯會帶來效能上的下降。這是因為,最早的EJB規範只允許用戶端通過特定協定(如CORBA)進行遠端方法呼叫來呼叫,即使大部分實際應用根本就不需要分散式計算。直到EJB 2.0才引入了本地介面,以支援可以開發不通過網路就能直接本地呼叫的EJB系統。

儘管如此,EJB的廣泛普及仍然為其複雜度所制約。儘管已經有一些高品質的整合開發工具可以協助開發人員通過自動編碼解決一部分重複作業,但這並不能降低學習此項技術的難度。另一方面,「草根階層」的編程愛好者們發起了一場旨在使用 「輕量級」技術以代替複雜的EJB的運動。這些技術包括Hibernate(用於提供資料持久化和物件-關係對映)及Spring框架(用於封裝業務邏輯)。儘管它們不像EJB那樣有巨頭支援,但其在庶民間卻更加流行,並且也被一些對EJB深感失望的企業所採用。

重生

EJB規範起初的一個主要價值—對分散式應用進行事務管理—在隨後的實踐中被一致認為幾乎沒能派上用場。對於企業級應用來說,Spring和Hibernate等簡化框架更加實用。因此,EJB 3.0規範(JSR 220)為了迎合這個趨勢相比於其前輩進行了一次激進的大跳躍。受到Spring 影響,EJB 3.0也使用所謂的「傳統簡單Java物件(POJO)」;同時,支援依賴注入來簡化全異系統的整合與配置。Hibernate的創始人Gavin King參與了這一新版規範的制訂,並對EJB大加提倡。Hibernate的許多特性也被引入到Java持久化API當中,從而取代原來的實體bean。EJB 3.0規範大幅採用Java注釋(annotation)來對代碼進行後設資料修飾,從而消減了此前EJB編程的冗雜性。

相應地,EJB 3.0幾乎成為了一個全新的API,與此前的數版可謂毫無相似度可言。

EJB種類

EJB容器可以接受三類EJB

  • 對談Bean(Session Beans)
    • 無狀態對談Bean(Stateless Session Beans)
    • 有狀態對談Bean(Stateful Session Beans)
  • 實體Bean(Entity Beans)
  • 訊息驅動Bean(Message Driven Beans ,MDBs)

無狀態對談Bean是一類不包含狀態資訊的分散式物件,允許來自數個用戶端的並行存取。例項變數的內容在前後數次呼出中不被保留(確切地說是不保證保留)。由於不必控制與用戶間的對話資訊而減少了開銷,無狀態對談Bean不像有狀態對談Bean那樣具有資源集約性。舉例來說,一個傳送郵件的EJB就可被設計為一個無狀態對談Bean。在整個對談期,用戶只向伺服器提交一個動作:傳送指定郵件到指定位址。(稱為開關行為)

有狀態對談Bean是包含狀態的分散式物件,即是說,貫穿整個對談它們都要保有用戶端資訊。舉例而言,在一個網上商店進行實施結帳很可能就需要一個有狀態對談Bean,因為結帳是一個多步動作,伺服器端必須可以隨時了解到用戶已經進行到了哪一步。此外,儘管有狀態對談Bean的狀態資訊可被保持,但始終只能同是由一個用戶來存取之。

實體Bean是含有持久化狀態的分散式物件。這個持久化狀態的管理既可以交給Bean自身(Bean-Managed Persistence,BMP),也可以託付於外部機制(Container-Managed Persistence,CMP)。

訊息驅動Bean是支援異步行為的分散式物件。它們並不對請求進行當即回應。比方說,某網站用戶點擊「請通知我更新資訊」按鈕,將會觸發某個MDB將這名用戶加入到資料庫的希望獲得更新資訊用戶列表中。這個動作就是一個異步的訊息驅動過程,因為用戶不必等待當時會返回某個結果。MDB的訊息源來自Java訊息服務(JMS)提供的訊息佇列或訊息主題。自EJB 2.0規範起,JMS被加入進來以允許在容器內部實施事件驅動處理。與其他EJB不同,MDB不存在一個用戶視圖(如需要用戶參照的遠端介面),用戶也不能通過資源定位獲得一個MDB例項。MDB只在後台監聽訊息源並實施自動處理。

除了上述以外,目前還有一些EJB處於設想階段,如JSR 86提出了用於在Java EE應用中整合多媒體物件的媒體Bean(Enterprise Media Beans)。

EJB實行

EJB部署於應用伺服器端的EJB容器中。規範給定了EJB與EJB容器之間,以及用戶代碼與EJB/EJB容器之間的互動方式。對於Java EE API,javax.ejb包定義了EJB類,javax.ejb.spi包定義了EJB容器應當實現的各個介面。

在EJB 2.1和以前的版本中,每個EJB都由一個類和兩個介面組成。EJB容器負責建立這個類別的例項,介面則供用戶端呼叫。

兩個介面分別被稱為Home介面和元件介面,負責提供各個EJB遠端方法聲明。這些EJB遠端方法可分成兩組:

  • 類別方法:由Home介面提供。與特定例項無關,僅負責一些公共內容,比如建立一個新的EJB例項(create方法),或尋找一個已經存在的EJB例項(find方法)等等。
  • 介面方法:由元件介面提供的針對特定例項的業務方法。

EJB容器將為這些介面提供對應的實現類以充當客戶遠端代理,當用戶端呼叫這個生成的代理類的某個方法時,代理類內部會將此呼叫的方法和參數封裝成一個訊息傳送給伺服器。伺服器收到訊息後在轉發給真實的EJB例項,後者負責執行真正的業務邏輯。

遠端通訊

EJB規範要求EJB容器能夠支援基於RMI-IIOP的EJB存取。EJB既可被任何CORBA應用存取,也能提供Web服務。

事務

EJB容器必須支援符合ACID(原子性/一致性/獨立性/永續性)特性的容器級事務管理,以及bean內部事務管理。容器級事務需在部署描述符中(EJB應用的設定檔)進行聲明。

事件

EJB使用JMS向客戶物件傳送訊息,客戶則可以異步地接受這些訊息。MDB則接受來自用戶端的訊息。

命名和目錄服務

EJB用戶端使用JNDI或CORBA名字服務定位Home介面實現 物件。通過此Home介面,用戶還可以尋找,建立或刪除實體物件。

安全

EJB容器對用戶端的存取權限負責。

部署EJB

EJB規範還定義了一個跨平台的統一部署機制。部署描述符中定義了關於EJB應用的一切相關內容。檔案名通常為ejb-jar.xml。

部署描述符是一個XML文件,負責為該EJB應用中的每一個EJB定義入口。部署描述符的主要內容包括:

  • Home介面名
  • Bean的Java類別名
  • Home介面的Java介面名
  • 元件介面的Java介面名
  • 持久化儲存(針對實體Bean)
  • 安全策略和角色分配

通常EJB容器提供者還定義了一些額外的XML或其他格式描述檔案來強化其容器的功能。他們還同時提供這些描述檔案的解讀工具類和對Home介面的自動實現類生成。

EJB3.0起開始廣泛使用Java注釋替代傳統的部署描述符ejb-jar.xml。但後者仍然有效。

版本變化

EJB 3.0

2006年5月2日發布,JSR 220定義。

  • 全面採用Java注釋代替部署描述符。(後者仍可使用,並且具有更高優先級)
  • 把2.X版的EntityBean改為由JPA支援。

EJB 2.1

2003年11月24日發布,JSR 153定義。

  • Web服務:可將無狀態對談bean暴露為Web服務;EJB可通過參照存取Web服務。
  • EJB定時器服務:提供一種新的基於定時器的事件驅動方式。可供訊息驅動bean作為訊息源使用。
  • 增加了訊息目的地。
  • 進一步豐富了EJB查詢語言,支援ORDER BY, AVG, MIN, MAX, SUM, COUNT和MOD。
  • 使用XML schema代替DTD以定義部署描述符。

EJB 2.0

2001年8月22日發布,JSR 19 定義。

  • 制定了構建物件導向商務應用的標準組建結構。
  • 支援構築使用不同開發工具所開發之元件的聯合應用部署。
  • 在多執行緒,連線池,事務管理等方面對用戶透明化。
  • 使符合「一次寫成,多次執行」的Java思想。
  • 關注企業級應用生命期間的開發,部署,執行等動作。
  • 定義了不同開發工具所需遵守的契約,以便其產品能夠在執行期互動。
  • 支援與現行系統相容,開發者可以擴充功能現有產品以使之支援EJB。
  • 與其他Java API相容。
  • 支援EJB與Java2平台企業版或者其他非Java應用程式之間的互操作性。
  • 支援與CORBA相容的RMI-IIOP。

EJB 1.1

1999年12月17日發布。

  • 開始採用XML部署描述符,預設的JNDI上下文以及可支援IIOP的RMI。
  • 安全機制由角色(Role)驅動,而非方法。
  • 支援實體類,且必須在應用中實現。

EJB 1.0

1998年3月24日發布。

  • 定義了EJB和EJB容器的作用,實現與互動。
  • 提供了最早的開發者與用戶視圖。