EJB实践和应用介绍

EJB实践和应用介绍

EJB实践:第一章:安装配置- -

一、准备:
要安装的操作系统: window2000 professional(sp4),内存256M。
下载:www.borland.com 下载 JB2005,www.jboss.org 下载 jboss3.2.6

目标读者:有JSP、Servlet编程经验的,正在看EJB书籍的朋友。

二、安装:
1、安装 JBuilder2005。假设安装在C盘根目录下。
2、解压 JBoss3.2.6。假设解压在C盘根目录下。(注:JB2005与JBoss的集成只支持JBoss3.X,JB自带有JDK1.4.2,JBoss是EJB容器,免费的,体积小,对于学习非常好用)。

三、配置:
1、设置环境变量
增加JAVA_HOME,值为JB2005自带的JDK目录,如:C:/Borland/JBuilder2005/jdk1.4
注:JBoss不用作任何的配置。配置JAVA_HOME只是为了在脱离JBuilder环境下能够单独启动JBoss。
2、设置JB与JBoss自动部署关联
(1)启动JB
(2)选择:菜单"Enterprise"-"Configure Servers"
(3)左边:在"UserHome"节点下,选择"JBoss3.x+",
(4)在右边,"Enable server"复选框选中,
(5)单击"Home directory"右边三个点,选中JBoss主目录,如:D:/jboss-3.2.6。
(6)单击"Save"保存

评:个人觉得比Eclipse的配置简单多了,因为在JB2005中不用象Eclipse要手工安装各种插件。
教训:集成工具的版本一定要搞清楚。因为这涉及到打包、部署一系列问题,版本不对,往往会搞得初学者丈二摸不着头脑的,我在Eclipse的配置中就吃尽了苦头。因此,在JB2005版本中,我就使用JBoss3.2.6,虽然也下载了JBoss4.0。

EJB实践:第二章:SessionBean2.0快速体验- -

一、目标:
初步体验EJB中第一种类型 SessionBean 是长什么样子的,它的部署都包括哪些。

二、使用JBuilder编写代码
1、新建一个工程项目,项目名称我取 "myTest" 。
2、保存后,修改项目属性,指定应用服务器采用JBoss。
在"Project--Properties"中,单击左边的"Server",在右边的"single server for all service in Project"中下拉列表中,选择"JBoss3.x+"。保存。
这时候工程项目下除了myTest.html,什么代码资源都没有。
3、建立EJB模块。
点"New",在"Enterprise--EJB"中选择"EJB Module"。
点击"Next"。
输入模块名称,如:"myEJB",选择EJB2.0。点击"Finish"。
这时能够发现工程目录中,出现一个"myEJB","myEJB"的"Deployment descriptors"下有一两个xml文件,一个是EJB2.0通用的有关Bean的描述,一个是有关JBoss部署的描述。暂时都没有什么内容。

注:包含html,jsp,servlet,javascript等的应用模块,叫做WEB Module,也可以称之为"Servlet容器模块",这些WEB模块,可以部署在支持Servlet的各种应用环境中,如:Tomcat。假设大家都对Servlet比较熟悉了,在这章中,我们不实践这一部分。
包含SessionBean,EntityBean等EJB程序的模块,叫做EJB Module。这些EJB模块,可以部署在支持EJB容器的各种应用环境中,如:JBoss,Webspere,weblogic。

4、设计SessionBean。
(1)双击"myEJB",在右边出来一个窗口,这是用来图形化设计各种Bean用的。
(2)在设计窗口的上部,有一个"新建"图标,选择一个"Session Bean"。
(3)在弹出的界面中,填写Bean的各种参数:
Bean name : Test
Interfaces: remote (只提供远种接口,本地接口暂不考虑)
Session type : Stateless (无状态的Session Bean)
单击Classes and packages,输入包名,如:com.zengabo

此时,JB工具会自动帮你产生三个JAVA源文件:
TestBean.java 这是一个SessionBean,运行在EJB容器服务端的。它里面将有我们要编写的各种方法,例如:要实现一个快速排序的算法。我们的编程工作量都在这。
TestHome.java 这是一个管理TestBean的远程接口(实例化、删除等管理)。如果使用JB之类的工具,都会自动根据TestBean.java和ejb-jar.xml的描述生成,一般我们不用手工改这个程序的代码。
Test.java 这是一个提供给客户端编译使用的接口文件。有了JB工具,一般我们不用手工改这个程序的代码。
具体可以看代码。可以说,在JB的各种模板下,编写EJB远比编写RMI程序方便多了。

5、增加一个你想要实现什么功能的方法。
(1)在Bean"Test"的图形中,鼠标右键,选择"Add--Method",
Method Name : getMyBirthday (方法名称,可以任意定)
Return type : String (返回值为字符串,测试用)
Interfaces : remote (支持远程调用)
注:Interfaces比较重要,JB工具会根据指定的类型,去更新相应的接口文件,如:指定remote,只更新Test.java和TestHome.java,如果不指定,则不更新Test.java和TestHome.java。

(2)打开"TestBean.java"源码,找到getMyBirthday方法,在里面增加你想实现的逻辑功能。
例如:在返回值中增加"2004-12-29" 。

三、使用JBuilder部署EJB
现在先看一看工程目录中"myEJB--Module directory",没有class。说明还没有编译。
1、编译myTest工程
单击主菜单"Project"里有"Rebuild Project myTest.jpx"会进行编译。
编译没有出错,此时会发现:在工程目录中"myEJB--Module directory"下有com等编译好的文件,
在"myEJB"下也会发现一个myEJB.jar,这就是我们将要部署的jar包。
注:在缺省的情况下,编译工程时会自动对myEJB模块进行打包。

2、部署myEJB模块到JBoss。
单击工程中"myEJB"节点,鼠标右键,选择"Deploy options for myEJB.jar -- Deploy"。

部署成功。

建议这时候去$jboss-3.2.6/server/default/deploy看看,有没有myEJB.jar。如果有,解压看看,都有什么文件(最简单的例子,也有六个文件)。尤其是看看ejb-jar.xml , ejb-modeler-layout.xml,jboss.xml 三个描述文件。这是JBoss加载myEJB模块将要用到的。

四、编写一个客户端程序来调用EJB

EJB是基于RMI的应用服务设计框架,它的程序中区分服务端和客户端。客户端使用的只是一些接口文件,从而让服务端的功能实现细节的变化可以不影响客户端。例如上面例子中,有具体功能算法的程序(TestBean.java)和接口程序(Test.java和TestHome.java)部署在服务端,而只有接口程序(Test.java和TestHome.java)被开放给客户端。因此,TestBean.java中的getMyBirthday方法内具体算法的变化不会影响到客户端编程上的变化。
下面,我们就利用接口程序(Test.java和TestHome.java)编写一个客户端来调用getMyBirthday方法。
1、使用JBuilder测试模板
(1)点"New",在"Enterprise--EJB"中选择"EJB Test Client"。
(2)选择"Application",点击"Next"。
(3)在"EJB Name"中选择"Test"。注:在这个例子中,我们设计了一个EJB。
在"Package"中选择已经存在的包"com.zengabo"。也可以是其它包名。
(4)点击Next,点击Finish

注:如何与服务端取得握手的关键代码如下:
Hashtable environment = new Hashtable();
environment.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
environment.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
environment.put(Context.PROVIDER_URL, "jnp://localhost:1099");
Context context = new InitialContext(environment);

//look up jndi name
Object ref = context.lookup("Test");

//look up jndi name and cast to Home interface
testHome = (TestHome) PortableRemoteObject.narrow(ref, TestHome.class);


2、添加显示结果的代码
在main()方法里面,最后一行加上
String returnValue = "";
// 取得对象句柄
Test myTest = client.create();
if (myTest == null) {
System.out.println("Error in getMyBirthday(): " + ERROR_NULL_REMOTE);
}
// 调用对象的具体功能方法 getMyBirthday 。
try {
returnValue = myTest.getMyBirthday();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(returnValue);

编译一下TestTestClient1.java是否成功。

五、运行
1、启动JBoss服务
运行$jboss-3.2.6/bin/run.bat
DOS窗口看到
22:14:41,986 INFO [EjbModule] Deploying Test
22:14:42,867 INFO [EJBDeployer] Deployed: file:/D:/jboss-3.2.6/server/default/d
eploy/myEJB.jar
表明部署 myEJB.jar成功。
...
...
22:14:49,186 INFO [Server] JBoss (MX MicroKernel) [3.2.6 (build: CVSTag=JBoss_3
_2_6 date=200410140106)] Started in 1m:51s:751ms
表明JBoss启动成功。

2、在JBuilder中,运行名为"TestTestClient1"的Application,在Messages窗口中,最后一行会看到:
2004-12-29
这就是TestBean.java中getMyBirthday返回的值。说明是从JBoss服务器返回的(JBoss服务器也可以部署在另一台机器)。

至此,我们完成了一个极其简单的EJB的实践,从中可以体会到EJB的基本实现原理。
第二章的JBuilder工程源码,见附件:http://blog.blogchina.com/upload/2004-12-30/20041230084940871531.rar
注:打包的文件中,有源程序,也有打好包要部署到JBoss的 myEJB.jar 。


第三章:我进行有状态的SessionBean、基于BMP的EntityBean、基于CMP的EntityBean三种方式的实践。
第四章:Spring的实践。

EJB实践:第三章:有状态的SessionBean- -

在EJB容器中,SessionBean主要有两种:无状态(stateless)和有状态(stateful)。
1、无状态EJB,类似Servlet,它只提供一个引用(Bean instance),被所有客户端使用,不保留某个客户的单独信息。
例如:在某无状态EJB中,有一个数据成员(变量) i_count (整型,用于访问计数,初始值为0,访问一次累加1),它是公共的。某客户端访问后,值累加为1。另一个客户端访问时是已经变化了的值为1。

2、有状态EJB,类似数据库的Connect链接,也类似线程守护,它提供引用池(Bean instance pool),每个客户端会有单独的信息。
例如:在某有状态EJB中,有一个数据成员(变量) i_count (整型,用于访问计数,初始值为0,访问一次累加1),它对每个客户端来说是隔离的。某客户端访问后,值累加为1。另一个客户端访问时还是原来的值为0。

这里提到的数据成员(变量) i_count ,在EJB规范中称作:conversational state 。对它的要求也很多的,例如类型为 Serializable objects。还有,还要在ejbActivate(),ejbPassivate(),ejbRemove()等生命周期约定的方法中处理。详见EJB规范吧。

我的感想:在看第一遍书时,还一点感觉都没有,根本就看不明白SessionBean中的session与Servlet容器中的session有什么区别。
动手编程后,才感觉到EJB只是比Servlet更规范,更重量而已。真正的区别就是接口协议一个是基于HTTP,一个是基于RMI/IIOP。Servlet与无状态的SessionBean在Session上是一样的控制。Servlet中的Session对象与有状态的SessionBean是一样的控制。
对于应用,例如有一个购物车,要记录正在采购的物品信息,没有EJB时,我们一般是存在Servlet容器中的session中。有了EJB,则可以存储在有状态的SessionBean中,并且该次有状态的sessionBean的instance还得保存在Servlet的session中。这样的好处是:至少可以减轻Servlet容器的负载。

EJB实践:第四章:远程接口与本地接口- -

在前面的实践中,EJB调用使用的是远程接口。我一直对EJB2.0提供的本地接口很感兴趣。今天终于实践成功!
附EJB中关于本地接口的描述
----------------------------------------------
本地接口,是EJB 2.0的新功能。本地客户端(指:jsp,servlet等web组件,也可以是EJB),运用相同JVM中传递的参数直接与EJBs通讯。这种技术消除了网络潜在的问题、参数复制的问题以及需要与Java RMI-IIOP兼容的问题。也意味着,EJB客户端可以运用一个更轻量级的编程模式来访问服务。
注:在启动JBOSS时,同时也启动了自带的TOMCAT,查看系统进程时,就会发现只有一个JAVA进程。这就说明SERVLET容器与EJB容器是在同一个JVM下。
目前主要有两种应用:
(1)EJB之间的调用。即SessionBean调用EntityBean。我测试的例子是一个SessionBean调用另一个SessionBean。
(2)客户端(jsp,Servlet或者Application)调用EJB。
详情参考:
http://www.ftponline.com/china/XmlFile.aspx?ID=2
----------------------------------------------

我的测试环境是:一个Application程序,两个EJB,一个EJB(Employee)只提供远程接口,一个EJB(CalWorkAge)只提供本地接口。
具体代码见:http://blog.blogchina.com/upload/2005-01-10/20050110123950468196.rar
运行EmployeeTestClient1后,控制端窗口输出的最后一行:get Age 150 就是表示是由Empolyee这个BEAN通过调用CalWorkAge这个EBAN的本地接口取得的值。

重点是:在ejb-jar.xml中,为了提供本地接口,需要调用本地接口BEAN的远程接口的BEAN的描述中,加上:
<ejb-local-ref>
<description>test it</description>
<ejb-ref-name>CalWorkAge</ejb-ref-name><!--采用sun推荐的命名方式-->
<ejb-ref-type>Session</ejb-ref-type>
<local-home>com.zengabo.CalWorkAgeLocalHome</local-home>
<local>com.zengabo.CalWorkAgeLocal</local>
<ejb-link>CalWorkAge</ejb-link><!--必须和被应用的ejb-name匹配-->
</ejb-local-ref>

这一段是专门对本地调用进行描述的。如果WEB组件(JSP或者SERVLET)要调用,则要把这一段描述放到 web.xml中。

不明白:JBUILDER为什么不自动产生这一段描述?害得我找了两天资料。
由此可想,E公司的RDAS其实也可封装一层EJB接口。理由:(1)技术上支持EJB,对外宣传非常有好处。(2)EJB也是基于RMI通讯协议,因此在性能上差别不大。(3)通过EJB,RDAS的扩展余地非常大,也能实现一些服务,由WEB容器转移到RDAS服务器。

EJB实践:第五章:基于BMP的EntityBean-

EntityBean,是指与数据存储(文件系统或者数据库)域(domain)密切相关的Bean。目前流行使用数据库进行存储数据,与数据库进行打交道,需要注意的一是SQL交互,二是事务。
把SQL、事务交给容器来处理的,称作CMP(Container Manager Persistence)规范。把SQL、事务交给Bean来处理的,称作BMP(Bean Manager Persistence)规范。这里所说的"处理",就是指用不用编程人员来手工编写代码。
考虑到BMP与我们以前不用EJB时的编程过程差不多,这章介绍BMP,下一章再介绍CMP。
一、环境准备
1、安装mysql4.1,并建立一个数据库jboss、建立一个用户jboss,口令也用jboss。
注:虽然JBuilder自带有一个JDataStore简易数据库。但是JBOSS的standardjbosscmp-jdbc.xml文件中没有对JDataStore的描述。只有mysql,db2,oracle9i等。因此我采用 mysql4.1。
2、建立一个表 Book ,脚本为:create table book ( id int , name varchar(50) ,primary key(id));
3、下载mysql jdbc实现。针对mysql4.1,我下载的是:mysql-connector-java-3.0.16-ga-bin.jar。
把它放到 $jboss-3.2.6/server/default/lib目录下,这是给JBOSS中部署的EJB用的。
4、编辑一个有关数据库访问的描述文件,供JBOSS中的EJB使用。文件名:mysql-ds.xml,放在$jboss-3.2.6/server/default/deploy目录下。内容如下:
<datasources>
<local-tx-datasource>
<jndi-name>mysql_jndi</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/jboss</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>jboss</user-name>
<password>jboss</password>
</local-tx-datasource>
</datasources>

注:JBOSS在启动时,就会在JNDI池中提供一个 mysql_jndi给EJB使用。

 

二、编写基于BMP的EntiryBean
1、JBuilder中新建一个工程项目,项目名称我取 myEJB_BMP,并修改项目属性,Server指定为 JBoss3.2.x。步骤同"第二章 SessionBean"。
2、建立EJB2.0模块,模块名: myEJB_BMP 。步骤同"第二章 SessionBean"。
3、设计EntityBean。
(1)双击"myEJB_BMP",在右边出来一个窗口,这是用来图形化设计各种Bean用的。
(2)在设计窗口的上部,有一个"新建"图标,选择一个"BMP EntityBean"。
(3)在弹出的界面中,填写Bean的各种参数:
Bean name : Book
Interfaces: remote (只提供远种接口,本地接口暂不考虑)
Always warp primary key: false
单击Classes and packages,输入包名,如:com.zengabo

(4)为这个Bean增加两个属性: id(Integer类型) 和 name(String类型) 。其中ID设为主键。

此时,JB工具会自动帮你产生三个JAVA源文件:
BookBean.java 这是一个EntityBean,代码编写工作量就在这。
BookRemoteHome.java 这是一个管理BookBean的远程接口(实例化、删除等管理)。
BookRemote.java 这是一个提供给客户端编译使用的接口文件。有了JB工具,一般我们不用手工改这个程序的代码。

还产生两个描述文件:
ejb-jar.xml 。里面有对 EntityBean的描述:
<ejb-jar>
<display-name>myEJB_BMP</display-name>
<enterprise-beans>
<entity>
<ejb-name>Book</ejb-name>
<home>com.zengabo.BookRemoteHome</home>
<remote>com.zengabo.BookRemote</remote>
<ejb-class>com.zengabo.BookBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.Short</prim-key-class>
<reentrant>False</reentrant>
</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Book</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

jboss.xml 描述文件(用于JBOSS提供jndi名称):
<jboss>
<enterprise-beans>
<entity>
<ejb-name>Book</ejb-name>
<jndi-name>Book</jndi-name>
</entity>
</enterprise-beans>
</jboss>

4、为BookBean.java增加SQL操作。
// 手工添加引用
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import javax.ejb.EJBException;

//在 public Integer ejbCreate(Integer id, String name) throws CreateException 方法内的改变代码如下:
注:如果没有这个方法,请建立一个。(我的JBuilder在第一个ejbCreate()总是只保留一个主键参数)
public Integer ejbCreate(Integer id, String name) throws CreateException {
Connection myConn = null;
PreparedStatement ps = null;
try{
myConn = getConnection();
ps = myConn.prepareStatement("insert into book (id ,name) values(?,?)");
ps.setInt(1,id.intValue());
ps.setString(2,name);
if( ps.executeUpdate() < 1 ) {
throw new CreateException("insert into office ");
}
}catch(SQLException se){
throw new CreateException(se.getMessage());
}
finally{
try{
if (ps!=null) ps.close();
if (myConn!=null) myConn.close();
}catch(SQLException sef){
}
}
return id;
}

// 增加以下方法 。注:mysql_jndi就是 JBOSS配置文件 mysql-ds.xml中指定的。
public Connection getConnection() throws SQLException{
try{
Context jndiCntx = new InitialContext();
DataSource ds = (DataSource)jndiCntx.lookup("java:/mysql_jndi");
return ds.getConnection();
}catch(NamingException ne){
throw new EJBException(ne);
}
}

-----至此 EntityBean的代码编写完毕。目前只实现一个 Create方法,也即实现我们常用的 insert 功能。查询、修改、删除功能在下一章时再提。可以看到,跟一个普通的Java Bean访问数据库没有多少区别。

三、使用JBuilder部署EJB
单击工程中"myEJB_BMP"节点,鼠标右键,选择"Deploy options for myEJB_BMP.jar -- Deploy"。
步骤同"第二章 SessionBean"。

四、编写一个客户端程序来调用EJB
(1)点"New",在"Enterprise--EJB"中选择"EJB Test Client"。
(2)选择"Application",点击"Next"。
(3)在"EJB Name"中选择"Book"。
(4)点击Next,点击Finish
(5)添加显示结果的代码
在main()方法里面,最后一行加上 client.create(new Integer(1),"Study J2EE step by step");
以上步骤类似"第二章 SessionBean"。

五、运行
1、启动JBoss服务
运行$jboss-3.2.6/bin/run.bat
2、在JBuilder中,运行名为"BookTestClient1"的Application,在Messages窗口中,最后一行会看到:
3、进入mysql查看: select * from book; 就会发现数据已经插入。
mysql> select * from book;
+----+-------------------------+
| id | name |
+----+-------------------------+
| 1 | Study J2EE step by step |
+----+-------------------------+
1 row in set (0.03 sec)

--------------------------------
至此,一个BMP开发及测试完成。感觉配置也不复杂。也许是因为有了JB的缘故。

附:如果不想编写一个EJB,想让JBuilder能够连到mysql数据库,根据罗列出来的表自动生成一个BMP EntityBean。就需要在JBuilder作如下配置:
1、把mysql-connector-java-3.0.16-ga-bin.jar放到$Borland/JBuilder2005/lib目录下。
2、在Tools|Configure|Libraries...中,新建一个库名:mysql_jdbc,指向$Borland/JBuilder2005/lib/mysql-connector-java-3.0.16-ga-bin.jar
3、在Enterprise|Enterprise Setup|Database Driver,增加一个数据库驱动,选择mysql_jdbc。重新启动JBuilder。
4、在Project|Project Proeerties...|Path,右边窗口"Required Libraries"中,增加"mysql_jdbc"
配置完毕。
这时弹出EJB设计器,在JBuilder大窗口的最左下角有一个"Structure"窗口,单击"DataSources",右键,选择"Add DataSource",在新窗口中填写mysql-ds.xml文件中的内容。保存后,会出现一个子项"mysql_jndi",单击它右键,选择"refresh from database",就会罗列出已经存在的表。
选择一个想要生成EntityBean的表名,单击右键,可以选择要生成的EntityBean类型。
注:生成后的EJB,要修改包名等。

EJB实践:第六章:基于CMP的EntityBean

书上说,开发一个CMP的EntityBean,比BMP的简单多了。开发过程如下:
一、环境准备
在上一章环境配置的基础上,还需要修改 $jboss-3.2.6/server/default/conf/standardjbosscmp-jdbc.xml
把 <datasource>java:/DefaultDS</datasource>
<datasource-mapping>Hypersonic SQL</datasource-mapping>
改为: <datasource>java:/mysql_jndi</datasource>
<datasource-mapping>mySQL</datasource-mapping>
注:这是EntityBean中容器管理的最关键的地方,也是比BMP多出的一个配置文件。它指明了如何与数据库进行映射。例如:表不存在,是否自动创建表;JAVA类型与数据库字段类型如何匹配等信息。这也是CMP自动产生SQL语句的依据。对于简单的查找、修改、删除等功能,在CMP的EntityBean不用人工再编写半点SQL语句。
其中<datasource-mapping>mySQL</datasource-mapping>中的"mySQL",是standardjbosscmp-jdbc.xml内容中已经包含有的标识<type-mapping>,大小写不能写错。
其中<datasource>java:/mysql_jndi</datasource>中的"mysql_jndi"是跟mysql-ds.xml中的描述一致,不能写错。
 

二、编写基于CMP的EntiryBean
1、JBuilder中新建一个工程项目,项目名称我取 myEJB_CMP,并修改项目属性,Server指定为 JBoss3.2.x。步骤同"第二章 SessionBean"。
2、建立EJB2.0模块,模块名: myEJB_CMP 。步骤同"第二章 SessionBean"。
3、设计EntityBean。
(1)双击"myEJB_CMP",在右边出来一个窗口,这是用来图形化设计各种Bean用的。
(2)在设计窗口的上部,有一个"新建"图标,选择一个"CMP2.0 EntityBean"。
(3)在弹出的界面中,填写Bean的各种参数:
Bean name : BookShop
Interfaces: remote (只提供远种接口,本地接口暂不考虑)
Always warp primary key: false
单击Classes and packages,输入包名,如:com.zengabo

(4)为这个Bean增加两个属性: id(Integer类型) 和 name(String类型) 。其中ID设为主键。Geters , Seters 方法都选 Remote。Column name 跟 Field name 一致。
4、修改jbosscmp-jdbc.xml文件。
注:基于CMP比基于BMP的,就多了一个配置文件:jbosscmp-jdbc.xml。
在jbosscmp-jdbc.xml中,数据源缺省使用JBoss自带的Hypersonic SQL。由于在standardjbosscmp-jdbc.xml中已经修改,因此可以把jbosscmp-jdbc.xml中<datasource>、<datasource-mapping>这两行删除。

-----至此,简单的基于CMP的EntityBean设计完毕。在JB中,完全不用编写一行代码就搞惦了。

注:如果不想修改standardjbosscmp-jdbc.xml,可以把standardjbosscmp-jdbc.xml中<jbosscmp-jdbc>和</jbosscmp-jdbc>之间的内容拷到jbosscmp-jdbc.xml中。

三、使用JBuilder部署EJB
步骤同"第二章 SessionBean"。

四、编写一个客户端程序来调用EJB
这次,我们要测试的功能有:
插入数据:通过create(xxx,xxx)方法。
查询一条数据:通过finder方法。
更改数据:通过 finder方法得到实体对象后,通过setXXX修改要改变的字段属性。
删除数据:通过 finder方法得到实体对象后,通过remove()方法。

其余功能,如:查询符合条件的记录,是通过EJB-QL,就暂不举例了。

(1)点"New",在"Enterprise--EJB"中选择"EJB Test Client"。
(2)选择"Application",点击"Next"。
(3)在"EJB Name"中选择"BookShop"。
(4)点击Next,点击Finish
(5)在main()方法的上一行,添加以下代码:
// add by zengabo 2005-01-13
public void executeFindByPrimaryKey(Integer i){
BookShopRemote myBookShop = this.findByPrimaryKey(i);
if( myBookShop == null ){
System.out.println("not found");
return;
}
try{
System.out.println(myBookShop.getName());
}catch(Exception e){
System.out.println(e.toString());
}
}
public void executeUpdate(Integer i,String name){
BookShopRemote myBookShop = this.findByPrimaryKey(i);
if( myBookShop == null ){
System.out.println("not found");
return;
}
try{
myBookShop.setName(name);
}catch(Exception e){
System.out.println(e.toString());
}
}
public void executeDelete(Integer i){
BookShopRemote myBookShop = this.findByPrimaryKey(i);
if( myBookShop == null ){
System.out.println("not found");
return;
}
try{
myBookShop.remove();
}catch(Exception e){
System.out.println(e.toString());
}
}
(6)在 main()方法内的最后一行加上以下代码:
// 以下分段注释,分段执行,到数据库去查看 bookshop 的记录。
// 1.插入记录
client.create(new Integer(1),"beijing shop");
client.create(new Integer(2),"guang dong shop");
client.create(new Integer(3),"guang xi shop");
// 2.查找记录
//client.executeFindByPrimaryKey(new Integer(2));
// 3.修改记录 , id 为2的,名称改为"guang zhou shop"
//client.executeUpdate(new Integer(2),"guang zhou shop");

// 4.删除记录 id 为3的。
//client.executeDelete(new Integer(3));

五、运行
1、查看mysql数据库
登录mysql,进入jboss数据库查看。
use jboss;
show tables;
会发现没有一个表。
2、启动JBoss服务
运行$jboss-3.2.6/bin/run.bat
启动成功后,再查看mysql数据库,看到:
mysql> show tables;
+-----------------+
| Tables_in_jboss |
+-----------------+
| bookshop |
+-----------------+
bookshop表已经自动建立,这是CMP根据配置文件,发现表不存在时,就自己建立。
如果没有建立,说明配置文件中的 jndi 等有错误,一定要注意与例子中的一样。<datasource>java:/mysql_jndi</datasource>中,是有"java:/"的。

注:有一个小问题,由于有其它服务使用了JBOSS缺省的DefaultDS这个jndi名称,我们已经把它改成了mysql_jndi,所以,会有些出错提示。但这不影响我们的测试。

3、在JBuilder中,先测试插入功能,进入mysql查看: select * from book; 就会发现数据已经插入。
然后测试查找功能,再测试修改功能,最后测试删除功能。
--------------------------------
至此,一个CMP开发及测试完成。感觉配置也不复杂。相对以前的编程模式,编码量真是太少了。当然,还有表之间的关系,事务控制,以及JMS等应用,都需要进一步了解。

整个EJB实践暂告一段落了。我感觉只触及了EJB的冰山中的一角,但前后持续花了两周时间。

对于我这个新手来说,一在环境搭建时,先是选择Eclipse浪费了不少时间,然后是用什么EJB容器浪费了不少时间;二是没有去买一本有关EJB实践的书,都是从网上参考的一些零星资料,当实践完一个问题,又要要实践新问题时,只能等待上网。

在这期间非常感谢:
利瓦伊, 庄永璋所编写的关于EJB2.0的《EJB系统开发实战录》1,2,3,4。
罗时飞,《J2EE Applications on JBoss 4.0》于2004 年10 月5 日翻译稿

这期间,也看了夏昕(xiaxin@gmail.com)编写的《Spring开发指南》和《ibatis 开发指南》,里面有他个人的项目应用体会,其中谈到各种技术架构的应用利弊,受益匪浅。同时也建议大家看看。下一步,有时间,我将实践Spring和ibatis等民间优秀产品,当然也实践一下最新推出的EJB3.0。