CSDN博客

img dengbo

我的EJB学习历程

发表于2004/7/15 18:11:00  2822人阅读

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

 

 

0 0

相关博文

我的热门文章

img
取 消
img