Entity Bean與Session Bean的不同表現(xiàn)在如下幾個(gè)方面:
持久性
在應(yīng)用或應(yīng)用服務(wù)器的運(yùn)行時(shí)間外,Entity Bean狀態(tài)數(shù)據(jù)仍存在于持久數(shù)據(jù)存儲(chǔ)之中。
Entity Bean有兩種持久類(lèi)型:Bean管理持久類(lèi)型(Bean-managed Persistence,BMP)和容器管理的持久類(lèi)型(Container-managed Persistence,CMP)。對(duì)于Bean管理的持久類(lèi)型,由組件模型中Enterprise Bean類(lèi)的代碼控制對(duì)持久存儲(chǔ)中狀態(tài)數(shù)據(jù)的訪(fǎng)問(wèn);容器管理持久性類(lèi)型的Entity Bean,則由容器生成和管理對(duì)應(yīng)持久存儲(chǔ)中狀態(tài)數(shù)據(jù)的訪(fǎng)問(wèn)方法。開(kāi)發(fā)者可以不用編寫(xiě)這些方法。
共享訪(fǎng)問(wèn)
相對(duì)于Session Bean對(duì)應(yīng)于特定的客戶(hù)端會(huì)話(huà)而言,Entity Bean可以在客戶(hù)端間被共享訪(fǎng)問(wèn),對(duì)于多個(gè)并發(fā)的客戶(hù)端訪(fǎng)問(wèn),由容器提供了完整的事務(wù)(transaction)管理機(jī)制,保證狀態(tài)數(shù)據(jù)的完整性。并且提供了通過(guò)修改部署描述,指定事務(wù)屬性的能力,無(wú)需在代碼中對(duì)事務(wù)邊界進(jìn)行控制。
Primary Key
每個(gè)Entity Bean實(shí)例擁有一個(gè)唯一的標(biāo)識(shí)對(duì)象,客戶(hù)端可以使用此標(biāo)識(shí)定位特定的Entity Bean實(shí)例。
關(guān)系
如存在于關(guān)系型數(shù)據(jù)庫(kù)中的業(yè)務(wù)實(shí)體數(shù)據(jù),Entity Bean之間也可以具有類(lèi)似的關(guān)系。對(duì)于Bean管理持久性的Entity Bean,需要在Entity Bean的組件類(lèi)中對(duì)關(guān)系進(jìn)行編碼;而對(duì)于容器管理持久性的Entity Bean,則由容器對(duì)關(guān)系進(jìn)行控制。因此,容器管理持久性的Entity Bean之間的關(guān)系,被稱(chēng)為容器管理關(guān)系(Container-managed relationship,CMR)。
容器管理持久性(Container-managed Persistence,CMP)
容器管理持久性指由EJB容器處理Entity Bean需要的對(duì)數(shù)據(jù)庫(kù)的訪(fǎng)問(wèn)。使Entity Bean可以脫離特定類(lèi)型的數(shù)據(jù)庫(kù),從而具有更高的靈活性。
為使Entity Bean可以由EJB容器對(duì)持久性進(jìn)行管理,需要提供Entity Bean的抽象模式(abstract schema)信息。
抽象模式(Abstract Schema)
抽象模式作為容器管理持久性的Entity Bean部署描述的一部分,提供對(duì)Entity Bean持久域和關(guān)系的定義。之所以稱(chēng)其為“抽象”模式,是為了與具體的底層數(shù)據(jù)存儲(chǔ)的物理模式區(qū)分開(kāi)來(lái)。例如,在關(guān)系型數(shù)據(jù)庫(kù)中,物理模式由諸如表或列等結(jié)構(gòu)構(gòu)成。
對(duì)于容器管理持久性的Entity Bean,需要在部署描述中定義抽象模式的名字。這些名字將可以通過(guò)使用Enterprise JavaBeas™ Query Language(EJB™ QL)編寫(xiě)的查詢(xún)語(yǔ)句進(jìn)行引用。例如,必須為每一個(gè)finder方法定義一個(gè)EJB QL查詢(xún)語(yǔ)句,通過(guò)此語(yǔ)句定義當(dāng)此finder方法被調(diào)用時(shí),容器執(zhí)行的查詢(xún)。
持久域(persistent fields)
被定義的Entity Bean的持久域保存在底層的數(shù)據(jù)存儲(chǔ)中,所有這些域構(gòu)成整個(gè)Entity Bean的狀態(tài)。在運(yùn)行時(shí),容器自動(dòng)對(duì)這些狀態(tài)與數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行同步。一般,容器在部署時(shí)將Entity Bean與特定的數(shù)據(jù)庫(kù)表進(jìn)行映射,將持久域與數(shù)據(jù)庫(kù)表中的列進(jìn)行映射。
關(guān)系域(relationship fields)
關(guān)系域可視為數(shù)據(jù)庫(kù)表中的外鍵(foreign key),用于標(biāo)識(shí)Bean之間的關(guān)系。
容器管理關(guān)系(Container-managed Relationship,CMR)
容器管理持久性的Entity Bean有以下四種容器管理關(guān)系:
one-to-one,一個(gè)Bean的單個(gè)實(shí)例關(guān)聯(lián)另一個(gè)Bean的單個(gè)實(shí)例;
one-to-many,一個(gè)Bean的單個(gè)實(shí)例關(guān)聯(lián)另一個(gè)Bean的多個(gè)實(shí)例;
many-to-one,一個(gè)Bean的多個(gè)實(shí)例關(guān)聯(lián)另一個(gè)Bean的單個(gè)實(shí)例;
many-to-many,一個(gè)Bean的多個(gè)實(shí)例關(guān)聯(lián)另一個(gè)Bean的多個(gè)實(shí)例;
容器管理關(guān)系的方向
容器管理關(guān)系的方向可以是雙向或單向。在一個(gè)雙向的關(guān)系中,涉及的Bean都有一個(gè)關(guān)系域與另外的Bean關(guān)聯(lián),通過(guò)關(guān)系域,可以從一個(gè)Bean的實(shí)例中訪(fǎng)問(wèn)關(guān)聯(lián)的Bean對(duì)象,反之亦可。在一個(gè)單向的關(guān)系中,只有一個(gè)Bean擁有關(guān)聯(lián)其他Bean的關(guān)系域,只能從這個(gè)Bean的實(shí)例訪(fǎng)問(wèn)被關(guān)聯(lián)的Bean對(duì)象,而不可從被關(guān)聯(lián)的Bean對(duì)象訪(fǎng)問(wèn)到這個(gè)實(shí)例。
EJB QL查詢(xún)可以通過(guò)關(guān)系進(jìn)行定位。關(guān)系的方向決定了是否可以從一個(gè)Bean定位另一個(gè)Bean。如訂單作為一個(gè)Bean,訂單中的項(xiàng)目作為一個(gè)Bean,二者擁有雙向關(guān)系,即訂單知道擁有哪些項(xiàng)目,而項(xiàng)目知道自己屬于某個(gè)訂單,因此,通過(guò)關(guān)系,可以從訂單定位訂單中的項(xiàng)目,也可以從訂單中的項(xiàng)目定位到訂單;
Entity Bean的特征
持久性
由于Entity Bean的狀態(tài)數(shù)據(jù)保持在持久存儲(chǔ)中,因此,即使容器或服務(wù)器失效,Entity Bean的狀態(tài)數(shù)據(jù)仍然存在。
持久業(yè)務(wù)數(shù)據(jù)的對(duì)象表示
Entity Bean是持久業(yè)務(wù)數(shù)據(jù)的對(duì)象表示,更改Entity Bean的實(shí)例的狀態(tài),數(shù)據(jù)庫(kù)中的對(duì)應(yīng)信息也將自動(dòng)更新。實(shí)例狀態(tài)是數(shù)據(jù)庫(kù)數(shù)據(jù)的視圖,而不是兩個(gè)分離的數(shù)據(jù)。
表示相同的底層數(shù)據(jù)的多個(gè)Entity Bean實(shí)例
在企業(yè)應(yīng)用中,通常出現(xiàn)多個(gè)客戶(hù)對(duì)某些業(yè)務(wù)實(shí)體的并發(fā)訪(fǎng)問(wèn),一般,EJB容器通過(guò)維護(hù)同一個(gè)EJB實(shí)例的多個(gè)拷貝,提供給不同的客戶(hù),以此提高對(duì)客戶(hù)請(qǐng)求的響應(yīng)速度,EJB容器提供保持實(shí)例狀態(tài)的一致性的機(jī)制。而這種特性對(duì)于客戶(hù)來(lái)說(shuō)是透明的,因此,客戶(hù)可以認(rèn)為操作中的EJB實(shí)例是唯一的實(shí)例,可以不用考慮EJB實(shí)例狀態(tài)在多個(gè)并發(fā)客戶(hù)間的一致性。
可查找的Entity Bean
因?yàn)镋ntity Bean實(shí)例擁有其獨(dú)有的標(biāo)識(shí),因此,除了可以創(chuàng)建Entity Bean實(shí)例外,如使用SQL中的SELECT語(yǔ)句,還可對(duì)在數(shù)據(jù)庫(kù)中已有的業(yè)務(wù)數(shù)據(jù)進(jìn)行查找。對(duì)Entity Bean實(shí)例的查找一般通過(guò)在Entity Bean的Home接口中定義finder方法實(shí)現(xiàn)
數(shù)據(jù)的對(duì)象視圖
多層企業(yè)應(yīng)用中,通常有邏輯層和數(shù)據(jù)層之分,邏輯層中的邏輯組件用于表示特定的業(yè)務(wù)邏輯或滿(mǎn)足特定的業(yè)務(wù)需求,邏輯組件中一般只封裝邏輯,而業(yè)務(wù)數(shù)據(jù)則通過(guò)數(shù)據(jù)層中的數(shù)據(jù)組件提供表示。
業(yè)務(wù)數(shù)據(jù)通常以數(shù)據(jù)庫(kù)表的方式保存在關(guān)系型數(shù)據(jù)庫(kù)中,在EJB編程模型成為企業(yè)應(yīng)用開(kāi)發(fā)的標(biāo)準(zhǔn)之前,開(kāi)發(fā)者一般通過(guò)JDBC或其他數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)機(jī)制,將數(shù)據(jù)映射成為內(nèi)存中的業(yè)務(wù)對(duì)象,并提供保證這兩個(gè)數(shù)據(jù)拷貝之間的一致性的方法,即業(yè)務(wù)對(duì)象知道如何從數(shù)據(jù)庫(kù)中獲得自身的狀態(tài),當(dāng)自身狀態(tài)改變時(shí),同步數(shù)據(jù)庫(kù)中的對(duì)應(yīng)數(shù)據(jù),對(duì)于關(guān)系型數(shù)據(jù),往往需要更復(fù)雜的控制。
這樣,數(shù)據(jù)層中的數(shù)據(jù)組件往往顯得非常臃腫,代碼中充斥大量的底層服務(wù)處理,不能提供業(yè)務(wù)實(shí)體清晰的面向?qū)ο蟊硎荆从删o湊的狀態(tài)和方法構(gòu)成的對(duì)象,而且給開(kāi)發(fā)和維護(hù)帶來(lái)極大的不便。
通過(guò)Entity Bean組件模型,開(kāi)發(fā)者可以快速地建立起緊湊、靈活而且具有分布式特性的業(yè)務(wù)數(shù)據(jù)的對(duì)象視圖,通過(guò)類(lèi)似于標(biāo)準(zhǔn)的Java語(yǔ)言中創(chuàng)建、清除對(duì)象實(shí)例、調(diào)用實(shí)例的方法,對(duì)組件進(jìn)行操作,組件中只需提供應(yīng)用的業(yè)務(wù)邏輯。
組件結(jié)構(gòu)
Entity Bean由以下幾部分構(gòu)成:
· Home接口,客戶(hù)端通過(guò)此接口對(duì)Entity Bean對(duì)象進(jìn)行創(chuàng)建、清除、查找等操作;
· 組件接口,客戶(hù)端通過(guò)此接口訪(fǎng)問(wèn)Entity Bean對(duì)象,訪(fǎng)問(wèn)對(duì)象狀態(tài)及執(zhí)行對(duì)象業(yè)務(wù)方法;
· 組件類(lèi),開(kāi)發(fā)人員在此類(lèi)中提供對(duì)以上兩個(gè)接口中定義的方法的實(shí)現(xiàn);
· 部署描述,提供Entity Bean的事務(wù)屬性、安全等配置信息。
Primary Key
與關(guān)系型數(shù)據(jù)庫(kù)中的數(shù)據(jù)類(lèi)似,每個(gè)Entity Bean實(shí)例也具有一個(gè)標(biāo)識(shí)數(shù)據(jù)的唯一性的Primary Key對(duì)象,Primary Key對(duì)象可以具有多個(gè)屬性。屬性可以是任意用于說(shuō)明此Entity Bean實(shí)例的的數(shù)據(jù)。某些情況下,用于表示復(fù)雜關(guān)系的Entity Bean,Primary Key甚至可以是整個(gè)Entity Bean。
可以通過(guò)定義Entity Bean組件中的Primary Key類(lèi),來(lái)為組件提供可以任何滿(mǎn)足要求的Primary Key,但必須保證此Primary Key符合Java編程語(yǔ)言中的串行化要求,即Primary Key必須是合法的RMI類(lèi)型。
客戶(hù)端
Entity Bean的客戶(hù)端按照客戶(hù)端與Entity Bean所處的JVM是否相同,分為遠(yuǎn)程客戶(hù)和本地客戶(hù)。
JNDI
由于Entity Bean運(yùn)行于EJB容器中,由容器提供對(duì)Entity Bean實(shí)例的生存周期管理,客戶(hù)端不能直接訪(fǎng)問(wèn)容器中的Entity Bean,容器使客戶(hù)端可以通過(guò)JNDI訪(fǎng)問(wèn)Entity Bean的Home接口,客戶(hù)端通過(guò)Home接口取得對(duì)Entity Bean對(duì)象的引用,通過(guò)引用對(duì)容器中的Entity Bean實(shí)例進(jìn)行訪(fǎng)問(wèn)。
遠(yuǎn)程客戶(hù)
Entity Bean的遠(yuǎn)程客戶(hù)端通過(guò)Entity Bean的遠(yuǎn)程Home接口和遠(yuǎn)程接口訪(fǎng)問(wèn)Entity Bean對(duì)象。
Entity Bean的遠(yuǎn)程客戶(hù)端與運(yùn)行客戶(hù)端的JVM是否與Entity Bean所處JVM是否相同無(wú)關(guān),相同或不同JVM中的客戶(hù)端都可通過(guò)遠(yuǎn)程Home接口和遠(yuǎn)程接口訪(fǎng)問(wèn)Entity Bean對(duì)象。只是遠(yuǎn)程客戶(hù)端對(duì)Entity Bean進(jìn)行調(diào)用時(shí),其調(diào)用通過(guò)網(wǎng)絡(luò)傳播,參數(shù)與返回值必須是合法的RMI類(lèi)型,并且都按值傳遞。
由于網(wǎng)絡(luò)延遲的原因,客戶(hù)端通過(guò)遠(yuǎn)程訪(fǎng)問(wèn)比本地訪(fǎng)問(wèn)效率上要差一些,但是,由于遠(yuǎn)程訪(fǎng)問(wèn)與客戶(hù)端的位置無(wú)關(guān),因此,可以提供Entity Bean的可分布特性,適合粗粒度的對(duì)象表示。
Entity Bean的遠(yuǎn)程客戶(hù)端可以是用Java語(yǔ)言編寫(xiě)的任意程序類(lèi)型,如Java應(yīng)用、applet、Servlet等等,也可以是非Java的客戶(hù)端。
本地客戶(hù)
Entity Bean的本地客戶(hù)通過(guò)本地Home接口與本地接口訪(fǎng)問(wèn)Entity Bean對(duì)象。
Entity Bean的本地客戶(hù)端必須位于同一個(gè)JVM中。
Entity Bean的本地客戶(hù)端在對(duì)Entity Bean進(jìn)行調(diào)用時(shí),按照標(biāo)準(zhǔn)Java語(yǔ)言中的對(duì)象調(diào)用方式,其參數(shù)和返回值按引用傳遞。
因?yàn)椴簧婕熬W(wǎng)絡(luò)延遲的因素,一般,通過(guò)本地訪(fǎng)問(wèn),效率要高一些,不過(guò),組件的分布式特性就受到了影響。通過(guò)定義本地和遠(yuǎn)程的訪(fǎng)問(wèn)接口,Entity Bean可以同時(shí)提供兩種訪(fǎng)問(wèn)方式,不過(guò),通常只提供二者之一。
具有容器管理關(guān)系的EJB,必須提供本地訪(fǎng)問(wèn)接口
容器與Entity Bean
從Entity Bean實(shí)例的產(chǎn)生到清除,它都運(yùn)行于EJB容器中,容器中可以部署多個(gè)Entity Bean,容器提供客戶(hù)端對(duì)Entity Bean實(shí)例的訪(fǎng)問(wèn)機(jī)制,容器為部署的在其中的Entity Bean提供安全、并發(fā)、持久等等服務(wù)。對(duì)于Entity Bean的客戶(hù)端而言,容器是透明的。
Entity Bean作為業(yè)務(wù)數(shù)據(jù)在應(yīng)用系統(tǒng)中的對(duì)象表示,多個(gè)客戶(hù)通常會(huì)并發(fā)地訪(fǎng)問(wèn)Entity Bean對(duì)象,開(kāi)發(fā)者不必提供對(duì)并發(fā)訪(fǎng)問(wèn)的支持,通過(guò)實(shí)例池與事務(wù)管理器,EJB容器會(huì)保證實(shí)例對(duì)客戶(hù)端請(qǐng)求進(jìn)行進(jìn)行高效的響應(yīng),并保證實(shí)例狀態(tài)與數(shù)據(jù)庫(kù)的同步。如果開(kāi)發(fā)者使用了容器管理持久性的Entity Bean,則如何取得與數(shù)據(jù)庫(kù)的連接、如何使用SQL語(yǔ)句操作數(shù)據(jù)、如何利用資源等等,都可以完全由容器進(jìn)行處理。開(kāi)發(fā)者只需通過(guò)部署描述,對(duì)組件的事務(wù)、安全等進(jìn)行聲明即可。
通過(guò)JNDI定位遠(yuǎn)程Home接口
客戶(hù)端可通過(guò)JNDI定位Entity Bean的遠(yuǎn)程Home接口,JNDI命名空間中可以包含多個(gè)部署在容器中的Entity Bean的遠(yuǎn)程Home接口。
如下代碼段示意如何通過(guò)JNDI定位Entity Bean的遠(yuǎn)程Home接口:
Context initialContext = new InitialContext();
AccountHome accountHome = (AccountHome) javax.rmi.PortableRemoteObject.narrow(
initialContext.lookup(“java:comp/env/ejb/accounts”),
AccountHome.class
);
通過(guò)JNDI定位本地Home接口
客戶(hù)端通過(guò)JNDI定位Entity Bean的本地Home接口與定位遠(yuǎn)程Home接口的方法非常類(lèi)似,只是沒(méi)有牽涉到遠(yuǎn)程訪(fǎng)問(wèn)的API。
如下代碼段示意如何通過(guò)JNDI定位Entity Bean的本地Home接口:
Context initialContext = new InitialContext();
AccountHome accountHome = (AccountHome) initialContext.lookup(
“java:comp/env/ejb/accounts”
);
組件模型
Home接口
根據(jù)Entity Bean是否提供遠(yuǎn)程或本地訪(fǎng)問(wèn),Entity Bean組件必須提供本地或遠(yuǎn)程的Home接口。通過(guò)JNDI,容器使Home接口可被客戶(hù)端訪(fǎng)問(wèn)。
遠(yuǎn)程Home接口
通過(guò)Entity Bean的遠(yuǎn)程Home接口,開(kāi)發(fā)者向Entity Bean的客戶(hù)端提供進(jìn)行如下操作的方法:
· 創(chuàng)建新的Entity Bean實(shí)例;
· 查找已存在的Entity Bean實(shí)例;
· 清除Entity Bean實(shí)例;
· 執(zhí)行Home接口中的業(yè)務(wù)方法;
· 取得Entity Bean的javax.ejb.EJBMetaData接口,javax.ejb.EJBMetaData接口用于表示此Entity Bean的信息,降低客戶(hù)端和服務(wù)器的綁定程度和用于支持客戶(hù)端腳本;
· 取得Home接口句柄(Handler),此句柄可串行化(serialization)到持久存儲(chǔ)中,然后,可在其他虛擬機(jī)中,從持久存儲(chǔ)中,對(duì)此串行化對(duì)象進(jìn)行解串行化(deserialization),取得對(duì)此遠(yuǎn)程Home接口句柄的引用;
Entity Bean的遠(yuǎn)程Home接口必須擴(kuò)展(extends)javax.ejb.EJBHome接口,并遵循Java語(yǔ)言的遠(yuǎn)程接口標(biāo)準(zhǔn)。
create方法
Entity Bean的遠(yuǎn)程Home接口可定義零個(gè)或多個(gè)create方法,每個(gè)create方法提供一種創(chuàng)建Entity Bean實(shí)例的方式,create方法中的參數(shù)一般被用于初始化Entity Bean實(shí)例。每個(gè)create方法必須以“create”作為前綴;
遠(yuǎn)程Home接口中定義的create方法的返回值必須是Entity Bean的遠(yuǎn)程接口,拋出語(yǔ)句必須包含java.rmi.RemoteException和javax.ejb.CreateException異常,同時(shí)可包含任意的應(yīng)用級(jí)的異常。
以下代碼段是遠(yuǎn)程Home接口中三個(gè)create方法的范例:
public interface AccountHome extends javax.ejb.EJBHome {
public Account create(String firstName, String lastName, double initialBalance)
throws RemoteException, CreateException;
public Account create(String accountNumber, double initialBalance)
throws RemoteException, CreateException, LowInitialBalanceException;
public Account createLargeAccount(String firstname, String lastname, double initialBalance)
throws RemoteException, CreateException;
... }
以下是客戶(hù)端如何通過(guò)create方法創(chuàng)建Entity Bean實(shí)例的代碼范例:
AccountHome accountHome = ...;
Account account = accountHome.create(“John”, “Smith”, 500.00);.
finder方法
通過(guò)Entity Bean的遠(yuǎn)程Home接口,可以定義一到多個(gè)finder方法。所謂finder方法,即是開(kāi)發(fā)者提供給客戶(hù)端的方法,用于查找某個(gè)Entity Bean對(duì)象或包含多個(gè)Entity Bean對(duì)象的集合。遠(yuǎn)程Home接口中定義的每個(gè)finder方法對(duì)應(yīng)一種查找的方式。finder方法的名稱(chēng)必須以“find”前綴開(kāi)始,如:findLargeAccounts(...)。方法中定義的參數(shù),被Entity Bean組件類(lèi)中的對(duì)應(yīng)實(shí)現(xiàn)方法用于定位需要查找的Entity Bean對(duì)象或?qū)ο蠹稀?/span>
finder方法的返回值類(lèi)型必須是Entity Bean的遠(yuǎn)程接口對(duì)象,或是只包含遠(yuǎn)程接口對(duì)象的集合(Collection)。
每個(gè)遠(yuǎn)程Home接口中定義的finder方法的拋出語(yǔ)句必須包含對(duì)java.rmi.RemoteException異常和javax.ejb.FinderException異常的拋出。
遠(yuǎn)程Home接口必須包含一個(gè)findByPrimaryKey(primaryKey)方法,客戶(hù)端可通過(guò)此方法使用Entity Bean的Primary Key對(duì)Entity Bean對(duì)象進(jìn)行查找。此方法的唯一參數(shù)必須與Entity Bean的Primary Key為同一類(lèi)型,其返回值必須是Entity Bean的遠(yuǎn)程接口類(lèi)型。
以下代碼范例定義了一個(gè)findByPrimaryKey方法:
public interface AccountHome extends javax.ejb.EJBHome {
...
public Account findByPrimaryKey(String AccountNumber) throws RemoteException, FinderException;
}
以下代碼范例是客戶(hù)端調(diào)用finder方法的方式:
AccountHome = ...;
Account account = accountHome.findByPrimaryKey(“100-3450-3333”);
Remove方法
javax.ejb.EJBHome接口中定義的方法,由于Entity Bean組件的遠(yuǎn)程Home接口擴(kuò)展(extends)javax.ejb.EJBHome接口,因此,客戶(hù)端可通過(guò)調(diào)用Entity Bean的遠(yuǎn)程Home接口中的remove方法清除容器Entity Bean實(shí)例。
Home方法
作為應(yīng)用中業(yè)務(wù)數(shù)據(jù)的對(duì)象表示,Entity Bean通常表示一類(lèi)業(yè)務(wù)實(shí)體,如雇員信息、訂單、賬戶(hù)等等,通常這些實(shí)體都會(huì)涉及針對(duì)所有或部分已存在數(shù)據(jù)的操作,如對(duì)所有雇員的某些信息進(jìn)行統(tǒng)計(jì),或者對(duì)所有雇員增加花紅等等,這些操作不涉及單個(gè)的Entity Bean實(shí)例。
Entity Bean組件模型中,可以通過(guò)在遠(yuǎn)程Home接口中定義Home方法,提供對(duì)不涉及單個(gè)特定的Entity Bean實(shí)例的操作。
在遠(yuǎn)程Home接口中定義的Home方法必須拋出java.rmi.RemoteException異常,可拋出任意應(yīng)用級(jí)異常。同時(shí),其參數(shù)類(lèi)型和返回值類(lèi)型必須是合法的RMI類(lèi)型。
下面是兩個(gè)Home方法的范例代碼:
public interface EmployeeHome extends javax.ejb.EJBHome {
...
// this method returns a living index depending on
// the state and the base salary of an employee:
// the method is not specific to an instance
public float livingIndex(String state, float Salary) throws RemoteException;
// this method adds a bonus to all of the employees
// based on a company profit-sharing index
public void addBonus(float company_share_index)
throws RemoteException, ShareIndexOutOfRangeException;
...
}
本地Home接口
通過(guò)Entity Bean的本地Home接口,開(kāi)發(fā)者向Entity Bean的客戶(hù)端提供進(jìn)行如下操作的方法:
· 創(chuàng)建新的Entity Bean實(shí)例;
· 查找已存在的Entity Bean實(shí)例;
· 清除Entity Bean實(shí)例;
· 執(zhí)行Home接口中的業(yè)務(wù)方法;
Entity Bean的本地Home接口必須擴(kuò)展(extends)javax.ejb.EJBLocalHome接口
create方法
Entity Bean的本地Home接口可定義零個(gè)或多個(gè)create方法,每個(gè)create方法提供一種創(chuàng)建Entity Bean實(shí)例的方式,create方法中的參數(shù)一般被用于初始化Entity Bean實(shí)例。每個(gè)create方法以“create”作為前綴;
本地Home接口中定義的create方法的返回值必須是Entity Bean的遠(yuǎn)程接口,拋出語(yǔ)句不可包含java.rmi.RemoteException異常,可包含任意的應(yīng)用級(jí)的異常,必須包含javax.ejb.CreateException異常。
以下代碼段是本地Home接口中三個(gè)create方法的范例:
public interface AccountHome extends javax.ejb.EJBLocalHome {
public Account create(String firstName, String lastName, double initialBalance)
throws CreateException;
public Account create(String accountNumber, double initialBalance)
throws CreateException, LowInitialBalanceException;
public Account createLargeAccount(String firstname, String lastname, double initialBalance)
throws CreateException;
...
}
以下是客戶(hù)端如何通過(guò)create方法創(chuàng)建Entity Bean實(shí)例的代碼范例:
AccountHome accountHome = ...;
Account account = accountHome.create(“John”, “Smith”, 500.00);
finder方法
通過(guò)Entity Bean的本地Home接口,可以定義一到多個(gè)finder方法。所謂finder方法,即是開(kāi)發(fā)者提供給客戶(hù)端的方法,用于查找某個(gè)Entity Bean對(duì)象或包含多個(gè)Entity Bean對(duì)象的集合。本地Home接口中定義的每個(gè)finder方法對(duì)應(yīng)一種查找的方式。finder方法的名稱(chēng)必須以“find”前綴開(kāi)始,如:findLargeAccounts(...)。方法中定義的參數(shù),被Entity Bean組件類(lèi)中的對(duì)應(yīng)實(shí)現(xiàn)方法用于定位需要查找的Entity Bean對(duì)象或?qū)ο蠹稀?/span>
finder方法的返回值類(lèi)型必須是Entity Bean的本地接口對(duì)象,或是只包含本地接口對(duì)象的集合(Collection)。
每個(gè)本地Home接口中定義的finder方法的拋出語(yǔ)句必須包含javax.ejb.FinderException異常的拋出,不可包含java.rmi.RemoteException異常。
本地Home接口必須包含一個(gè)findByPrimaryKey(primaryKey)方法,客戶(hù)端可通過(guò)此方法使用Entity Bean的Primary Key對(duì)Entity Bean對(duì)象進(jìn)行查找。此方法的唯一參數(shù)必須與Entity Bean的Primary Key為同一類(lèi)型,其返回值必須是Entity Bean的本地接口類(lèi)型。
以下代碼范例定義了一個(gè)findByPrimaryKey方法:
public interface AccountHome extends javax.ejb.EJBLocalHome {
...
public Account findByPrimaryKey(String AccountNumber) throws FinderException;
}
以下代碼范例是客戶(hù)端調(diào)用finder的方式:
AccountHome = ...;
Account account = accountHome.findByPrimaryKey(“100-3450-3333”);
Remove方法
javax.ejb.EJBLocalHome接口中定義的方法,由于Entity Bean組件的本地Home接口擴(kuò)展(extends)javax.ejb.EJBLocalHome接口,因此,客戶(hù)端可通過(guò)調(diào)用Entity Bean的本地Home接口中的remove方法清除容器Entity Bean實(shí)例。
Home方法
作為應(yīng)用中業(yè)務(wù)數(shù)據(jù)的對(duì)象表示,Entity Bean通常表示一類(lèi)業(yè)務(wù)實(shí)體,如雇員信息、訂單、賬戶(hù)等等,通常這些實(shí)體都會(huì)涉及針對(duì)所有或部分已存在數(shù)據(jù)的操作,如對(duì)所有雇員的某些信息進(jìn)行統(tǒng)計(jì),或者對(duì)所有雇員增加花紅等等,這些操作不涉及單個(gè)的Entity Bean實(shí)例。
Entity Bean組件模型中,可以通過(guò)在本地Home接口中定義Home方法,提供對(duì)不涉及單個(gè)特定的Entity Bean實(shí)例的操作。
每個(gè)Home方法的拋出語(yǔ)句可以包含任意應(yīng)用級(jí)異常的拋出,不能拋出java.rmi.RemoteException異常。
下面是兩個(gè)Home方法的范例代碼:
public interface EmployeeHome extends javax.ejb.EJBLocalHome {
...
// this method returns a living index depending on
// the state and the base salary of an employee:
// the method is not specific to an instance
public float livingIndex(String state, float Salary);
// this method adds a bonus to all of the employees
// based on a company profit-sharing index
public void addBonus(float company_share_index) throws ShareIndexOutOfRangeException;
...
}
Primary Key
同一個(gè)Entity Bean組件的每個(gè)實(shí)例,都擁有一個(gè)用于標(biāo)識(shí)實(shí)例的同一類(lèi)型的Primary Key,如果兩個(gè)Entity Bean對(duì)象擁有相同的Home接口,擁有相同的Primary Key,即可認(rèn)為這兩個(gè)Entity Bean對(duì)象相等。
Entity Bean的Primary Key可以是任何合法的RMI類(lèi)型。每個(gè)Entity Bean都必須指定其唯一的Primary Key的類(lèi)型,不同的Entity Bean可以使用相同的primary key類(lèi)型。客戶(hù)端可通過(guò)Entity Bean實(shí)例的組件接口引用,調(diào)用getPrimaryKey()方法,取得實(shí)例關(guān)聯(lián)的Primary Key對(duì)象。
在整個(gè)Entity Bean實(shí)例的生存周期中,其關(guān)聯(lián)的Primary Key對(duì)象不會(huì)發(fā)生改變,即在生存周期內(nèi),客戶(hù)端調(diào)用實(shí)例的getPrimaryKey()方法返回的Primary Key對(duì)象是相同的。如果實(shí)例同時(shí)擁有遠(yuǎn)程接口和本地接口,則這兩個(gè)接口的getPrimaryKey()方法返回的Primary Key對(duì)象也是相同的。
因此,客戶(hù)端除了可以使用組件接口中的isIdentical方法判斷兩個(gè)Entity Bean實(shí)例是否相等之外,也可使用實(shí)例關(guān)聯(lián)的Primary Key對(duì)象的equals方法進(jìn)行判斷。
下面是使用isIdentical方法判斷兩個(gè)對(duì)Entity Bean實(shí)例的引用是否相等的代碼范例:
Account acc1 = ...;
Account acc2 = ...;
if (acc1.isIdentical(acc2)) {
//acc1 and acc2 are the same entity object
} else {
//acc2 and acc2 are different entity objects
}
知道Entity Bean實(shí)例的Primary Key的客戶(hù)端,可以使用Home接口中定義的findByPrimaryKey方法,取得對(duì)Entity Bean實(shí)例組件接口的引用。
注意 |
|
當(dāng)判斷兩個(gè)Entity Bean實(shí)例引用是否相等,不可使用“==”運(yùn)算符,只可使用Primary Key對(duì)象的equals方法或組件接口的isIdentical方法進(jìn)行判斷。 |
組件接口
客戶(hù)端通過(guò)Entity Bean提供的組件接口訪(fǎng)問(wèn)Entity Bean對(duì)象。開(kāi)發(fā)者必須為組件提供組件接口,并在組件接口中對(duì)客戶(hù)所能調(diào)用的業(yè)務(wù)方法進(jìn)行定義。
根據(jù)Entity Bean是否提供遠(yuǎn)程或本地訪(fǎng)問(wèn),組件接口分為遠(yuǎn)程接口和本地接口。
遠(yuǎn)程接口
Entity Bean組件中的遠(yuǎn)程接口必須擴(kuò)展(extends)javax.ejb.EJBObject接口。并在其中定義可供客戶(hù)端調(diào)用業(yè)務(wù)方法。業(yè)務(wù)方法的拋出語(yǔ)句必須包含java.rmi.RemoteException異常,可包含任意的應(yīng)用級(jí)異常。
下面是Entity Bean組件遠(yuǎn)程接口的范例代碼:
public interface Account extends javax.ejb.EJBObject {
void debit(double amount) throws java.rmi.RemoteException, InsufficientBalanceException;
void credit(double amount) throws java.rmi.RemoteException;
double getBalance() throws java.rmi.RemoteException;
}
javax.ejb.EJBObject提供為客戶(hù)端提供對(duì)Entity Bean對(duì)象引用進(jìn)行如下操作的方法:
· 取得Entity Bean對(duì)象的遠(yuǎn)程Home接口;
· 清除Entity Bean對(duì)象;
· 取得Entity Bean對(duì)象的句柄;
· 取得Entity Bean對(duì)象的Primary Key。
容器為以上操作提供實(shí)現(xiàn),開(kāi)發(fā)者只需在Entity Bean的組件類(lèi)中提供對(duì)遠(yuǎn)程接口中定義的業(yè)務(wù)方法的實(shí)現(xiàn)。
本地接口
Entity Bean組件中的本地接口必須擴(kuò)展(extends)javax.ejb.EJBLocalObject接口。并在其中定義可供客戶(hù)端調(diào)用的業(yè)務(wù)方法。業(yè)務(wù)方法的拋出語(yǔ)句不能包含java.rmi.RemoteException異常,可包含任意的應(yīng)用級(jí)異常。
下面是Entity Bean組件本地接口的范例代碼:
public interface Account extends javax.ejb.EJBLocalObject {
void debit(double amount) throws InsufficientBalanceException;
void credit(double amount);
double getBalance();
}
javax.ejb.EJBLocalObject提供為客戶(hù)端提供對(duì)Entity Bean對(duì)象引用進(jìn)行如下操作的方法:
· 取得Entity Bean對(duì)象的本地Home接口;
· 清除Entity Bean對(duì)象;
· 取得Entity Bean對(duì)象的Primary Key。
容器為以上操作提供實(shí)現(xiàn),開(kāi)發(fā)者只需在Entity Bean的組件類(lèi)中提供對(duì)本地接口中定義的業(yè)務(wù)方法的實(shí)現(xiàn)。
組件類(lèi)
由于Entity Bean具有兩種不同的持久類(lèi)型,Bean管理持久性(Bean-managed Persistence,BMP)和容器管理持久性(Container-managed Persistence,CMP),兩種持久類(lèi)型的組件類(lèi)的開(kāi)發(fā)方式具有較多的不同。因此,將在以下兩章中分別對(duì)這兩種持久性類(lèi)型的Entity Bean進(jìn)行介紹,并對(duì)不同持久類(lèi)型的組件類(lèi)的開(kāi)發(fā)進(jìn)行描述。
生存周期
Entity Bean對(duì)象的生存周期
上圖是Entity Bean生存周期內(nèi)的狀態(tài)圖。
在容器創(chuàng)建了Entity Bean實(shí)例之后,調(diào)用Entity Bean組件類(lèi)的setEntityContext方法,將Entity Bean的上下文傳遞到實(shí)例。
實(shí)例化之后,Entity Bean被轉(zhuǎn)移到實(shí)例池成為可用實(shí)例。實(shí)例池中的實(shí)例沒(méi)有任何標(biāo)識(shí),只有在實(shí)例進(jìn)入就緒狀態(tài)時(shí),容器將為實(shí)例分配標(biāo)識(shí)。
實(shí)例有兩種方式從實(shí)例池進(jìn)入就緒狀態(tài)。一種方式是客戶(hù)端調(diào)用了Entity Bean的Home接口的create方法,使容器調(diào)用Entity Bean的ejbCreate和ejbPostCreate方法;另一種方式是容器調(diào)用Entity Bean的ejbActivate方法。
當(dāng)實(shí)例進(jìn)入就緒狀態(tài)之后,即可對(duì)實(shí)例的業(yè)務(wù)方法進(jìn)行調(diào)用。
同樣,實(shí)例也有兩種方式從就緒狀態(tài)進(jìn)入實(shí)例池。一種方式是客戶(hù)端調(diào)用了remove方法,使容器調(diào)用Entity Bean的ejbRemove方法;另一種方式是容器調(diào)用Entity Bean的ejbPassivate方法。
當(dāng)Entity Bean實(shí)例的生命周期結(jié)束,容器將Entity Bean從實(shí)例池中移出,并調(diào)用Entity Bean的unsetEntityContext方法