EJB 3.0 在 WAS V7 上開發部署的最佳實踐

CloudSpace發表於2010-01-04

轉;http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0912_zhuzq_ejbwas7/index.html

引言

IBM WebSphere Application Server 從 7.0 版本起開始正式支援 EJB 3.0(在之前的 6.1 版本有釋出針對 EJB 3.0 的功能部件包)。目前建立於 WAS V7 上的 EJB 3.0 應用並不常見。作者在實際專案中總結了使用 WAS V7 部署 EJB 3.0 應用遇到的一些問題(部分為開發細節)及最佳實踐,並試圖通過一些簡單的例子將這些經驗展現給需要在 WAS V7 環境下開發 EJB 3.0 應用的開發者們。

本文建立在如下條件之上:

  • 使用 IBM WebSphere Application Server V7.0(WAS V7)作為應用伺服器
  • 使用 IBM Rational Application Developer for WebSphere Software V7.5 進行開發工作

    建立工程的若干最佳實踐

    介面,業務物件與實現邏輯相分離 :

    建議將 EJB 客戶端以及所有定義的業務物件(Business Objects)放到一個類似依賴庫的工程中以便將來可以方便地在其他工程中進行呼叫。此外這樣做也提高了介面和業務物件的可維護性。於是在建立工程時我們選擇“Create an EJB Client JAR module to hold the client interfaces and classes”選項(這樣由 RAD 自動生成的客戶端會被放置於該客戶端工程中,將來我們可以將自定義的業務物件也放置於該工程內)。


    圖 1. 建立客戶端 JAR 模組
    圖 1. 建立客戶端 JAR 模組

    使用視覺化工具生成介面程式碼 :

    如果在新增無狀態會話 Bean 的時候選擇了“Add bean to Class Diagram”,可以在類圖中對 Bean 進行基本操作。如選擇該 Bean 的一個方法後在右鍵選單中點選“Java EE Tools”— >“Promote Methods”,可以將該方法新增入該 Bean 的客戶端介面程式碼中。


    圖 2. 生成介面程式碼
    圖 2. 生成介面程式碼 

    對外介面設計開發的若干最佳實踐

    開發企業應用時難免需要和其他元件進行互動,下面將分節討論 EJB 3.0 元件和其他一些元件的互動方式。

    將 EJB 釋出為 Web Service

    使用 EJB 客戶端呼叫釋出到應用伺服器上的會話 Bean 往往具有一定的侷限性(需要有容器上下文 -Context)。於是很多情況下我們希望將其釋出為 Web Service 使其方便呼叫。

    自底向上生成 Web Service:

    右鍵單擊需要釋出為 Web Service 的無狀態會話 Bean,選擇“Web Services”— >“Create Web Services”,選擇“Bottom up EJB Web Service”( 自底向上由 EJB 釋出 Web Service) 以及 EJB 實現 Bean(SLBSampleBean),該實現 Bean 會自動被選擇。 確認 Web Service 源工程以及 EAR 工程後,點選“Next”。

    接下來的配置中,我們需要關注稱為“HTTP router”的配置項。當我們通過 IBM 匯出工具將一個會話 Bean 釋出為 Web Service 後,工具實際上會生成一個接受對該 Web Service 請求的代理類,執行中它將接收到的 Web Service 呼叫請求轉化為對實際會話 Bean 的呼叫,並將呼叫結果以 Web Service 響應的形式返回。由於這個代理是一個 Servlet,因此必須將其置於一個 Web 應用程式中。IBM 匯出工具可以幫助我們生成這樣一個 Web 應用程式並將代理 Servlet 置於其中,而“HTTP router”配置項的值就是該 Web 應用程式的工程名。


    圖 3. EJB 3.0 Web Service 的架構
    圖 3. EJB 3.0 Web Service 的架構

    使用訊息驅動 Bean 連線 Message Queue

    使用啟用規範(Activation specifications)取代偵聽器埠(Listener port):

    啟用規範是一組訊息屬性的配置,通過這組配置可以將 Websphere Application Server 和企業資訊系統(Enterprise Information System)通過 JCA-Java™ EE 聯結器架構(Java™ EE Connector Architecture)1.5 規範連線整合起來。在 WebSphere Application Server V7 之前的版本(V6)中僅支援採用偵聽器埠連線 Message Queue 與訊息驅動 Bean,而從 Version 7 開始支援使用啟用規範連線 Message Queue,並且偵聽器埠已經不再推薦使用,因此在今後的開發中我們更多地使用啟用規範來取代之前的偵聽器埠。

    需要建立一個連線 Message Queue 的啟用規範,在管理控制檯左側點選“Resources” “JMS” “Activation specifications”。右邊的頁面中我們能夠看到所有 JMS 啟用規範的列表。點選“New”按鈕。在接下來的表單中,選擇 WebSphere MQ messaging provider,表示建立一個連線到 MQ 的啟用規範。設定好目標佇列的 JNDI 名和型別(Queue),目標佇列是 MDB 的訊息來源。

    選擇“Enter all the required information into this wizard”來設定連線的細節。輸入 MQ 伺服器上的佇列管理器名稱。設定好連線細節,特別注意確保連線通道(Connection Channel)的配置正確,該值可以在 MQ 伺服器上檢視。


    圖 4. MQ 啟用規範的連線配置
    圖 4. MQ 啟用規範的連線配置

    以上的操作是在管理控制檯中完成的,為了提高環境配置的自動化程度以便在實際專案中提高部署和測試的效率,我們也可以使用 JACL 指令碼來完成以上配置(方便批量操作)。以下是一個使用 JACL 指令碼的例子:


    清單 1. 建立啟用規範的 JACL 指令碼
    				
     $AdminTask createWMQActivationSpec [$AdminConfig getid /Server:server1] 
     {-name "ActSpecSample" -jndiName "ActSpecSample" -destinationJndiName "QSample"
      -destinationType javax.jms.Queue -qmgrName QueueSample -qmgrHostname localhost
       -wmqTransportType CLIENT -qmgrPortNumber 1414 
       -qmgrSvrconnChannel SYSTEM.DEF.SVRCONN} 
    
     $AdminConfig save 
    

    如果希望瞭解更多關於 JACL 指令碼語法及其他細節,請參考相關文件。

    建立訊息驅動 Bean 和啟用規範之間的繫結關係 :

    在建立好訊息驅動 Bean(MDB)和對應的啟用規範後,還需要對二者進行繫結。可以通過繫結檔案來實現 MDB 和 MQ 啟用規範之間的繫結:該檔案的檔名必須命名為 ibm-ejb-jar-bnd.xml,並置於工程的 META-INF 目錄下。


    圖 5. 手動建立 MDB 繫結檔案
    圖 5. 手動建立 MDB 繫結檔案

    以下是繫結檔案的一個例子,我們需要配置需要繫結的 MDB 的名稱以及需要使用的 MQ 啟用規範的 JNDI 名。


    清單 2. 繫結檔案內容示例
    				
      
      
      
      
      
      
    

    請注意以上例子的 標籤,該標籤完成了將 MDBSampleBean 與啟用規範 ActSpecSample 繫結的功能。

    不過,我們也有另一種方法來取代使用繫結檔案:可以在將 EJB 工程部署到 WAS V7 時,在管理控制檯中進行配置繫結。如果對應的 EJB 工程中不包含繫結檔案,在部署的過程中,我們可以看到多出的一個步驟(如下圖 Step 3)Bind listener for message-driven beans,在該步驟中,我們可以指定需要繫結的啟用規範。


    圖 6. 部署過程中繫結啟用規範
    圖 6. 部署過程中繫結啟用規範

    類似配置繫結檔案,在控制檯中我們也需要設定要繫結的啟用規範的 JNDI 名。


    圖 7. 啟用規範的配置
    圖 7. 啟用規範的配置

    完成部署步驟之後,我們建立的 MDB 就可以正常工作了(測試過程略)。

    持久層實現的若干最佳實踐

    EJB 3.0 中,我們使用 JPA (Java Persistent API)來處理有關持久化相關的操作。作者並不打算在本章節中對 JPA 展開深入討論,如果需要了解更多有關 JPA 的技術細節,請參考相關文獻或使用手冊。

    建立 JPA 工程

    不使用 ORM 檔案:

    在建立工程之前,應該先在 RAD 環境中建立一個到目標資料庫的連線(在資料來源瀏覽器檢視 -Data Source Explorer View 中建立連線)。在建立 JPA 工程時,選擇之前建立的資料庫連線,並配置好預設的資料庫方案(Schema)。由於 EJB 3.0 為了簡化開發,增加了對 Java 註釋(annotation)的支援,因此,作者建議不為專案指定一個 ORM(物件關係對映)檔案而是使用 Java 註釋(annotation)來代替,因此不用啟用“Create orm.xml”選項。


    圖 8. JPA 工程的配置
    圖 8. JPA 工程的配置

    生成持久層程式碼

    使用 IDE 輔助生成程式碼:

    在建立好的 JPA 工程中,我們在“JPA Content”中能夠看到一個名為 persistence.xml 的檔案,該檔案是整個持久化環境的配置檔案,維護著大部分 JPA 工程的配置資訊,在其上右鍵單擊並選擇 Configure Project for JDBC Deployment 來設定其中的 JDBC 相關配置項。完成設定之後將會在 persistence.xml 檔案中加入連線相關資訊。

    接下來,我們使用 JPA 工具由資料庫表生成實體(Entity)。右鍵單擊 JPA 工程選擇“JPA Tools” “Generate Entities”,接著選擇已經配置好的連線以及方案(Schematic)。選擇需要生成實體的表,這裡我們選擇已經建立好的表 TABLESAMPLE,並指定生成的目標目錄和包(package)。


    圖 9. 選擇需要生成實體的表
    圖 9. 選擇需要生成實體的表

    流程結束後,對應的包下會生成一個實體類,生成的實體類會在 persistence.xml 檔案中註冊,如下:


    清單 3. 實體註冊程式碼

    				
     com.ibm.gbsc.entity.Tablesample 
    

    EntityManager 的使用

    EntityManager 是 JPA 的一個重要概念。一個 EntityManager 例項和一個持久化上下文(persistence context)相關聯,而持久化上下文是一組具有唯一標識的持久化實體的例項(Instance)的集合,實體例項(Entity Instance)及其生命週期都交由持久化上下文來維護。EntityManager 定義了和持久化上下文互動的介面方法,並且向上層提供 API 用於建立或移除一個持久化的實體例項(Entity Instance),通過主鍵或其他條件來查詢實體例項(Entity Instance)。

    EntityManager 例項的獲取:

    我們可以通過註釋(annotation)的方式在會話 Bean 中注入一個 EntityManager 物件,程式碼如下:


    清單 4. EntityManager 的註釋

    				
     @PersistenceContext(unitName = "JPASample") 
        private EntityManager em; 
    

    避免使用 DAO 模型:

    當然我們也可以使用 RAD 提供的 JPA 工具(JPA Tools)來生成一種稱之為“JPA 管理 Bean(JPA Manager Bean)”的物件來管理實體。這種管理 Bean 採用我們所熟知的 DAO 模型來構建管理體系,在 EntityManager 之上進行了一次封裝,並提供基本的 CRUD 方法。但是在企業級應用中並不推薦使用 JPA 管理 Bean 而是使用之前的方法,依賴容器來注入 EntityManger,這樣的優點是容器可以幫我們更好地管理和維護 EntityManager,並且能夠輕鬆地將其加入到一個全域性事務當中(JPA 管理 Bean 在全域性事務中無法使用)。以下方法(會話 Bean 的一個方法)示例了 EntityManager 物件的使用:


    清單 5. EntityManager 的使用

    				
     public void insertDB(long id) { 
            Tablesample bo=new Tablesample(); 
            bo.setId(id); 
            bo.setName("test"+id); 
            em.persist(bo);       
     } 
    

    事務策略最佳實踐

    事務是企業應用中非常重要的一環。通常情況下,存在三種事務模型:本地事務模型(Local Transaction Model),程式設計式事務模型(Programmatic Transaction Model),宣告式事務模型(Declarative Transaction Model)。

    本地事務模型 :

    在本地事務模型中,事務由底層資料庫(DBMS)或訊息提供者(Message Provider)來管理維護,從開發者的角度來看,只需要管理使用連線(connections)而不需要管理事務。例如我們一般情況下的簡單的 JDBC 應用開發。

    本地事務模型在小型工程的簡單更新操作中能夠很好地工作,但是在更加複雜的應用場景下,這種模型會讓開發者面對很多問題。一個問題就是在處理複雜邏輯時,面向連線的程式設計容易造成程式的錯誤。另一個問題是在一個 XA 全域性事務中難以協調各資源的工作。

    一般情況下,EJB 工程不使用這樣的事務模型,讓我們關注另外兩種事務模型:

    程式設計式事務模型 :

    在程式設計式事務模型中,開發者不再面向連線而是面向事務進行開發。在 EJB 工程中這類事務模型體現為 Bean 管理的事務(Bean-Managed Transactions--BMT)。

    我們可以如下開發來使用程式設計式事務模型:


    清單 6. EJB 中使用程式設計式事務模型

    				
     UserTransaction txn = sessionCtx.getUserTransaction(); 
            txn.begin(); 
            try { 
                // Some operation 
     // ... 
                txn.commit(); 
            } catch (Exception e) { 
                log.error(e); 
                txn.rollback(); 
                throw e; 
            } 
    

    程式碼中 sessionCtx 是 Bean 的一個私有屬性(field),可以通過註釋 @Resource 來實現從容器注入。此外,我們還需要在 Bean 的實現類的定義中告訴容器該 Bean 的事務模式是 Bean-Managed 的(同樣通過註釋):

    清單 7. BMT 事務宣告

    @TransactionManagement(TransactionManagementType.BEAN)

    當然,這種事務模型也不侷限於 BMT,它同樣可以應用於容器內的 Servlet 或者 POJO,在容器中獲取一個可操作的事務物件,我們使用如下的程式碼:


    清單 8. Servlet 中使用程式設計式事務模型

    				
     InitialContext ctx = new InitialContext(); 
     UserTransaction txn = (UserTransaction)ctx .lookup("java:comp/UserTransaction"); 
    

    程式碼中所使用的 JNDI 名“java:comp/UserTransaction”是在 Websphere v5+ 的環境下的用法,如果你所開發的應用不是部署於這樣的環境中,請參考該應用伺服器的相關文件。

    在 EJB(特別是無狀態會話 Bean)中,程式設計式事務模型存在一個重大的架構上的限制:我們不能在兩個都使用程式設計式事務模式的 Bean 之間傳遞事務上下文(transaction context)。不過,我們可以將一個使用程式設計式事務模型的 EJB 或客戶端的事務上下文傳遞給一個使用宣告式事務模型的 EJB。

    因此在一般情況下,我們僅在呼叫 EJB 的客戶端中使用程式設計式事務模型。接下來我們將討論宣告式的事務模型。

    宣告式事務模型 :

    在宣告式事務模型中,由容器來管理維護事務,這意味著開發者不需要通過寫 Java 程式碼來開始或提交一個事務,取而代之的是使用一定的“宣告”告訴容器如何來管理事務。我們可以通過 ejb-jarv.xml 配置檔案來實現對容器的宣告,同樣也可以使用註釋或部署描述符來宣告使用事務。在 EJB 中,宣告式的事務模型體現為容器管理的事務(Container-Managed Transactions--CMT)。

    在使用宣告式事務模型的程式碼中,我們僅僅需要使用一個方法 -- setRollbackOnly(),其他都可以通過註釋或配置來實現。setRollbackOnly() 方法告訴容器本事務不論接下來進行何種操作,最終都將被回滾。以下是使用宣告式事務的 EJB 中一個方法實現的例子:


    清單 9. EJB 中使用宣告式事務模型

    				
     @TransactionAttribute(TransactionAttributeType.REQUIRED) 
        public void operation() { 
            try { 
                // Some business logic 
     // ... 
            } catch (Exception ex) { 
                ex.printStackTrace(); 
                sessionCtx.setRollbackOnly(); 
            } 
    
     } 
    

    當然,我們還需要使用註釋來通知容器本 EJB 是一個容器管理事務(CMT)的 Bean:


    清單 10. CMT 事務宣告

    				
     @TransactionManagement(TransactionManagementType.CONTAINER) 
    

    事務策略的組合:

    結合以上各種事務模型的討論結論以及工程中的實際情況,在大部分情況下,我們在實現 EJB 的時候使用宣告式的事務模型(即 CMT),而在呼叫這些 EJB 的客戶端程式碼中使用程式設計式的事務模型。

    總結

    本文通過一些簡單的例子對 WAS V7 環境下 EJB 3.0 應用開發容易遇到的問題及解決的最佳實踐進行了講解和說明,主要介紹了 EJB 3.0 應用中對外介面,持久層,事務策略三大部分的內容。相信在工程實踐中能夠給開發者們提供參考。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-624207/,如需轉載,請註明出處,否則將追究法律責任。

相關文章