BigAdmin System Administration Portal
EJB 3.0 相容性及遷移,以及使用 EJB 階段作業 Bean 當作模型外觀
Print-friendly VersionPrint-friendly Version
本期簡介

歡迎閱讀 2007 年 2 月 24 日的企業 Java 技術祕訣。您可在本期中獲得有關使用企業 Java 技術與 API (如 Java Platform, Enterprise Edition (Java EE)) 的秘訣。

本期涵蓋下列內容:

這些祕訣是使用 Java EE 5 SDK 發展而成。您可以從「Java EE Downloads」網頁下載 SDK。

您可以下載「EJB 3.0 - EJB 2.x 互通的功能」祕訣的歸檔範例

您可以下載「使用 EJB 階段作業 Bean 當作模型外觀」祕訣的歸檔範例

使用此程式碼及/或下列資訊應遵循授權規定

 
EJB 3.0 相容性及遷移
作者:Ken Saks  

Enterprise JavaBeans (EJB) 3.0 規格採用了全新、大幅簡化的新 API,以便實作及存取階段作業 Bean。很多開發人員對於根據新 API 寫成的應用程式能否與舊式 EJB 應用程式互動,以及舊式應用程式能否與這個新的 API 互動存有疑問。

要求開發人員整個重寫現有 EJB 應用程式以便利用新功能的作法並不可行。在某些情況下,開發人員雖然打算升級自己的應用程式,但卻希望能分階段升級。而在另外一些情況下,他們想要撰寫新的 EJB 3.0 應用程式,但仍想利用現有的應用程式服務。EJB 3.0 規格能夠實現這兩項策略。本祕訣就是要說明該怎麼做。

本祕訣隨附一個應用程式套裝模組範例。祕訣中的程式碼範例取自範例 (內含於套裝模組中) 的原始碼。該範例使用 Java EE 5 SDK。您可以從「Java EE Downloads」網頁下載 Java EE 5 SDK。

EJB 3.0 與 EJB 2.x 的相容性

首先我們看一個範例,有一個寫成簡化 EJB 3.0 API 的應用程式,呼叫舊式 EJB 應用程式。在本祕訣隨附的範例原始碼當中,您將發現一個稱為 MigrationBean 的 EJB 3.0 無狀態階段作業 Bean。這個 Bean 會呼叫一個稱為 EJB 2xBean 的遠端 EJB 2.x 無狀態階段作業 Bean。MigrationBean 可以是全新的 Bean,或是為了使用 EJB 3.0 API 而重新編碼的現有 Bean。為了簡化,此範例中的兩個 Bean 都封裝在同一個歸檔之中,但這並非必要。以下是 EJB 2xBean 的 EJB 2.x 首頁及遠端介面:


   public interface EJB2xHome extends EJBHome {

       public EJB2xRemote create()
           throws CreateException, RemoteException;
   }

   public interface EJB2xRemote extends EJBObject {

       public void foo() throws RemoteException;

   }
   
以下是 MigrationBean 類別的第一部份:

   @Stateless
   public class MigrationBean implements MigrationRemote {

       // Inject a reference to the Home interface 
       // of the EJB 2.x bean.
       @EJB private EJB2xHome ejb2xHome;

       private EJB2xRemote ejb2x;   

MigrationBean 使用 @EJB 附註將參照插入 EJB2xHome 中。@EJB 附註是隨 EJB 3.0 規格推出的新功能。但是依設計,它除了搭配 EJB 3.0 商務介面檢視使用以外,也能搭配舊式 EJB 2.x 首頁檢視使用。每當 EJB 容器實例化 MigrationBean 時,就會在 ejb2xHome 資料成員中插入 EJB2xHome 的參照。

搭配 2.x 首頁介面使用 @EJB 附註的一大好處,就是讓您不必使用 PortableRemoteObject.narrow()。使用 PortableRemoteObject.narrow() 方法,可以將查找首頁介面時傳回的 Object 轉換成正確的類型。在 EJB 3.0 中,不需進行任何特殊類型轉換,就能使用插入的首頁參照。

MigrationBean 類別會定義 @PostConstruct 方法,以使用首頁參照來建立 EJB2xRemote 參照。接著,該類別會將結果存入另一個資料成員中。

    @PostConstruct
    private void initialization() {
        try {
            ejb2x = ejb2xHome.create();
        } catch(Exception e) {
            throw new EJBException(e);
        }
    }
    
在此類別的最後一部份,MigrationBean 會呼叫位於其本身商務方法內的 EJB2x 商務方法。

    public void bar() {

      try {
          // Call operation on legacy EJB.
          ejb2x.foo();
      } catch(Exception e) {
          throw new EJBException(e);

      }
    }    

所有標準 EJB 服務 (像是安全性及作業事件傳遞) 都會按照預期的方式在兩個 Bean 之間運作。

請注意,使用 @EJB 附註來存取 EJB 2.x Bean 的方式不限於 EJB 元件。您可以使用相同的方法,從 Java EE 5 應用程式的其他元件類型 (例如 Servlet 或應用程式用戶端) 存取舊式 Bean。此外,雖然這個範例使用遠端 EJB 2.x Bean,您還是可以使用此方法來存取本機 EJB 2.x Bean。

EJB 2.x 與 EJB 3.0 的相容性

在第一個範例中,您看到了使用新 EJB 3.0 API 撰寫的 EJB 元件如何成為舊式 EJB 元件的用戶端。現在,讓我們來看看相反的範例。在該範例中,您將了解使用 EJB 2.x 用戶端 API 寫成的舊式元件,如何存取使用 EJB 3.0 簡化 API 所實作的階段作業 Bean。這裡指的是使用新的 EJB,而不對現有的 EJB 用戶端程式碼做任何變更。

在第二個範例中,稱為 AdaptedBean 的有狀態階段作業 Bean 是使用簡化 EJB 3.0 API 來實作的。這個 Bean 會對獨立的 Java 用戶端公開 2.x 遠端首頁介面。以下是 AdaptedBean 的首頁及遠端介面:

   public interface AdaptedHome extends EJBHome {

       public AdaptedRemote create(String id)
           throws CreateException, RemoteException;
   }

   public interface AdaptedRemote extends EJBObject {

       public String getId() throws RemoteException;
   }
   
以下是 AdaptedBean 類別:

   @Stateful
   @RemoteHome(AdaptedHome.class)
   public class AdaptedBean {

       private String myId = "unknown";

       @Init
       public void create(String id) {
           myId = id;
       }

       public String getId() {
           return myId;
       }

   }   

請注意,此 Bean 類別是使用類似 POJO 的簡化 EJB 3.0 來實作的。但是,它使用 @RemoteHome 附註來公開 EJB 2.x 型的遠端首頁介面。此附註告知 EJB 容器:該 Bean 有一個稱為 AdaptedHome 的首頁介面,以及一個稱為 AdaptedRemote 的遠端介面。您不需用不同的附註來指定 AdaptedRemote 介面。這是因為容器從 AdaptedHomecreate() 方法簽名,就能導出介面。如果此 Bean 公開了一個本機首頁介面,它就會改用 @LocalHome 附註。

類別中的另一個重要附註就是 @Init。EJB 2.x 檢視一律會定義 create 方法,因此您必須在 Bean 類別上定義一個方法來處理建立作業。@Init 附註就會告訴 EJB 容器是哪個方法。此方法可以具有任何名稱,但其方法參數必須符合對應首頁介面中的 create 方法。

以下是用來存取 AdaptedBean 的獨立用戶端程式碼:

   try {

        InitialContext ic = new InitialContext();
        Object o = ic.lookup(AdaptedHome.class.getName());

        AdaptedHome adaptedHome = (AdaptedHome)
            PortableRemoteObject.narrow(o, AdaptedHome.class);

        AdaptedRemote adapted = adaptedHome.create("duke");

        System.out.println("Adapted id = " + adapted.getId());

   } catch(Exception e) { ... }
   

請注意,此用戶端程式碼使用標準 EJB 2.x 用戶端程式設計模型。它不需要知道目標 Bean 是使用 EJB 3.0 來實作的。

執行範例程式碼

本祕訣隨附一個套裝模組範例。若要安裝及執行該範例:

  1. 如果您尚未從「Java EE Downloads」網頁下載 Java EE 5 SDK,請先執行此作業。此外,請確定已安裝 Java Platform Standard Edition (Java SE) 5 SDK。

  2. 下載本秘訣隨附的套裝模組範例,並將其內容解壓縮。您現在應看到新解壓縮的目錄為 <sample_install_dir>/ttfeb2007ejbmigration,其中 <sample_install_dir> 是套裝模組範例的安裝目錄。例如,若在 Windows 機器上將內容解壓縮到 C:\,則新建的目錄應該位於 C:\ttfeb2007ejbmigration。在這個目錄下,您應該會看到兩個子目錄:MigrationAdapted

  3. 若要建立及執行 EJB 3.0 與 EJB 2.x 的相容性範例,請切換到 Migration 目錄。若要建立及執行 EJB 2.x 與 EJB 3.0 的相容性範例,請切換到 Adapted 目錄。然後,將所選目錄中 build.xml 檔案裡的 javaee.home 位置屬性,設定為 Java EE 5 應用程式伺服器的安裝目錄。

  4. 輸入下列指令來啟動應用程式伺服器:

       <appserv_install>/bin/asadmin start-domain domain1
          
    其中,<appsrv_install> 是 Java EE 5 應用程式伺服器的安裝位置。

  5. 輸入指令:

        ant all

    這會建立應用程式範例,然後加以部署及執行。

    在 EJB 3.0 與 EJB 2.x 的相容性範例輸出中,您會看到下列內容:

            runappclient:
              [exec] Successfully called EJB 3.0 bean

    在 EJB 2.x 與 EJB 3.0 相容性範例輸出中,您會看到下列內容:

            runjavaclient:
              [java] Adapted id = duke

    隨後將自動取消部署應用程式,並清除其建置資源。

摘要

EJB 3.0 規格大幅簡化了階段作業 Bean API。但在簡化時已經顧慮到企業早就投入大量資源,利用舊版規格建立了 EJB 應用程式。有鑑於此,EJB 3.0 的目標在於確保新應用程式與現有應用程式之間能順利地互通。如果您是使用 EJB 3.0 的開發人員,就有很大的彈性可以決定是將舊式應用程式遷移到新的 API,還是透過新元件來利用舊式應用程式。

關於作者

Ken Saks 是 Java EE5 SDK 中 EJB 3.0 容器的首席架構師。他於 1999 年就加入 Sun Microsystems 的 Enterprise Java 團隊。

使用 EJB 階段作業 Bean 當作模型外觀
作者:Sean Brydon 及 Yutaka Yoshida  

2006 年 11 月 18 日的技術祕訣「使用模型外觀」一文,主要探討使用 Java Persistence API 管理 Java EE 5 應用程式的網域模型持續性時,會使情況變複雜的一些因素。此祕訣說明模型外觀 (或簡稱為「外觀」) 如何降低這種複雜性。

本秘訣的範例是說明 Servlet 如何與實作為 Web 層級元件的「外觀」互動。在本祕訣中,您將了解如何將「外觀」實作為 Enterprise JavaBeans (EJB) 技術階段作業 Bean。

為什麼要使用階段作業 Bean 當作模型外觀?

如果您想擁有純 Web 的架構,而且不想使用 EJB 容器,那麼將「外觀」實作為 Web 元件會是個好辦法。但是,使用 EJB 容器有明顯的好處:例如,EJB 容器可提供各種服務,如容器管理式作業事件的支援。如果您將「外觀」實作為階段作業 Bean,即可運用這項支援。在這種情況下,EJB 容器會管理作業事件,讓您不必納入程式碼來管理作業事件。

外觀範例

在此範例中,Servlet 會與實作為階段作業 Bean 的「外觀」互動。如果您熟悉 EJB 3.0 技術,就會知道階段作業 Bean 需要商務介面才能讓用戶端檢視 Bean。這是 Servlet 用來存取「外觀」的商務介面。

在此範例中,用於「外觀」的商務介面如下所示:

   import java.util.List;

   import com.sun.javaee.blueprints.sessionfacade.InvalidItemException;
   import com.sun.javaee.blueprints.sessionfacade.model.Item;

   public interface CatalogFacade {
       public void addItem(Item item)throws InvalidItemException;
       public Item getItem(int itemID);
       public List<Item> getAllItems();
   }

在本祕訣隨附的應用程式套裝模組範例中,您可以找到此商務介面的原始碼,以及此祕訣中其他程式碼範例的原始碼。

請注意,這個介面相當簡單。但是,儘管很簡單,此介面還是包含了用戶端 Servlet 存取此 Web 應用程式的模型層級時,所需的一切資訊。另請注意,就像任何 EJB 3.0 商務介面一樣,它不需要匯入 EJB 套裝模組特有的類別。這種簡單性是使用「外觀」的主要好處。所有用戶端 Web 元件都要經過「外觀」才能存取模型層級物件。「外觀」會封裝在管理持續性物件時可能牽涉到的 Java Persistence API 或 Java Transaction API 的所有詳細資訊。

現在,就讓我們來看看「外觀」。

   @Stateless
   public class CatalogFacadeBean implements CatalogFacade {  
   
     @PersistenceContext(unitName="CatalogPu")
     private EntityManager em;
   
     public void addItem(Item item) throws 
             InvalidItemException {
       if(item.getName().length() == 0)
         throw new InvalidItemException("The item" +
           " name cannot be empty." +
           " Please specify a name for the item. ");
       em.persist(item);
     }
   
     public Item getItem(int itemID) {
       Item item =  em.find(Item.class,itemID);
       return item;
     }
   
     public List<Item> getAllItems() {
       List<Item> items = em.createQuery(
               "SELECT OBJECT(i) FROM Item i").getResultList();  
       return items;
     }
   }

「外觀」有幾點需要注意的事項:

  • 它是無狀態的。@Stateless 附註會將 CatalogFacadeBean 標示為無狀態的階段作業 Bean。如果您需要維持用戶端 Web 請求之間的階段作業狀態,則可以對「外觀」使用有狀態的階段作業 Bean,或將狀態儲存在其他地方,例如 Web 層級的 HttpSession 中。一般而言,無狀態的階段作業 Bean 比較常用來在 Java EE 5 應用程式中實作「外觀」。

  • 它位於本機。無狀態的階段作業 Bean 可以是本機物件也可以是遠端物件。無狀態的階段作業 Bean 可以是本機物件也可以是遠端物件。無狀態的階段作業 Bean 預設為本機,因此不需要指定附註來註解它位於本機。

  • 它使用容器管理式作業事件。在 CatalogFacadeBean 中,沒有用來區分作業事件的程式碼。階段作業 Bean 使用 EJB 容器的容器管理式作業事件服務。如果階段作業 Bean 不使用容器管理式作業事件服務,而改用應用程式管理式作業事件,您就需要納入對 Java Transaction API 的呼叫,以便標示每個作業事件的界限。

  • 它依賴預設的作業事件運作方式。依預設,「外觀」的每種方法都在由容器管理的作業事件中執行。您也可以指定值為 "REQUIRED"@TransactionAttribute 附註來取得這個運作方式,或在部署描述元中指定此運作方式。

  • 它利用容器管理式實體管理員,其中 EJB 容器管理實體管理員的生命週期。@PersistenceContext 附註告知 EJB 容器將 EntityManager 物件插入階段作業 Bean 中。如果 Bean 使用了應用程式管理的實體管理員,您就需要納入用來建立及銷毀實體管理員的程式碼。

  • 它傳回 Java Persistence 物件。「外觀」所傳回的資料傳輸物件或值物件不會是 Java Persistence 物件的副本。Java Persistence API 的一個特性,就是 Java Persistence 物件可由容器管理,也可以當作一般舊式 Java 物件 (POJO) 使用,而事實上,「外觀」用戶端都將這些物件當作 POJO 使用。在某些情況下,Web 元件用戶端可能需要與網域模型以更鬆散的方式耦合。在此情況下,它可以選擇使用 POJO (代表模型層級) 以外的其他物件。但是,在這個範例中,在 Web 層級中使用 Item POJO 就已足夠。這使得程式設計模型變得相對簡單。

  • 丟出應用程式異常。如果使用者並未指定項目的名稱,此階段作業 Bean 會丟出 InvalidItemException,並附帶適當的更正動作提示。InvalidItemException 是一種應用程式異常,和系統異常有所不同。在 EJB 中,應用程式異常是由應用程式開發人員所定義,而且可視為應用程式商務邏輯的一部份。

  • 使用泛型。方法宣告 public List<Item> getAllItems 使用泛型,把 List 指定成 Item 類型的集合。泛型提供一種方法讓您傳達集合的類型,以便 Java 編譯器進行檢查。泛型也讓方法宣告更易於讀取與理解。

使用外觀

現在,讓我們看看使用「外觀」範例的 Servlet:

   public class CatalogServlet extends HttpServlet {
     
     @EJB private CatalogFacade cf;  
     
     ...      
   
     public void doGet(HttpServletRequest request, 
         HttpServletResponse response) throws 
         ServletException, IOException {
       ...       
       
       if ("additem.do".equals(selectedURL))  {
             //get values from request and place 
             // them into new Item
             String desc = request.getParameter("item_desc");
             String name = request.getParameter("item_name");
             ...
             Item item = new Item();
             item.setName(name);
             item.setDescription(desc);
             ...
             //use facade to add new Item to database
             cf.addItem(item);
         ...         
       }
       ...
   }

請注意,Servlet 將透過 @EJB 附註使用相依性插入,以查找及取得「外觀」。另請注意,「外觀」將存為 cf 這個欄位,以便讓其他的用戶端請求共用及使用。

使用「外觀」就能讓 Servlet 不需處理實體的詳細資料以及存取實體所需的任何持續性作業。

透過 Java Server Faces 技術使用階段作業 Bean 外觀

在本祕訣提供的程式碼範例中,Servlet 透過「外觀」存取位於模型層級的 Java Persistence 物件。但是,您也可以使用 JavaServer Faces 技術 (通常稱為 JSF) 元件當作 Web 元件。在這種作法下,每個 JSF 頁面通常會存取受 JSF 管理的 Bean (也稱為 Backing Bean)。接著,受管理的 Bean 會使用階段作業 Bean 的介面來存取階段作業 Bean「外觀」。對於使用 JSF 及 EJB 3.0 的 Java EE 5 應用程式來說,這是預期的程式設計模型。

下圖說明這種方法。

JSFwithFacade3

執行程式碼範例

本祕訣隨附的套裝模組範例包含實作為階段作業 Bean 的「模型外觀」。若要安裝及執行該範例:

  1. 如果您尚未從「Java EE Downloads」網頁下載 Java EE 5 SDK,請先執行此作業。此外,請確定已安裝 Java Platform Standard Edition (Java SE) 5 SDK。

  2. 下載本秘訣隨附的套裝模組範例,並將其內容解壓縮。您現在應看到新解壓縮的目錄為 <sample_install_dir>/ttfeb2007beanfacade,其中 <sample_install_dir> 是套裝模組範例的安裝目錄。例如,如果在 Windows 機器上將內容解壓縮到 C:\,則新建的目錄應該位於 C:\ttfeb2007beanfacadettfeb2007beanfacade 下的 TechTipEJBSessionfacade 目錄包含範例的原始碼檔案及其他支援檔案。

  3. 編輯 build.properties 檔案 (位於 TechTip-EJBsessionfacade 目錄的 bp-project 子目錄中),並設定適合工作環境的特性。例如,設定 javaee.home 指向 Java EE 5 安裝目錄。

  4. 輸入下列指令來啟動 derby 資料庫:

       <appsrv_install>/bin/asadmin start-database

    其中,<appsrv_install> 是 Java EE 5 應用程式伺服器的安裝位置。

  5. 輸入下列指令來啟動應用程式伺服器:

       <appsrv_install>/bin/asadmin start-domain domain1

  6. 切換到 TechTip-EJBsessionfacade 目錄,並輸入指令:

       ant setup

    如此即可設定資料庫資源。

  7. 輸入指令:

       ant run

    如此即可建立應用程式範例,並且部署到 http://localhost:8080/bp-sessionfacade,並從這裡啟動。

    這個應用程式是取自 Java BluePrints Solutions Catalog 的 Java Persistence 應用程式範例。

EJBFacadePage

按一下所顯示頁面上的連結,以擷取或新增目錄中的項目。如果檢查應用程式的原始碼,就會看到應用程式使用 EJB 階段作業 Bean 當作模型外觀,以便在目錄中的持續性實體上操作。

用完應用程式之後,可以輸入下列指令將它移除:

   ant clean - 清除應用程式工作區。
   ant undeploy - 從應用程式伺服器取消部署應用程式
   ant unsetup - 從應用程式伺服器清除資料庫資源

摘要

若要建立使用 Java Persistence API 的 Java EE 5 Web 應用程式,請考慮引入「模型外觀」來重新建構程式碼。

如需「外觀」及 Java Persistence API 的詳細資訊,請參閱:

關於作者

Sean Brydon 是 Sun Microsystems 的工程師,同時也是 Java BluePrints 計畫的技術總監。他從 Java BluePrints 計畫展開以來就一直參與這項計畫。他是 Addison-Wesley Java 系列叢書《Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition》及《Designing Web Services with the J2EE 1.4 Platform》的作者,並且是企業應用程式設計的常任講師。Sean 也曾參與 Java Pet Store 2.0 參考應用程式及 Java BluePrints Solutions Catalog 的設計與開發。

Yutaka Yoshida 是 Servlet 2.4 規格的負責人,目前從事 Java BluePrints 專案工作。他曾參與 Java Adventure Builder 參考應用程式、Java BluePrints Solutions Catalog 及 Java Pet Store 2.0 參考應用程式的設計與開發。

開發人員協助

需要關於 Java EE 的程式設計建議嗎?試用一下開發者專家協助服務吧。

 

Unless otherwise licensed, code in all technical manuals herein (including articles, FAQs, samples) is provided under this License.


BigAdmin