第二部分: 确定 Enterprise JavaBeansTM 远程接口
在本步骤的操作中,您可创建一个Enterprise JavaBeans 远程接口。
- 阅读下面说明。
- 按照提示,将示例中代码保存为一个文件。
远程接口是Enterprise JavaBeans 的客户视图,Enterprise JavaBeans 开发者的任务就是通过 JavaTM RMI (远程方法调用)语法对该远程接口进行定义。接口的代码由Enterprise JavaBeans 容器工具供应商负责生成。
注意:什么可以在接口中被定义是有限制的。欲了解这方面详情,请参阅Enterprise JavaBeans 技术要求,第 16 部分。其中重要的一点就是,所使用的所有对象、参数、返回值及异常事件都应当是“Java 到 IDL 映射技术规范”中指定的有效类型。
以下的简化DemoBean 程序是远程接口的source(源程序)。请将其保存到名称为 Demo.java 的文件中。
/**
* Demo -- this is the "remote" interface of
* our enterprise JavaBean, it
* defines only one simple method called
* demoSelect(). As this is meant to be
* the simplest of examples demoSelect()
* never goes to a database, it just
* returns a string
*
* Note: The implementation of this interface is
* provided by the container tools
* but the demoSelect() method and any
* other methods in this interface
* will need to have equivalent
* implementations in the demobean.java
* which is supplied by the bean writer
* ..i.e., you!
*/
package ejb.demo;
import java.rmi.RemoteException;
import java.rmi.Remote;
import javax.ejb.*;
public interface Demo extends EJBObject, Remote {
// NB this simple example does not even do a
// lookup in the database
public String demoSelect() throws RemoteException;
}
第三部分: 确定Home接口
session bean 的home接口提供了一种机制,通过这种机制,容器就可为客户创建新的 session beans。与远程接口相同,本地接口也是由 bean 开发者通过 RMI 语法来定义,并且也是利用容器供应商提供的工具来实现的。从这一点上讲,几乎不需程序员编写任何代码——除了做一些说明性的工作。
- 阅读下面有关home接口的说明,同时应注意代码中的注释语句。
- 将示例中的源程序代码保存为指定文件,然后转到下一步。
这里是 DemoBean EJB 的源程序代码:
/**
* DemoHome.java - This is the Home interface it must
* extend javax.ejb.EJBHome and define one or more
* create() methods for the bean.
*
* Note: The implementation of this interface is
* generated by the container tools.
*/
package ejb.demo;
import javax.ejb.*;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.*;
/**
* This interface is extremely simple it declares only
* one create method.
*/
public interface DemoHome extends EJBHome {
public Demo create() throws CreateException,
RemoteException;
}
第四部分: 编写 Enterprise JavaBeanTM 类
在这一步骤中,将向您介绍应用程序(商业逻辑)代码的编写过程。目前为止,您已对接口作了声明,而其代码将由容器工具完成,此处仅介绍 JavaBean 功能性代码的编写。
对于 bean 的实现,重要一点就是您只需编写极少量的代码。大部分代码已简化为实现Enterprise JavaBeans 技术规范中规定的方法。绝大部分的实现工作由模板和工具完成,使您的工作变得非常轻松。这与实现工具在 GUI beans 环境下的应用相类似。
- 阅读下面有关
DemoBean 代码的说明,同时请注意代码示例中的注释语句,尤其是标题为“Business Logic”的注释。
- 将例子中的源程序代码保存为指定的文件。然后,进行下一步。
这里是 DemoBean Enterprise JavaBeans 的源代码 DemoBean.java:
/**
* DemoBean -- This is implemented by the EnterPrise
* Bean author This class must extend
* javax.ejb.SessionBean and implement
* the methods in this interface as well as providing
* the implementation of the business methods.
*
*/
package ejb.demo;
import javax.ejb.*;
import java.io.Serializable;
import java.util.*;
import java.rmi.*;
public class DemoBean implements SessionBean {
static final boolean verbose = true;
private transient SessionContext ctx;
private transient Properties props;
// Implement the methods in the SessionBean
// interface
public void ejbActivate() {
if (verbose)
System.out.println("ejbActivate called");
}
public void ejbRemove() {
if (verbose)
System.out.println("ejbRemove called");
}
public void ejbPassivate() {
if (verbose)
System.out.println("ejbPassivate called");
}
/**
* Sets the session context.
*
* @param SessionContext
*/
public void setSessionContext(SessionContext ctx) {
if (verbose)
System.out.println("setSessionContext called");
this.ctx = ctx;
props = ctx.getEnvironment();
}
/**
* This method corresponds to the create method in
* the home interface DemoHome.java.
* The parameter sets of the two methods are
* identical. When the client calls
* DemoHome.create(), the 容器 allocates an
* instance of the EJBean and calls ejbCreate().
*/
public void ejbCreate () {
if (verbose)
System.out.println("ejbCreate called");
}
/**
* **** HERE IS THE BUSINESS LOGIC *****
* Do the demoSelect() but don't even go to
* the database in this eg but instead just
* return a String.
* The really BIG thing to notice here is that
* this is the only code we have invented at all
* the rest of the code has been declarations
* or simply implementing methods which are
* part of the EJB interfaces and in this example
* are not even used.
*/
public String demoSelect()
throws RemoteException
{
return("hello world");
}
}
第五部分: 创建ejb-jar 文件
Enterprise JavaBeans 的最大优势,就在于它可以对服务器端的逻辑进行打包和拆分,这种可移植性风格与 GUI 组件相同。在该操作步骤中,需要对源文件进行编译。然后,将其打包为 ejb-jar 文件。按照下面的四个步骤操作,就可以创建 Demo.jar ejb-jar 文件。该文件可在Enterprise JavaBeans 容器内配置或安装。
1. .java 文件的编译
- 创建DeploymentDescriptor(部署描述文件)
- manifest的创建
- 应保证包含所有的部件
- 创建
ejb-jar 文件
1. .java 文件的编译
在刚创建的文件,即home及远程接口、Enterprise JavaBeans bean 上,运行 javac。
javac ejb/demo/DemoHome.java
javac ejb/demo/Demo.java
javac ejb/demo/DemoBean.java
2. 创建Deployment Descriptor(部署描述文件)
注意:部署是Enterprise JavaBeans 中的术语,指的是在Enterprise JavaBeans 容器中安装Enterprise JavaBeans 组件。
部署描述文件的作用是在部署之前,允许您通过 bean的程序对 bean 的诸多属性进行定制。在Enterprise JavaBeans 技术规范(15.2 部分)中,部署描述文件被描述成一个javax.ejb.deployment.SessionDescriptor 或javax.ejb.deployment.EntityDescriptor的实例。在 DemoBean 的例子中,是 javax.ejb.deployment.SessionDescriptor 的实例。以下是一个输入到 WebLogic的实用工具的文本文件,介绍创建该部署描述文件的过程。
值得注意的是,对创建部署描述文件的方法没有具体的规定。因此,Enterprise JavaBeans 的创建和部署工具可能会在外观和感觉上各不相同,这不会对 beans 本身的跨平台部署能力产生影响。
在下面的例子中,将继续通过 WebLogic 工具创建部署描述文件。BEA Weblogic 服务器工具可为用户提供命令行及图形界面(GUI)配置工具。通过命令行工具对Enterprise JavaBean 进行配置时,需执行以下命令:
java weblogic.ejb.utils.DDCreator -dir ejb/demo ejb/demo/DeploymentDescriptor.txt
这样,就可以在目录 ejb/demo 下生成一个 DemoBeanDD.ser 文件。
以下是一个输入到 BEA Weblogic 工具的文本文件实例 DeploymentDescriptor.txt (源程序):
(SessionDescriptor
; This file must start with SessionDescriptor or
; EntityDescriptor
; Indicate the name which the bean will be bound
; into the JNDI name as
beanHomeName demo.DemoHome
; The enterprise Java Bean class (see step 4)
enterpriseBeanClassName ejb.demo.DemoBean
homeInterfaceClassName ejb.demo.DemoHome
; The home interface implemented by a class
; generated by the container provided tools
; see step 3
remoteInterfaceClassName ejb.demo.Demo
; See step 2
isReentrant false
; Always false for session beans
stateManagementType STATELESS_SESSION
; Either STATELESS_SESSION or STATEFUL_SESSION.
; DemoBean is a stateless session bean
sessionTimeout 5
; seconds
(controlDescriptors
; This section decides the run-time properties when
; a method is called. The DEFAULT sub-section applies
; to all methods, but can be overridden on a per-method
; basis, similar to the "accessControlEntries" above.
(DEFAULT
isolationLevel TRANSACTION_SERIALIZABLE
transactionAttribute TX_REQUIRED
runAsMode CLIENT_IDENTITY
)
; end isolationLevel
)
; end controlDescriptors
(environmentProperties
maxBeansInFreePool 100
)
; end environmentProperties
)
; end SessionDescriptor
注意:此处是以BEA Weblogic 服务程序为例作介绍的,其注释行以分号 (;) 作为开头。
3. manifest的创建
manifest是由 jar 应用程序自动生成的,但这需要一个模板。故需创建一个包含如下内容的文本文件(如,ejb/demo/manifest.txt)。如需了解该文本文件的使用,请参见下一章节的“bean 的打包”部分。
欲获取有关manifest文件的说明,请参见Enterprise JavaBeans 技术规范中的 15.3 部分。
Name: ejb/demo/DemoBeanDD.ser
Enterprise-Bean: True
4. 确保包含所有部件
以下是Enterprise JavaBeans 的开发者和提供者应提供的创建有效 ejb-jar 文件,即Enterprise JavaBeans bean,所需的各种部件:
- Enterprise bean 类 + 其它支持 bean 的各种类(步骤 4)。
- Enterprise bean 远程接口(步骤 2)。
- Enterprise bean home接口(步骤 3)。
- A deployment descriptor (部署描述文件)(参见以上说明)。
- 如 bean 需要,还应包含一个
java.util.Properties 的实例。
ejb-jar 文件中用来确定配置描述符的manifest(货单)文件。
欲了解更多详情,请参见Enterprise JavaBeans 技术规范,第 16 章。
Enterprise JavaBeans bean 提供商应将以上提及的所有类都包含在 ejb-jar 文件中。并且,绝大部分的容器和服务器提供商一般都会提供打包和配置工具。
manifest
manifest是由 jar 应用程序自动生成的,但这需要有一个模板。因此,应按以下说明创建一个文本文件(比如, ejb/demo/manifest.txt)。如需了解该文本文件的使用,请参见下一章节的“bean 的打包”部分。
欲了解manifest文件的有关说明,请参见Enterprise JavaBeans Specification,15.3 部分。
Name: ejb/demo/DemoBeanDD.ser
Enterprise-Bean: True
5. ejb-jar 文件的创建
在本例中,只需将所有的部件压缩为名为 Demo.jar 的一个文件。有理由相信,未来的工具会使打包及 ejb-jar 文件的创建变得更加简便。这就像 GUI 向导能够引导您进行相关的安装和检查一样容易。
比如,要创建一个名为 Demo.jar 的 ejb-jar 文件,假定压缩文件的所有部分均在名称为 ejb 的目录下。您所要做的只是在该目录下创建一个压缩文件。
注意:通过 m 参数,将文件压缩并以 ejb/demo/manifest.txt,以作为manifest模板。将文件manifest.txt 添加到该压缩文件中,这并不是必需的。
jar cvfm Demo.jar ejb/demo/manifest.txt ejb/demo/*.class \
ejb/demo/*.ser
检查 Demo.jar 文件的输出是否与下列文件相同:
jar tf Demo.jar
META-INF/MANIFEST.MF
ejb/demo/Demo.class
ejb/demo/DemoBean.class
ejb/demo/DemoHome.class
ejb/demo/DemoBeanDD.ser
从上面的例子可以看出,对于 ejb-jar 文件也没有什么特别的规定。
第六部分:部署DemoBean Enterprise JavaBean
在本步骤中,将在Enterprise JavaBeans 容器内安装 DemoBean Enterprise JavaBean。值得注意的一点,每个服务程序经销商都通过其指定的工具来完成其安装,并且日益完善其工具以适应安装的需要。
请按下面提示在 BEA Weblogic服务程序(已在步骤 1中安装)中安装 DemoBean:
BEA WebLogic 的部署
在 BEA WebLogic 目前版本的 Weblogic 服务程序中,部署Enterprise JavaBeans bean 就是意味着“将 bean 的类放到 Weblogic 服务程序能够找到的地方”。这并不是一件困难的工作,但也并不太简单。所以我们期望可以通过工具进一步简化这一过程,并使发生的一切更加明显。
- 生成Bean的实现
- 将
Demo.jar 添加到 Weblogic 服务程序的 CLASSPATH 中
- 对 weblogic.properties 文件进行编辑,使之包括新的Enterprise JavaBean
- 终止 Weblogic 服务程序,然后重新启动
注意: 在本例中,假定 Weblogic 服务程序已安装在目录 /export 下。
1.生成Bean的实现
这一步的任务是创建先前指定接口的实现,以及为 DemoBean 创建 BEA WebLogic-指定的类。注意这些不和你的Bean一起打包。创建的类,如本地及远程接口,也是支持通信协议所必需的。事实上,这些类是在部署期间创建的,而不是由 bean 提供者(程序员)编写的。这是Enterprise JavaBean 能够与协议无关的主要原因。
注意: 本步骤中,假定您已将 Weblogic 服务程序安装在 /export 目录下。如未安装在该目录下,请对其目标目录进行调整(即下面 –d 参数后面的部分)。
通过 BEA WebLogic 工具创建 DemoBean 的实现文件,需要运行以下程序:
java weblogic.ejbc -d /export/weblogic/classes ejb/demo/DemoBeanDD.ser
该应用程序创建与下面类名称相似的类,并将其保存在目录 /export/weblogic/classes 下。
ejb/demo/DemoBeanEOImpl.class
ejb/demo/DemoBeanHomeImpl.class
ejb/demo/Skel5k5x705r2x671nd1i1vy2v524ua5y.class
ejb/demo/Skel5q585f5sfzo601q4e725b233m5140.class
ejb/demo/Stub5k5x705r2x671nd1i1vy2v524ua5y.class
ejb/demo/Stub5q585f5sfzo601q4e725b233m5140.class
2. 将 Demo.jar 文件添加到 Weblogic 服务程序的 CLASSPATH 中
完成该任务有多种方法,但最简单的方法是将文件 Demo.jar 放在目录/export/weblogic/classes 下,再对 /export/weblogic/startWebLogic.sh 脚本文件进行编辑,使其包含文件 Demo.jar。
/export/weblogic/startWebLogic.sh
#!/bin/sh
#
# Shell script to manually start Weblogic
# Server on UNIX systems
CLASSPATH=$CLASSPATH:/export/weblogic/classes/Demo.jar
echo $CLASSPATH
java -ms16m -mx16m -verbosegc weblogic.Server
3. 对 weblogic.properties 文件的编辑
加入装载及启动新的Enterprise JavaBeans 的指令。
/export/weblogic/weblogic.properties
# # # # # # # # # # # # # # # # # # # # # # # # # #
# Weblogic Enterprise JavaBeans DEMO PROPERTIES
# -------------------------------------------------
# Uncomment the appropriate lines below and modify
# DBMS-related info and paths to match your particular
# installation.
#
# Deploys the Enterprise JavaBean examples.
Uncomment to use:
weblogic.ejb.deploy=\
/export/weblogic/classes/beanManaged.jar,\
/export/weblogic/classes/containerManaged.jar,\
/export/weblogic/classes/statefulSession.jar,\
/export/weblogic/classes/demo.jar
#
# weblogic.properties file continues below...
#
4. 终止及重新启动Weblogic 服务程序
您可通过 BEA Weblogic 工具来终止和重新启动 Weblogic 服务程序,在某环境下也可简单的将主 Weblogic 过程中断,再通过 /export/weblogic/startWebLogic.sh 脚本重新启动。欲知详情,参见 BEA Weblogic 工具文档。
第七部分:编写Enterprise JavaBean 客户程序
如果您顺利完成了步骤 1 到 6,DemoBean就应该已经在EJB Container中部署好了,并且DemoBean 可以接受客户对在远程接口中指定的任何方法的调用。
- 检查下面的客户代码。
- 将代码保存为指定的文件。
客户程序编写概述
在编写代码过程中,有一处是编写客户程序。除此之外,Enterprise JavaBeans 的bean 业务逻辑本身也需要填写。Enterprise JavaBeans bean 的客户程序可有多种形式:如 servlet、applet,或者也可能为 C/C++ 程序。下面的示例 DemoClient.java 就是由前面步骤创建的 DemoBean Enterprise JavaBean 的客户程序。关于本程序,需要注意的几点问题是:
- 创建 JNDI 初始环境(context)。
- 通过 JNDI,对Enterprise JavaBean 的home接口进行定位。
- 通过home接口,通知容器创建Enterprise JavaBean 实例。
- 远程接口的作用是通知容器执行Enterprise JavaBeans bean 程序。
另一个值得注意的问题就是,当您在不同的容器/服务器对 bean 进行部署时,需要采用不同版本的客户程序代码。客户程序代码之间的不同虽不是主要的问题,但确实存在,如进行初始连接的正确字符串。例如,考虑通过下面为 BEA WebLogic 创建属性对象的代码,检索 JNDI initialContext 对象。这可能与从 Oracle 属性字符串获取 initialContext 对象有所不同。
p.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.T3InitialContextFactory");
此外,还可能会存在一些其它的小问题,需要对客户程序代码作一些调整和重新编译,但这些问题不可能会带来特别大的工作量。
下面的Enterprise JavaBeans 客户示例说明了Enterprise JavaBean 的定位过程及其对远程方法的调用。
DemoClient.java (source)
/**
* DemoClient -- demonstrates using a minimal
* Java application to talk to the DemoBean
* stateless session bean
*/
package ejb.demo;
import javax.ejb.*;<BR>
import javax.naming.*;<BR>
import java.rmi.*;<BR>
import java.util.Properties;
/**
* DemoClient demonstrates using a minimal stateless
* session bean.
* Remember view session beans as an extension of your
* client running in the server.
*/
public class DemoClient {
public static void main(String[] args) {
System.out.println("\nBegin DemoClient...\n");
parseArgs(args);
try {
// Create A DemoBean object, in the server
// Note: the name of the class corresponds to the
// JNDI property declared in the
// DeploymentDescriptor
// From DeploymentDescriptor ...
// beanHomeName demo.DemoHome
Context ctx = getInitialContext();
DemoHome dhome = (DemoHome)
ctx.lookup("demo.DemoHome");
// Now you have a reference to the DemoHome object
// factory use it to ask the container to creat an
// instance of the Demo bean
System.out.println("Creating Demo\n");
Demo demo = dhome.create();
// Here is the call that executes the method on the
// server side object
System.out.println("The result is "
+ demo.demoSelect());
}
catch (Exception e) {
System.out.println(" => Error <=");
e.printStackTrace();
}
System.out.println("\nEnd DemoClient...\n");
}
static void parseArgs(String args[]) {
if ((args == null) || (args.length == 0))
return;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-url"))
url = args[++i];
else if (args[i].equals("-user"))
user = args[++i];
else if (args[i].equals("-password"))
password = args[++i];
}
}
static String user = null;
static String password = null;
static String url = "t3://localhost:7001";
/**
* Gets an initial context.
*
* @return Context
* @exception java.lang.Exception if there is
* an error in getting a Context
*/
static public Context getInitialContext()
throws Exception {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.T3InitialContextFactory");
p.put(Context.PROVIDER_URL, url);
if (user != null) {
System.out.println ("user: " + user);
p.put(Context.SECURITY_PRINCIPAL, user);
if (password == null)
password = "";
p.put(Context.SECURITY_CREDENTIALS, password);
}
return new InitialContext(p);
}
}
第八部分: 编译及运行客户程序
最后一项工作就是对客户程序进行编译和运行,以保证安装在服务器中的Enterprise JavaBeans 能够正常工作。
- 客户程序的编译
- 客户程序的运行
在各种平台上,客户程序的编译和运行过程都是相同的,其运行结果也是相同的。
1. 客户程序的编译
javac ejb/demo/DemoClient.java
2. 客户程序的运行
通过Enterprise JavaBeans 的 DemoSelect() 方法就可以产生“Hello World”字符串。运行该客户程序时会出现下列信息:
java ejb.demo.DemoClient <cr>
Begin DemoClient... (开始DemoClient...)
Creating Demo (创建Demo)
The result is hello world(结果是hello world )
End DemoClient... (结果DemoClient...)
--------------------------------------------------------------------------------
现在,您已经可以使用 DemoBean示例并已成功运行客户程序了。如果实际情况就是这样,您就会对Enterprise JavaBean 应用程序需要的部件有所了解,同时还可体会到创建真正的分布式的、多层的应用程序是一件多么简单的事情。
基本方法
需要重视的是在一个“真正”的应用程序的设计和实现时,可能需要花费较多的时间。同时,还可能会在构建业务模型方面引入更加复杂的逻辑,但其在基本方法上是一致的。Java 程序员按照指定接口、远程、本地等步骤进行操作。然后,根据情况的不同,在 bean 中写入相应的逻辑代码。
无需您再费力做的工作
Enterprise Java beans 的优势就在于可为程序员减轻很大负担,比如,Java 开发人员不用再去学习 CORBA IDL,也不必去处理一些多线程问题。事实上,在所有符合Enterprise JavaBeans规范的容器/服务程序中,程序员创建的显式线程都是非法的——因为这是服务程序/容器经销商的工作。其它还有一些不需Enterprise JavaBeans 程序员编写的代码包括:安全问题(已由部署描述文件声明),任何与底层协议有关的问题,任何与平台相关的问题。
下一步骤
简单的例子易学,但其内容肯定不会非常全面,这可能会使人厌烦。尤其其中没有包含任何访问数据库的例子。如前所述,虽然安全性和“交易”(transactional)在编程方面只需做比较少的工作,但它们确实是很重要的。同样,在stateful-session bean和entity bean中,也需要做点儿额外的工作,以充分利用服务程序上保存的“状态”,这一点并未强调指出。
最后一点,就是许多 Sun 公司的合作伙伴都在致力于Enterprise JavaBean 开发的高级工具的研究。通过这些高级工具,就可使许多由手工完成的创建及声明接口等工作,变得非常简单。比如,就像单击按钮一样简单!
结论
希望本简介能使您对Enterprise JavaBeans 模型的功能有所了解。无论您是经验丰富的 CORBA、Perl,还是 VB 程序员,我们都希望您能够看到Enterprise JavaBeans 功能的强大和使用的简单。
关于作者
Tom Daly 和 Uday Shetty 就职于 Sun 公司市场开发工程部。Tom Daly 具有Enterprise系统管理和性能测试方面的经验,并且从 alpha 0.3 的推出开始,一直致力于 Java 技术的研究。Uday Shetty 一直从事与应用服务程序相关的研究工作。