轉載自:http://www.java-cn.com/technology/technology_detail.jsp?id=781
開發Beans
一、會話Beans介紹
按功能可把EJB分為兩類:Session Beans 與 Entity Beans。
企業級Bean類
為了使bean可以在任一容器中工作,bean必須被附在介面中。在EJB中,在enterprise bean class中提供了企業級bean組件的實現。這是個簡單的遵循介面的java類。
一個enterprise bean class 包含對組件的實現細節。會話bean的實現不同於實體bean的實現,
一個Session Beans針對單一的客戶完成一次串連或會話,其生存直到客戶完成串連與會話,或系統意外中止。當一個新的客戶從EJB Server訪到一個Session Beans時,那麼EJB Container建立一個新的Session Beans執行個體,其運行直到會話結束,Session Beans必須實現介面javax.ejb.SessionBean。
Entity Beans實現介面javax.ejb.EntityBean,其描述了特定資料來源中的資料,能長時間存在於EJB Container中,不會隨系統的意外中止而消失,並且可以讓多個客戶同時訪問。
EJB規範定義了許多bean類能夠實現的標準介面。定義了所有的bean類必須有的方法。容器調用這些方法用來管理bean。
所有bean類(無論是會話bean還是實體bean)必須實現的最基本的介面是javax.ejb.EnterpriseBean介面。
public interface javax.ejb.EnterpriseBean extends java.io.Serializable
{
}
值得注意的是:它繼承了java.io.Serializable。
所有的會話bean必須實現javax.ejb.SessionBean,
所有的實體bean必須實現javax.ejb.EntityBean.
EJB對象
當客戶想使用enterprise bean class的一個執行個體時,客戶不必直接在實際的執行個體上調用方法,調用過程被EJB容器截取,bean執行個體被容器中對象所代表。
1、Enterprise bean class不能通過網路直接被調用,我們知道EJB容器可以操縱網路,因此它通過容器將bean封裝成可在網路上使用的對象。
2、通過截取請求,容器可以自動執行許多必要的管理工作。
3、EJB容器可以跟蹤哪個方法被調用,在系統管理者的使用者介面上顯示其用法等等。
因此,EJB容器可以看作間接的存在於客戶代碼和bean之間的層。這個間接的層使用單獨的網路對象來表示自己,這個對象稱為EJB對象。
EJB對象作為容器物理的部分;所有的EJB對象都有針對容器特殊要求的代碼。因此,容器供應商提供專門工具,用來自動為EJB對象產生類檔案。
遠程介面
我們前面瞭解到,bean客戶調用EJB對象上的方法來代替調用bean,為了執行它,EJB對象必須複製bean類中的每個業務方法。但是,怎樣才能使自動產生的EJB對象知道複製了哪個方法呢?這就用到了bean提供者寫的一個特殊的介面,這個介面複製所有的與bean類相關聯的商務邏輯方法。這個介面被稱為遠程介面。
這個介面必須遵循EJB規範的定義,所有的遠程介面必須從sun公司提供的通用介面繼承而來,即javax.ejb.EJBObject。
EJB對象
public interface javax.ejb.EJBObject
extends java.rmi.Remote
{
public abstract javax.ejb.EJBHome getEJBHome()
throws java.rmi.RemoteException;
public abstract java.lang.Object getPrimaryKey()
throws java.rmi.RemoteException;
public abstract void remove()
throws java.rmi.RemoteException,
javax.ejb.RemoveException;
public abstract javax.ejb.Handle getHandle()
throws java.rmi.RemoteException;
public abstract boolean isIdentical(javax.ejb.EJBObject)
throws java.rmi.RemoteException;
}
以上是對於所有EJB對象必須擁有的方法,你不需實現這些方法,這些方法的實現,產生EJB對象時由容器自動產生。
用戶端代碼通過調用javax.ejb.EJBObject的方法來和bean協同工作。
Java RMI和EJB對象
你應當注意到:java.ejb.EJBObject繼承了Java.rmi.Remote。Java.rmi.Remote介面是java遠程方法調用(RMI)的一部分,任一個實現java.rmi.Remote的對象都是rmote對象,它可以被另外的java虛擬機器所調用。
被容器提供的EJB對象實現了遠程介面,同時也間接實現了java.rmi.Remote,這樣也就意味著你的EJB對象是完全符合網路需要的,可以被網路上的其他java虛擬機器調用。當然,EJB介面也必須遵守EJB規範。
EJB遠程介面必須遵守java的RMI遠程介面規範。例如:錯誤處理,二者相同。
遠程介面同樣也必須遵守java RMI參數傳遞規範。不是什麼都可以通過VM方法調用來在網路上傳遞,傳遞的參數必須符合RMI類型。
EJB也繼承了RMI的優點,對於RMI,你正在調用的遠程對象的物理地址是不可見的。這個特點同樣也適用於EJB。客戶代碼不必關心正使用的EJB對象是在鄰近的電腦上還是從internat傳遞來的。這樣,EJB對象可以和用戶端處在同一個java VM中。
EJB保證了本地分布式組件的透明度。這種透明對於多層配置來說是非常必要的。用戶端代碼是非常容易移植的,不受限於特殊的多層配置。EJB容器可以以最佳化方式在本地執行。
Home對象
我們看到,用戶端代碼處理EJB對象,而從不直接操作beans。那麼,用戶端如何得到EJB對象的參考呢?
用戶端不直接將EJB對象執行個體化。因為EJB對象可以存在於不同的機器中。同樣的,EJB使本地透明化,因此用戶端不知道它的確切所在。
用戶端代碼通過EJB對象工廠得到EJB對象的參考。EJB規範裡稱這種工廠為home對象。它主要起一下作用:
建立EJB對象。
找到已經存在的EJB對象。
刪除EJB對象。
在一些細節方面,EJB對象工廠同EJB對象的特徵相同。
Home介面
Home介面簡單的定義了建立、刪除和尋找EJB對象的方法。容器的home對象實現了home介面。
通常,EJB定義了所有home介面必須支援的許多方法,這些必須的方法被定義在javax.ejb.EJBHome介面上,home介面必須繼承Java.ejb.EJBHome介面。
public interface javax.ejb.EJBHome
extends java.rmi.Remote
{
public abstract EJBMetaData getEJBMetaData()
throws java.rmi.RemoteException;
public abstract void remove(Handle handle)
throws java.rmi.RemoteException
javax.ejb.RemoveException;
public abstract void remove(Object primaryKey)
throws java.rmi.RemoteException,
javax.ejb.RemoveException;
}
javax.ejb.EJBHome介面
注意javax.ejb.EJBHome繼承了java.rmi.Remote,這意味著home介面同樣也支援RMI遠程對象,傳遞的參數和RMI也相同。
Home對象
所有home對象所需的方法
配置描述符
配置描述符允許EJB容器向企業級的bean組件提供隱含的中介軟體服務。隱含的中介軟體服務是bean可以獲得不必將任何中介軟體API解碼,可以自動獲得服務的一種服務。
Bean的特殊屬性
最後,你還需要有一個基於java的bean的屬性檔案。Bean在運行時讀這些屬性,這些屬性在使用bean函數時會被用到。
Ejb-jar檔案
一旦產生bean的類、home介面、遠程介面、配置描述符和bean的屬性,我們就可以把它們打包成一個實體。這個實體稱作Ejb-jar檔案。這是個壓縮檔。
建立Ejb-jar檔案
什麼是會話bean
一個Session Beans針對單一的客戶完成一次串連或會話,其生存直到客戶完成串連與會話,或系統意外中止。Session Beans必須實現介面javax.ejb.SessionBean。
會話bean的生存期
會話bean和實體bean的主要不同是它們的生存期的長短。會話bean的生存期短。與客戶的會話時間相當。在與客戶串連端開時,EJB容器會破壞會話bean。
相反,實體bean可以存活相當長的時間,實體bean是永久存取的一部分,例如:資料庫。
會話bean不能儲存永久的儲存資料,但是,它可以進行資料庫操作。
所有的會話bean都需要管理callback方法,容器定時的調用它,用來對bean的重要事件發出警告。這個方法僅能被容器調用。
Conversational versus Nonconversational Session Beans
如何寫會話Bean
寫會話bean的類,必須實現javax.ejb.SessionBean介面
public interface javax.ejb.SessionBean
extends javax.ejb.EnterpriseBean
{
public abstract void setSessionContext(SessionContext ctx)
throws java.rmi.RemoteException;
public abstract void ejbPassivate()
throws java.rmi.RemoteException;
public abstract void ejbActivate()
throws java.rmi.RemoteException;
public abstract void ejbRemove()
throws java.rmi.RemoteException;
}
會話bean和實體bean都繼承了javax.ejb.EnterpriseBean介面
讓我們詳細看看介面中的各種方法:
setSessionContext(SessionContext ctx)
容器調用這個方法來通過會話上下文與bean串連。Bean可以通過會話上下文向容器查詢當前事物的狀態和當前的安全狀態等。
import javax.ejb.*;
public class MyBean implements SessionBean {
private SessionContext ctx;
public void setSessionContext(SessionContext ctx) {
this.ctx = ctx;
}
...
}
ejbCreate(…)
用來初始化你的會話bean,可以定義多個不同參數的ejbCreate()方法來用不同的方法初始化bean。
import javax.ejb.*;
public class MyBean implements SessionBean {
private int memberVariable;
public void ejbCreate(int initialValue) {
this.memberVariable = initialValue;
}
...
}
ejbCreate()方法是容器可以調用的callback方法,用戶端代碼不能調用它,因為用戶端不能直接處理beans??他們必須通過容器,但是用戶端必須採用某種方法向ejbCreate方法傳遞參數,用戶端提供初始化參數。Home介面是用戶端用來初始化調用的介面工廠。你必須在home介面中複製每一個ejbCreate()方法,例如:如果在bean類中你有下面的ejbCreate方法
public void ejbCreate(int i) throws ...
那麼你必須在你的home介面裡有下面的create()方法
public void create(int i) throws ...
用戶端調用home介面中的create()方法,將參數傳遞給ejbCreate()。
EjbPassivate()
如果出現太多的執行個體bean,EJB容器可以將它們中的一些鈍化,將它們寫到臨時的存出空間例如資料庫或檔案系統。容器釋放它們所申請的空間。
import javax.ejb.*;
public class MyBean implements SessionBean {
public void ejbPassivate() {
<close socket connections, etc...>
}
...
}
ejbActivate()
當客戶需要使用被鈍化的bean時,容器將被鈍化的bean重新匯入記憶體,啟用它們。
Bean又被導致記憶體,這時需要重新得到bean所需要的資源。
import javax.ejb.*;
public class MyBean implements SessionBean {
public void ejbActivate() {
<open socket connections, etc...>
}
...
}
ejbRemove()
當容器將會話bean執行個體remove掉時,調用此方法。所有的bean都有這種方法,它沒有參數,它將釋放所有以分配的資源。
import javax.ejb.*;
public class MyBean implements SessionBean {
public void ejbRemove() {
<prepare for destruction>
}
...
}
容器可以在任何時候調用ejbRemove()方法,但如果遇到異常,則有可能禁止容器調用此方法。
業務方法
應該定義一些解決業務問題的方法:例如:
import javax.ejb.*;
public class MyBean implements SessionBean {
public int add(int i, int j) {
return (i + j);
}
...
}
因為用戶端要調用這些方法,因此,你必須在bean的遠程介面中列出這些方法。
如何調用會話beans
我們現在來看客戶方,客戶方要通過使用一個或多個bean解決一些現實的問題。
有兩種不同的客戶方:
Java RMI-based clients:這種客戶方通過使用JNDI定位對象,使用JTA控制事務。
CORBA客戶方:客戶方也可以使用CORBA標準來寫。CORBA客戶方使用CORBA名字服務(COS Naming)在網路上定位對象,使用CORBA的OTS控制事務。
無論是用CORBA還是RMI,典型的用戶端代碼都必須實現:
1、 定位Home介面
2、 使用Home介面建立EJB對象
3、在EJB對象上調用業務方法
4、清除EJB對象
定位Home介面
用戶端使用JNDL定位Home對象。
J2EE中JNDL的作用
J2EE的目標之一是使應用程式實現“write once,run anywhere”。任何的運行在企業級配置的java代碼在多層結構中應該是不受約束的。因此必須實現定位的透明化。
J2EE通過使用JNDL來實現定位的透明化。已有目錄服務的產品如Netscape的Directory Server,微軟的Active Directory,IBM的Lotus Notes。
通常我們使用目錄服務儲存使用者名稱、密碼、機器位置、印表機位置等等。J2EE擴充目錄服務儲存資源的本地資訊,這些資源也可以是Home對象、企業級bean的環境屬性、資料庫驅動、資訊服務驅動和其他資源。使用目錄服務,在些應用程式代碼時可以不必關心確切的機器名字和機器地址,這樣保證了代碼的可移植性。無論資源在何處,都不需要重新編譯代碼。
JNDL通過為本機使用者、機器、網路、對象和服務提供一個標準介面向企業級配置中增加值。
為了在J2EE中定位資源,必須實現以下兩步:
1、 用配置描述符中的“綽號”關聯資源,J2EE將向資源綁定綽號。
2、 資源的用戶端使用JNDL中的綽號定位資源。
怎樣使用JNDL定位Home對象
用戶端不必關心Home對象在網路的什麼地方。JNDL為Home對象提供綽號來定位Home對象。通過綽號可以得到Home對象的參考。
具體點,用戶端代碼必須執行以下幾步來通過JNDL得到參考。
1、 建立環境。必須配置將要使用目錄服務,包括為驗證身份所需的使用者名稱、密碼。
2、 建立初始的上下文。初始上下文是串連目錄結構的本地出發點。通過初始上下文得到設定的環境屬性。
3、 得到Home對象。執行lookup()操作,返回一個RMI遠程對象。
得到Home對象的參考
/*
* Get System properties for JNDI initialization
*/
Properties props = System.getProperties();
/*
* Form an initial context
*/
Context ctx = new InitialContext(props);
/*
* Get a reference to the home object - the
* factory for EJB objects
*/
MyHome home = (MyHome) ctx.lookup("MyHome");
建立EJB對象
得到Home對象以後,可以將Home對象作為建立EJB對象的工廠。調用create()方法建立EJB對象。
MyRemoteInterface ejbObject = home.create();
無參數是因為無狀態beans不需要初始參數。
調用方法
用戶端有了EJB對象以後就可以通過它來調用方法。當用戶端在EJB對象上調用方法時,EJB對象必須選擇一個bean執行個體來應答。EJB對象可以建立一個新的執行個體或是重用已經存在的執行個體。
ejbObject.add();
破壞EJB對象
調用EJB或Home對象上的remove()方法來破壞EJB對象。
ejbObject.remove();