EJB

從 华夏文化百科
於 2014年8月16日 (六) 06:48 由 Test 32(對話 | 貢獻) 所做的修訂 (1個修訂:HDwiki 数据迁移 - 批次 863)
(差異) ←上個修訂 | 最新修訂 (差異) | 下個修訂→ (差異)
跳到: 導覽、 搜尋


在J2EE里,Enterprise Java Beans(EJB)稱為Java 企業柄,是Java的核心代碼,分為整體柄和片段柄和消息柄三個部分,其中的消息柄將在以後再作討論。現在我們來看看什麼是整體柄和片段柄。


整体柄是一种对象: 标准Java对象由创建它的程序创建,当程序终止时,对象也随之丢失,这就意味着当再次运行些程序时,将无法找到先前创建的柄,而整体柄会一直存在着直到它被删除。 一个程序可以创建一个整体柄,并且这个程序可以在被保存后随时停止和重启。整体柄将会依然存在。重启后,程序可以找到与之相对应的整体柄,并且会继续使用这个整体柄。


EJB實際上是SUN的J2EE中的一套規範,並且規定了一系列的API用來實現把EJB概念轉換成EJB產品.EJB是BEANS,BEANS是什麼概念,那就是得有一個容納她,讓她可勁造騰的地方,就是得有容器.EJB必須生存在EJB容器中.這個容器可是功能強大之極!她首先要包裝你BEAN,EJB的客戶程序實際上從來就不和你編寫的EJB直接打交道,他們之間是通過HOME/REMOTE接口來發生關係的.它負責你的BEAN的所有的吃喝拉薩睡,比如BEAN的持續化,安全性,事務管理...


一.什麼是 EJB?


一個技術規範:EJB 從技術上而言不是一種"產品"EJB 是一種標準描述了構建應用組件要解決的:可擴展 (Scalable)分佈式 (Distributed)事務處理 (Transactional)數據存儲 (Persistent)安全性 (Secure)


二.Sun 對 EJB 的期望


提供一個標準的分佈的、基於 OO 的組件架構屏蔽複雜的系統級功能需求Write once, run anywhere與非 Java 應用之間的互操作能力兼容 CORBA 標準


三.為什麼選擇 EJB?


EJB 服務器完成"繁雜"的工作:應用開發人員關注於業務邏輯的實現而不是底層的實現機制(類似於 4GL 語言設計的目標)支持事務處理多個業務操作同時成功,或全部失敗可以通過在代碼外的描述來定義事務處理級別可擴展性EJB 可以根據您應用的增長而擴展EJB 服務器往往還提供了負載均衡和安全性:由 EJB 服務器提供資源的訪問權限控制


四.EJB 架構


為了滿足架構的目標,規範中描述了服務器 (Server)容器 (Container)類 (Class) 和實例 (Instance)Home 和 Remote 接口客戶端 (Client)


五. 簡化的編程模型


關注於業務邏輯實現:EJB 負責生命周期 (lifecycle), 數據存儲 (persistence), 事務處理語義 (transactional semantic), 安全(security), ...通用的編程模型:各種服務的高層 APIJava 是其編程語言


1.EJB 特點


由一個 EJB 容器在運行時創建和管理 EJB在部署 EJB 時定製其運行方式由 EJB 容器和服務器來協調客戶端的訪問可以部署到任何兼容的 EJB 容器中客戶端對 EJB 的視圖是由 Bean 開發人員決定的


2.EJB 服務器


管理 EJB 容器i/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F target="_new" class=innerlink作業系統服務的存取提供 Java 相關的服務,尤其是通過 JNDI 訪問命名空間基於 OTS 的事務處理服務


3.EJB 容器


管理 Bean 生命周期:將 EJB 服務器提供的服務傳遞給 Bean生成代碼來實現對 Bean 的存取訪問強制事務處理的限制創建、初始化和回收 Bean管理持久數據的存儲對客戶端而言 EJB 容器是透明的


4.在一個 EJB 服務器中的容器


目前容器通常是由 EJB 服務器本身提供的在 EJB 1.0 或 1.1 規範中沒有定義容器-到-服務器的接口各廠商可以根據他們的見解來實現服務器和容器的各自責任


5.容器提供服務: 數據存儲


容器決定何時載入/儲存狀態Container-Managed Persistence(容器管理存儲/CMP)容器負責存儲您的 Bean容器生成必要的類和代碼Bean-Managed Persistence(Bean 管理存儲/BMP)Bean 開發人員提供存儲代碼開發人員決定 如何存儲, 容器仍然決定 何時進行


6.容器提供服務: 事務處理


可以由容器代理來實現容器將得到業務邏輯方法的事務處理需求容器提供事務控制代碼也可以由程式設計師通過代碼實現


7.容器提供服務: 其它服務


其它服務包括命名 (Naming)安全 (Security)線程管理 (Thread management)這些服務由容器代理完成將減少應用開發人員的負擔


8.分佈式對象運算


遠程對象被作為本地對象來處理:傳遞信息的方式不變,但開銷更大Enterprise JavaBeans 永遠運行在服務器上:對 Bean 的訪問永遠是遠程調用


9.Stub 和 Skeleton


由 EJB 生成:"Stub" 對要傳遞出去的信息編碼"Tie/Skel" 將接受到的信息解碼並傳遞給目標對象


10.分類: Enterprise JavaBeans


+---Entity Beans--CMP/BMPEjb--|+---Session Beans--Stateful/Stateless


會話 Bean (Session Bean):根據 EJB 規範,一個會話 Bean 是:


代表單個客戶端來執行可以參與到事務處理中不直接代表共享於數據庫中的數據,但它能訪問和更新這些數據相對而言是短暫存在的當 EJB 容器失效後就不存在---客戶端需要重新建立一個信新的會話對象來繼續運算


實體 Bean (Entity Bean):根據 EJB 規範,一個實體 Bean 是:


提供在數據庫中數據的對象視圖允許被多個用戶共享存取訪問可以是長期存在 (只要它存在於數據庫中)實體 Bean, 它的主鍵對象, 以及它的遠程引用將能跨 EJB 容器的宕機而存在


11.EJB 類和實例


構建 EJB 應用包括來自三方的代碼開發人員編寫的代碼由 EJB API 定義的類和接口由容器自動生成的代碼開發人員編寫的代碼包括Bean 類 (定義了業務邏輯)Home 接口 (如何查找或創建 bean)Remote 接口 (如何存取 bean)其它組件,根據 bean 實際要求


12.EJB Home 接口


每個 bean 有一個用於:創建新的 bean 實例、查找現存的 bean (只能是實體 bean)


Remote 接口:定義 bean 的公共接口---只有在 Remote 接口中定義的方法才能被客戶端訪問


EJB 客戶端


可以為 servlet, JSP, 應用程式或其它 bean通過 JNDI 來查找 EJB home 接口,步驟為:創建一個 JNDI Context (initial context)使用 JNDI Context 來查找 bean home 接口使用 bean home 接口來創建/查找 bean 實例使用 bean 實例完成業務操作實際的存取 (對 EJB) 是通過容器生成的類來完成


EJB 架構


客戶端對 bean 訪問永遠不是直接的EJBObject (tie) 是由容器自身提供的:用來幫助管理 bean 的生命周期


EJB 中的角色


EJB 服務器供應商: 開發並銷售 EJB 服務器EJB 容器供應商: 開發並銷售 EJB 容器Enterprise bean 開發人員: 開發並銷售 EJB應用組裝人員: 將不同的 EJB 搭建成應用


六、EJB的體系結構


  目前,EJB最新的標準是2.1,EJB3.0規範正在討論中,預計將於明年推出。EJB2.1定義了三種企業Bean,分別是會話Bean(Session Bean),實體Bean(Entity Bean)和消息驅動Bean(MessageDriven Bean)。


  Session Bean用於實現業務邏輯,它可以是有狀態的,也可以是無狀態的。每當客戶端請求時,容器就會選擇一個Session Bean來為客戶端服務。Session Bean可以直接訪問數據庫,但更多時候,它會通過Entity Bean實現數據訪問。


  Entity Bean是域模型對象,用於實現O/R映射,負責將數據庫中的表記錄映射為內存中的Entity對象,事實上,創建一個Entity Bean對象相當於新建一條記錄,刪除一個Entity Bean會同時從數據庫中刪除對應記錄,修改一個Entity Bean時,容器會自動將Entity Bean的狀態和數據庫同步。


  MessageDriven Bean是EJB2.0中引入的新的企業Bean,它基於JMS消息,只能接收客戶端發送的JMS消息然後處理。MDB實際上是一個異步的無狀態Session Bean,客戶端調用MDB後無需等待,立刻返回,MDB將異步處理客戶請求。這適合於需要異步處理請求的場合,比如訂單處理,這樣就能避免客戶端長時間的等待一個方法調用直到返回結果。


  調用一個EJB組件要比調用一個JavaBean麻煩些,由於EJB組件可以分佈在多口,然後使用Home接口創建EJB之後就可以調用EJB的方法了。


七、EJB設計模式


常見EJB設計模式


SESsion Facade pattern


通常项目中,客户端往往需要频繁的对服务器端数据进行操作。当采用实体EJB作为数据的抽象层时,如果直接让客户端程序与实体EJB交互,会产生实现一个业务需求便需要大量的EJB属性操作(如下图1)。这直接导致如下问题:网络负载大(远程客户端时)、并发性能低、客户端与服务器端关联度大、可重用性和可维护性差、性能因此有必要在客户端与实体EJB层间加入Session EJB层,在Sessino EJB中实现商业逻辑并封装对实体EJB的操作。(如下图2)

圖1:客戶端直接與實體EJB交互


圖2:通過SessionEJB層實現


Session Facade模式的好处是:降低了网络负载,SessionEjb可以调用实体EJB的本地接口;将商业逻辑与商业数据隔离;维护与开发方便;显著提高性能。


Session Facade模式因其簡單使用,是目前使用很廣的模式。但具體應用過程中應注意:避免將所有的操作封裝到一個很大的SessionEJB內;服務器端數據結構應由實體EJB實現,除非特例否則避免直接的數據庫操作;SessionEjb內某些系統通用操作的代碼容易重複(比如權限檢查等,解決辦法是將系統通用服務封裝在Java Class內)。


MesSAge Facade Pattern


很多時候,一次RequeST需要操作多個EJB又不需要得到即時返回。對這種異步調用,通常應用Message Fa?ade Pattern.


这种时候,如采用Session Fa?ade Pattern存在如下问题: 1. 客户端等待返回的时间过长。一个SessionEjb的实例在完成客户请求过程中中涉及到的每一次对其他实体Ejb的调用过程中都会被锁定直到得到实体EJB返回信息后才能进行下一步操作。这样造成客户不必要的等待,并很容易因时间导致整个事务失败。 2. 系统可靠性和容错性低。如果需要调用不同系统或服务器上或多个异构数据源的多个EJB时,任何一个环节出错,均导致客户请求失败。以Message-Driven Bean为基础的Message Facade Pattern则可以解决上述异步请求需求。具体架构见下图3

圖3:使用Message Facade Pattern


Message Facade Pattern的不足之處在於:1. Message-Driven Bean沒有返回值。這樣通知客戶執行結果只能依賴於EmAIl或人工等其他手段。2. Message-Driven Bean執行過程中無法將捕獲的異常直接返回給客戶端,即無法使客戶端直接直到錯誤信息。3. Message-Driven Bean通過接收Message響應客戶請求,對Message內容的合法性(比如對象的類型等)依賴與客戶端.容易產生運行時錯誤。Message Facade Pattern經常與Session Facade Pattern在同一個項目里共同使用。


EJB Command Pattern


Session Facade Pattern中将商业逻辑实现封装在Session EJB中,这种做法带来诸多益处之外也带来如下问题:


1. 由於業務經常的變化,導致經常需要更新Session EJB代碼。2. 客戶端代碼不得不包含大量EJB相關的API,不利於後期項目維護。3. 項目開發測試需要經常的EJB重部署過程。


引起上述问题的重要根结就是Session EJB本身重量级组件,其开发测试部署工作量较大,开发周期较长。以上不足可以通过EJB Command Pattern克服。


EJB Command Pattern中將商業邏輯實現封裝在普通的Java ClASs(稱之為Command Bean)中。該模式的具體實現有很多種,通常的框架都包括三部分:


1. Command Bean.由應用開發者寫的具體實現某商業操作的Java Class.主要包含getXXX(),setXXX(),exECute()方法。2. Client-Side Routing Logic.由多個Class組成,用於將請求轉發至Command Sever,這個過程對客戶是透明的。這部分代碼可以跨項目使用。路由規則中可以考慮用XML技術。3. Remote Command Server.實際執行商業操作請求。通常可以用Session EJB層實現。


整個框架見下圖4:



圖4:Command的基本框架


EJB Command Pattern具有如下好处:


1. 適應與需要快速開發環境。因Command Bean是輕量級的Java Class,其編譯和調試比較方便。2. 將表現層與商業實現層隔離,同時將客戶端代碼與EJB層隔離。3. 將客戶端代碼開發與服務器端代碼開發相對清晰。早期可以創建空的Command Bean方便客戶端代碼調試。


EJB Command Pattern的弱處在於:1. Command Bean中對事務的控制不如Session EJB中。2. Command Bean是無狀態的。3. 無法將異常直接返回給客戶。4. 在大項目中,由於商業邏輯複雜,常導致大數量的Command Bean存在.5. 作為Command Server的Session EJB打包時必須包含Command Bean以致存在維護上的不便。


EJB Command Pattern的一個實際實現可以參考IBM's Command framework.


Data Transfer object Factory


基於EJB的J2EE項目,經常需要在客戶端與服務器端傳輸大量數據。數據的組織形式常用的是DTO(Data Transfer Object,服務器端數據對象的抽象)。但因為客戶端表現層經常是變化的,所需要服務器端數據也變動頻繁,換句話說,DTO的數量和屬性經常要更改。因此如何以及在何處生成和維護DTO便是需要考慮的問題。


一种解决方案是直接在Entity EJB中直接处理,即在Entity EJB的Bean类中加入getXXXDTO()、setXXXDTO()等。但这样做导致EJB与DTO层紧紧绑定。一旦DTO更改,与该DTO相关的EJB即需要重编译打包。EJB层与客户端层相关联不仅使维护困难而且导致EJB的重用性大大降低。


更好的解決方案是利用Data Transfer Object Factory封裝對DTO的操作邏輯(如下圖6)。


圖6:DTO Factory示例


DTO Factory具体实现方式通常有两种:


1. 普通Java Class實現,用於Session Facade Pattern使用DTO環境下。2. Stateless Session EJB實現,用於非EJB客戶端使用DTO環境下(見圖7)。


圖7:SessionEJB實現DTOFactory


DTO Factory带来如下好处:


1. 使Entity EJB的重用成為可能。由於不含DTO處理邏輯,Entity EJB功能單一化,只作為數據源。不通客戶端通過各自的DTO Factory可以從同一個Entity EJB得到各自所需的個性化數據(自定義DTO)。2. 提高可維護性和性能。3. 可以根據在DTO Factory層生成很複雜的DTO結構,諸如繼承、關聯關係等,而對客戶端提供一個透明、細化的數據接口。


使用DTO Factory時需要注意的是:不需為每個Entity EJB定義一個Factory。可以為一系列相關的Entity EJB創建一個Factory,或者只創建一個Factory。


Generic Attribute Access


使用Entity EJB作为商业数据层时,我们首先需要从数据库加载数据,创建对应的Entity EJB实例,之后对内存中Entity EJB实例的属性进行相应操作。对属性的操作比较直接的做法是:直接调用Entity EJB的getXXX()/setXXX(),通常利用EJB2.0的本地接口;通过DTO Factory生成DTO。但这两种做法都存在如下问题:


1. 當Entity EJB的屬性特別多時候,以上做法會帶來複雜羅嗦的代碼,使EJB變的龐大無比。2. 使Entity EJB的客戶端(比如Session EJB)和Entity EJB的接口緊密關聯。Entity EJB屬性的增刪都需要更改客戶端代碼,給項目開發和維護帶來不便。


事实上可以利用更通用的方式访问Entity EJB的属性,即定义Generic Attribute Access Interface。见下图8:

圖8:Generic Attribute Access Interface示例


Generic Attribute Access Interface由Entity EJB的本地或远程接口实现,并利用Hash Maps传输数据。实现方式常见如下:


1. BMP類型實體EJB可以在Bean類中定義包含所有屬性的私有成員變量HashMap。2. CMP類型實體EJB可以在Bean類中可以適用Java Reflection API實現。3. 建立一個父類,在不同的情況下定義子類重載父類方法。使用Generic Attribute Access Interface需要在客戶端與服務器端對屬性以及對應的關鍵字建立統一的命名習慣。常見的做法如下:1. 建立並保持良好的文檔記錄和命名約定。2. 在實體EJB的實現類中定義靜態成員映射屬性。3. 創建共享靜態類,通過成員變量映射實體EJB屬性。4. 通過JNDI在服務器端保存屬性映射關係。Generic Attribute Access Interface的運用帶來一下益處:1. 接口實現後對不通實體EJB都適用。2. 對屬性較多實體EJB能精簡代碼,並更具維護性。3. 使運行中動態增刪實體EJB屬性成為可能。Generic Attribute Access Interface的缺點在於:1. 訪問EJB屬性時增加了額外的操作。需要通過關鍵字映射屬性,最後還需進行類型轉換。2. 需要建立客戶端與服務器端的命名約定。3. 因為通過HashMap操作時候需要進行類型轉換,容易產生運行時類型不匹配異常。


Business Interface


EJB規範要求Bean實現類必須實現所有在遠程(或本地)接口中定義的所有方法,同時不允許Bean實現類直接繼承遠程(或本地)接口。這就導致編譯時候很容易產生兩者不一致的問題,即遠程(或本地)接口中定義的某方法為在Bean實現類中被實現等錯誤。為避免上訴錯誤,可以利用應用服務器廠商所提供的工具。但也可以應用EJB的設計架構來實現:定義商業接口。Business Interface即創建自定義商業接口,在接口中定義所有EJB提供的商業方法,並讓Bean實現類和遠程(或本地)接口都實現該商業接口。其繼承關係見下圖9:


圖9:商業接口的使用


Business Interface是个普通的Java Class。依赖于使用本地接口与远程接口的不通,Business Interface的定义略有不同:应用与远程接口时,在接口中的方法需要抛出java.rmi.RemoteException;而应用与本地接口时候则不需要作任何特别处理。应用Business Interface时候必须注意一点:EJB规范不允许直接EJB的实例将对自己的引用(this对象)返回给客户端,否则编译时候即报错。但使用Business Interface后,编译时候无法检查出有无将this对象返回给客户端。这一点需要程序员自己保证。


三. 內部數據轉換策略


Data Transfer Object


基於EJB的J2EE多層架構應用中,經常涉及的一個問題就是如何在各層之間傳遞批量數據,比如客戶端對服務器端數據的批量讀寫操作等。比如需要得到實體EJB的屬性,直接的方法是多次調用不通的屬性,如下圖10:


圖10:低效的數據傳遞方式


但這種方法容易導致許??辦法是在一個調用中得到所有需要的屬性。所以可以引入Data Transfer Object來封裝所需要的屬性,並在客戶與服務器端通過傳遞該對象一次實現對數據的操作。如下圖11:

圖11:通過DTO傳遞數據


DTO為普通的Java Class,通常是服務器端數據的快照。由於網絡傳輸的需要,DTO應該實現java.io.Serializable接口。DTO的設計有兩種模型:Domain DTO以及Custom DTO。Domain DTO僅僅實現對服務器數據的拷貝,通常與實體EJB為一對一的關係(也存在為多個相關聯的實體EJB對應一個Domain DTO)。Domain DTO通常除用於讀取更改實體EJB屬性外也可用於創建實體EJB時候。實體EJB與Domain DTO對應關係如下圖12:


圖12:Account EJB 與 Account DomainDTO


Domain DTO的应用除了DTO所具有的一般优点外,还有别的益处:


1. 開發迅速。因為一旦實體EJB設計好後,很容易轉換得到Domain DTO。2. 可以利用Domain DTO的setXXX()方法在客戶端進行屬性有效性效驗。Domain DTO的缺點有:1. 客戶端綁定了服務器端數據模型,不利於維護。2. 不夠靈活,無法處理客戶端的多樣化數據要求。對一個數百個屬性的實體EJB請求一個屬性時候卻返回一個包含所有屬性值的Domain DTO明顯是笨重的實現。3. 導致代碼的重複。4. Domain DTO中如果嵌套包含了別的Domain DTO時,一旦需服務器端數據的更改而需要重定義Domain DTO模型時候異常困難。


Custom DTO则可以克服上述的一些缺点。Customer DTO仅仅封装用户感兴趣的服务器数据集即可以根据客户端需求创建Customer DTO。这样作的优点是灵活高效;缺点是大项目中可能导致大量的Customer DTO存在。


通常Domain DTO可以用於數據的更新與創建;Customer DTO可以用於客戶用於表現層的數據讀取。兩者可以相輔相成。而且使用DTO一般與DTO Factory同時使用。


Domain Transfer Hash Map


DTO的使用往往缺乏通用性。不通的用戶案例需要創建不同的DTO。當項目很複雜時,從維護性考慮需要更好的數據傳輸的實現方式。Domain Transfer Hash Map即利用HashMap作為客戶所需數據集的封裝。好處是:


1. 良好的維護性。2. 較大的通用性。不同的客戶端可以使用相同的數據傳遞方式。缺點是:1. 需要維護客戶端與服務器端在屬性及其對應關鍵字的映射關係。2. 當需要使用基本類型的數據時候,因為Hash Map的限制必須將基本類型先轉換成對象。3. 使用得到的數據時,需要進行類型強制轉換。


Data Transfer RowSet


当需要处理直接的JDBC调用得到的结果集时,显然用DTO/Hash Map已经不合适,因为需要对大量数据进行类型转换等额外操作是很费资源和不必要的,而且最终用户常需要以表格式样显示数据。


所以對二維表式數據,更好的處理方式是利用Data Transfer RowSet。Data Transfer RowSet通過將ResultSet直接轉換為RowSet傳遞給客戶端。在Session EJB中使用RowSet的一段示例代碼如下圖13:


圖13:使用RowSet


使用RowSet的好處很多:1. 接口通用於各樣的數據庫查詢操作。2. 當需要表格式數據顯示時,因為直接從ResultSet得到,所以不需要額外的數據類型轉換。缺點是:1. 數據庫結構暴露給客戶端。2. 不符合面向對象設計思想。3. 依賴於SQL。 Data Transfer RowSet通常用於只讀式數據的顯示操作,經常和JDBC for Reading Pattern連用。


四.事務和數據持久機制


JDBC for Reading Pattern


基於EJB的J2EE應用中,通過EJB對數據庫的操作可以有兩種方式:實體EJB或者Session EJB中直接利用JDBC訪問。客戶很多時候取出數據庫中數據並以表格方式顯示。這種情形如果使用實體EJB會導致如下問題:1. 引用服務器端頻繁的數據庫查詢和加載操作。因為加載N個實體EJB總需要進行一次find()操作N次數據加載。2. 如果使用Remote接口,引起頻繁的額外網絡操作。3. 對關聯關係比較複雜的數據庫表結構,很難直接通過Entity EJB表現。


因此建议在只需对数据库表数据进行只读访问时候,应该采用JDBC for Reading Pattern,即通过JDBC直接访问数据库。除了避免上述使用实体EJB的缺点还带来一下好处:1. 充分利用数据库能力,比如数据库的缓存机制。2. 减少了对事务控制的资源。3. 利用自定义SQL可以按需要比较灵活的读取数据。4. 只需要一次数据查询,减少了数据库操作。


缺點是:1. 於J2EE應用的面向對象設計相違背。2. 因為Session EJB代碼中包含了自定義SQL,維護性差。3. Session EJB中不得不包含JDBC的API,並且需要了解數據庫結構。


部屬人員: 使用相應工具在運行環境下配置 EJB系統管理員: 監視運行時情況