阅读本文前,请先阅读《 J2EE 连接器的开发》一文,并且下载、安装相关的应用服务器的试用版。
本文的参考资料见 参考资料。
本文的全部代码在这里 下载。
EJB 组件通过资源适配器来访问 EIS,在 EJB 组件中,定义了最终客户端要使用的业务方法,一般实现为会话 Bean,它一般通过和多个 J2EE 组件或者资源适配器交互来完成具体的业务逻辑。在这个案例中,EJB 组件的功能非常简单,就是接收最终客户端的请求,然后通过资源适配器调用 EIS 并获得结果,最终把结果返回给客户端。
EJB 组件定义了一个业务方法,它的远程接口的代码如例程 1 所示。
例程 1 EJB 组件的远程接口
package com.hellking.jca.ejb;
import java.rmi.RemoteException;
import javax.ejb.*;
public interface Demo extends EJBObject
{
public String sayHello(String arg) throws RemoteException;
}
|
在这个接口里,定义了一个业务方法,就是 sayHello(String name)。我们来看 EJB 组件的实现类部分代码,如例程 2 所示。
例程 2 EJB 实现类的部分代码
package com.hellking.jca.ejb;
import … .
public class DemoEJB implements SessionBean
{
private SessionContext sessionCtx;
// 业务方法
public String sayHello(String arg)throws Exception
{
System.out.println("echo, arg="+arg);
String result="";
try
{
InitialContext iniCtx = new InitialContext();
Context enc = (Context) iniCtx.lookup("java:comp/env");
Object ref = enc.lookup("eis/DemoEISFactory");// 获得连接工厂
ConnectionFactory dcf = (ConnectionFactory) ref;
DemoConnection dc =(DemoConnection) dcf.getConnection();// 从连接工厂创建连接
result=dc.sayHello(arg);// 调用虚拟连接的业务方法
dc.close();// 使用完,关闭虚拟的连接。
}
catch(NamingException e)
{
System.err.println("在查找 JNDI 名字时遇到错误 :"+ e);
}
return result;// 返回调用的结果
}
…
}
|
以上代码是典型的使用资源适配器的方法,首先通过 JNDI 来查找连接工厂实例(这个实例由应用服务器自动绑定),然后从这个连接工厂获得连接实例,接下来从连接实例调用业务方法,最后关闭连接。
本案例使用了两种类型的客户端,一种客户端基于浏览器,它通过 HTTP 访问 JSP 组件,JSP 组件通过 RMI 调用 EJB 组件,EJB 组件再通过资源适配器调用 EIS;另一种客户端是普通的 Java 程序,这个 Java 程序通过 RMI 调用 EJB,EJB 组件再通过资源适配器调用 EIS。
在实现中,JSP 代码和普通 java 程序的代码基本一样,不同的是它们获得初始上下文环境(InitialContext)的方法不同。
我们看一下简单的 JSP 客户端,如例程 3 所示。
例程 3 JSP 客户端
<%@ page contentType="text/html;charset=gb2312"
import="com.hellking.jca.ejb.*,javax.naming.*"%>
<html><body><form><table><tr><td> 请输入名字:
</td><td><input name=name type=text></td></tr>
<tr><td><input value=submit type=submit></td></tr>
</table>
</form>
<%
String name=(String)request.getParameter("name");
try
{
InitialContext context=new InitialContext();
DemoHome home=(DemoHome)javax.rmi.PortableRemoteObject.narrow(
context.lookup("ejb/demo"),DemoHome.class);
Demo demo=home.create();
if(demo!=null)out.println("demo is ok");
out.println("调用 ejb-->jca-->eis");
out.println("发送了 :hellking, 返回以下的值:<hr><font color=red>");
out.println(demo.sayHello(name));
out.println("</font>");
out.flush();
}
catch(Exception e)
{
}
%></body></html>
|
普通的 java 客户端和 JSP 基本一样,只是需要指定相关的属性才能获得 InitialContext 实例。可以通过以下的方法获得 InitialContext 实例。
例程 4 在普通的 Java 客户端获得 InitialContext 实例
// 创建初始的上下文环境
public Client()
{
context=this.getInitialContext();
}
public InitialContext getInitialContext()
{
try
{
Properties p=new Properties();
p.load(new FileInputStream("config.properties"));
return new InitialContext(p);
}
catch(Exception e)
{
System.out.println("got ee");
e.printStackTrace();
return null;
}
}
|
Java 客户端的详细代码见 src/client/Client.java 文件。
下面介绍装配和部署的相关问题。
在不同的应用服务器下部署 J2EE 应用时,基本上大同小异。部署工作基本上按照以下步骤进行:
- 把 J2EE 应用和连接器打包成 ear 文件;
- 使用应用服务器厂商提供的工具把 ear 装配成可以部署的 ear 包,在装配的过程中,和应用服务器特定的部署描述符自动添加到 ear 包中;
- 使用应用服务器提供的控制台进行部署,在部署时,可能需要指定一些属性。
对于 JBOSS,没有提供装配工具和部署控制台,需要手工进行编写专有的部署描述,并且手工部署。
在进行装配、部署工作前,请把 J2EE 应用打包成 ear 文建,打包后的结构如下:
+resource.ear +hello.jar -META-INF/ejb-jar.xml +com/hellking/jca +com/hellking/jca/ejb +demo.rar -META-INF/ra.xml +com/hellking/jca +web.war -WEB-INF/web.xml -test.jsp -META-INF/application.xml |
下面首先介绍在 J2SDKEE1.3 下装配和部署 J2EE 应用。
step1 首先启动 J2EE 和部署工具,在控制台输入:
start j2ee -verbose
start deploytool
step2 新建一个应用。
依次点击【 File 】à【 new 】à【 Application 】,选择应用的目录,输入应用的名称,如图 1 所示。
图 1 新建一个应用

step3 把资源适配器添加到应用中
依次点击【 File 】→【 new 】→【 Resource Adapter 】,在第一个窗口点击【 next 】,然后把资源适配器的类添加进来,然后点击【 next 】,如图 2 所示。
图 2 添加资源适配器相关的类

在下一个窗口指定资源适配器的相关接口和实现类,如图 3 所示。
图 3 指定资源适配器的相关接口和实现类

然后点击【 vsersion information 】按钮,输入版本相关的信息,完成后,点击【 next 】。
在下一个窗口为连接工厂添加两个属性,然后点击【 next 】,它们的名称和值如图 4 所示。
图 4 为连接工厂添加属性

在解下来的窗口直接点击【 next 】,最后将生成部署代码,点击【 finish 】。
Step4 把 EJB 组件添加到 J2EE 应用中
【 File 】→【 new 】→【 Enterprise Bean 】,然后把 EJB 组件相关的类添加进来,如图 5 所示。
图 5 添加 EJB 组件相关的类

接下来的窗口指定 Bean 的类型为无状态会话 Bean,实现类为 DemoEJB,远程接口为 Demo,Home 接口为 DemoHome,然后在接下来的窗口直接点击【 Next 】,直到出现资源工厂引用窗口,添加一个资源工厂引用,它的名字为"eis/DemoEISFactory",类型是"javax.resource.cci.ConnectionFactory",如图 6 所示。
图 6 为 EJB 添加资源引用

然后点击【 finish 】。
Step5 新建一个 Web 组件,把 test.jsp 测试页面添加进来。
Step6 在部署工具中指定 EJB 的 JNDI 名字为"ejb/demo"。
Step 7 指定 Web 组件的 Context(上下文)为"/resource"。
Step8 检查装配的描述是否正确,选中 resource 应用,然后点击工具栏 图标即可。
Step9 部署,选中 resource 应用,然后点击工具栏 ,在弹出的对话框点击【 finish 】即可。
Step10 部署成功后,把资源适配器添加到对应的应用服务器,使其运行。如图 7 所示,选择 localhost,点击【 new 】。
图 7 把资源适配器添加到服务器

然后指定连接工厂的 JNDI,如图 8 所示。
图 8 指定连接工厂的 JNDI

部署成功后,启动 EIS 服务器,EIS 服务器通过执行 src/eis-server/run.bat 进行启动,然后就可以进行测试了,在浏览器里输入:
http://localhost:8000/resource/test.jsp
进行测试。如果一切顺利,将在页面中返回测试的结果,如图 9 所示。
图 9 测试资源适配器

在测试时,通用可以看到 EIS 服务器也输出了类似以下的信息:
启动服务 .... 监听客户端连接 ... 接收到一个连接监听客户端连接 ... 接收到以下输入 : hellking
在 IBM WebShpere5.0 下部署连接器和 J2EE 应用
step1 启动应用程序组装器,打开需要装配的 J2EE 应用,如图 10 所示。
图 10 打开需要装配的 J2EE 应用

step2 选中 DemoEJB,点击【绑定】选项卡,输入 DemoEJB 的 JNDI 名字,然后点击【应用】,如图 11 所示。
图 11 确定 DemoEJB 的 JNDI 名字

step3 其它的值都默认,然后保存更改。
Step4 生成部署代码。顺次点击【文件】→【生成部署代码】,在弹出的对话框里点击【现在生成】。如图 12 所示。
图 12 生成部署代码

注意生成代码时应该是没有错误的,如果有错误,请参考对应的错误信息。
Step5 启动 IBM Websphere 服务器,在浏览器里输入:
http://localhost:9090/admin
进入管理控制台。
Step6 部署 J2EE 应用。
选择【应用程序】→【安装新的应用程序】,浏览到刚才生成的部署代码,如图 13 所示,然后点击【下一步】。
图 13 安装应用程序第一步

在接下来的几个窗口直接点击【下一步】,直到出现如图 14 所示的窗口,在这个窗口中指定映射资源引用到资源的 JNDI 名字,这个是"eis/DemoEISFactory"。
图 14 指定映射资源引用到资源的 JNDI 名字

其它的步骤全部默认即可,配置完成后,保存配置。
Step7 启动刚部署的 J2EE 应用
顺次选择【应用程序】à【企业应用程序】,然后选中刚部署的程序,点击【启动】。
Step8 为资源适配器指定 J2C 连接工厂
选中刚才部署的 J2EE 应用,顺次选择【连接器模块】→【 demo.rar 】→【 J2C 连接工厂】,新建一个 J2C 连接工厂,它的名称为 DemoEISFactory,JNDI 名称为"eis/DemoEISFactory",其它默认,然后点击确定。最后别忘了保存配置。
Step9 重新启动应用服务器,启动 EIS 服务(src/eis-server/run.bat),在浏览器里输入:
http://localhost:9080/resource/test.jsp?name=hellking
进行测试,如果测试成功,那么结果和图 9 一样。
JBOSS 虽然没有装配工具和部署控制台,但是在 JBOSS 下部署 J2EE 应用和资源适配器同样非常方便,JBOSS 支持及时开发、及时部署的方式,当把要部署的应用拷贝到 JBOSS 的部署目录下,JBOSS 应用服务器会自动部署它。
在 JBOSS 下部署应用时,可以不打包,而是直接 J2EE 应用放在名称为 ***.jar、***.ear 的文件夹下。如图 15 所示。
图 15 JBOSS 下的 J2EE 应用的结构

Step1 手工编写资源适配器的部署描述符,如例程 5 所示。
例程 5 JBOSS 下的资源适配器的部署描述符
<server>
<mbean code="org.jboss.resource.connectionmanager.NoTxConnectionManager"
name="jboss.jca:service=NoTxCM,name=DemoRA">
<depends>jboss.jca:service=RARDeployer</depends>
<depends optional-attribute-name="ManagedConnectionFactoryName">
<mbean code="org.jboss.resource.connectionmanager.RARDeployment"
name="jboss.jca:service=NoTxDemo,name=DemoRA">
<depends optional-attribute-name="OldRarDeployment">
jboss.jca:service=RARDeployment,name=DemoRA
</depends>
<attribute name="JndiName">NoTransDemo</attribute>
</mbean>
</depends>
<depends optional-attribute-name="ManagedConnectionPool">
<mbean code="org.jboss.resource.connectionmanager.JBossManagedConnectionPool"
name="jboss.jca:service=NoTxPool,name=DemoRA">
<attribute name="MinSize">0</attribute>
<attribute name="MaxSize">50</attribute>
<attribute name="BlockingTimeoutMillis">5000</attribute>
<attribute name="IdleTimeoutMinutes">15</attribute>
<attribute name="Criteria">ByContainer</attribute>
</mbean>
</depends>
<depends optional-attribute-name="CachedConnectionManager">
jboss.jca:service=CachedConnectionManager
</depends>
<depends optional-attribute-name="JaasSecurityManagerService">
jboss.security:service=JaasSecurityManager
</depends>
</mbean>
</server>
|
注意上面的两个黑体字,name=DemoRA,这里的 DemoRA 必须和资源适配器部署描述符 ra.xml 中的"DemoRA"保持一致,NoTransDemo 是使用这个资源适配器的 JNDI 名字,使用"java:/ NoTransDemo"来引用它。把这个文件保存为 hellkingjca-service.xml。
Step2 手工编写 EJB 的部署描述符 jboss.xml。
并且在部署描述符里指定对资源适配器的引用。如例程 6 所示。
例程 6 在 EJB 的描述中指定对资源适配器的引用
<?xml version="1.0"?>
<jboss>
<secure>false</secure>
<container-configurations />
<resource-managers />
<enterprise-beans>
<session>
<ejb-name>DemoEJB</ejb-name>
<jndi-name>ejb/demo</jndi-name>
<resource-ref>
<res-ref-name>eis/DemoEISFactory</res-ref-name>
<jndi-name>java:/NoTransDemo</jndi-name>
</resource-ref>
</session>
</enterprise-beans>
</jboss>
|
注意对资源适配器引用的 JNDI 名字,它必须和 hellkingjca-service.xml 的指定的 JNDI 名字一致。把这个文件保存在 resource.ear/hello.jar/META-INF/ 目录下。
Step 3 部署,把 resource.ear 文件夹和 hellkingjca-service.xml 拷贝到 %JBOSS_HOME%\\server\\default\\deploy\\ 目录下。启动 JBOSS,部署就会自动完成。
Step4 测试,启动 JBOSS 和 EIS 服务(src/eis-server/run.bat),在浏览器里输入:
http://localhost:8080/resource/test.jsp?name=hellking
即可进行测试,如果一切成功,那么结果应该和图 9 一样。
在 BEA Weblogic8.1 下部署连接器和 J2EE 应用
step1 启动 Weblogic Builder,打开待装配的应用(resource.ear)。
step 2 指定 DemoEJB 的 JNDI 名字。
选中 DemoEJB,点击【 General 】选项卡,在 JNDI name 中输入"ejb/demo",如图 16 所示。
图 16 在 Weblogic Builder 里指定 EJB 的 JNDI 名字

step3 指定资源适配器连接工厂的名字和 JNDI 名字:
选择 DemoRA,点击【 Weblogic Settings 】选项卡,找到"Connection Factory name"标签,在下面的输入框输入"DemoEISFactory",然后找到"JNDI name"标签,在下面的文本框输入"eis/DemoEISFactory",它是这个连接工厂绑定的 JNDI 名字。
Step4 指定 EJB 对资源适配器连接工厂的引用:
点击 DemoEJB,选择 Resource,再点击【 Resource References 】选项卡,编辑这个引用的属性,把 JNDI 名字改为"eis/DemoEISFactory",如图 17 所示。
图 17 确定 EJB 引用的资源适配器的连接工厂的名字

step5 其它的值都默认,保存这个应用,weblogic Builder 会自动生成可以部署的代码。
Step 8 部署
启动 Weblogic 引用服务器,在浏览器里输入:
http://localhost:7001/console
输入用户名和密码进行验证,进入控制台,顺次点击【 mydomain 】à【 Applications 】à【 Deploy a new Application 】à【 upload your file(s) 】,然后上载刚生成的可部署代码。上载完成后,选择这个上载的文件,点击【 Contnue 】,在接下来的窗口点击【 Deploy 】,如果出现图 18 所示的窗口,表示部署成功了。
图 18 在 Weblogic 下部署成功

Step 9 测试,部署完成后,启动 EIS 服务(src/eis-server/run.bat),然后在浏览器里输入:
http://localhost:7001/resource/test.jsp
进行测试,如果一切顺利,获得的结果和图 9 一致。
从以上不同的部署过程可以看出,J2EE 应用和资源适配器在不同的服务器平台下具有良好的可移植性。对于 EJB 组件,需要在应用服务器特有的部署描述符中指定 JNDI 名字。至于 EJB 对资源适配器连接工厂的引用方式的指定,它们又有所差别,有的在装配时就指定资源适配器连接工厂的 JNDI 名字,这种方式下,应用服务器启动或者资源适配器部署时,它的连接工厂就绑定到 JNDI 名称空间,比如 Weblogic 就是这样;而有的应用服务器需要在部署时为资源适配器指定连接工厂的 JNDI 名字,然后再在 EJB 的部署中进行映射,比如 Websphere 就是这种方式。
- Connect the enterprise with the JCA:
http://www.javaworld.com/javaworld/jw-11-2001/jw-1121-jca.html
- J2EE 连接器技术规范:
http://java.sun.com/j2ee/connector/
- 《为 EAI 选择 JCA、JMS 或 Web 服务》
http://www-900.ibm.com/developerWorks/cn/webservices/ws-jcajms/index.shtml
- http://www.bea.com
- http://www.jboss.org
- http://www.ibm.com/software/
陈亚强:北京华园天一科技有限公司高级软件工程师,擅长J2EE技术,曾参与多个J2EE项目的设计和开发,对Web服务有很大的兴趣并且有一定的项目经验。热爱学习,喜欢新技术,曾参与多本图书的写作。好交朋友,您可以通过 cyqcims@mail.tsinghua.edu.cn 和他联系。