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)。不过这句话翻译的不错:其他需要特别注意的(是)服务器方资源包括线程,数据库连接,安全、事务等等。定制处理这些资源的基础结构是相当费劲的。这种工作在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容器就相当于一个“功能“服务器,可以把一些业务功能写在这个里边。然后用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与基础的数据库同步。
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():很简单,删除了。哈哈,玩笑,其实对不同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 菜单下找这个ITEM,CREATE 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();
}
}
OK,SAVE然后运行!!!!成功!!!
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 生命周期:
OK,状态会话BEAN就是这么回事。应该是很简单的东西,完全可以理解。
呵呵,大家看见了那个总回我帖子的QUGHOST了吗?他是我的好朋友。
他有好多的搞笑故事,我和他商量了一下,准备把他的搞笑经历发在我的一个新版块里,可是不知道他同意不同意。
OK,话归正传。我马上就要把第三章结束了,其实第三章的会话BEAN到5就已经讲完了,可是这里边还有一个很关键的东西,那就是序列化。
序列化 (Serialization)
其实很简单了,就是把某个对象的所有东西都输出到一个文件上。这里也可以是别的东西。好多。
然后当你还想用他的时候,就再在这个文件上把这个对象的状态等等的一些信息全部找回来。
真正发生了什么
什么会被序列化?
部分序列化
这些全是我从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.xml,NND,我根本就没有这个文件,后来查了好多的资料,才知道,原来他那个是旧版本,郁闷~~~~~~旧版本还要往上贴。
我们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 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。