nterpriseJavaBean 入門 一 基本知識 1. 背景 Java由於其良好的跨平台行而成為服務器端的理想語言,為了利用Java實現服務器端的計算,SUN推出了一個完整的開發平台J2EE,其目的是為基於Java的服務器端配置提供一個獨立於平台的可攜帶的多用戶企業級的安全平台,而J2EE的基石就是Enterprise JavaBeans(EJB),EJB是建立基於JAVA的服務器端組件的標准,它定義了如何編寫服務器端組件,提供了組件與管理組件的應用服務器之間的標准約定,EJB是一種組件架構,使得開發人員能夠快速開發出具有伸縮性的企業級應用。 2. EJB簡介 1)JavaBeans和Enterprise JavaBeans JavaBeans是Java的組件模型。在JavaBeans規范中定義了事件和屬性等特征。Enterprise JavaBeans也定義了一個Java組件模型,但是Enterprise JavaBeans組件模型和JavaBeans組件模型是不同的。 JavaBeans重點是允許開發者在開發工具中可視化的操縱組件。JavaBeans規范詳細地解釋了組件間事件登記、傳遞、識別和屬性使用、定制和持久化的應用編程接口和語意。 Enterprise JavaBeans的側重點是詳細地定義了一個可以portably地部署Java組件的服務框架模型。因此,其中並沒提及事件,因為enterprise bean通常不發送和接受事件。同樣也沒有提及屬性------屬性定制並不是在開發時進行,而是在運行時(實際上在部署時)通過一個部署描述符來描述。 不要尋找JavaBeans和Enterprise JavaBeans之間的相似性。他們都是組件模型規范,但是前者說明了開發工具中應用程序組裝的問題,而後者則側重於部署組件的服務框架的細節。不要錯誤地認為JavaBeans是用於客戶端的開發,Enterprise JavaBeans是用於服務器端的開發。JavaBeans也可作為進行非圖形化服務器端Java應用開發的組件模型。區別是當你使用JavaBeans創建服務器應用時,你還得設計整個的服務框架。用Enterprise Javabeans框架是現成的,你只需遵守它的APIs.對於復雜的服務器端應用程序,顯然使用Enterprise JavaBeans比重新開發更簡單 2)EJB體系結構 EJB是一種組件架構,它采用分而制之的方法實現服務器端的計算。 EJB規范定義了六種不同的角色來完成其任務, 包括: ? Bean provider: 提供可重用的商業組件 ? Container provider: 為ejb 應用提供低層次的運行環境 ? Server provider:提供應用程序服務器用以包含,管理和配置ejb組件,目前EJB規范沒有提供EJB Container和EJB Server之間的接口,故二者的提供商是合一的,有:BEA的Weblogic server,SUN的NetDynamics,IBM的WebSphere,Oracle的8i等。 ? Application assembler:負責將不同的組件組織起來構成能夠運行的應用程序 ? Deployer: 負責將要使用的組件安裝到應用服務器中並加以配置 ? System Administrator: 負責配置好的系統的管理等 這六種角色的流程圖如下: Enterprise JavaBean 駐留在EJB Container中,通過EJB Container對ejb進行管理。EJB規范定義了二者之間的接口。 Javax.ejb.EJBHome接口列出了所有定位、創建、刪除EJB 類實例的方法。Home對象是home接口的實現。EJB類開發者必須定義home接口。EJB Container Provider應該提供從home接口中產生home對象實現的方法。 遠程接口(remote interface)列出了EJB類中的商業方法。Javax.ejb.EJBObject實現遠程接口,並且客戶端通過它訪問EJB實例的商業方法。EJB開發者定義遠程接口,EJB Container Provider提供產生相應的EJBObject的方法。客戶端不能得到EJB實例的引用,只能得到它的EJBObject實例的引用。當客戶端調用一個方法,EJBObject接受請求並把它傳給EJB實例,同時提供進程中必要的包裝功能。客戶端應用程序通過home對象來定位、創建、刪除EJB類的實例,通過EJBObject來調用實例中的商業方法。客戶端可以用Java來編程,通過Java RMI來訪問訪問home對象和EJBObject,或用其他語言編程並通過CORBA/IIOP訪問,使得部署的服務器端組件可以通過CORBA接口來訪問。 Enterprise JavaBean規范將Enterprise Beans 分為兩種:session bean和entity bean. I. session bean表示的是調用它的客戶端代碼索要完成的工作,是一種商業處理過程對象,它實現商業邏輯,商業規則以及工作流程,例如:報價,訂單處理,視頻壓縮,股票交易等。session bean之所以叫session bean是因為其生命周期與調用它的客戶端相同。 session bean又分為兩種:stateless和stateful, stateful session bean用於貫穿多個方法請求和事務的商業過程,例如:網上商店,用戶進入商店後,可以將商品加入再現的購物車,組件必須跟蹤用戶的狀態(如:購物車);而stateless session bean用於客戶調用方法期間不用維護任何狀態信息,例如:解決復雜數學運算的視頻壓縮/解壓縮。 II. entity bean用來代表商業過程中處理的永久性的數據,例如:銀行出納員組件完成儲蓄等商業過程,其中涉及的數據時銀行賬戶數據 entity bean用來代表底層的對象。最常用的是用entity bean代表關系庫中的數據。一個簡單的entity bean 可以定義成代表數據庫表的一個記錄,也就是每一個實例代表一個特殊的記錄。更復雜的entity bean可以代表數據庫表間關聯視圖。在entity bean中還可以考慮包含廠商的增強功能,如對象--關系映射的集成。 通常用entity類代表一個數據庫表比代表多個相關聯的表更簡單且更有效。反過來可以輕易地向entity類的定義中增加關聯,這樣可以最大地復用cache並減小舊數據的表現。 III. entity bean和session bean的比較 看起來session bean好象沒什麼用處,尤其對於數據驅動的應用程序。當然事實並不是這樣。因為entity bean(譬如說)代表底層數據庫的一行,則entity bean實例和數據庫記錄間就是一對一的關系。因為多個客戶端必須訪問底層記錄,這意味著,不同於session bean,客戶端必須共享entity bean。因為是共享的,所以entity bean不允許保存每個客戶端的信息。session bean允許保存客戶端的狀態信息,客戶端和session bean實例間是一對一的。entity bean允許保存記錄的信息,entity bean實例和記錄間是一對一的。一個理想的情況是客戶端通過session bean連接服務器,然後session bean通過entity bean訪問數據庫。這使得既可以保存客戶端的信息又可以保存數據庫記錄的信息。 同時session bean也不能提供在相同或不同的EJB類調用間進行全局的事務控制。沒有session bean,應用程序開發者(客戶端開發者)就必須理解EJB類的事務要求,並使用客戶端的事務劃分來提供事務控制。EJB的主要好處就是應用開發者不需知道EJB類的事務需求。一個session bean可以代表一個商業操作,進行事務控制,不需要客戶端進行事務劃分。 以下我們作為EJB provider的角色來討論Enterprise javaBean的開發。 3,EJB 開發 A) Enterprise JavaBean的由如下部分構成 Enterprise Bean 類: 包含ejb 組件的詳細實現,對於session Bean它代表了 與業務處理相關的邏輯的實現,而對於entity Bean 它代表了與數據邏輯相關的實現 EJB Object :是由EJB Container來實現的遠程接口,它是客戶端和bean 實例之間的中介,傳遞客戶端調用到bean 實例; Home 接口:充當EJB Object工廠的java接口,創建EJB Object,Home接口的實現由EJB Container負責。 Deploy descriptor:描述你的ejb 中間件的相關要求,包括:通知EJB Container如何管理你的bean,事務的需要,安全需要等等。 特定於bean 的屬性: 利用該屬性,bean可以在運行時讀取並調整自己的功能 Ejb-jar 文件:將生成的bean 類,home接口,Ejb object,deployment descriptor和bean 的propertIEs 打包進ejb jar 文件,這樣就可以deploy了。 B) Enterprise JavaBean編程的具體步驟 實現javax.ejb.EnterpriseBean接口: 對於session bean 可以直接實現javax.ejb.SessionBean接口,對於entity bean 可以直接實現javax.ejb.EntityBean接口,而後實現本bean特有的功能。 擴展javax.ejb.EJBObject接口: 增加在Enterprise Bean實現類中供客戶調用的方法的相應的方法,必須相同 擴展javax.ejb.EJBHome接口: 增加創建上述擴展的javax.ejb.EJBObject接口的相應的create()方法。 編寫deploy descriptor文件: 目前EJB 1.1規范規定了用XML文件來描述它,並提供了相應的DTD. 生成EJB jar 文件: 利用jar命令將上述生成的相應文件進行打包。 在第二部分給出了ejb開發的詳細說明及相關注意事項 二 例子程序 以下的例子程序是以weblogic server(ver5.1)作為EJB Server(EJB Container)的, 不同的EJB Server 在一些方面有所不同 (不同的地方另加注釋) 例子一. Hello, world (Stateless Session Bean) 包括EJB相應接口的擴展和實現、deploy descriptor文件的生成以及.jar文件生成; 服務器端EJB開發 EJB相應接口的擴展和實現:(與EJB Server無關) 第一步: 實現javax.ejb.SessionBean 接口,並提供該Bean的特定功能, "Hello, world" Stateless SessionBean 僅僅向客戶端返回“Hello,world!”字符串 注意:除了要實現javax.ejb.SessionBean接口外(ejbActivate(),ejbPassivate(), ejbRemove(), setSessionContext()),必須: 1).實現公共方法ejbCreate(),該方法對於stateless SessionBean 無需帶任何參數而對stateful SessionBean則根據需要自定; 2)提供給客戶調用的方法, 如:本例的hello()方法 package com.jsper.ejbexample.session.helloworld; import javax.ejb.*; import java.rmi.RemoteException; public class HelloBean implements SessionBean { public HelloBean() { super(); } /** *由EJB Server(EJB Container) 調用,用於激活SessionBean的實例 */ public void ejbActivate() throws EJBException, java.rmi.RemoteException { System.out.println("ejbActivate()"); } /** *由EJB Server(EJB Container) 調用,用於創建本SessionBean的實例 * 創建日期:(2000-8-1 16:00:45) */ public void ejbCreate() throws javax.ejb.CreateException { System.out.println("ejbCreate()"); } /** * 由EJB Server(EJB Container) 調用,用於惰化SessionBean的實例 */ public void ejbPassivate() throws EJBException, java.rmi.RemoteException { System.out.println("ejbPassivate()"); } /** * 由EJB Server(EJB Container) 調用,用於刪除SessionBean的實例 */ public void ejbRemove() throws EJBException, java.rmi.RemoteException { System.out.println("ejbRemove()"); } /** * 本SessionBean提供給客戶調用的方法,但不能由客戶直接調用,而是通過EjbObject遠程接口調用 * 創建日期:(2000-8-1 16:04:58) * @return java.lang.String */ public String hello() { return "Hello, World!"; } /** * 由EJB Server(EJB Container) 調用,用於設置SessionBean的上下文 */ public void setSessionContext(SessionContext arg1) throws EJBException, java.rmi.RemoteException { System.out.println("setSessionContext()"); } } 第二步:擴展javax.ejb.EJBObject接口,增加在第一步SessionBean 接口實現中提供給客戶調用 的方法, 如本例的hello()方法 注意:1)增加的方法名稱必須與相應的SessionBean實現中方法相同(case-sensitive); 2) 增加的方法必須拋出java.rmi.RemoteException異常 package com.jsper.ejbexample.session.helloworld; import java.rmi.*; import javax.ejb.*; public interface Hello extends EJBObject { /** * 由客戶端直接調用,返回“hello,world!”,實現由相應的SessionBean完成 * 創建日期:(2000-8-1 15:56:25) * @return java.lang.String * @exception java.rmi.RemoteException 異常說明。 */ String hello() throws java.rmi.RemoteException; } 第三步:擴展javax.ejb.EJBHome接口,增加創建EJBHome接口對象的create()方法 注意: 1)create()方法中參數的有無無關緊要,但必須與SessionBean接口實現類中ejbCreate()方法相對應,包括從方法的個數上和參數上;例如:若SessionBean接口實現類中有ejbCreate(),ejbCreate(int nVal)方法,則該接口擴展中必須增加create(),create(int nVal)方法 2)create()方法必須拋出javax.ejb.CreateException 和java.rmi.RemoteException 異常 package com.JSper.ejbexample.session.helloworld; import java.rmi.*; import javax.ejb.*; public interface HelloHome extends EJBHome { /** * 創建EJBObject擴展對象Hello * 創建日期:(2000-8-1 16:13:53) * @return com.JSPer.ejbexample.session.helloworld.Hello * @exception javax.ejb.CreateException 異常說明。 * @exception java.rmi.RemoteException 異常說明。 */ Hello create() throws javax.ejb.CreateException, Java.rmi.RemoteException; } ? deploy descriptor文件的生成 EJB1.1規范規定了必須利用xml文件構造deploy descriptor文件,並給出了相應的DTD。本例的ejb-jar.XML文件如下:
images/green-cube.gif images/orange-cube.gif helloworld com.JSPer.ejbexample.session.helloworld.HelloHome com.JSPer.ejbexample.session.helloworld.Hello com.JSPer.ejbexample.session.helloworld.HelloBean Stateless Container BEAS Java.lang.Double 100.0 MSFT Java.lang.Double 150.0 helloworld Remote * Required 對於weblogic Server還必須構造一個名為weblogic-ejb-jar.XML的文件,BEA公司給出了相應的DTD.它描述了相應的EJB的名稱以及JNDI的名稱(**該部分與EJB Server有關,ejb開發人員可省去,而由DEPLOYER來完成**)
helloworld 100 hello.HelloHome ? 提供用於標示本EJB的大小圖標(icon),注意:圖像的格式必須是JPEG 或 GIF。 本例提供了圖像文件:orange-cube.gif和green-cube.gif(見附件) ? 構造.jar文件 第一步:編譯相應的.java文件 本例中包括:Hello.java,HelloBean.java,HelloHome.java ,位於包com.JSper.ejbexample.session.helloworld中。編譯後相應的.class文件放在相對目錄com\JSPer\ejbexample\session\helloworld 中。 第二步:創建與com的同級目錄META-INF,將相應的.xml文件拷貝到該目錄下;將相應的圖標文件拷貝到相對目錄(相對於該.xml文件父目錄)中(本例為與com的同級目錄images) 第三步:利用JAR命令將目錄com,images,META-INF中的內容做成.jar文件 本例JAR文件名成為std_hello.jar jar cv0f std_hello.jar META-INF com images 至此, 對於EJB Provider的工作已經完成。 但是由於我們的開發人員在開發ejb的時候需要進行本地調試等工作,因此其既充當ejb provider的角色,又充當其他的腳色, 因此,其可能需要作如下工作(僅供參考,接上述工作): ? 生成可deployable的jar文件 前邊生成的jar文件(若不含weblogic-ejb-jar.XML文件)是不依賴於ejb server(ejb container)的,而如前所述,不同的ejb server對於ejb的配置是不同的,因此需要加上特定的信息 對於weblogic server則是通過相應的ejbc命令或deploy utility在原.jar文件的基礎上生成新的可deployable的.jar文件。(關於ejbc的詳細使用請參見有關資料): java ?classpath e:\weblogic\classes;e:\weblogic\lib\weblogicaux.jar -Dweblogic.home=e:\weblogic weblogic.ejbc -compiler javac std_hello.jar ejb_helloworld.jar ? 設定weblogic的環境 將最終的jar文件(本例ejb_helloworld.jar)放在weblogic的某一子目錄下(例如:myserver),而後將.jar文件所在的路徑( e:/weblogic/myserver/ ejb_helloworld.jar)添加到weblogic.properties文件的入口weblogic.ejb.deploy中(weblogic.ejb.deploy=e:/weblogic/myserver/ejb_helloworld.jar) ? 啟動weblogic server, 在其啟動的控制台中可以見到相應的ejb的裝載成功的信息。 ? 客戶端調用 當EJB裝載成功後,就可以通過客戶端對其進行調用,以進行測試或運行 客戶端調用比較簡單,但與EJB Server有很大關系,主要體現在利用JNDI服務搜尋相應的EJBHome 接口對象上。 1. 編寫.java 文件 主要包括:利用相關屬性初始化運行的Context;搜尋EJBHome接口;利用EJBHome接口創建EJBObject接口對象;利用EJBObject接口對象調用有關的方法。 注意: 1) 遠程訪問ejb與本地訪問ejb有所不同,不同之處在於獲取Bean的InitialContext的方法。 遠程訪問ejb可以通過如下的getInitialContext()方法。 本地客戶(如servlet等)訪問只需簡單的利用InitialContext的卻省構造函數即可 Context ctx = new InitialContext(); 2)客戶端可以通過如下四個不同的協議之一同weblogic server 連接:T3,T3S. HTTP,HTTPS 但是卻省端口不同: T3,HTTP---7001;T3S,HTTPS----7002,而且最好使用T3協議(詳細情況請參見文檔weblogic\classdocs\API_clIEnt.Html) 3)必須導入EJB提供的客戶端接口(即接口EJBHome和EJBObject的擴展),如本例的 import com.JSper.ejbexample.session.helloworld.* import com.JSPer.ejbexample.session.helloworld.*; import java.rmi.*; import javax.rmi.*; import java.util.*; import javax.ejb.*; import javax.naming.*; public class HelloClient extends Object { public static void main(String[] args) { try { // Get an InitialContext String url="t3://localhost:7001"; Context ctx = getInitialContext(url,null,null); //look up EJBHome interface object HelloHome home = (HelloHome)ctx.lookup("hello.HelloHome"); //create the EJBObject interface object Hello hello = home.create(); //call the corresponding method in EJB System.out.println(hello.hello()); hello.remove(); } catch(Exception e) { e.printStackTrace(); } } /** * Using a PropertIEs object will work on JDK 1.1.x and Java2 * clIEnts */ static Context getInitialContext(String url, String user, String passWord ) throws NamingException { try { // Get an InitialContext Properties h = new PropertIE
ejb內部資參之一 ejb內部資參之二 ejb內部資參之三 ejb內部資參之四 ejb內部資參之五