我的EJB學習歷程

http://blog.csdn.net/sinapaper/archive/2004/06/28/28659.aspx

http://blog.csdn.net/sinapaper/archive/2004/06/29/29634.aspx

http://blog.csdn.net/sinapaper/archive/2004/06/30/30538.aspx

http://blog.csdn.net/sinapaper/archive/2004/07/01/31231.aspx

http://blog.csdn.net/sinapaper/archive/2004/07/05/34109.aspx

http://blog.csdn.net/sinapaper/archive/2004/07/05/34202.aspx

http://blog.csdn.net/sinapaper/archive/2004/07/14/41058.aspx

http://blog.csdn.net/sinapaper/archive/2004/07/15/42234.aspx

 

爲了力求新的進步,我覺得從今天起開始學習EJB編程。

希望各位志同道合的朋友能一起參加進來。

我選用的參考書是wroxEJB編程指南。這個書有1000多頁,爭取能全部完成他吧!

 

好了,不多說沒用的了。現在開始進入第一章的學習。

 

第一章    Enterprise Javabeans 體系機構。

開始將講了一大堆廢話,從單層體系結構講到了多層體系結構,又講到了N層體系結構。這樣引出了主題(J2EE)。不過這句話翻譯的不錯:其他需要特別注意的(是)服務器方資源包括線程,數據庫連接,安全、事務等等。定製處理這些資源的基礎結構是相當費勁的。這種工作在INTERNET環境中是不可能的。如果你的開發週期只有三個月,能夠對數據庫訪問建立連接池、對象緩衝區或“精彩的”對象層嗎?

暈!說了一大堆話終於引出了偉大的J2EE。不過要是不知道N層結構的真應該看看!

 

容器:說白了容器就是JAVA程序的運行環境。不知道我的理解是否正確。現在的程度就只能理解到這了。

 

書上說J2EE規範定義了四種容器類型:

1.       小應用程序(APPLET)。

2.       應用程序客戶容器。(自己以爲就是SWING

3.       WEB容器(SERVLET JSP

4.       EJB容器。

 

看來123都已經掌握了,現在就差4了,所以EJB容器還是要學習的哦!~

 

書上對EJB寫了個更加深入的解釋:EJB是個分佈式組件模型,可以開發安全的、可伸縮的、事務性的多用戶組件。簡單的說,EJB是包含業務邏輯的可複用軟件單元。就象JSP可以將應用程序與業務邏輯分開一樣,EJB可以將應用程序邏輯和系統層服務分開,使開發人員集中考慮業務問題,而不必考慮系統編程。

 

J2EE API

RMI/IIOPRemote Method Invocation類似網絡連接使用的一些東西。

JNDIJava Naming and Directory Interface

JDBC:這個不用說了吧?

JAVAMAIL/JAFJAVAMAIL服務,JAF是郵件的附件。

JMSJAVA MESSAGE SERVERJAVA消息服務。

 

設計中爲何使用EJB:說了一大堆,我還是不確定是爲什麼。再接着看吧!

 

不過這次我更加的確定了,原來EJB容器就相當於一個“功能“服務器,可以把一些業務功能寫在這個裏邊。然後用123來調用咯!(不知道這麼說是不是有點搞笑)。

 

哈哈,我的理解正確了,果然書的第8頁就說了,容器可以看成是執行環境!

 

EJB的容器服務:(這裏的容器服務都是不用編碼,而是容器管理自己實現的啊。不錯)

 

組件池和壽命週期管理:

哈哈,來點白話的,這是我個人理解的,組件池在容器啓動的時候就自己生成了好多的BEAN的實例,假如說是10個吧,這個時候客戶1來了,他就拿了BEAN1,這個時候別人是不能使用BEAN1的,再來了第2個客戶,他不能拿BEAN1了,就只能拿BEAN2了。。。。。。。這個時候客戶11來了,容器發現已經沒有BEAN給他用了,於是就找個現在沒人用的BEAN給他用,可是發現全都在被佔用,沒辦法了,就只好再生成一個給他用了。哈哈,就是這麼簡單,可是有人會問了,這不是越生成越多嗎?沒關係,容器發現生成的BEAN沒人用了,就會自動的給刪掉,釋放空間,釋放系統資源嘛!

 

客戶會話管理:

理解鈍化和激活就行了。

鈍化就是把客戶的BEAN狀態保存在池中。

激活就是把客戶的這個BEAN狀態再還給客戶。

 

數據庫連接池:

這個好象不用講了吧!數據資源共享!這個名起的COOL B了。

 

事務管理:

事務很是昂貴啊!

 

驗證和訪問控制:

這個很簡單!

 

 

容器如何提供服務:這一部分先不寫,以後再寫,因爲我也不怎麼理解。哈哈

 

EJB類型:*****這可是關鍵的地方。*****

分爲3種類型:

會話BEAN(壽命和所在客戶的會話一樣長啊)

1.       無狀態會話BEAN

2.       狀態會話BEAN

這兩個BEAN非常的重要,但是在第3章纔有講。哈哈,先擱這!

 

實體BEAN

自己理解就好象是數據庫BEAN,就是把數據庫的內容都讀出來放在BEAN裏,也不知道它具體是怎麼讀的,這樣做會不會很浪費系統資源!???

 

實體BEAN根據同步的不一樣又可以分爲:

CMP(容器管理的持久性):容器負責BEAN與基礎的數據庫同步。

BMPBEAN管理的持久性):這裏要編程人員負責和基礎數據庫同步!容器在適當的時候調用編程人員寫好的SQL語句!

 

真不明白,爲什麼已經有CMP了還要出了個BMP,書上是這麼解釋的:

有時需要增加設計的靈活性或在非關係型存儲中支持持久性??這是人話嗎?

還有個比方:EJB規範V1.1只允許實例變量和表格列之間的一對一映射。這樣,使用這個版本時,如果要在實體BEAN中表示在多個表格中存儲狀態的累計對象,則無法使用CMP,而要使用BMPEJB2.0規範定影了複雜的查詢語言!還是很費解!~~~~不過應該是有用吧!!以後估計就能搞明白!呵呵!~~

 

消息驅動BEAN。第6章講!等着吧!兄弟們~~~~

 

哈哈!看完第一章了。明天再看第2章!

 

 

先說點題外話, bromon說的真有點恐怖,不知道消息來源的真實性,如果真是那樣我想國內的人也不會馬上就全部跑去轉用EJB3吧。呵呵,不過還是要謝謝bromon 我的鐵杵我的針 ,我的第一篇文章終於有人看了,希望越來越多的人的加入!J

 

 

第一章    EJB開發

 

EJB的角色:(規定了6種開發和部署的角色)

l         企業BEAN提供者(Enterprise Bean Provider

工作任務如下:

1.編寫BEAN的主接口。

2.編寫BEAN的組件接口,聲明應用程序需要的各種業務方法。

3.編寫實現遠程接口中定義的各種業務方法的實現類。

4.編寫部署描述項。

5.打包。

 

其實就是編寫EJB的編程人員。至於什麼是主接口,什麼是組件接口,什麼是實現類以後再說吧!先死記吧!

 

l         應用程序彙編者:其實就是把BEAN提供者寫好的東西組織在一起的人了。沒什麼大用,還號稱是行業專家!(開玩笑了)

 

l         部署者

 

l         系統管理員

 

l         EJB服務提供者,容器提供者(書上是分兩條的,但是我認爲他們應該是一樣的東西,至少暫時是一樣的東西)

 

其實話說回來了,別的人都不怎麼重要,我們要做的人就是企業BEAN提供者。

 

開發第一個EJB

高興,終於有個HELLOWORLD了!

大家一定要記住BEAN提供者的那幾個要素啊!很關鍵的,全是從那幾個要素之間展開的。

 

HELLOWORD的題目是:根據年薪、公積金和所得稅計算每月的淨收入。(無狀態會話BEAN)。

EJB客戶視圖:

本地客戶:使用本地接口和本地主接口。按引用傳遞值。

遠程客戶:使用遠程接口和遠程主接口。按變量傳遞值。會有java.rmi.RemoteException錯誤。

標準的設計模式是,業務邏輯層的所有訪問使用會話BEAN,這些會話BEAN需要發表遠程接口,使客戶層可以訪問這些會話BEAN。其餘實體和無狀態會話BEAN可以看成“實施細節”,只發表本地接口。

 

這是書上原話,大家明白嗎?反正我就只能明白個80%。哈哈~~~再接着來。

 

開發主接口

倒!前邊講了一大堆主接口,現在纔想起來解釋,不知道老外這個書是怎麼寫的。

主接口負責控制BEAN的壽命週期操作:生成,刪除和尋找。主接口是客戶在BEAN中的第一個聯繫點。客戶通過JNDI取得引用。其實是在部署的時候確定JNDI的,不着急。

當客戶引用了主接口之後,就可以通過這個接口對BEAN進行下列操作:

l         生成新的實例或者尋找現有的BEAN實例。(本地或者遠程)

l         訪問EJBMetaData接口(遠程)。

l         取得BEAN實例的序列化引用(遠程)。

l         刪除BEAN實例。

l         執行主業務方法。

 

在這個例子中只使用主接口生成BEAN的新實例。

 

EJB裏定義了本地接口和遠程接口。(EJBHome EJBLocalHome)。這兩個接口的源程序書上有。

 

EJBHome接口中的方法:

getEJBMetaData():返回EJBMetaData接口的引用,取得BEAN信息。(還是不知道EJBMetaData是什麼東西。查字典是元數據的意思)。

getHomeHandle():返回主對象的句柄。

remove():很簡單,刪除了。哈哈,玩笑,其實對不同BEAN結果不一樣啦,會話BEAN是將BEAN再放回池中,而實體BEAN則是從數據庫中刪除數據。這次纔對嘛!

 

下邊就是程序了,我先試試程序到底是怎麼回事再給大家講啊!

 

通過本人對書本上示例程序的分析,自我感覺書上的示例程序實在是沒有說服力,主要是部署工具出奇的麻煩,在這個JAVA不花錢的年代,怎麼能用J2EE自帶的部署工具,一大堆的配置實在是另人煩躁!呵呵。

說了一大堆,開始進入關鍵議題了,各位聽好了。

 

我選用的是ECLIPSE,這個免費的東西實在做的不錯,在我但是做STRUTS的時候就發現他的好多優點,但是實在遺憾,本人沒有用過JBUILDER,也不知道他們是不是一樣。

 

ECLIPSE有個LOMBOZ的插件,這個插件裏邊包含有所有服務器的配置方案。可以配置WEB MODEL,和EJB MODEL,這裏邊我選用JBOSS服務器吧,因爲聽說他也是不要錢的。

 

至於ECLIPSE下JBOSS是怎麼培植,這非常簡單,只要上GOOGLE上搜索‘ECLIPSE部署‘就有好多,聯想公司姜巍巍先生就寫了一篇配置,但是大家不要看他的EJB部署,實在是垃圾。按照他說的要想讓初學者學會第一個EJB是有難度的!

大家還是來看我的HELLOWORLD吧!

 

摘自http://www.objectlearn.com/support/docs/firstEJB.jsp

 

其實我只是幫大家翻譯一下,呵呵。看原文可以上上邊這個網址。

 

好了,不多說廢話了。現在開始。對了,一定要保證你的LOMBOZ和ECLIPSE都已經配置好了啊。

 

1.     新建一個Lomboz J2EE Project,叫"MyFirstEJBProject"。其他的地方都不要改,NEXT。

2.     然後就能進入這個界面:

 

       

 

看見了吧,在這個的EJB MODULES中加一個新的MODULES,叫mybeans

              然後再選擇TARGET SERVER選項。就是這。

 

 

 

 

 

    選擇我們剛纔說的已經配置好的JBOSS

 

 

 

3.     好了,現在如果不報錯的話。就點FINISH吧!

4.     第一個EJB模塊已經完成,它可以給你生成EJB和EJB HOME,但是開發的實現類需要自己寫!下邊就是怎麼寫一個實現類。

5.     

 

     

 

這副圖能明白吧,可是有人要問了,這個東西哪兒來的?主界面,WINDOW菜單下的PERFERNECE,點他!哈哈,把裏邊有LOMBOZ的全選上就有了。

 

6.OK拉,按照下邊的圖把名字輸上:

 

 

 

 

這個時候FINISH就會生成一個TestSessionBean.java。這個就是生成的實現類了。

 

7.然後就是給這個實現類填加一些方法了。怎麼填呢?別改源代碼,行不通,要這麼做:

 

 

 

然後,

 

 

 

這樣就可以加入方法了,千萬別手動加代碼啊,這樣會讓你組件接口找不到你寫的方法!

然後把這個實現類的方法改成:

public String helloWorld(){

 return "Hello from lomboz!";

}//這個都知道是什麼意思吧

到現在爲止就算我們已經做出來一個EJB程序了,只不過是缺少主接口,組件接口的一些東西,但是不要怕,ECLIPSE會給你自動生成的。厲害吧?接下來我們就需要做這麼幾步:

a)     把剛纔寫的這個EJBBEAN加入到EJB中.

b)   生成主接口,組件接口.

c)      把他部署到服務器上.

d)     寫一個客戶程序來實驗他.

EASY吧!真的很EASY啊!

8.這是a)那一步,把他加入到EJB中。就是剛纔我們在EJB MODULES中建立的那個EJB。

 

 

9.各位觀衆,現在大家以最快的速度把這個界面找到。

 

 

然後做這個操作:

 

 

這個操作就是完成任務b)的任務。

 

10.OK了,現在開始做c)了,就是把剛纔寫好的EJB部署到服務器上,按照下邊兩個圖來做。

 

 

 

 

找控制檯,看看你的部署成功不成功,要是成功的話。就可以做d)了。不成功的話,再來一遍!要是還不成功的話。找我吧。

 

11.現在我們就要寫一個客戶程序來實驗他了,真是興奮啊!

先重新建立一個JAVA項目,這樣才能顯示出EJB的功能嘛。

 

 

新建立的項目叫這個名MyEjbClientProject,其實隨便叫什麼名了。

NEXT進下一頁的時候一個要在PROJECT裏邊把我們剛纔做的MyEJBClientProject給加上啊!否則白做了。

 

然後在NEW 菜單下找這個ITEMCREATE AN EJB TEST CLIENT。點上。

 

12.這麼配置。這個其實根本都不用說。

 

 

FINISH之後就能看見這個類:TestClient.java

修改這個方法

public void testBean() {

            try {

                  com.testing.session.TestSession

                        myBean = getHome().create();

                  //--------------------------------------

                  //This is the place you make your calls.

                  System.out.println(myBean.helloWorld());

            } catch (RemoteException e) {

                  e.printStackTrace();

            } catch (CreateException e) {

                  e.printStackTrace();

            } catch (NamingException e) {

                  e.printStackTrace();

            }

      }

OKSAVE然後運行!!!!成功!!!

 

 

 

 

 

OK,一個最簡單的EJB完成。終於可以進入到第三章了啊!

 

前邊的程序好用吧,我覺得比書上寫的麻煩的程序強多了,所以還是得用工具的。

終於有了點EJB方面的成就,趁熱打鐵,現在馬上就看第三章。

 

第一章           開發會話BEAN

大家都知道了,會話BEAN又分爲狀態會話BEAN和無狀態會話BEAN

書上總結了他們的共同點是:

1.      兩者都可實現javax.ejb.SessionBean接口,因此具有相同的容器回調。容器回調?現在中國的翻譯啊!

2.      兩者都表示生成BEAN的客戶的專用資源。

3.      兩者都可以構造一個進程或一個任務模型

4.      兩者都可以更新共享數據,但不象實體BEAN中一樣表示共享數據。

NND,說了這麼多的共同點,說實話,我一點都不知道他說的是什麼意思?爲什麼要這麼專業??:(

 

不過不同點但是很清楚:

狀態會話BEAN可以在客戶訪問之間保存數據,而無狀態則不可以!

 

管他呢,從例子上找切入點。

 

無狀態會話BEAN的一個簡單例子是計算數字,數字可以任意複雜,但是隻在客戶程序中存放。哦!是這樣啊,其實就相當沒有SESSION拉,但是好象還不能這麼說,姑且先這麼理解。

 

好拉,這次我決定採用書上的例子,書上的例子相當於一個BANK的系統!誇張,其實就是加減數字的BEAN

 

這樣,我們還是用(三)裏邊講的方法來部署他:

記得是一個無狀態會話BEAN的例子啊。

新建一個實現類,我的是這麼寫的:

 

 

 

package com.testing.fund;

 

import javax.ejb.SessionBean;

 

/**

 * @ejb.bean name="FundManger"

 *  jndi-name="FundMangerBean"

 *  type="Stateless"

 *

 *--

 * This is needed for JOnAS.

 * If you are not using JOnAS you can safely remove the tags below.

 * @jonas.bean ejb-name="FundManger"

 *  jndi-name="FundMangerBean"

 *

 *--

 **/

 

public abstract class FundMangerBean implements SessionBean {

 

/**

 * @ejb.interface-method

 *  view-type="remote"

**/

public double add(double b,double a){

    b=b+a;

 return b;

}

/**

 * @ejb.interface-method

 *  view-type="remote"

**/

public double withdraw(double b,double a){

    b=b-a;

 return b;

}

}

 

 

要記得這裏邊的ADD和WITHDRAW方法不是手動加上的啊,是用WIZARD的啊。要是不會的話,看我的(三)去!!!!

 

然後按照(三)裏邊的方法部署到JBOSS上邊去!

 

一切成功的話,還是按照(三)的方法寫一個實現類!我的是這樣寫的,和書上有點不一樣,不過實現方法是完全一樣的!

 

 

 

package com.testing.client;

 

import java.rmi.RemoteException;

import java.util.Hashtable;

 

import javax.ejb.CreateException;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.text.*;

import com.testing.fund.FundManger;

 

public class FundTest extends JFrame implements ActionListener{

   

    public FundTest(){

       super("fund manger");

    }

 

    private com.testing.fund.FundMangerHome getHome() throws NamingException {

       return (com.testing.fund.FundMangerHome) getContext().lookup(

           com.testing.fund.FundMangerHome.JNDI_NAME);

    }

   

    private InitialContext getContext() throws NamingException {

       Hashtable props = new Hashtable();

 

       props.put(

           InitialContext.INITIAL_CONTEXT_FACTORY,

           "org.jnp.interfaces.NamingContextFactory");

       props.put(InitialContext.PROVIDER_URL, "jnp://127.0.0.1:1099");

 

       // This establishes the security for authorization/authentication

       // props.put(InitialContext.SECURITY_PRINCIPAL,"username");

       // props.put(InitialContext.SECURITY_CREDENTIALS,"password");

 

       InitialContext initialContext = new InitialContext(props);

       return initialContext;

    }

   

   

    public void testBean() {

      

       buildGUI();

      

       addWindowListener(new WindowAdapter(){public void WindowClosing(WindowEvent evt){System.exit(0);}});

       CreateFund();

       addFund.addActionListener(this);

       withdraw.addActionListener(this);

       currencyFomat=NumberFormat.getCurrencyInstance();

       String currency=currencyFomat.format(0);

       status.setText(msg+currency);

      

       pack();

       show();

    }

   

    public void actionPerformed(ActionEvent e){

       String str=amout.getText();

      

       try{

           if(e.getSource()==addFund){

              balance=(double)myBean.add(balance,Double.parseDouble(str));

              currencyFomat=NumberFormat.getCurrencyInstance();

              strBar=currencyFomat.format(balance);

              status.setText(msg+strBar);

           }

           if(e.getSource()==withdraw){

              balance=(double)myBean.withdraw(balance,Double.parseDouble(str));

              currencyFomat=NumberFormat.getCurrencyInstance();

              strBar=currencyFomat.format(balance);

              status.setText(msg+strBar);

           }         

          

       }catch(Exception ex){}

    }

 

 

 

    public void CreateFund(){

      

 

       try {

            myBean = getHome().create();

 

           //--------------------------------------

           //This is the place you make your calls.

           //System.out.println(myBean.callYourMethod());

 

       } catch (RemoteException e) {

           e.printStackTrace();

       } catch (CreateException e) {

           e.printStackTrace();

       } catch (NamingException e) {

           e.printStackTrace();

       }

    }

 

    public static void main(String[] args) {

       FundTest test = new FundTest();

       test.testBean();

 

    }

   

    public void buildGUI(){

       GridBagLayout gl=new GridBagLayout();

       GridBagConstraints gc=new GridBagConstraints();

       Container container=getContentPane();

       container.setLayout(gl);

      

       gc.fill=GridBagConstraints.BOTH;

       JLabel label=new JLabel("enter amout");

       gl.setConstraints(label,gc);

       container.add(label);

      

       gc.gridwidth=GridBagConstraints.REMAINDER;

       gl.setConstraints(amout,gc);

       container.add(amout);

      

       gl.addLayoutComponent(addFund,gc);

       container.add(addFund);

       gl.addLayoutComponent(withdraw,gc);

       container.add(withdraw);

      

       status=new JLabel(msg);

       gl.addLayoutComponent(status,gc);

       container.add(status);     

      

       

      

      

      

      

    }

   

 

   

    double balance=100;

    JTextField amout=new JTextField(10);

    JButton addFund=new JButton("add funds");

    JButton withdraw=new JButton("withdraw funds");

    String msg="current funds is:";

   

    String strBar="0";

   

    JLabel status;

   

    FundManger myBean;

   

    NumberFormat currencyFomat;

   

}

 

運行爲JAVA 應用程序!成功了!界面如下:

 

現在來想想爲什麼是無狀態會話BEAN了,其實這個EJB就相當於一個簡單的應用程序後臺數據處理器!你的所有數據記錄信息全部都在前臺了,也就是上邊這個界面上邊。

 

OK,下節課就是狀態會話BEAN了。

 

哈哈,過了一個輕鬆的週末,又要開始寫東西咯。

週末本來也想寫,可是還是覺得玩有意思,姑且放幾天假。

 

上次講的是無狀態會話BEAN

好象還是有點不明白爲什麼要分無狀態和狀態會話BEAN這兩種BEAN,不過不要緊,看完狀態會話BEAN的程序就能明白了。對了,還有一點要說的。我週五那天搞了一天的ECLIPSE3,聽說他出新版本了,所以趕緊下載試驗試驗,他在裏邊新加了功能叫EJB EDITOR,這個東西不錯,有好多新東西。可是唯一另我費解的是爲什麼用他CREATE CLIENT TEST PROGRAMM的時候卻總是報錯!所以還是比較的煩躁的!也不知道是ECLIPSE的毛病還是我機器自己運行環境的毛病,大家也試試然後告訴我啊!

 

我的這個狀態會話BEAN還是用ECLIPSE2.1寫的拉。

我先把程序寫給大家,然後再分析吧,我好象是那種喜歡先看程序然後再看理論的人。不知道是不是有人和我一樣。

 

這是客戶端的實現程序:

package com.test.session;

 

import javax.ejb.*;

 

/**

 * @ejb.bean name="Stateful"

 *  jndi-name="StatefulBean"

 *  type="Stateful"

 *

 *--

 * This is needed for JOnAS.

 * If you are not using JOnAS you can safely remove the tags below.

 * @jonas.bean ejb-name="Stateful"

 *  jndi-name="StatefulBean"

 *

 *--

 **/

 

public abstract class StatefulBean implements SessionBean {

 

/**

 * @ejb.create-method

 *  view-type="remote"

**/

public void ejbCreate(double amout) throws CreateException{

    this.amout=amout;

}

/**

 * @ejb.interface-method

 *  view-type="remote"

**/

public void addFunds(double amout){

    this.amout+=amout;

}

/**

 * @ejb.interface-method

 *  view-type="remote"

**/

public void withdrawFunds(double amout){

    this.amout-=amout;

}

/**

 * @ejb.interface-method

 *  view-type="remote"

**/

public double getBalance(){

 return this.amout;

}

 

double amout;

 

}

 

對了,ejbCreate(double amout)方法是在BEAN生成過程中,容器調用ejbCreate(double amout)方法的。

就好象是初始化的方法一樣。

還有你一定要確保在主接口中有個Create(double amout)方法和ejbCreate(double amout)對應啊!這段是必須的,如果不明白的話,趕緊找資料。你這個ejbCreate(double amout)方法在新建的時候要選擇CREATE哦!

 

在把客戶端的測試程序給你們:

package com.testing.client;

 

import java.rmi.RemoteException;

import java.util.Hashtable;

 

import javax.ejb.CreateException;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import javax.swing.JFrame;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.text.*;

 

import com.test.session.*;

 

/**

 * @author sy

 *

 * 更改所生成類型註釋的模板爲

 * 窗口 > 首選項 > Java > 代碼生成 > 代碼和註釋

 */

public class testStateful extends JFrame  implements ActionListener{

   

    public testStateful(){

        super("fund manger");

    }

 

    private com.test.session.StatefulHome getHome() throws NamingException {

        return (com.test.session.StatefulHome) getContext().lookup(

            com.test.session.StatefulHome.JNDI_NAME);

    }

    private InitialContext getContext() throws NamingException {

        Hashtable props = new Hashtable();

 

        props.put(

            InitialContext.INITIAL_CONTEXT_FACTORY,

            "org.jnp.interfaces.NamingContextFactory");

        props.put(InitialContext.PROVIDER_URL, "jnp://127.0.0.1:1099");

 

        // This establishes the security for authorization/authentication

        // props.put(InitialContext.SECURITY_PRINCIPAL,"username");

        // props.put(InitialContext.SECURITY_CREDENTIALS,"password");

 

        InitialContext initialContext = new InitialContext(props);

        return initialContext;

    }

    public void CreateFund() {

 

        try {

            myBean = getHome().create(1000);

 

            //--------------------------------------

            //This is the place you make your calls.

            //System.out.println(myBean.callYourMethod());

 

        } catch (RemoteException e) {

            e.printStackTrace();

        } catch (CreateException e) {

            e.printStackTrace();

        } catch (NamingException e) {

            e.printStackTrace();

        }

    }

   

    public void testBean() {

       

            buildGUI();

       

            addWindowListener(new WindowAdapter(){public void WindowClosing(WindowEvent evt){System.exit(0);}});

            CreateFund();

            addFund.addActionListener(this);

            withdraw.addActionListener(this);

            currencyFomat=NumberFormat.getCurrencyInstance();

            try{

            String currency=currencyFomat.format(myBean.getBalance());

            status.setText(msg+currency);

           

            }catch(Exception e){}

       

            pack();

            show();

        }

   

        public void actionPerformed(ActionEvent e){

            String str=amout.getText();

       

            try{

                if(e.getSource()==addFund){

                    myBean.addFunds(Double.parseDouble(str));

                    currencyFomat=NumberFormat.getCurrencyInstance();

                    strBar=currencyFomat.format(myBean.getBalance());

                    status.setText(msg+strBar);

                }

                if(e.getSource()==withdraw){

                    myBean.withdrawFunds(Double.parseDouble(str));

                    currencyFomat=NumberFormat.getCurrencyInstance();

                    strBar=currencyFomat.format(myBean.getBalance());

                    status.setText(msg+strBar);

                }          

           

            }catch(Exception ex){}

        }

       

    public void buildGUI(){

            GridBagLayout gl=new GridBagLayout();

            GridBagConstraints gc=new GridBagConstraints();

            Container container=getContentPane();

            container.setLayout(gl);

       

            gc.fill=GridBagConstraints.BOTH;

            JLabel label=new JLabel("enter amout");

            gl.setConstraints(label,gc);

            container.add(label);

       

            gc.gridwidth=GridBagConstraints.REMAINDER;

            gl.setConstraints(amout,gc);

            container.add(amout);

       

            gl.addLayoutComponent(addFund,gc);

            container.add(addFund);

            gl.addLayoutComponent(withdraw,gc);

            container.add(withdraw);

       

            status=new JLabel(msg);

            gl.addLayoutComponent(status,gc);

            container.add(status);     

       

       

       

       

       

       

        }

   

 

   

        double balance=100;

        JTextField amout=new JTextField(10);

        JButton addFund=new JButton("add funds");

        JButton withdraw=new JButton("withdraw funds");

        String msg="current funds is:";

   

        String strBar="0";

   

        JLabel status;

   

    Stateful myBean;

   

        NumberFormat currencyFomat;

 

    public static void main(String[] args) {

        testStateful test = new testStateful();

        test.testBean();

 

    }

}

 

看出來門道了嗎?我終於知道爲什麼這個要叫做:狀態會話BEAN了。因爲,因爲。。。。。哈哈,他有個amout變量,這個完全是EJB內部的變量,在EJB容器中保存!而和那個無狀態會話BEAN不一樣的地方就是,無狀態會話BEAN是在客戶端保存數據。很大的區別!這就是問題的關鍵!也不知道你們看懂了沒有!反正我覺得真的很明顯。

 

下邊這個是我在IBM文章庫裏找的一副圖,感覺不錯,完全講明白了狀態BEAN是怎麼回事拉:

 

這些是些講解,和書上的差不多,省得我打字了。

有狀態會話 Bean 生命週期:

  • Bean 在下列情況下被回收:

    • 超時 (無論是激活的或鈍化的)

    • 被調用 remove()

  • Passivation 是根據 Least-Recently-Used 算法

  • Activation 由對 Bean 的方法調用產生

  • afterBegin()
    beforeCompletion()
    afterCompletion()
    方法僅對實現 SessionSynchronization 接口的 Bean 有效

  • 在一個事務環境下,調用的方法必需具有相同的事務類型

OK,狀態會話BEAN就是這麼回事。應該是很簡單的東西,完全可以理解。

 

 

 

呵呵,大家看見了那個總回我帖子的QUGHOST了嗎?他是我的好朋友。

他有好多的搞笑故事,我和他商量了一下,準備把他的搞笑經歷發在我的一個新版塊裏,可是不知道他同意不同意。

 

OK,話歸正傳。我馬上就要把第三章結束了,其實第三章的會話BEAN5就已經講完了,可是這裏邊還有一個很關鍵的東西,那就是序列化。

 

序列化 (Serialization)

  • Java 序列化機制可以將整個對象的狀態輸出到一個流上

  • 對象可以再從其原始狀態重新構建回來

其實很簡單了,就是把某個對象的所有東西都輸出到一個文件上。這裏也可以是別的東西。好多。

然後當你還想用他的時候,就再在這個文件上把這個對象的狀態等等的一些信息全部找回來。

 

真正發生了什麼

  • Bean 的實例沒有被序列化
    如果 Bean 實例本身被序列化,當它被重新構建時一個新的實例需要被創建這就丟失了實例池的意義

  • Bean 的狀態被序列化
    每個屬性需要被單獨考慮

什麼會被序列化?

  • 一個可序列化 (serializable) 的對象

  • 一個 null

  • 對特定不可序列化對象的直接引用:

    • 一個 Bean home remote 接口的引用

    • SessionContext 的引用

  • 對不可序列化部分的直接引用的序列化

    • 容器必需對不可序列化的 EJB 在鈍化時保存它們的 remote home 接口

    • 也許依賴於 Java java.io.ObjectOutputStream java.io.ObjectInputStream 中的對象替換技術來實現

部分序列化

  • 構成狀態的每樣屬性必需是可序列化的

  • 所有屬性的內容必需包含可序列化的值

  • Helper

  • 否則容器可以選擇在鈍化時回收該 Bean 實例

 

這些全是我從IBM抄下來的。希望對大家理解序列化有幫助。

 

把我的程序也給你們吧,我用的還是那個狀態會話BEAN的那個EJB

 

/*

 * 創建日期 2004-7-5

 *

 * 更改所生成文件模板爲

 * 窗口 > 首選項 > Java > 代碼生成 > 代碼和註釋

 */

package com.testing.client;

 

import java.rmi.RemoteException;

import java.util.Hashtable;

 

import javax.ejb.CreateException;

import javax.naming.InitialContext;

import javax.naming.NamingException;

import com.test.session.*;

 

import java.io.*;

import javax.ejb.Handle;

 

 

/**

 * @author sy

 *

 * 更改所生成類型註釋的模板爲

 * 窗口 > 首選項 > Java > 代碼生成 > 代碼和註釋

 */

public class HandleTest {

 

    private com.test.session.StatefulHome getHome() throws NamingException {

        return (com.test.session.StatefulHome) getContext().lookup(

            com.test.session.StatefulHome.JNDI_NAME);

    }

    private InitialContext getContext() throws NamingException {

        Hashtable props = new Hashtable();

 

        props.put(

            InitialContext.INITIAL_CONTEXT_FACTORY,

            "org.jnp.interfaces.NamingContextFactory");

        props.put(InitialContext.PROVIDER_URL, "jnp://127.0.0.1:1099");

 

        // This establishes the security for authorization/authentication

        // props.put(InitialContext.SECURITY_PRINCIPAL,"username");

        // props.put(InitialContext.SECURITY_CREDENTIALS,"password");

 

        InitialContext initialContext = new InitialContext(props);

        return initialContext;

    }

    public void testBean() {

 

        try {

            com.test.session.Stateful myBean = getHome().create(1000);

           

            //System.out.println("adding 1000");

           

            myBean.addFunds(1000);

           

            System.out.println("adding 1000");

           

            System.out.println("Now Account is:"+myBean.getBalance());

           

            myBean.withdrawFunds(100);

           

            System.out.println("withdrawing 100");

           

            System.out.println("Now Account is:"+myBean.getBalance());

           

            System.out.println("saving Handle");

           

            saveHandle(myBean);

           

            System.out.println("saving success");

           

            myBean=null;

           

            System.out.println("loading Handle");

           

            myBean=loadHandle();

           

            System.out.println("loading success");

           

           

           

            System.out.println("Now Account is:"+myBean.getBalance()+",withdrawing 100");

           

            myBean.withdrawFunds(100);

           

            System.out.println("Now Account is:"+myBean.getBalance());

           

 

            //--------------------------------------

            //This is the place you make your calls.

            //System.out.println(myBean.callYourMethod());

 

        } catch (RemoteException e) {

            e.printStackTrace();

        } catch (CreateException e) {

            e.printStackTrace();

        } catch (NamingException e) {

            e.printStackTrace();

        }

    }

 

    public static void main(String[] args) {

        HandleTest test = new HandleTest();

        test.testBean();

 

    }

   

    private static void saveHandle(Stateful mybean){

        try{

            FileOutputStream fos=new FileOutputStream("symic");

            ObjectOutputStream out=new  ObjectOutputStream(fos);

           

            out.writeObject(mybean.getHandle());

           

            out.close();

        }catch(Exception e){}

    }

   

    private static Stateful loadHandle(){

        try{

            FileInputStream fis =new FileInputStream("symic");

            ObjectInputStream in =new ObjectInputStream(fis);

           

            Handle handle=(Handle)in.readObject();

           

            Stateful mybean=(Stateful)handle.getEJBObject();

           

            in.close();

           

            return mybean;

        }catch(Exception x){}

        return null;

    }

}

 

其實很簡單,看我的程序就好,然後找找SYMIC文件,看看他裏邊寫了些什麼東西。哈哈~~~~

 

說點別的,我最近發現原來ITLAY真的是個不錯的國家。可是好象在中國根本就沒有機會去吧!

ITaly ,SHopper's DEstinatiON!

 

在他那買東西很合適啊!聽說PRADA,AMANI在那有很多TAX REBATE的店啊,只有國內的一半價錢,而且東西全是最TOP 的CLASS。

 

真想去啊~~~~~~~~~~

 

ITALY MY DREAM-PRADISE!

 

呵呵!~~~

 

終於可以又出新東西了。上個禮拜一直沒忙,公司帶我們出去HAPPY了。不過現在水好涼,不能下水。纔下去兩分鐘瞬間就被凍上來了。特別的冷。

 

恩,言歸正傳。我一直在看CMP,實體BEAN,可是發現要弄好ENTITYBEAN首先要做的是知道怎麼配置服務器,我找到了一篇配置JBOSS服務器的指南,覺得不錯,就在這給大家SHARE一下。

http://www.uml.org.cn/j2ee/j2ee121505.htm

JBoss3.07的配置

    這裏需要對JBoss進行配置的地方有兩處,一處爲JBoss的日誌信息選項,使得我們今後在部署EJB時能夠得到關於部署的詳細信息;另一處爲JBoss中的數據源,使得我們可以使用容器持久化管理的EntityBean對數據庫中的數據進行操作。

    (1)首先我們講述日誌信息選項的更改,進入JBoss所在目錄下的server/default/conf目錄,找到文件log4j.xml,將其用文本編輯器打開,將屬性作如下修改:

修改一:

 

  < category name="org.jboss" >

    < priority value="INFO" / >

  < / category >

 

修改爲:

 

  < category name="org.jboss" >

    < priority value="INFO" / >

  < / category>

修改二:

 

 

  < appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender" >

    < param name="Threshold" value="INFO" / >

    < param name="Target" value="System.out" / >

修改爲:

  < appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">

    < param name="Threshold" value="DEBUG"/>

    < param name="Target" value="System.out"/>

將這些屬性進行修改之後,當我們部署CMP EntityBean的時候將能看見JBoss針對所部署的CMP EntityBean自動產生的SQL插入語句與CMP EntityBean中包含的EJB-QL語句;並且在EntityBean被使用時發生的SQL查詢語句。

(2)接着我們講述數據源的配置,第一步:我們進入JBoss的文件夾下的docs/examples/jca目錄,用文本編輯器打開mysql-service.xml,將其中的部分內容作如下修改:

< attribute name="JndiName">MySqlDS(數據源名稱)< / attribute>

< attribute name="ManagedConnectionFactoryProperties">

< properties>

< config-property name="ConnectionURL" type="java.lang.String" >jdbc:mysql://localhost:3306/resultmanager

 

(數據庫URL)

       

< / config-property>

< config-property name="DriverClass" type="java.lang.String" >com.mysql.jdbc.Driver

(數據庫驅動程序)

< / config-property>

< config-property

name="UserName" type="java.lang.String">DataBase

(數據庫用戶)

< / config-property>

< config-property

name="Password" type="java.lang.String" >

sailing

(數據庫用戶密碼)

< / config-property>

< / properties>

< /attribute>

 

將修改好的內容保存後,複製mysql-service.xml文件至JBoss文件夾下server/default/deploy 目錄,此時deploy目錄中的文件如下圖所示:

第二步,我們將含有MySQL JDBC 2.0.14驅動程序的jar文件複製到JBoss安裝目錄的server/default/lib目錄下,此時lib目錄中的文件如下圖所示:

現在我們已經完成了前期的配置工作,接下來我們將講述CMP EntityBean的開發。

大家先按照以上的方法把JBOSS配置好,然後做好準備,我們要開始CMP了,是數據庫的東西啊!!!

 

這個禮拜發生了好多事情啊。所以一直沒有時間寫。不過好多人問我怎麼不寫了啊?我是要寫的,現在就開始寫。(五)裏邊有個弟兄問我的IBM的網站在哪兒,我的收藏夾被DEL了,在GOOGLE上找了好久也沒找到,等我找到了,再發上去!

 

不過我以後會把我所有引用網址都給打上去。

 

好了,現在進入我的第4章咯。

開發EJB1.1實體BEAN,好象關於EJB實體BEAN還要分版本的,不過現在我也不清楚爲什麼分版本。

由於數據庫BEAN這個地方的部署我也沒有搞清楚,所以我找了LOMBOZ上邊有個示例程序,咱們先把這個實驗好了,然後再照書做,OK?

 

摘自:http://www.objectlearn.com/support/docs/cmp.jsp

 

1-9步和我以前寫的一樣,是如何建立J2EE項目的,這在我以前的我文章裏有寫。

從第10步開始寫吧:

現在選中CMP這一項。 然後打上你自己中意的名字和包名,做NEXT。

然後就會進入到CMP這個界面了:其實這個界面一看就知道是怎麼回事:

 

寫上表名,加上字段,一切簡單的OK了。記得啊,這裏DATASOURCE一定要和表裏邊的字段一樣。

還有對應的數據類型。可以加好多的字段,但是這個例子裏邊就給了兩個字段,我們也姑且用他這兩個字段。

對對了,還有就是設置一個PRIMARY KEY。搞定。FINISH。

 

這個時候ECLIPSE會自己就把你剛纔建立的AddressBean給打開。

然後你照着這個例子改代碼,其實不講爲什麼這麼改大家也都能明白:

package com.testing.cmp;

import javax.ejb.EntityBean;

/**
* @ejb.bean name="Address"
* jndi-name="AddressBean"
* type="CMP"
* primkey-field="name"
* schema="addressSchema"
* cmp-version="2.x"
*
* @ejb.persistence
* table-name="address"
*
* @ejb.finder
* query="SELECT OBJECT(a) FROM addressSchema as a"
* signature="java.util.Collection findAll()"
*
**/

public abstract class AddressBean implements EntityBean {

...

 

Modify the ejbCreate and ejbPostcreate methods to accepts two parameters:

/**
* The ejbCreate method.
*
* @ejb.create-method
*/

public java.lang.String ejbCreate(String name, String phone)
     throws javax.ejb.CreateException {
        setName(name);
        setPhone(phone);
        return null;
}

/**
* The container invokes this method immediately after it calls ejbCreate.
*
*/

public void ejbPostCreate(String name, String phone) throws javax.ejb.CreateException {
}

必須改POST和CREATE方法的內容啊。等下再告訴你們爲什麼要這樣做,對了,他裏邊還都幫你寫好了

setName();

setPhone();方法。直接用就好了。

 

然後SAVE,把剛纔寫的BEAN加到EJB裏邊,就是用J2EE->Add Ejb to Modules ,然後選擇你剛纔建立的EJB就好了。

 

下邊是最討厭的東西了,就是寫個EJBDOCLET,示例給的是要改ejbGenerate.xmlNND,我根本就沒有這個文件,後來查了好多的資料,才知道,原來他那個是舊版本,鬱悶~~~~~~舊版本還要往上貼。

 

我們3.X要改的是xdoclet.xml這個文件,這個文件保證有,大家找到之後就能看見,他裏邊有好多種配置服務器的數據庫的XML,我用的是JBOSS,所以就改這塊了。

< jboss

            version="3.0"

            unauthenticatedPrincipal="nobody"

            xmlencoding="UTF-8"

            destdir="${ejb.dd.dir}"

            validatexml="false"

            datasource="java:/MySqlDS"

            datasourcemapping="mySQL"

            preferredrelationmapping="PLEASE_MODIFY_THIS"

/ >

 

對了對了,說到這我找到了文章也不錯,是個小J寫的。給你們地址:
http://nemuneko.com/jboss/lomboz_cmp.html

因爲我最近在學日語,所以能看明白點,看不明白的就看圖理解咯~~~~~

 

注意啊,這裏是最關鍵的地方,我覺得,可能是因爲我比較的笨。呵呵。

 

這裏的MySqlDS是我在(7)裏邊寫的在JBOSS裏邊配置的DEFUALT DATASOUCE,對了,我按照7裏邊寫的把mysql-service.xml這個配置文件放的位置好象不可以,我查了好久才找到,原來是你的EJB部署到哪個文件夾下,這個mysql-service.xml文件就要跟着放到那個文件夾下,我機器上的是:D:/jboss-3.0.8/server/default/deploy

這個文件夾。最後就是把你的DB DRIVER放在和這個文件夾對應的LIB裏邊。

我機器上是這個:

D:/jboss-3.0.8/server/default/lib

 

我用的是Mysql 的driver,沒有問題的。

 

這樣配置就應該是沒問題了。

對了,把建表的語句也給你們:create table address ( name varchar(40) , phone varchar(40));

 

然後SAVE你的XDOCLET.XML。做GENERATE EJB FILES,和DEPLOY。

假如你成功的話,就能看見這麼一段的輸出:

 

22:50:11,031 INFO [MainDeployer] Starting deployment of package: mybeans.jar
22:50:11,302 INFO [EjbModule] Creating
22:50:11,342 INFO [EjbModule] Deploying Address
22:50:11,392 INFO [EjbModule] Created
22:50:11,392 INFO [EjbModule] Starting
22:50:11,822 INFO [Address] Table 'ADDRESS' already exists
22:50:11,842 INFO [EjbModule] Started
22:50:11,842 INFO [MainDeployer] Deployed package: mybeans.jar

 

一定要看輸出啊!很關鍵的地方。

 

這樣就完成了我們的EJB CMP的BEAN了。再寫個CLIENT測試他就OK了。

 

把我的CLIENT程序給你們。

 

public void testBean() {

            try {
                Address address = getHome().create("John Smith", "+212 223 4455");
                Collection all = getHome().findAll();
                Iterator it = all.iterator();
                while (it.hasNext()) {
                    Address element = (Address) it.next();
                    System.out.println("Name:" +
                        element.getName() + " Phone: " +element.getPhone() );
                 }

            } catch (Exception e) {

                  e.printStackTrace();

            }

      }

IMPORT自己記得加啊~哈哈。

運行,成功!!!!!!

 

下次又的寫些理論上的東西,說實話,我最討厭理論的東西,因爲看上去真的很頭大!~~

 

 

 

http://nemuneko.com/jboss/lomboz_cmp.html

 

下邊這段文字是在CN-JAVA下COPY過來的。(http://www.cn-java.com/target/news.php?news_id=2174)

一、entity Bean 代表了以持久存儲機制保存的一個實體,通常爲一個DB。客戶機通過entity beanremote接口訪問它,實現該remote接口的對象被稱爲EJB對象。每一個
entity
對象都有一個標識符。
Entity Bean
的特徵:持久的(分爲BMPCMP),允許共享訪問,並且有一個主鍵。
二、編寫規則:
 
 1.(1)實現EntityBean的接口。
  (2).類定義爲PUBLIC
  (3).類不能定義爲abstract final
  (4).實現finaler方法(僅用於BMP)
  (5).實現商業方法。
(6).
含有一個空構造器。
(7).
不能實現finalize方法。
 2.ejbCreate應滿足的規則:
  (1).訪問控制修飾符必須爲public
(2).
返回類型必爲主鍵(僅對於BMP)
(3).
參數必須爲僉的JAVA RMI類型。
(4).
方法修飾符不能爲finalstatic
(5).throws
子句可以包括CreateException以及應用程序中指定的其它異常。
3.ejbPostCreate:
每一個ejbCreate必須對應一個ejbPostCreate方法,通常爲空。
(1).
參數的數量和類型必與相應ejbCreate方法匹配。
(2).
訪問控制修飾符必須爲public
(3).
方法修飾符不能爲final static
(4).
返回類型必須爲void
(5).throws
子句包括CreateException以及應用程序中指定的其它Exception
  4.ejbRemove方法:當EJB客戶調用此方法時,將刪除DB中該實體的狀態或EntityBean
    被一個DB刪除直接移走。
  5.ejbLoad方法:利用DB刷新實體變量。
   ejbStore方法:將變量寫到DB中。
這兩個方法用於同步與存貯在DB中的值所對應的EntityBean實體變量。
  6.finder方法的規則:
(1).
必須ejbFindByPrimaryKey方法。
(2).finder
方法務必須以ejbFind爲前綴。
(3).
訪問控制修飾符必須爲public
(4).
方法修飾符不能爲final static
(5).
參數必須是合法的Java RMI類型。
(6).
返回類型必須爲主鍵或主鍵的集合。
(7).throws
子句包括FinderException以及應用程序中指定的其它Exception
  7.商業方法
(1).
方法名不能與EJB結構定義的方法名衝突。
(2).
訪問控制修飾必爲public.
(3).
方法修飾不能final static
(4).
參數必須爲合法的Java RMI類型。
.Home接口的編寫規則:
1.Create
方法的編寫規則:
(1).
它與enterprise Bean類中對應的方法一樣,含有相同的參數。
(2).
返回Remote接口類型。
(3).throws
子句包括對應的ejbCreate ejbPostCreate方法的異常。
2.finder
講法的編寫規則:
(1).Remote
接口中的每一個方法必須與enterpriseBean類中的方法匹配。
(2).
每個方法命名規則與enterprise Bean類中的方法的命名規則一樣。
(3).
參數和返回類型必須是合法的Java RMI類型。
(4).throws
子句包括RemoteException

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章