第 2 章 Enterprise JavaBeans
2.5 如何开发 EJB(二)
第一部分 JSP 技术与 J2EE 技术
2.5 如何开发 EJB(二)
2.5.1 运行环境配置
本节我们接着介绍如何开发EJB 及如何配置 EJB 组件的运行环境 在 JBuilder4 的主 窗口中 左侧 右键单击 HelloWorldHome.java 选择 Properties…. 选择 Build Tab VisiBroker 在 Generate IIOP 前面的小方框前打勾 如图 2.12 所示
图2.12 配置 Java2IIOP 的属性
单击OK 然后选择 Run Configuration….. 如图 2.13 所示
图2.13 配置 EJB 的运行环境
在图2.13 中 选中<Default> 单击 OK 即可 这样 EJB 的运行环境就算配置好了
第 2 章 Enterprise JavaBeans
2.5.2 创建 EJB Container
本小节中 我们将创建一个EJB Container 方法很简单 只需要 Make Project 就可以 了 JBuilder4 会根据 Remote Interface 和 Home Interface 自动产生十几个 Java 类文件 这些 文件的名字如下所示
HelloWorldRemoteHelper.java HelloWorldRemoteHolder.java HelloWorldHomePOA.java _HelloWorldHome_Stub.java
HelloWorldRemotePOAInvokeHandler.java HelloWorldRemoteOperations.java
HelloWorldRemotePOA.java _HelloWorldRemote_Stub.java HelloWorldHomeHelper.java HelloWorldHomeHolder.java
HelloWorldHomePOAInvokeHandler.java HelloWorldHomeOperations.java
这些文件的作用就是产生Home Object 和 EJB Object 须知 EJB Container 就是由 Home Object 构 成 的 在 上 面 列 举 的 文 件 中 以 _HelloWorldHome_Stub.java 和 _HelloWorldRemote_Stub.java 最为重要 前者实现了 Home Interface 所定义的 create()方法 后者实现了Remote Interface 所定义的商业方法 在本例中是 getMessage()方法 这两个文 件的源代码如程序清单2.11
程序清单 2.11(_HelloWorldHome_Stub.java) package helloworld;
public class _HelloWorldHome_Stub extends javax.ejb._EJBHome_Stub implements HelloWorldHome HelloWorldHomeOperations {
final public static java.lang.Class _opsClass = helloworld.HelloWorldHomeOperations.class;
public java.lang.String[] _ids () {
return __ids;
}
private static java.lang.String[] __ids = {
"RMI:helloworld.HelloWorldHome:0000000000000000"
"RMI:javax.ejb.EJBHome:0000000000000000"
};
第一部分 JSP 技术与 J2EE 技术
public helloworld.HelloWorldRemote create ()
throws java.rmi.RemoteException javax.ejb.CreateException {
org.omg.CORBA.portable.OutputStream _output = null;
org.omg.CORBA.portable.InputStream _input = null;
helloworld.HelloWorldRemote _result;
try
{
_output = this._request("create" true);
_input = this._invoke(_output);
//FIX: Cannot use helper class //because of potential stub downloading _result= (helloworld.HelloWorldRemote)
catch (org.omg.CORBA.portable.ApplicationException _exception)
{
final org.omg.CORBA.portable.InputStream in = _exception.getInputStream();
java.lang.String _exception_id = _exception.getId();
if (_exception_id.equals("IDL:javax/ejb/CreateEx:1.0")) {
throw new java.rmi.UnexpectedException
("Unexpected User Exception: " + _exception_id);
final org.omg.CORBA.portable.ServantObject _so = _servant_preinvoke("create" _opsClass);
catch (org.omg.CORBA.portable.UnknownException ex) {
if (ex.originalEx instanceof java.lang.RuntimeException) {
throw (java.lang.RuntimeException) ex.originalEx;
}
else if (ex.originalEx instanceof Exception) {
throw new java.rmi.ServerException(ex.getMessage() (java.lang.Exception)ex.originalEx);
}
catch (org.omg.CORBA.SystemException ex) {
throw javax.rmi.CORBA.Util.mapSystemException(ex);
} } }
在 程 序 清 单 2.11 中 实 现 了 create() 方 法 该 方 法 是 在 Home Interface(HelloWorldHome.java)中声明的 该方法的返回值为 HelloWorldRemote 对象
程序清单 2.12(_HelloWorldRemote_Stub.java) package helloworld;
public class _HelloWorldRemote_Stub extends javax.ejb._EJBObject_Stub implements HelloWorldRemote HelloWorldRemoteOperations {
final public static java.lang.Class _opsClass = helloworld.HelloWorldRemoteOperations.class;
public java.lang.String[] _ids () {
return __ids;
}
private static java.lang.String[] __ids = {
"RMI:helloworld.HelloWorldRemote:0000000000000000"
"RMI:javax.ejb.EJBObject:0000000000000000"
};
public java.lang.String getMessage () throws java.rmi.RemoteException {
User Exception: " + _exception_id);
}
catch (org.omg.CORBA.portable.UnknownException ex) {
if (ex.originalEx instanceof java.lang.RuntimeException) {
throw (java.lang.RuntimeException) ex.originalEx;
}
else if (ex.originalEx instanceof Exception) {
catch (org.omg.CORBA.SystemException ex) {
throw javax.rmi.CORBA.Util.mapSystemException(ex);
} } }
在程序清单 2.15(_HelloWorldRemote_Stub.java)中 实现了商业方法 getMessage() 方法 该方法是在Remote Interface(HelloWorldRemote.java)中声明的 至于实现的细节 我 们就不在这里讨论了
2.5.3 发布 EJB 服务
经过上面这么多步的工作 EJB 组件的开发应该告一段落了 下面我们应该发布 EJB 服务 因为我们还不知道EJB 能不能够按照我们的设计正确运行 所以暂时不把 EJB 发布 到真正的 EJB Server 上去 而是使用 IAS 服务器所带的 Smart Agent 作为临时的 EJB Server/Container 发布我们刚刚编写好的 EJB 以便进行测试 测试成功以后再把它分发 到真正的EJB Server 上去
首先需要运行Smart Agent 即 osagent.exe 程序 osagent.exe 程序在 IAS 安装目录的 bin 文件夹内
然后转回到JBuilder4 的主界面 选择 Run Run Project JBuilder4 首先会编译 EJB 然后把它分发到Smart Agent 中 JBuilder4 会出现类似于下面的提示信息
Inprise EJB Container
java class path : D:\Inprise\AppServer\lib\navigator.jar : D:\Inprise\AppServer\lib\vbdev.jar
Initializing JSS...Developer's License (no connection limit) Copyright (c) 1996-2000 Inprise Corporation. All rights reserved.
License for JDataStore development only - not for redistribution Registered to:
Inprise Application Server Development Licensee Inprise Application Server Customer
... done
Initializing JDB... done Initializing EJBs... done
第一部分 JSP 技术与 J2EE 技术
Container [ejbcontainer] is ready EJB Container Statistics
========================
Time Tue Mar 16 00:00:21 CST 1999 Memory (used) 1714 Kb (max 1714 Kb) Memory (total) 2680 Kb (max 2680 Kb)
Memory (free) 36.0%
---
Home HelloWorld Total in memory 0
Total in use 0
========================
如果出现了上面的信息 那么就表明 这个HelloWorld EJB 已经成功地部署到 Smart Agent 中了 下面我们应该编写一个简单的 EJB 客户端程序来测试这个 EJB 了
2.5.4 测试 EJB 服务
本小节我们将介绍如何利用 JBuilder4 来编写一个 EJB 客户端测试我们刚才所发布的 EJB 在 JBuilder4 中 选择 File New… Enterprise Tab EJB Test Client OK 将出现如 图2.14 所示的窗口
图2.14 JBuilder4 的 EJB Test Client Wizard 对话框
在图2.14 中 我们把 Class 框的缺省值 HelloWorldTestClient1 改为 HelloWorldTestClient 其他的一切都不要改动 单击OK 回到 JBuilder4 的主界面 JBuilder4 为我们自动创建了 HelloWorldTestClient.java 程序 编辑 HelloWorldTestClient.java 使得它如下面的程序清单
第 2 章 Enterprise JavaBeans
2.13 所示 其中黑体的部分是我们自己加上去的 其余的部分是 JBuilder4 自动产生的 程序清单 2.13
package helloworld;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
/**
* Title:HelloWorldTestClient.java
* Description:test the EJB
* Copyright: Copyright (c) 1999
* Company:Peking University
* @author:fancy
* @version 1.0
*/
public class HelloWorldTestClient {
private static final String ERROR_NULL_REMOTE = "Remote interface reference is null.It must be created by calling one of the Home interface methods first.";
private static final int MAX_OUTPUT_LINE_LENGTH = 50;
private boolean logging = true;
private HelloWorldHome helloWorldHome = null;
private HelloWorldRemote helloWorldRemote = null;
/**Construct the EJB test client*/
public HelloWorldTestClient() {
long startTime = 0;
if (logging) {
log("Initializing bean access.");
startTime = System.currentTimeMillis();
}
try {
//get naming context
Context ctx = new InitialContext();
//look up jndi name
Object ref = ctx.lookup("HelloWorld");
//cast to Home interface
helloWorldHome = (HelloWorldHome)
PortableRemoteObject.narrow(ref HelloWorldHome.class);
第一部分 JSP 技术与 J2EE 技术
HelloWorldRemote hwr=create();
String msg=hwr.getMessage();
// Methods that use Home interface methods to generate a Remote interface reference //---
public HelloWorldRemote create() {
helloWorldRemote = helloWorldHome.create();
if (logging)
// Methods that use Remote interface methods to access data through the bean //---
System.out.println("Error in getMessage(): " + ERROR_NULL_REMOTE);
return returnValue;
if (message.length() > MAX_OUTPUT_LINE_LENGTH) {
System.out.println("-- " +
message.substring(0 MAX_OUTPUT_LINE_LENGTH) + " ...");
}
HelloWorldTestClient client = new HelloWorldTestClient();
// Use the client object to call one of the Home interface wrappers // above to create a Remote interface reference to the bean.
// If the return value is of the Remote interface type you can use it // to access the remote interface methods. You can also just use
// the client object to call the Remote interface wrappers.
} }
HelloWorldTestClient.java 的运行流程如下 首先调用构造函数 HelloWorldTestClient() 在构造函数中 先是使用lookup()方法 定位 Home Interface 的位置 获取 Home Object 亦即helloWorldHome 然后调用 create()方法 该方法返回一个 Remote 对象(hwr) 接下来 调用hwr 对象的 getMessage()方法 这其实是调用 HelloWorld EJB 的商业方法 getMessage() getMessage()方法的返回值为 Hello World 我们把返回值赋给一个字符串 然后输出
客户端程序的运行方法如下
在JBuilder4 的主界面中 左侧 右键单击 HelloWorldTestClient.java Run 运行输出
第 2 章 Enterprise JavaBeans
如下所示
-- Initializing bean access.
-- Calling create() -- Succeeded: create() -- Execution time: 380 ms.
-- Return value from create(): Stub[repository_id=RMI ...
Hello World
-- Succeeded initializing bean access.
-- Execution time: 10660 ms.
读者也许已经发现了 这个EJB 客户端程序的输出结果显示 调用这个 HelloWorld EJB 组件的商业方法(getMessage())花费了很长的时间 一共是 10660ms 亦即 10.66 秒 这并 非是 EJB 组件的运行效率不佳 而是因为这个 EJB 组件的服务端(SmartAgent)和客户端 (JBuilder4)都在笔者的电脑上面运行 与此同时 笔者的电脑上还运行了一个数据库服务器 (MS SQL Server) 一个 Web 服务器(IAS) 还有一个字处理软件(Word) 系统资源有限 所 以运行速度才这么慢 如果EJB Server 在别的电脑上运行 EJB Client 在本地机上运行 真 正实现了分布式处理的梦想 那时候EJB 组件的运行效率还是相当高的 闲话少说 现在 转入正题 由上面的运行结果可见 HelloWorld EJB 已经成功发布 成功运行了 怎么样 是不是很简单呢?下面我们该把这个 EJB 正式部署到商业服务器上去了 我们首先选用的服 务器是IAS4.1
2.5.5 打包分发 EJB 服务
在这一小节中 将介绍如何把上面编写好的HelloWorld EJB 分发到 IAS 服务器上 作 为一项服务发布
启动IAS 服务器
第一步是启动 IAS 服务器 你可以从开始菜单启动 IAS 服务器 也可以进入 IAS 的 bin 目录下面 双击执行 ias.exe 程序 这样也可以运行 IAS 服务器 当出现了类似于下面 的字样 那说明IAS 服务器已经成功了
Inprise Application Server 4.1.1
Copyright (c) 1999-2000 Inprise Corporation. All Rights Reserved.
Portions Copyright (c) 1997-1999 Sun Microsystems Inc. All Rights Reserved.
Server rainbow Started 运行EJB Deployment
在JBuilder4 的主运行界面中 选择 Tools EJB Deployment…. 出现了如图 2.15 所示 的窗口
第一部分 JSP 技术与 J2EE 技术
图2.15 JBuilder4 的 IAS EJB Deployment Wizard 窗口
在图2.15 中 有两个选项 Quick 和 Advanced Quick 选项适合于发布单个 EJB 组件 而 Advanced 选项适合于发布多个 EJB 组件 在这个例子中 我们选择 Quick 然后单击 Next 出现了如图 2.16 所示的窗口
图2.16 JBuilder4 的 IAS EJB Deployment Wizard 窗口 选择需要发布的EJB 组件
在这一步 我们将选择需要发布的EJB 组件和 EJB Container 如图 2.16 所示 在图2.16 中 Jar file 一栏用于填写你所希望发布的 EJB 组件所在的 jar 文件的路径
第 2 章 Enterprise JavaBeans
你可以单击Browse 按钮修改它 在 Container 一栏 列出了目前可用的 EJB Container 缺 省状态下是ias://localhost/ejbcontainer 如果这一栏为空 那么请确定 IAS 服务器是否已经 运行了 如果IAS 服务器不是出于运行状态 那是没有办法分发 EJB 服务的
设置停当后 单击Next 出现如图 2.17 所示的窗口 EJB 组件分发成功
如果你上面的步骤没有出什么漏子的话 那么你将会看到如图2.17 所示的画面 EJB 组件已经分发成功了 在图2.17 中 单击 Finish 按钮 关闭这个窗口 回到 JBuilder4 的主 界面 再次运行EJB 的客户端程序(右键单击 HelloWorldTestClient.java Run) 我们会看到 这次的运行结果和上面使用SmartAgent 作为 EJB Container 得到的结果几乎没有不同 如 果有不同 那就是运行所耗费的时间不同
到此为止 我们已经成功地开发了一个EJB 组件 成功地测试了这个 EJB 组件 并且 成功地把它发布到一个EJB Container(IAS)中去了 我们是否应该到此结束呢?不!事情还没 有结束呢 我们应该选用一个更好的EJB Container 把 EJB 组件发布到哪里去 IAS 服务 器作为EJB Container 还不是最好的选择 对于 EJB Container BEA 的 WebLogic IBM 的 WebSphere 才是更好的选择 好了 你现在可以关闭 JBuilder4 进入下一小节的学习 在 下一小节 我们将介绍如何把EJB 组件分发到 WebLogic 服务器上 以 WebLogic 服务器作 为EJB 组件的 EJB Server/Container
图2.17 EJB 组件分发成功了
第一部分 JSP 技术与 J2EE 技术
2.5.6 使用 WebLogic 服务器分发 EJB 服务
在本小节 我们将介绍如何把使用JBuilder4 开发的 EJB 组件分发到 WebLogic 服务器 上 笔 者 认 为 WebLogic 服 务器 是 最好 的商 用 J2EE 运 行环 境 也 是 最 好 的 EJB Server/Container 这是有一定根据的 例如 WebLogic 支持最新的 EJB 技术规范 WebLogic 的市场占有率最高等 我们之所以首先介绍如何把EJB 组件分发到 IAS 服务器上面去 那 是因为JBuilder4 和 IAS 都是 Borland 公司的产品 利用 JBuilder4 开发的 EJB 组件最容易 发布到IAS 服务器中 并不是 IAS 服务器最适合做 EJB Server/Container
现在让我们开始吧 安装WebLogic 服务器
第一步应该安装 WebLogic 服务器 笔者推荐使用 WebLogic 5.1/6.0 你可以到 www.weblogic.com 去下载一个试用版 然后配置好 WebLogic 服务器 使它支持 JSP 关于 如何配置WebLogic 服务器的方法 请参考本书的附录 3
封装EJB 组件
第二步是把 EJB 组件所用到的 class 文件都打包到一个 jar 文件中 如果我们是使用 JBuilder4 开发的 EJB 组件 那么在编译 EJB 工程的时候 JBuilder4 会自动把所有相关的文 件都打包到一个jar 文件中 这个 jar 文件的名字就是工程的名字
转移jar 文件
把jar 文件从 JBuilder4 的开发目录转移到 WebLogic 服务器安装目录的 myserver 文件 夹的根目录下面 这样做的目的是为了便于管理EJB 组件 如果略过这一步也可以
配置EJB Deployer
从开始菜单运行WebLogic 附带的 EJB Deployer 如图 2.18 所示
从开始菜单运行WebLogic 附带的 EJB Deployer 如图 2.18 所示