我的EJB学习历程

时间:2021-07-23 05:58:22

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编程。

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

我选用的參考书是wrox的EJB编程指南。这个书有1000多页,争取能全部完毕他吧!

好了,不多说无用的了。如今開始进入第一章的学习。

第一章    Enterprise Javabeans 体系机构。

開始将讲了一大堆废话,从单层体系结构讲到了多层体系结构,又讲到了N层体系结构。这样引出了主题(J2EE)。只是这句话翻译的不错:其他须要特别注意的(是)server方资源包含线程,数据库连接,安全、事务等等。定制处理这些资源的基础结构是相当费劲的。这样的工作在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/IIOP:Remote Method Invocation相似网络连接使用的一些东西。

JNDI:Java Naming and Directory Interface。

JDBC:这个不用说了吧?

JAVAMAIL/JAF:JAVA的MAIL服务,JAF是邮件的附件。

JMS:JAVA MESSAGE SERVER。JAVA消息服务。

设计中为何使用EJB:说了一大堆,我还是不确定是为什么。再接着看吧!

只是这次我更加的确定了,原来EJB容器就相当于一个“功能“server,能够把一些业务功能写在这个里边。然后用123来调用咯!(不知道这么说是不是有点搞笑)。

哈哈,我的理解正确了,果然书的第8页就说了,容器能够看成是执行环境!

EJB的容器服务:(这里的容器服务都是不用编码,而是容器管理自己实现的啊。不错)

组件池和寿命周期管理:

哈哈,来点白话的,这是我个人理解的,组件池在容器启动的时候就自己生成了好多的BEAN的实例,假如说是10个吧,这个时候客户1来了,他就拿了BEAN1,这个时候别人是不能使用BEAN1的,再来了第2个客户,他不能拿BEAN1了,就仅仅能拿BEAN2了。。。。。。。这个时候客户11来了,容器发现已经没有BEAN给他用了,于是就找个如今没人用的BEAN给他用,可是发现全都在被占用,没办法了,就仅仅好再生成一个给他用了。哈哈,就是这么简单,可是有人会问了,这不是越生成越多吗?没关系,容器发现生成的BEAN没人用了,就会自己主动的给删掉,释放空间,释放系统资源嘛!

客户会话管理:

理解钝化和激活即可了。

钝化就是把客户的BEAN状态保存在池中。

激活就是把客户的这个BEAN状态再还给客户。

数据库连接池:

这个好象不用讲了吧!数据资源共享!这个名起的COOL B了。

事务管理:

事务非常是昂贵啊!

验证和訪问控制:

这个非常easy!

容器怎样提供服务:这一部分先不写,以后再写,由于我也不怎么理解。哈哈

EJB类型:*****这可是关键的地方。*****

分为3种类型:

会话BEAN:(寿命和所在客户的会话一样长啊)

1.       无状态会话BEAN。

2.       状态会话BEAN。

这两个BEAN非常的重要,可是在第3章才有讲。哈哈,先搁这!

实体BEAN

自己理解就好象是数据库BEAN,就是把数据库的内容都读出来放在BEAN里,也不知道它具体是怎么读的,这样做会不会非常浪费系统资源!???

实体BEAN依据同步的不一样又能够分为:

CMP(容器管理的持久性):容器负责BEAN与基础的数据库同步。

BMP(BEAN管理的持久性):这里要编程人员负责和基础数据库同步!容器在适当的时候调用编程人员写好的SQL语句!

真不明确,为什么已经有CMP了还要出了个BMP,书上是这么解释的:

有时须要增加设计的灵活性或在非关系型存储中支持持久性??这是人话吗?

还有个例如:EJB规范V1.1仅仅允许实例变量和表格列之间的一对一映射。这样,使用这个版本号时,假设要在实体BEAN中表示在多个表格中存储状态的累计对象,则无法使用CMP,而要使用BMP。EJB2.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():非常easy,删除了。哈哈,玩笑,事实上对不同BEAN结果不一样啦,会话BEAN是将BEAN再放回池中,而实体BEAN则是从数据库中删除数据。这次才对嘛!

下边就是程序了,我先试试程序究竟是怎么回事再给大家讲啊!

通过本人对书本上演示样例程序的分析,自我感觉书上的演示样例程序实在是没有说服力,主要是部署工具出奇的麻烦,在这个JAVA不花钱的年代,怎么能用J2EE自带的部署工具,一大堆的配置实在是另人烦躁!呵呵。

说了一大堆,開始进入关键议题了,各位听好了。

我选用的是ECLIPSE,这个免费的东西实在做的不错,在我可是做STRUTS的时候就发现他的好多长处,可是实在遗憾,本人没实用过JBUILDER,也不知道他们是不是一样。

ECLIPSE有个LOMBOZ的插件,这个插件里边包含有全部server的配置方案。能够配置WEB MODEL,和EJB MODEL,这里边我选用JBOSSserver吧,由于听说他也是不要钱的。

至于ECLIPSE下JBOSS是怎么培植,这非常easy,仅仅要上GOOGLE上搜索‘ECLIPSE部署‘就有好多,联想公司姜巍巍先生就写了一篇配置,可是大家不要看他的EJB部署,实在是垃圾。依照他说的要想让刚開始学习的人学会第一个EJB是有难度的!

大家还是来看我的HELLOWORLD吧!

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

事实上我仅仅是帮大家翻译一下,呵呵。看原文能够上上边这个网址。

好了,不多说废话了。如今開始。对了,一定要保证你的LOMBOZ和ECLIPSE都已经配置好了啊。

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

2.     然后就能进入这个界面:

我的EJB学习历程

看见了吧,在这个的EJB MODULES中加一个新的MODULES,叫mybeans。

然后再选择TARGET SERVER选项。就是这。

我的EJB学习历程

选择我们刚才说的已经配置好的JBOSS。

我的EJB学习历程

3.     好了,如今假设不报错的话。就点FINISH吧!

4.     第一个EJB模块已经完毕,它能够给你生成EJB和EJB HOME,可是开发的实现类须要自己写!下边就是怎么写一个实现类。

5.

我的EJB学习历程

这副图能明确吧,可是有人要问了,这个东西哪儿来的?主界面,WINDOW菜单下的PERFERNECE,点他!哈哈,把里边有LOMBOZ的全选上就有了。

6.OK拉,依照下边的图把名字输上:

我的EJB学习历程

这个时候FINISH就会生成一个TestSessionBean.java。这个就是生成的实现类了。

7.然后就是给这个实现类填加一些方法了。怎么填呢?别改源码,行不通,要这么做:

我的EJB学习历程

然后,

我的EJB学习历程

这样就能够增加方法了,千万别手动加代码啊,这样会让你组件接口找不到你写的方法!

然后把这个实现类的方法改成:

public String helloWorld(){

return "Hello from lomboz!";

}//这个都知道是什么意思吧?

到如今为止就算我们已经做出来一个EJB程序了,仅仅只是是缺少主接口,组件接口的一些东西,可是不要怕,ECLIPSE会给你自己主动生成的。厉害吧?接下来我们就须要做这么几步:

a)     把刚才写的这个EJBBEAN增加到EJB中.

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

c)      把他部署到server上.

d)     写一个客户程序来实验他.

EASY吧!真的非常EASY啊!

8.这是a)那一步,把他增加到EJB中。就是刚才我们在EJB MODULES中建立的那个EJB。

我的EJB学习历程

9.各位观众,如今大家以最快的速度把这个界面找到。

我的EJB学习历程

然后做这个操作:

我的EJB学习历程

这个操作就是完毕任务b)的任务。

10.OK了,如今開始做c)了,就是把刚才写好的EJB部署到server上,依照下边两个图来做。

我的EJB学习历程

我的EJB学习历程

找控制台,看看你的部署成功不成功,要是成功的话。就能够做d)了。不成功的话,再来一遍!要是还不成功的话。找我吧。

11.如今我们就要写一个客户程序来实验他了,真是兴奋啊!

先又一次建立一个JAVA项目,这样才干显示出EJB的功能嘛。

我的EJB学习历程

新建立的项目叫这个名MyEjbClientProject,事实上随便叫什么名了。

点NEXT进下一页的时候一个要在PROJECT里边把我们刚才做的MyEJBClientProject给加上啊!否则白做了。

然后在NEW 菜单下找这个ITEM,CREATE AN EJB TEST CLIENT。点上。

12.这么配置。这个事实上根本都不用说。

我的EJB学习历程

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();

}

}

OK,SAVE然后执行!!!!成功!!!

我的EJB学习历程

我的EJB学习历程

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 应用程序!成功了!界面例如以下:

我的EJB学习历程

如今来想想为什么是无状态会话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是怎么回事拉:

我的EJB学习历程

这些是些解说,和书上的差点儿相同,省得我打字了。

有状态会话 Bean 生命周期:

  • Bean 在下列情况下被回收:
    • 超时 (不管是激活的或钝化的)
    • 被调用 remove()
  • Passivation 是依据 Least-Recently-Used 算法
  • Activation 由对 Bean 的方法调用产生
  • afterBegin()
    beforeCompletion()
    afterCompletion()
    方法仅对实现 SessionSynchronization 接口的 Bean 有效
  • 在一个事务环境下,调用的方法必需具有同样的事务类型

OK,状态会话BEAN就是这么回事。应该是非常easy的东西,全然能够理解。

呵呵,大家看见了那个总回我帖子的QUGHOST了吗?他是我的好朋友。

他有好多的搞笑故事,我和他商议了一下,准备把他的搞笑经历发在我的一个新版块里,可是不知道他允许不允许。

OK,话归正传。我立即就要把第三章结束了,事实上第三章的会话BEAN到5就已经讲完了,可是这里边另一个非常关键的东西,那就是序列化。

序列化 (Serialization)

  • Java 序列化机制能够将整个对象的状态输出到一个流上
  • 对象能够再从其原始状态又一次构建回来

事实上非常easy了,就是把某个对象的全部东西都输出到一个文件上。这里也能够是别的东西。好多。

然后当你还想用他的时候,就再在这个文件上把这个对象的状态等等的一些信息全部找回来。

 

真正发生了什么

  • 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;

}

}

事实上非常easy,看我的程序就好,然后找找SYMIC文件,看看他里边写了些什么东西。哈哈~~~~

说点别的,我近期发现原来ITLAY真的是个不错的国家。可是好象在中国根本就没有机会去吧!

ITaly ,SHopper's DEstinatiON!

在他那买东西非常合适啊!听说PRADA,AMANI在那有非常多TAX REBATE的店啊,仅仅有国内的一半价钱,而且东西全是最TOP 的CLASS。

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

ITALY MY DREAM-PRADISE!

呵呵!~~~

最终能够又出新东西了。上个礼拜一直没忙,公司带我们出去HAPPY了。只是如今水好凉,不能下水。才下去两分钟瞬间就被冻上来了。特别的冷。

恩,言归正传。我一直在看CMP,实体BEAN,可是发现要弄好ENTITYBEAN首先要做的是知道怎么配置server,我找到了一篇配置JBOSSserver的指南,认为不错,就在这给大家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文件夹中的文件例如以下图所看到的:

我的EJB学习历程

第二步,我们将含有MySQL JDBC 2.0.14驱动程序的jar文件拷贝到JBoss安装文件夹的server/default/lib文件夹下,此时lib文件夹中的文件例如以下图所看到的:

我的EJB学习历程如今我们已经完毕了前期的配置工作,接下来我们将讲述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步開始写吧:

我的EJB学习历程

如今选中CMP这一项。 然后打上你自己中意的名字和包名,做NEXT。

然后就会进入到CMP这个界面了:事实上这个界面一看就知道是怎么回事:

我的EJB学习历程

写上表名,加上字段,一切简单的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.xml,NND,我根本就没有这个文件,后来查了好多的资料,才知道,原来他那个是旧版本号,郁闷~~~~~~旧版本号还要往上贴。

我们3.X要改的是xdoclet.xml这个文件,这个文件保证有,大家找到之后就能看见,他里边有好多种配置server的数据库的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 bean的remote接口訪问它,实现该remote接口的对象被称为EJB对象。每个
entity 对象都有一个标识符。
Entity Bean的特征:持久的(分为BMP和CMP),允许共享訪问,而且有一个主键。
二、编写规则:
 
 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).方法修饰符不能为final或static。
(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。