亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

全面研讀EJB 2.0

2019-11-18 14:46:35
字體:
來源:轉載
供稿:網友

  EJB 2.0 中引人注目的變化增強了應用程序開發的靈活性和可移植性

Richard Monson-Haefel
OpenEJB 首席設計師

新的 EJB 2.0 規范不僅僅是一個新的階段性發行版,它加入了許多引人注目的變動,包括 CMP 組件模型中的一些變動和一種新的 bean 類型,它們將增強您在開發應用程序時的靈活性和可移植性。請率先了解此新規范的功能,本月已發布了它的公開草案。

6 月 2 號發布的 EnterPRise javaBeans 2.0 不僅是一個階段性發行版,而且是該規范的一個新版本。整個規范有 500 多頁,比以前的 EJB 1.1 規范長了 200 頁 (66%)。該規范中最重要的變動是對容器治理的持久性 (CMP) 所作的更改,以及引入了一種全新的 bean 類型,即 MessageDrivenBean。

EJB 2.0 中的大量更改都集中在一種新 CMP 組件模型的定義中。它完全不同于舊的 CMP 模型,因為它引入了一個全新的成員,即持久性治理器,并引入了全新的方式來定義容器治理的字段,以及定義這些字段與其它 bean 和從屬對象的關系。

MessageDrivenBean (消息 bean)的引入也是非常重要的。消息 bean 體現出 JMS (Java Message Service)與 EJB 相集成,以創建出一種全新的 bean 類型,它設計用來處理異步的 JMS 消息。這種振奮人心的新型 bean 為 JMS 客戶機提供一種組件模型,答應將它們部署到 EJB 容器系統的豐富而強健的環境中去。

對該規范還作了許多較小的其它更改。這些其它更改雖然也重要,但它們主要是涉及使該規范更嚴格,以便消除多義性,并使這些組件具有更高的可移植性。本文集中討論 EJB 2.0 中引入的新 CMP 和消息 bean 組件模型。

我將提供幾個具體的例子,所以讀者應該很輕易跟上并理解它。但是,EJB 初學者可能發現這個材料比較困難,因為它假定讀者已對 EJB 有了基本的了解。有關 EJB 的具體信息,請參閱參考資料。

容器治理的持久性
容器治理的持久性在 EJB 2.0 中發生了根本變化。在 EJB 2.0 中,持久性治理器在運行時自動處理 CMP 實體 bean 的持久性。持久性治理器負責根據一種稱為抽象持久性方案的新的 bean 持久性治理器合約,將實體 bean 映射到數據庫。此外,持久性治理器還負責實現和執行多種查找方法,這些查找方法均基于一種稱為 EJB QL 的新型查詢語言。

注重到以下事實是很重要的,即符合 EJB 2.0 規范的產品必須能支持 EJB 1.1 CMP 模型,又能支持新的 EJB 2.0 模型。雖然這兩種模型并不兼容,但是為了保證向后兼容性,就必須能支持 EJB 1.1 模型。

抽象持久性方案
為了理解抽象持久性方案是如何工作的,以及它為什么重要,我將為您快速地回顧一下在 EJB 1.1 中是如何處理 CMP 的,隨后再討論在 EJB 2.0 中如何定義它。

EJB 1.1 中的 CMP 模型
在 EJB 1.1 中,bean 開發人員負責將 bean 類的持久性字段聲明為 Java 基本類型或可序列化類型。下列示例顯示了一個 Employee 企業級 bean 類,它是按 EJB 1.1 定義的,帶有幾個 CMP 字段:

// Employee bean 類
public class EmployeeBean implements
java.ejb.EntityBean {
// 實例字段
EntityContext ejbContext;
// 容器治理的字段
public int identity;
public String firstName;
public String lastName;
public double salary;
public Address address;
public Integer ejbCreate(int id, String fname,
String lname){
identity = id;
firstName = fname;
lastName = lname;
return null;
}
...
}
// Address 從屬類
public class Address implements Serializable{
public String street;
public String city;
public String state;
public String zip;
}



當將關系數據庫用于持久性時,基本字段如 identity、firstName、lastName 和 salary,很輕易持久化,因為它們很好地映射為 SQL 類型,如 INTEGER、CHAR 和 DOUBLE。

在 EJB 1.1 中,CMP bean 的 xml 部署描述符提供 cmp-field 元素,用以標識此 bean 類中的持久性字段(容器治理的字段)。如下所示,cmp-field 元素用來區分寫入數據庫的字段和不寫入數據庫的字段。例如,ejbContext 字段就不包括在容器治理的字段的列表中,因此它不是持久性字段。

<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>EmployeeEJB</ejb-name>
...
<persistence-type>Container</persistence-type>
...
<cmp-field><field-name>identity</field-name></cmp-field>
<cmp-field><field-name>firstName</field-name></cmp-field>
<cmp-field><field-name>lastName</field-name></cmp-field>
<cmp-field><field-name>salary</field-name></cmp-field>
<cmp-field><field-name>address</field-name></cmp-field>
...


容器提供者提供一種工具,用來將 bean 的持久性字段映射到數據庫表中的列,通常每個 bean 對應一個表。但是,可序列化的類型,如 Address,就比較難于持久化。在 EJB 1.1 中,沒有標準的方法將可序列化的對象映射到關系數據庫。雖然 Address 類有其自身的字段集,但 XML 部署描述符并沒有提供一種機制,來將這些字段映射到數據庫。在大多數情況下,人們期望將可序列化的對象(如 Address)作為二進制類型(有時稱為 blob 類型)持久化到某個數據庫表中。

由于實體 bean 的數據方案逐漸復雜起來,所以這個問題也變得嚴重了。例如,Employee bean 可能有多個類似于 Address 的子對象,如 Benefits 和 JobPosition。這些子對象稱為從屬對象,可以形成關系數據庫中跨幾個表的復雜對象圖。另外,EJB 1.1 中的 CMP 在很大程度上不足以持久化與其它 bean 的關系。在 EJB 1.1 中,假如某個 bean 預備維持與另一個 bean 的關系,則容器會自動將主要害字或句柄用作一個鏈接。與某些其它 bean 的關系其性質可能是雙向的,或者要依靠于一些不易用主要害字或句柄來表示的字段,為了保持與這類 bean 的關系,上面的辦法已被證實是一種遠未完善的機制。

EJB 2.0 的 CMP 模型
在 EJB 2.0 中,CMP 實體 bean 和持久性治理器之間的新合約,使您能夠在實體 bean 中定義更復雜的、可移植性更強的關系,包括 bean 與 bean 之間、bean 與從屬對象之間、甚至從屬對象與從屬對象之間的關系。

持久性治理器是新加入到 Enterprise JavaBeans 部署過程中的。容器廠商,或專長于特定數據庫的持久性的廠商,將能提供這種持久性治理器。其思路是將用于治理 bean 關系的機制從容器中分離出來,容器只負責治理安全、事務和資源。這種職責上的分離使不同的持久性治理器能夠與不同的容器一起工作。它也使實體 bean 在不同 EJB 廠商之間以及在各種持久性治理器之間具有更強的可移植性。

假如您使用或學習過 Thought Inc. 生產的,能自動為 EJB 1.1 容器生成 BMP(bean 治理的持久性)bean 的產品 CocoBase,則您對持久性治理器工具如何工作就已經比較熟悉了。CocoBase 根據 bean 部署者提供的,從對象到關系的映射信息,為 BMP bean 生成全部數據庫訪問邏輯。在 EJB 2.0 中,持久性治理器能夠根據部署描述符、bean 的抽象持久性方案和部署者完成的工作所提供的信息,生成 CMP 實體到關系數據庫的映射。但是,持久性治理器并不局限于關系數據庫。也可以為對象數據庫以及遺留的系統和 ERP 系統(如 SAP)開發持久性治理器。

為了將持久性治理器從容器中分離出來,必須定義 bean 與持久性治理器之間的合約。這個合約在新的抽象持久性方案中表現出來。此方案是通過部署描述符中一組新的 XML 元素和 CMP 實體 bean 中的一組代碼習語定義的。在 EJB 2.0 中,CMP bean 類被聲明為抽象類,它的持久性字段和關系字段是使用抽象的讀方法和寫方法來訪問的,而這兩種方法的方法特征則映射為 XML 部署描述符中的特定元素。

在部署該 bean 時,您將使用持久性治理器工具,根據 XML 部署描述符和 bean 類,來具體實現此抽象 bean 類及其從屬對象類。具體實現將包括數據訪問代碼,此代碼將在運行時將 bean 的狀態實際讀出和寫到數據庫中。在運行時,容器使用由持久性治理器工具生成的子類,而不使用 bean 提供者定義的抽象類。

bean 類的繼續層次結構


為了使討論更充實,這里提供一個 CMP 實體的示例,它更具體地說明了抽象持久性方案是如何工作的。

EJB 2.0 中的一個示例 CMP 實體
在 EJB 2.0 中,容器治理的實體 bean 被定義為抽象的,而且它的持久性字段并不在 bean 類中直接定義。作為替代,開發了一種抽象的持久性方案,從而答應 bean 提供者間接地聲明持久性字段和 bean 關系。下面是 Employee bean 的一個示例,它使用了新的抽象持久性方案。請注重,該 bean 類中未聲明任何持久性字段。

public abstract EmployeeBean implements
javax.ejb.EntityBean {
. // 實例字段
EntityContext ejbContext;
// 容器治理的持久性字段
public abstract void setIdentity(int
identity);
public abstract int getIdentity();
public abstract void setFirstName(String
firstName);
public abstract String getFirstName();
public abstract void setLastName(String
lastName);
public abstract String getLastName();
// 容器治理的關系字段
public abstract void
setContactInfo(ContactInfo info);
public abstract ContactInfo
getContactInfo();
...
}


在此 bean 的 XML 部署描述符中,抽象的持久性方案聲明容器治理的各個字段和各種關系。

<ejb-jar>
<enterprise-beans>
<entity>
<ejb-name>EmployeeEJB</ejb-name>
...
<persistence-type>Container</persistence-type>
...
<cmp-field><field-name>identity</field-name></cmp-field>
<cmp-field><field-name>firstName</field-name></cmp-field>
<cmp-field><field-name>lastName</field-name></cmp-field>
...
</entity>
</enterprise-beans>
<dependents>
<dependent>
<dependent-class>ContactInfo</dependent-class>
<dependent-name>ContactInfo</dependent-name>
<cmp-field>street</cmp-field>
<cmp-field>city</cmp-field>
<cmp-field>state</cmp-field>
<cmp-field>zip</cmp-field>
<cmp-field>homePhone</cmp-field>
<cmp-field>workPhone</cmp-field>
<cmp-field>email</cmp-field>
...
</dependent>
<relationships>
<ejb-relation>
<ejb-relation-name>Employee-ContactInfo</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>
employee-has-contactinfo
</ejb-relationship-role-name>
<multiplicity>one</multiplicity>
<role-source>
<ejb-name>EmployeeEJB</ejb-name>
</role-source>
<cmr-field>
<cmr-field-name>contactInfo</cmr-field-name>
<cmr-field-type>ContactInfo</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>
contactinfo_belongsto_employee
</ejb-relationship-role-name>
<multiplicity>one</multiplicity>
<role-source>
<dependent-name>ContactInfo<dependent-name>
</role-source>
</ejb-relationship-role>
</ejb-relation>
</relationships>
<ejb-jar>


用來描述容器治理的關系的 XML 元素可能變得非常復雜,因為他們必須處理各種關系的對應性和方向(單向的還是雙向的)。上面的代碼段說明,為了描述 bean 與其從屬對象類之間的簡單關系,您需要哪些元素。雖然即使是簡單的關系也會被轉換為冗長的 XML,但所有這些元素都是必需的,以便持久性治理器能夠將復雜的對象圖映射到數據庫中。

雖然用于定義 CMP bean 的抽象持久性方案的 XML 元素是 EJB 2.0 中的 CMP 的主要問題,但為了簡潔起見,本文不再提供 XML 示例。作為替代,本文將純粹依靠 bean 類中必須使用的抽象習語,來說明 EJB 2.0 中的 CMP 背后的基本概念。這些代碼習語與 XML 部署描述符中的關系元素一起使用,并由后者定義,所以您不能只有其一而沒有另一個,但它們比該方案的 XML 部分較輕易理解。

除了 XML 元素之外,抽象的持久性方案還定義了一組習語,它們在聲明 bean 類及其相關的對象時必然會用到。用來訪問和修改字段的方法是嚴格定義了的,要求用 set<METHOD> 方法修改持久性字段,而用 get<METHOD> 方法訪問它們。這些方法的名稱和返回類型由部署描述符中它們相應的 XML 關系元素規定。

實體 bean 類和從屬類都遵循相同的抽象持久性方案。下面是如何將 ContactInfo 對象定義為從屬對象類的示例。

public abstract class ContactInfo {
// 家庭地址信息
public abstract void setStreet(String street);
public abstract String getStreet();
public abstract void setState(String state);
public abstract String getState();
public abstract void setZip(String zip);
public abstract String getZip();
public abstract void setHomePhone(String phone);
public abstract String getHomePhone();
// 工作地址信息
public abstract void setWorkPhone(String phone);
public abstract String getWorkPhone();
public abstract void setEMail(String email);
public abstract String getEMail();
...
}


從屬對象隨實體 bean 的存在而存在,隨實體 bean 的中止而中止,這是理解從屬對象與實體 bean 之間關系的要害。從屬對象包含在一個具體的實體中,所以刪除這個實體將導致從屬對象也被刪除。用關系數據庫的術語來說,有時這就稱為級聯刪除。

從屬對象,如 ContactInfo,用在關系字段中。與實體 bean 形成關系的從屬對象技術上稱為從屬對象類。EJB 客戶端應用程序永遠不能直接訪問從屬對象類;這種類不能用作 bean 的遠程或本地接口中的參數或返回值。從屬對象類只對 bean 類才是可見的。

從屬對象類不適合作為遠程參數類型,因為它們與 bean 在運行時的持久性邏輯有密切的聯系。持久性治理器擴展了抽象的從屬對象類,以便能提供一種實現,可用于在運行時治理 bean 的持久性狀態。此外,抽象的持久性方案還為數據建模 -- 而不是為那些由企業級 bean 表示的業務概念建模 -- 所以,作為一種設計策略,將抽象的持久性方案對 EJB 客戶機隱藏起來是有意義的。

例如,ContactInfo 關系字段中除了 bean 的客戶機所需的簡單地址信息之外,還包含許多其它信息。雖然您可以使用抽象持久性方案中的從屬對象類 ContactInfo(它對 bean 的客戶機是隱藏的),但是,您得用其它的對象來把這些數據實際表露給客戶機。下面是一個示例,說明了如何對 EJB 客戶機隱藏 ContactInfo 從屬對象。在此例中,地址信息是通過在 EJB 1.1 的示例中開發的 Address 對象來表露的。

// Employee bean 的遠程接口
public interface Employee extends javax.ejb.EJBObject {
public Address getHomeAddress();
public void setHomeAddress(Address address);
public int getIdentity() throws RemoteException;
public void setFirstName(String firstName) throws
RemoteException;
public String getFirstName()throws RemoteException;
public void setLastName(String lastName) throws
RemoteException;
public String getLastName() throws RemoteException;
}
// Employee bean 的 bean 類
public abstract EmployeeBean implements
javax.ejb.EntityBean {
...
public Address getHomeAddress(){
ContactInfo info = getContactInfo();
Address addr = new Address();
addr.street = info.getStreet();
addr.city = info.getCity();
addr.state = info.getState();
addr.zip = info.getZip();
return addr;
}
public void setHomeAddress(Address addr){
ContactInfo info = getContactInfo();
info.setStreet(addr.street);
info.getCity(addr.city);
info.getState(addr.state);
info.getZip(addr.zip);
}
....
// 容器治理的關系字段
public abstract void setContactInfo(ContactInfo
info);
public abstract ContactInfo getContactInfo();
...
}


盡管容器治理的關系字段沒有表露給客戶機,但您仍然可以從遠程接口直接使用容器治理的持久性字段。請注重,用來訪問 firstName 和 lastName 的容器治理的持久性字段是在遠程接口中使用的。

一個 bean 與各種從屬對象類之間可能具有多種不同的關系,它們由這種關系的對應性和方向來定義。Bean 與從屬對象類之間可以有一對多和一對一的關系。例如,Employee bean 可能僅有一個 Benefit 從屬對象類,但可能有許多 ContactInfo 從屬對象類。

public abstract EmployeeBean implements
javax.ejb.EntityBean {
...
public abstract void setContactInfos(Collection
addresses);
public abstract Collection getContactInfos():
public abstract void setBenefit(Benefit benefit);
public abstract Benefit getBenefit();
...
}


與從屬對象類的一對多關系既可表示為 java.util.Collection 類型,也可表示為 ava.util.Set 類型(注:在本規范的后續版本中,java.util.Map 和 java.util.List 被視為附加的返回類型),而與從屬對象的一對一關系則使用從屬對象的類型。

實體 bean 也可以定義與其它實體 bean 的關系。這些關系可以是一對一、一對多或多對多。例如,Employee bean 可能有許多子級 bean,而只有一個配對的 bean。下面的代碼段使用抽象持久性方案的方法習語,說明了如何為這些關系建模。該應用程序中,子級 bean 和配對的 bean 都表現為 Person bean。

public abstract EmployeeBean implements
javax.ejb.EntityBean {
...
public abstract void setSpouse(Person manager);
public abstract Person getSpouse();
public abstract void setChildren(Collection
family);
public abstract Collection getChildren();
...
}


與另一個 bean 的一對多關系表示為 java.util.Collection 類型或 java.util.Set 類型,而一對一關系則使用該 bean 的遠程接口類型。

從屬對象本身與同一個 bean 中的其它從屬對象之間可以有一對一、一對多和多對多的關系。此外,從屬對象與其它實體 bean(除其父級 bean 之外)也可以有一對一、一對多的關系。下面的示例顯示,Benefit 從屬對象類與 Salary 從屬對象(一種報酬計算程序)之間怎樣具有一對一的關系,而與 Investment bean 又怎樣具有一對多的關系。

public abstract class Benefit {
public abstract void setSalary(Salary salary);
public abstract Salary getSalary();
public abstract void setInvestments(Collection
investments);
public abstract Collection getInvestments();
}


在部署時,部署者將使用持久性治理器工具來具體實現這個 bean 類及其從屬類。這些具體實現將在運行時保持各種關系,并使各 bean 實例的狀態與數據庫同步。容器將在運行時治理持久性實例,從而提供一種強健的環境,其中具有自動的訪問控制和事務控制。

bean 也可以定義從屬對象的值,這些對象是可序列化的對象,如 EJB 1.1 示例中的 Address 對象。這些值通過序列化而變為持久的,它們并不形成與 bean 的關系 -- 它們是嚴格的容器治理的持久性字段。

容器與持久性治理器之間也已經定義了一個合約,使持久性治理器可以獲得事務的句柄,并訪問由該容器治理的數據庫連接池。這個合約稍嫌寬松,將來還需要使其更為嚴格,但它是答應持久性治理器跨 EJB 容器移植的基礎。容器和持久性治理器之間合約的細節已超出了本文的范圍。

除了通過抽象持久性方案定義持久性之外,EJB 2.0 還提供了一種新的查詢語言,用來說明持久性治理器應該如何實現 CMP 中的各種查找方法。

EJB 查詢語言
EJB 查詢語言 (EJB QL) 規定了持久性治理器應該如何實現在本地接口中定義的各種查找方法。 EJB QL 以 SQL-92 為基礎,可由持久性治理器自動編譯,這使得實體 bean 具有更高的可移植性,并且更輕易部署。

EJB QL 和查找方法
EJB QL 語句是在實體 bean 的部署描述符中聲明的。使用 EJB QL 非常簡單。作為一個例子,Employee bean 的本地接口可以按以下方式聲明:

public interface EmployeeHome extends javax.ejb.EJBHome
{
...
public Employee findByPrimaryKey(Integer id)
throws RemoteException, CreateException;
public Collection findByZipCode(String zipcode)
throws RemoteException, CreateException;
public Collection findByInvestment(String
investmentName)
throws RemoteException, CreateException;
}



給定了上面的本地接口定義之后,您就可以使用 EJB QL 來指定持久性治理器應該如何執行查找方法。每個實體 bean 都必須有一個 findByPrimaryKey() 方法。為執行該方法所需的查詢是很明顯的 -- 使用主要害字的(一個或幾個)字段在數據庫中查找 bean,這樣就不需要任何 EJB QL 語句。

findByZipCode() 方法用來獲得具有某個郵政編碼的所有 Employee bean。這將使用部署描述符中的下列 EJB QL 來表達。

FROM contactInfo WHERE contactInfo.zip = ?1

該語句本質上是表示“選擇其郵政編碼等于 zipcode 參數的所有 Employee bean”。

在用于查找方法的 EJB QL 語句中,不需要使用 SELECT 子句來表明要選擇的內容。這是因為,查找方法將總是選擇與其自身的 bean 類型相同的遠程引用。在這種情況下,就可以認為選擇語句將返回遠程 Employee bean 的全部引用。

假如各種查找方法都一起部署在同一個 ejb-jar 文件中,并且其間具有可導航的實際關系,那么這些查找方法就甚至可以跨越到另一些 bean 的抽象持久性方案中去。例如,findByInvestment() 方法將要求該查找查詢從 Employee 導航到投資 bean 的抽象持久性方案中去。聲明來表達這種查找操作的 EJB QL 語句如下所示。

FROM element IN benefit.investments WHERE element.name
= ?1


以上語句是說:“選擇全部這樣的 Employee bean:其獲利從屬對象至少包含一個投資 bean 的引用,并且其名稱等于 findByInvestment() 方法的 investmentName 參數?!?br />
EJB QL 和選擇方法
EJB QL 也用于一種稱為 ejbSelect 方法的新查詢方法中,該方法類似于查找方法,只是它僅供 bean 類使用。該方法不在本地接口中聲明,所以也不顯露給客戶機。此外,ejbSelect 方法可返回范圍更大的各種值,而不僅限于 bean 本身的遠程接口類型。

存在兩種選擇方法:ejbSelect<METHOD> 和 ejbSelect<METHOD>InEntity。ejbSelect<METHOD> 方法是全局執行的,這是指這種方法并非專用于執行該方法的 bean 實例。ejbSelect<METHOD>InEntity 方法則專用于執行該方法的實體實例。這些選擇方法在 bean 類中被聲明為抽象方法,并在這些類的業務方法中使用。下面是 ejbSelect<METHOD> 方法和 ejbSelect<METHOD>InEntity 方法的示例,同時說明了可以如何在業務方法中使用它們。

public abstract class EmployeeBean implements
javax.ejb.EntityBean {
...
// ejbSelectInEntity
public abstract Collection
ejbSelectInvestmentsInEntity (String risk);
// ejbSelect
public abstract Collection
ejbSelectInvestments(String risk);
...
}


在上面的聲明中,兩種選擇方法運行于不同的范圍。ejbSelectInvestmentsInEntity() 僅在當前的 Employee bean 實例上執行,所以它只返回雇員的風險投資。

SELECT invest FROM invest IN benefit.investments WHERE
invest.type = ?1


另一方面,ejbSelect<METHOD> 方法的范圍則是全局性的,所以同一個查詢將返回整個企業內所有雇員的全部風險投資。

ejbSelect<METHOD>InEntity 選擇方法可以返回 bean 的遠程類型(如在上面的查詢中那樣)、從屬對象或任何其它 Java 類型。另一方面,全局選擇方法則不能返回 bean 的從屬對象類型。

選擇方法的 EJB QL 語句要求使用 SELECT 子句,因為它們能夠返回范圍更廣的各種值。

新的 ejbHome 方法
在 EJB 2.0 中,實體 bean 可以聲明一些 ejbHome 方法,用來執行與 EJB 組件相關的操作,但并不專用于某個 bean 實例。在 bean 類中定義的 ejbHome 方法在本地接口中必須有一個與其相匹配的本地方法。下面的代碼說明了一個本地方法,它正是作為 Employee bean 的本地接口定義的。applyCola() 方法用來根據最近 COLA(生活費用調整)的增長來更新所有雇員的薪水。


public interface EmployeeHome extends javax.ejb.EJBHome
{
// 本地方法
public void applyCola(double increate) throws
RemoteException;
...
}


applyCola() 方法在 bean 類中必須有匹配的 ejbHome 方法,它被聲明為 ejbHomeApplyCola()。ejbHomeApplyCola() 方法并非專用于一個 bean 實例,它的范圍是全局的,所以它將對所有雇員的薪水使用同一個 COLA。

public abstract class EmployeeBean implements
javax.ejb.EntityBean {
...
// ejbHome 方法
public void ejbHomeApplyCola (double increase ){
Collection col = ejbSelectAllEmployees ();
Iterator employees = col.iterator();
while(employees.next()){
Employee emp =
(Employee)employees.next();
double salary =
emp.getAnnualSalary();
salary = salary + (salary*increase);
emp.setAnnualSalary(salary);
}
}
}


bean 的開發人員需要為 BMP 和 CMP 實體 bean 都實現 ejbHome 方法。CMP 實現可能在很大程度上要依靠于全局的選擇語句(如上面所說明的那樣)和 finder 方法,而 ejbHome 的 BMP 實現則將使用直接數據庫訪問和 bean 的 finder 方法,來查詢數據和進行更改。

MessageDrivenBean
在 EJB 2.0 中,對規范的一個基礎性更改是添加了一種全新的企業級 bean 類型,即 MessageDrivenBean。MessageDrivenBean 專門設計來處理入網的 JMS 消息。對于許多開發人員來說,JMS 是一種新的范例,所以本文將花一些時間逐步說明對 JMS 的理解,以及它們在 EJB 2.0 中的用法。

什么是 JMS?
JMS 是一種與廠商無關的 API,用來訪問消息收發系統。它類似于 JDBC (Java Database Connectivity):這里,JDBC 是可以用來訪問許多不同關系數據庫的 API,而 JMS 則提供同樣與廠商無關的訪問方法,以訪問消息收發服務。許多廠商目前都支持 JMS,包括 IBM 的 MQSeries、BEA 的 Weblogic JMS service 和 Progress 的 SonicMQ,這只是幾個例子。

JMS 使您能夠通過消息收發服務(有時稱為消息中介程序或路由器)從一個 JMS 客戶機向另一個 JML 客戶機發送消息。消息是 JMS 中的一種類型對象,由兩部分組成:報頭和消息主體。報頭由路由信息以及有關該消息的元數據組成。消息主體則攜帶著應用程序的數據或有效負載。根據有效負載的類型來劃分,可以將消息分為幾種類型,它們分別攜帶:簡單文本 (TextMessage)、可序列化的對象 (ObjectMessage)、屬性集合 (MapMessage)、字節流 (BytesMessage)、原始值流 (StreamMessage),還有無有效負載的消息 (Message)。

消息收發系統是異步的,也就是說,JMS 客戶機可以發送消息而不必等待回應。比較可知,這完全不同于基于 RPC 的(基于遠程過程的)系統,如 EJB 1.1、CORBA 和 Java RMI 的引用實現。在 RPC 中,客戶機調用服務器上某個分布式對象的一個方法。在方法調用返回之前,該客戶機被阻塞;該客戶機在可以執行下一條指令之前,必須等待方法調用結束。在 JMS 中,客戶機將消息發送給一個虛擬通道(主題或隊列),而其它 JMS 客戶機則預訂或監聽這個虛擬通道。當 JMS 客戶機發送消息時,它并不等待回應。它執行發送操作,然后繼續執行下一條指令。消息可能最終轉發到一個或許多個客戶機,這些客戶機都不需要作出回應。

EJB 2.0 中的 JMS
EJB 2.0 以兩種方式支持 JMS 的集成:作為一種 bean 可用的資源,和作為一個 MessageDrivenBean。當將 JMS 用作一種資源時,使用 JMS API 的 bean 就是消息的產生者或發送者。在這種情況下,bean 將消息發送給稱為主題或隊列的虛擬通道。另一方面,MessageDrivenBean 則是消息的使用者或接收者。它監聽特定的虛擬通道(主題或隊列),并處理發送給該通道的消息。為了更好地理解消息產生者和消息使用者的作用,用 sessionBean bean 來發送一條使用 JMS 的消息,然后使用一個新的 MessageDrivenBean 來使用該同一條消息。

作為 EJB 2.0 資源的 JMS
會話 bean 和實體 bean 都是基于 RPC 的組件,為了將各種事務性的組件裝配到一起,這是一種卓越的體系結構。但是,在某些情況下,RPC 的同步性質會成為一種障礙,這正是 EJB 1.1 中將對 JMS API 的訪問作為一種資源包括在內的原因。利用 JNDI 環境命名的上下文,bean 可以獲得一個 JMS 工廠,并將一條異步消息發送給主題或隊列(也從 JNDI 獲得),而不必等待回應。下面是 ShoppingCart bean 的一個例子,它使用 JMS 將 Order 的具體信息發送給消息收發主題。

public class ShoppingCartBean implements SessionBean {
// 訂單具體信息是一個可序列化的對象,它包含全部訂單信息。
public OrderDetail orderDetail;
public void processOrder(){
// 處理訂單的邏輯從此處開始
....
// ... 處理訂單以后,向其它系統發送有關此訂單的一條消息
InitialContext jndiEnc = new
InitialContext();
// 使用 JNDI ENC 獲取 JMS 工廠和主題標識符
TopicConnectionFactory factory =
jndiEnc.lookup("java:comp/env/jms/topicfactory");
Topic orderTopic =
jndiEnc.lookup("java:comp/env/jms/ordertopic");
// 獲得一個用來發送消息的發布者
TopicConnection con =
factory.createTopicConnection();
TopicSession session =
con.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE );
TopicPublisher publisher =
session.createPublisher(orderTopic);
// 將一個 ObjectMessage 發送給主題(虛擬通道)
ObjectMessage message =
session.createObjectMessage();
message.setObject(orderDetail);
publisher.publish(message);
con.close();
}
...
}


在這種情況下,JMS 是用來通知另外的應用程序,訂單已被處理。這些另外的應用程序對于處理訂單來說并不重要,但它們會因為得到一個訂單已被處理的通知而受益。這樣的例子包括自動調整庫存的庫存系統,和能將客戶添加進產品目錄郵寄名單中的銷售應用程序。

使用 JMS 使 bean 能夠發布(發送)消息而不會發生阻塞。bean 并不知道誰將收到消息,因為它是將消息發送給某個主題(虛擬通道),而不是直接發送給另一個應用程序。應用程序可以選擇預訂該主題,并接收有關新訂單的通知。這樣就有可能動態地在虛擬通道中添加或刪除應用程序,從而產生了一種更加靈活的系統。

預訂了訂單主題的應用程序將收到有關新訂單的通知,應用程序可以使用它們認為合適的任何方式來處理這個通知。預訂了各種主題的應用程序或者從各個隊列中接收消息的應用程序可以是 Java 應用程序、EAI 系統(用于集成遺留系統和 ERP 系統)或者 MessageDrivenBean 組件,在 JMS 的術語中,它們全部被認為是 JMS 客戶機。

JMS 和 MessageDrivenBean
雖然大多數 JMS 廠商都提供消息中介工具,來將消息從發送者路由到接收者,但構建使用(接收)消息的 JMS 客戶機卻是應用程序開發人員的職責。在許多情況下,接收消息的應用程序必須強健、安全、快速而且可伸縮;它需要的基礎結構基本上與 EJB 應用程序相同。

由于熟悉到這種需要,EJB 2.0 現在包括了 MessageDrivenBean 類型,它可以使用 JMS 消息,并且在同一個強健的、基于組件的基礎結構中處理這些消息,這樣的基礎結構對于會話 bean 和實體 bean 都非常有用。MessageDrivenBean 類型(消息 bean)是一種企業級 bean 組件,它設計來使用異步的 JMS 消息。

除了提供容器基礎結構以外,EJB 還具有另一個重要的優點:并發處理。在 EJB 中,一個已部署的消息 bean 表示一個單一的消息使用者,但這個 bean 本身是由許多 bean 實例提供服務的。每個 bean 實例都可以分別地使用消息 bean 接收到的消息。這意味著,消息 bean 不必像常規 JMS 客戶機那樣連續地使用消息。消息 bean 可以并發地使用接收到的多個消息,這樣就能達到比傳統 JMS 應用程序高得多吞吐量和好得多的可伸縮性。

為了說明消息 bean 的作用,就開發了 MarketingBean 類,并將它從訂單主題中部署到供使用的消息中去。MarketingBean 將從消息中提取 OrderDetail 對象,并使用它將客戶添加到適當的目錄郵寄名單中。這是一種最精致的大量郵寄系統。

下面是 MarketingBean 類的定義,這個類使用發布給訂單主題的消息。

public class MarketingBean implements
javax.ejb.MessageDrivenBean {
public void onMessage(Message message) {
ObjectMessage orderMessage =
(ObjectMessage)orderMessage:
OrderDetail orderDetail =
(OrderDetail)orderMessage.getObject();
Integer customerID =
orderDetail.getCustomerID();
InitialContext jndiEnc = new
InitialContext();
CatalogHome catalogHome =
(CatalogHome)jndiEnc.lookup("java:comp/env/ejb/catalog");
Iterator prodUCtIDs =
orderDetail.getProductsIDs();
while(productIDs.hasNext()){
Integer productID =
(Integer)productIDs.next();
Catalog cat =
CatalogHome.findByProductID(productID);
cat.addCustomerToMailingList(customerID);
}
}
}


正像會話 bean 和實體 bean 一樣,MessageDrivenBean 也是一種完備的企業級 bean,但其間仍存在一些重要的區別。消息 bean 沒有遠程接口或本地接口。這是因為消息 bean 不是 RPC 組件。它沒有供 EJB 客戶機調用的業務方法。消息 bean 監聽虛擬消息通道(主題或隊列),并使用其它 JMS 客戶機發送給該通道的消息。

各個消息 bean 構成一個 bean 類,這個類實現 MessageDrivenBean 接口和一個 XML 部署描述符。下面是 MessageDrivenBean 接口的定義,所有消息 bean 都必須實現這個接口。

package javax.ejb;
import javax.jms.Message;
import javax.jms.MessageListener;
public interface MessageDrivenBean extends
MessageListener{
public void onMessage(Message message);
public void ejbCreate();
public void ejbRemove();
public void
setMessageDrivenContext(MessageDrivenContext mdc);
}


當部署了一個消息驅動的 bean 以后,它就被指派來處理特定主題或隊列中的消息。JMS 客戶機(Java 應用程序、bean 或本地客戶機)發送的任何消息,將由消息路由器轉發給消息 bean,該消息 bean 正是被指派來從該虛擬通道中接收消息的。當一條消息被發送給一個消息 bean 時,EJB 容器就會從某個池中選擇該 bean 的一個實例,來處理這條消息。當 bean 實例調用其 onMessage() 方法時,它就會接收到這條消息,并能夠以它認為合適的任何方式來處理這條消息。一旦這條消息被使用,則只要事務沒有異常中止,這條消息都不會被傳送給這個消息 bean 的任何其它實例。

消息 bean 在某點上類似于無狀態的會話 bean,即這兩種 bean 在兩次請求之間都不保持任何狀態。因此,消息驅動的 bean 是無狀態的,但是,就像無狀態的會話 bean 一樣,它們也可以有實例變量,這些變量在這個 bean 實例的整個生存期內均保持。

對消息 bean 的最后一點說明是,理解這樣一個事實是很重要的,即 bean 使用的消息不一定要是由其它 bean 所產生的。消息 bean 可以使用由符合 JMS 的廠商提供的任何主題或隊列中的消息。消息 bean 使用的消息可以來自其它 bean(會話 bean、實體 bean 或消息 bean)、非 EJB 的 Java 應用程序、或者甚至非 Java 的應用程序(假如其供給商符合 JMS)。例如,遺留應用程序可能使用 IBM 的 MQSeries 向隊列發送消息,而該消息既可以由其它遺留應用程序使用,同樣可以由消息 bean 使用。

結論
與以前的規范相比,Enterprise JavaBeans 2.0 中作了一些相當大的更改。新的 CMP 模型比以前的模型要靈活得多,它答應各種實體為復雜的對象圖建立模型,而同又提供跨容器的更大的可移植性。人們迫切地期待著為查找和選擇操作定義一種通用的查詢語言,而它也將有助于提高可移植性。

這種新的 MessageDrivenBean 類型將有助于使這種強大的消息收發范例成為眾人矚目的焦點,就像 EJB 那樣。消息收發在分布式的混合計算中是一個極其重要的組成部分,將它包括在 EJB 內就是其重要性的一個證實。

在寫這篇文章時,EJB 2.0 剛剛作為公開草案發布,這意味著在它成為一個最終規范之前仍有可能更改。假如更改對此處提供的材料有重大影響,屆時我將設法對本文作一些注釋,但這個規范正在趨于穩定,所以不太可能有真正重大的更改。

參考資料

"A Beginner′s Guide to Enterprise JavaBeans," Mark Johnson(JavaWorld,1998 年 10 月):
Richard Monson-Haefel 的 EJB 開發者網站,EJBNow.com
EJB 2.0,規范
Thought 的 CocoBase
IBM 的 MQ Series
BEA 的 WebLogic JMS Service
Progess Sonic MQ
Richard Monson-Haefel 所寫的其它文章:

"Create forward-compatible beans in EJB, Part 1"(JavaWorld,1999 年 12 月)
"Create forward-compatible beans in EJB, Part 2"(JavaWorld,2000 年 1 月)
作者簡介
Richard Monson-Haefel 是最近發布的 Enterprise JavaBeans 第二版的作者。他是 OpenEJB 的首席設計師(OpenEJB 是一種開放源代碼的 Enterprise JavaBeans 2.0 容器),他曾經以設計師身份為 Enterprise JavaBeans、CORBA、Java RMI 以及其它 Java 方案提供咨詢。Monson-Haefel 還維護著一個網站,供人們討論 Enterprise JavaBeans 和相關的分布式計算技術??梢酝ㄟ^ richard.monson-haefel@javaworld.com 與 Richard Monson-Haefel 聯系。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91在线高清视频| 亚洲欧美国产一本综合首页| 国产中文字幕91| 欧美高清videos高潮hd| 日韩有码在线播放| 国产精品一区二区av影院萌芽| 日韩一二三在线视频播| 91久久国产综合久久91精品网站| 久久精品在线视频| 国产精品久久久久久久天堂| 久久不射电影网| 国产在线不卡精品| 欧美日韩在线第一页| 亚洲片av在线| 日韩黄色高清视频| 国产91成人在在线播放| 性色av一区二区三区在线观看| 久久香蕉精品香蕉| 欧美激情综合色综合啪啪五月| 国产精品美女主播在线观看纯欲| 日韩欧美在线免费| 福利视频第一区| 欧美性猛交xxxx乱大交极品| 欧美成人精品在线播放| 欧美日韩美女视频| 九九久久国产精品| 成年无码av片在线| 91视频免费在线| 欧美床上激情在线观看| 欧美日韩成人网| 一本一本久久a久久精品牛牛影视| 51色欧美片视频在线观看| 亲子乱一区二区三区电影| 青草成人免费视频| 一本一本久久a久久精品牛牛影视| 亚洲最新中文字幕| 黑人与娇小精品av专区| 在线播放国产精品| 欧美色videos| 欧美成人h版在线观看| 亚洲精品小视频| 自拍偷拍亚洲精品| 欧洲日本亚洲国产区| 欧美日韩国产精品专区| 久久亚洲精品国产亚洲老地址| 国产精品亚洲网站| 欧美色道久久88综合亚洲精品| 亚洲精品国产成人| 青草青草久热精品视频在线观看| 全球成人中文在线| 日韩精品视频在线观看网址| 2019最新中文字幕| 欧美性精品220| 午夜精品久久久久久久白皮肤| 国产精品久久久久久久久久| 亚洲视频精品在线| 91精品国产免费久久久久久| 国产精品高清在线观看| 91精品国产高清久久久久久| 成人黄色中文字幕| 久久久精品一区二区| 国产午夜精品全部视频播放| 91沈先生作品| 国自产精品手机在线观看视频| 亚洲精品在线不卡| 久久99国产精品久久久久久久久| 色视频www在线播放国产成人| 精品日韩美女的视频高清| 日日噜噜噜夜夜爽亚洲精品| 日韩亚洲精品电影| 亚洲第一区在线| 成人免费视频a| 奇米一区二区三区四区久久| 亚洲视频网站在线观看| 在线观看国产成人av片| 国产精品久久999| 日韩国产在线播放| 午夜精品在线视频| 久久这里只有精品视频首页| 亚洲精品久久久久久久久| 91视频国产高清| 日韩av免费看| 日韩视频第一页| 中日韩美女免费视频网站在线观看| 亚洲色图偷窥自拍| 精品亚洲国产成av人片传媒| 亚洲视频国产视频| 欧美激情精品久久久久久蜜臀| 高清日韩电视剧大全免费播放在线观看| 91精品久久久久久久| 久久婷婷国产麻豆91天堂| 亚洲美女在线视频| 在线观看日韩专区| 国产精品99久久久久久白浆小说| 性色av一区二区三区在线观看| 成人免费淫片视频软件| 国产精品精品一区二区三区午夜版| 91精品国产99久久久久久| 91久久精品日日躁夜夜躁国产| 欧美日产国产成人免费图片| 97久久精品视频| 日本不卡免费高清视频| 欧美性xxxx| 国产精品福利片| 欧洲精品久久久| 日本一本a高清免费不卡| 国产精品黄色av| 欧美激情国产精品| 国产视频一区在线| 日韩免费电影在线观看| 国产91精品在线播放| 欧美日韩激情视频8区| 精品国产老师黑色丝袜高跟鞋| 亚洲综合精品伊人久久| 亚洲小视频在线观看| 日韩大陆欧美高清视频区| 黄网动漫久久久| 久久视频免费观看| 久久av在线播放| 国产精品对白刺激| 久久av中文字幕| 中文字幕9999| 欧美激情综合亚洲一二区| 奇米四色中文综合久久| 日韩黄在线观看| 亚洲男女性事视频| 狠狠久久五月精品中文字幕| 伊人亚洲福利一区二区三区| 成人在线激情视频| 欧洲成人午夜免费大片| 国产国语刺激对白av不卡| 日韩欧美综合在线视频| 国产精品美女久久久久av超清| 欧美日韩中文在线观看| 亚洲国产日韩一区| 国产日韩欧美在线看| 久久人人爽人人爽人人片亚洲| 日韩成人中文字幕| 国产精品99蜜臀久久不卡二区| 国产精品99久久久久久www| 97人人做人人爱| 欧美大尺度激情区在线播放| 欧美大全免费观看电视剧大泉洋| 欧美大荫蒂xxx| 国产精品视频最多的网站| 国产精品羞羞答答| 成人午夜黄色影院| 成人免费观看a| 91欧美精品午夜性色福利在线| 国产亚洲精品一区二区| 久久久午夜视频| 人妖精品videosex性欧美| 亚洲精品98久久久久久中文字幕| 91精品国产综合久久男男| 亚洲加勒比久久88色综合| 秋霞午夜一区二区| 欧美精品激情在线| 久久精品电影网| 国产精品久久精品| 欧亚精品中文字幕| 亚洲成人黄色在线| 亚洲精品日韩丝袜精品| 国产精品啪视频| 久久91精品国产|