实体EJB用在处理客户端请求大量、并发的情况,它在实现业务逻辑的同时,作为数据库的一个缓冲。在服务量大的情况下,减轻数据库的负担,提高业务处理能力。本章介绍实体EJB、两种持久性管理方法、编程模型和实例开发过程。
5.1 实体EJB编程模型
1.实体EJB
实体EJB封装了业务逻辑实现,并且可以供多个客户使用。除了实现业务逻辑外,实体EJB的属性用来代表商业过程中处理的永久性数据。一个简单的实体Bean可以定义成代表数据库表的一个记录,也就是每一个实体对象代表 一条具体的记录。更复杂的实体Bean可以代表数据库表间关联视图。
2.实体EJB的持久性
持久性是实体EJB的一个重要概念。
图5-1 EJB客户端视图
和会话Bean的编程模型一样,实体EJB的客户端视图也是由主接口和远程接口组成。主接口实现类负责实体对象的创建和查询,远程接口实现类负责逻辑方法的调用。
3.定位一个会话Bean主接口
客户端使用JNDI定位一个实体Bean主接口。例如,Account实体Bean的主接口可使用以下代码进行查找:
Context initialContext = new InitialContext();
AccountHome accountHome = (AccountHome)
javax.rmi.PortableRemoteObject.narrow(initialContext.lookup("java:comp/env/ejb/accounts"),
AccountHome.class);
一个客户端的JNDI命名空间可以配置起来包含网络上在不同机器上的、不同EJB容器中的EJB的主接口。而EJB容器的实际位置对使用企业Bean的客户端来说是透明的。
4.实体Bean主接口
部署在容器中实体Bean的主接口的实现是由容器提供的。并且,容器确保客户端能够通过JNDI访问到部署在容顺中的每个实体Bean的主接口。实现实体Bean主接口的对象是EJBHome。
通过实体Bean主接口,客户端可以进行如下操作:
·创建新的实体对象。
·查找存在的实体对象。
·删除实体对象。
·执行主逻辑方法。
·获取主接口的句柄。
主句柄能被序列化,并且能被写入存储设备中。然后,句柄可以在另一个不同的JVM中,从固定存储器中反序列化,获取主接口的引用。
实体Bean主接口必须扩展javax.ejb.EJB主接口,并遵循Java语言远程接口规范。
5.create方法
实体Bean主接口可以定义多个create方法,每种方法都能创建一个实体对象。create方法的参数一般用来初始化实体对象的状态。每种create方法名的前缀是“create”。
create方法的返回类型是实体bean的远程接口。每个create方法都要定义抛出两个异常java.rmi.RemoteException和javax.ejb.CreateExcention。也可以包含其它的引用级异常。例如:下面主接口定义中演示了三个create方法:
public Interface AccountHome extends javax.ejb.EJBHome{
public Account create(String firstName,String lastName,double initialBalance)
throws RemoteException,CreateException;
public Account create(String accountNumber,double initialBalance)
throws RemoteException,CreateException,LowInitialBalanceException;
public Account createLargeAccount(String firstname,String lastname,
double initialBalance)
throws RemoteException,CreateException;
...
}
下面代码演示客户端程序如何创建一个新的实体对象:
AccountHome accountHome =...;
Account account = accountHome.create("John","Smith",500.00);
6.finder方法
实体Bean主接口可以定义一个或多个finder方法,每个方法定义一种查询一个实体EJB和多个EJB对象的方法。
finder方法必须以“find”为前缀,如findLargeAccounts(...),参数由实体Bean的来定位请求的实体对象。finder方法的返回值必须是实体Bean的远程接口,或者是实现实体Bean远程接口对象的集合。定义finder方法的异常有java.rmi.RemoteException和javax.ejb.FinderException。
每个实体Bean的主接口包含一个findByPrimaryKey(primaryKey)方法。它允许客户端使用主键定位一个实体对象,它的名字总是findByPrimaryKey,只有一个参数,这个参数具有和实体Bean主键相同的类型,返回类型是实体Bean的远程接口。每个实体Bean有惟一的findByPrimaryKey(primaryKey)方法,该方法不能被重载,其实现必须确保实体对象存在。下面代码片断演示findByPrimaryKey方法:
public Interface AccountHome extends javax.ejb.EJBHome{
...
public Account findByPrimaryKey(String AccountNumber)
throws RemoteException,FinderException;
}
下面代码片断演示客户端如何使用findByPrimaryKey方法:
AccountHome=...;
Account account = account 主findByPrimaryKey("100-3450-3333");
7.remove方法
javax.ejb.EJBHome接口定义了允许客户端删除实体对象的方法:
public Interface EJBHome extends Remote{
void remove(Handle handle) throws RemoteException,RemoveException;
void remove(Object primaryKey) throws RemoteException,RemoveException;
}
实体对象删除后,客户端访问实体对象会产生java.rmi.NoSuchObjectException异常。
8.Home方法
实体Bean的主接口可以定义一个或多个主方法。主方法是不特定于某个实体Bean实例业务逻辑方法。主方法的名字必须以“create”、“ind”或“remove”作为开关。主方法的参数被实体Bean的实现类使用,不依赖于某个特定的实体Bean实例。方法的参数和返回值必须是RMI-IIOP的合法类型。
主方法的定义必须招聘java.rmi.RemoteException异常。也可以包括其它引用级异常。
下面代码片断演示两个方法:
public Interface EmployeeHome extends javax.ejb.EJBHome{
...
public float livingIndex(String state,float Salary)
throws RemoteExcetption;
public void addBonus(float company_share_index)
throws RemoteException,ShareIndexOutOfRangeException;
...
}
9.主键和对象标识
每个实体对象有一个惟一的标识。如果两个实体对象有相同的主键,则它们是同一的。EJB架构允许主键是任何合法类型的类。
拥有实体对象远程接口引用的客户端可以通过getPrimaryKey()方法获取主键标识。和引用联系的对象标识在被引用期间不会改变。
客户端可以测试两个实体对象是否指向同一个实体对象,用isIdentical(EJBObject)方法。也可以采用equals方法比较它们的主键。
下面代码片断演示使用isIdentical方法测试指向同一个实体对象的两个对象引用:
Account acc1 = ...;
Account acc2 = ...;
if (acc1.isIdentical(acc2)){
//acc和acc2是同一个实体对象
}else{
//acc1和acc2是不同一个实体对象
}
如果客户端知道实体对象的主键,则调用实体Bean主接口的findByPrimaryKey(key)方法,可以获得实体对象的的引用。
注意,比较两个引用是否指向同一个实体对象,不能使用Object.equals(Object obj)方法,只能使用isIdentical方法。
10.实体Bean的远程接口
客户端通过实体Bean的远程接口访问实体对象。实体Bean的远程接口必须扩展javax.ejb.EJBObject接口。远程接口定义客户端使用的逻辑方法。
下面代码片断演示实体Bean远程接口的定义:
public Interface Account extends javax.ejb.EJBObject{
void debit(double amount)
throws java.rmi.RemoteException,InsufficientBalanceException;
void credit(double amount)
throws java.rmi.RemoteException;
double getBalance()
throws java.rmi.RemoteException;
}
javax.ejb.EJBObject接口定义允许客户端使用实体对象引用进行,如下操作:
·获取实体对象的主接口。
·删除实体对象。
·获取实体对象句柄。
·获取实对象主键。
容器实现javax.ejb.EJBObject接口中定义的方法,而业务方法以EJB的形式,以代理的方式被调用。
注意 实体对象没有把javax.ejb.EnterpriseBean中定义的方法暴露给客户端,这些方法是被容器调用的。
11.实体Bean的句柄
实体对象的句柄是在网络上标识实体的,拥有实体对象的远程接口客户端可以通过调用getHandle()方法获取实体对象句柄,该句柄类继承java.io.Serializable,所以客户端可以序列化句柄。客户端可以在另一个进程和消息系统中,反序列化该句柄,以重新获得实体对象的引用。
客户端代码必须使用javax.rmi.PortableRemoteObject.narrow(...)方法来把getEJBObject()方法的结果转换成实体Bean远程接口类型。
下面代码片断演示了句柄的使用:
//客户端获取account实体句柄,并保存
ObjectOutputStream stream = ...;
Account account = ...;
Handle bandle = account.getHandle();
stream.writeObject(handle);
//客户端可以从存储设备中读取句柄,使用句柄获取
//account实体对象的引用
ObjectInputStream stream = ...;
Handle handle=(Handle)stream.readObject(handle);
Account account = (Account)javax.rmi.PortableRemoteObject.narrow(
handle.getEJBObject(),Account.class);
account.debit(100.00);
12.实体主句柄
EJB规范允许客户端获取主接口的句柄。客户端把实体Bean的主接口引用以句柄的方式存到存储设备中,然后可以重新获取。当客户端不知道主接口的JNDI名,又想使用主接口,这是个解决的办法。
主接口的句柄必须实现javax.ejb.HomeHandle接口。
客户端代码必须使用java.rmi.PortableRemoteObject.narrow(...)方法来把getEJBHome()方法的结果转化成主接口类型。
5.2 实体对象的生命周期
实体对象在创建后,有一个标识。客户端使用实体Bean的主接口创建实体对象。创建成功后,客户端获取这个新创建的实体对象的引用。
实体对象可以通过create方法以外的其他方式创建(如直接插入数据库一条记录),它仍可以通过finder方法访问。同时,实体对象可以不使用remove()方法,而是直接删除(如直接删除数据库一条记录)。
客户端可以通过多种方式获取一个实体对象的远程接口引用:
·在方法调用中,引用作为参数传递过来。
·使用实体Bean主接口中定义的finder方法找到实体对象。
·从实体对象句柄中获取引用。
拥有实体对象远程接口引用的客户端能做下面的事:
·通过远程接口调用实体对象的业务逻辑方法。
·获取主接口的引用。
·把引用作为参数或作为远程方法调用的返回值。
·获取实体对象的主键。
·获取实体对象的句柄。
·删除实体对象。
使用不存在实体对象的引用是无效的。调用不存在的实体对象引用的方法会抛出异常java.rmi.NoSuchObjectException。
多个客户端可以同时访问实体对象。事务处理把每个客户端分离开。
5.3 容器管理持久性实体EJB
5.3.1实例说明
本示例演示容器管理持久性实体EJB实例的开发过程,内容包括:
(1)实体EJB主接口、远程接口定义和实现类编写;
(2)EJB说明文件和部署文件的编写;
(3)EJB属性与数据表字段映射文件的编写:
(4)如何定义连接池;
(5)如何编译EJB程序;
(6)测试EJB程序。
示例文件包括:
AccountHome.java,Account.java,AccountBean.java,ProcessingErrorException.java,Client.java,ejb-jar.xml,weblogic-cmp-rdbms-jar.xml,weblogic-ejb-jar.xml。
5.3.2编写源文件
1.编写主接口程序
编辑文件AccountHome.java并保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。AccountHome.java源文件如下:
//AccountHome.java
//定义本接口在包examples.ejb.basic.containerManaged中
package examples.ejb.basic.containerManaged;
//本接口用到的其他类
//javax.ejb.*中定义了实现EJBean的接口。
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.FinderException;
import java.rmi.RemoteException;
import java.util.Enumeration;
/**
* 这是AccontBean的主接口定义,这个接口是被EJB容器产生的类AccontBeanC实现的。
* 在这里只需定义EJB创建的方法,这些方法要和EJBean中的"ejbCreate"方法对应。
*/
//EJBean主接口必须继承javax.ejb.EJBHome接口
public interface AccountHome extends EJBHome {
/**
* 这个方法和"AccountBean.java"中定义的的Bean的"ejbCreate"方法相对应
* 这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器
* 会找到EJBean的实例,并调用它的"ejbCreate()"方法。
* 对容器管理的ejb,ejbCreate方法返回为null,而bean管理的ejb,返回的是主键类。
* @参数 accountID String 账号ID
* @参数 initialBalance double 初始化结算值
* @参数 type String 账号类型
* @返回 Account 远程对象
* @异常 javax.ejb.CreateException
* 创建bean错误时抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.containerManaged.AccountBean
*/
public Account create(String accountId, double initialBalance, String type)
throws CreateException, RemoteException;
/**
* 根据主键对象,返回账号对象
*
* @参数 primaryKey 主键
* @返回 Account 账号
* @异常 javax.ejb.FinderException
* 访问数据库错误抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.containerManaged.AccountBean
*/
public Account findByPrimaryKey(String primaryKey)
throws FinderException, RemoteException;
/**
* 找到所有结算值等于balanceEqual的账号
*
* @返回 Account 账号
* @参数 double balanceEqual,给定的结算值
* @异常 javax.ejb.FinderException
* 访问数据库错误抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.containerManaged.AccountBean
*/
public Account findAccount(double balanceEqual)
throws FinderException, RemoteException;
/**
* 找到所有结算值大于balanceGreaterThan的账号
*
* @返回 Enumeration 所有账号枚举
* @参数 double balanceGreaterThan,给定的结算值
* @异常 javax.ejb.FinderException
* 访问数据库错误抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.containerManaged.AccountBean
*/
public Enumeration findBigAccounts(double balanceGreaterThan)
throws FinderException, RemoteException;
/**
* 找到所有类型为'null'的EJBeans。
*
* @返回 Enumeration 所有账号枚举
* @异常 javax.ejb.FinderException
* 访问数据库错误抛出的异常
* @异常 RemoteException 当系统通讯发生故障时抛出
* @参看 examples.ejb.basic.containerManaged.AccountBean
*/
public Enumeration findNullAccounts()
throws FinderException, RemoteException;
}
2.编写远程接口程序
编辑文件Account.java并保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。Account.java源文件如下:
//Account.java
//定义本接口在包examples.ejb.basic.containerManaged中
package examples.ejb.basic.containerManaged;
//本接口用到的其他类
//javax.ejb.*中定义了实现EJBean的接口。
import java.rmi.RemoteException;
import javax.ejb.*;
/**
* 这是AccontBean的远程接口定义。远程接口中定义了客户端能远程调用EJBean的方法。这些方法除了
* 要抛出异常java.rmi.RemoteException之外,和EJBean中的定义是一致的。但并不是EJBean来实
* 现这个接口,而是由容器自动产生的类AccontBeanE实现的。
*/
//这个接口必须继承javax.ejb.EJBObject接口
public interface Account extends EJBObject {
/**
* 远程方法:存入一定数目的金额
*
* @参数 amount 存入金额的数量
* @返回 double 操作实际结果
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public double deposit(double amount)
throws RemoteException;
/**
* 远程方法:提取一定数目的金额
*
* @参数 amount 提取金额的数量
* @返回 double 操作实际结果
* @异常 RemoteException 当系统通讯发生故障时抛出
* @异常 ProcessingErrorException
* 购买操作出错时抛出的异常
*/
public double withdraw(double amount)
throws ProcessingErrorException, RemoteException;
/**
* 远程方法:结算
* @返回 double 结算值
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public double balance()
throws RemoteException;
/**
* 返回账号类型
*
* @返回 String 账号类型
* @异常 RemoteException 当系统通讯发生故障时抛出
*/
public String accountType()
throws RemoteException;
}
3.编写实现类程序
编辑文件AccountBean.java并保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。AccountBean.java源文件如下:
//AccountBean.java
//定义本接口在包examples.ejb.basic.containerManaged中
package examples.ejb.basic.containerManaged;
//本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库。
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Vector;
import javax.ejb.CreateException;
import javax.ejb.DuplicateKeyException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.FinderException;
import javax.ejb.NoSuchEntityException;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/**
* AccountBean是实体EJB,它演示了:
* 容器管理的JDBC持续性管理和事务管理;
* 在这个文件中的代码并没有直接访问数据库;
* 用户定义的异常;
* 使用isModified方法,这个方法改变容器管理的字段,通过设置isDirty
*/
//这个类是实体Bean,必须实现接口 EntityBean
public class AccountBean implements EntityBean {
//设置是否打印控制台
final static boolean VERBOSE = true;
//声明实体上下文变量
private EntityContext ctx;
//声明实体EJB属性变量
public String accountId; // 这也是主键类
public double balance;
public String accountType;
private transient boolean isDirty; // 决定bean是否谢数据库的标志
/**
* 为EJBean设置实体EJB上下文
*
* @参数 ctx EntityContext
*/
public void setEntityContext(EntityContext ctx) {
log("setEntityContext called (" + id() + ")");
this.ctx = ctx;
}
/**
* 取消实体上下文设置
*
*/
public void unsetEntityContext() {
log("AccountBean.unsetEntityContext (" + id() + ")");
this.ctx = null;
}
/**
* 返回EJBean是否被改变
*
* 这个方法必须为public 以使被容器调用
*
* @返回 boolean isDirty
*/
public boolean isModified() {
log("isModified(): isDirty = " + (isDirty ? "true" : "false"));
return isDirty;
}
/**
* 设置EJBean的改变标志
*
* @参数 flag 改变标志
*/
public void setModified(boolean flag) {
isDirty = flag;
log("setModified(): " + id() + (String) (flag ? ": requires saving"
: ": saving not required"));
}
/**
* 返回标识这个EJBean的主键
*
* @返回 String 标志
*/
private String id() {
return "" + System.identityHashCode(this) + ", PK = " +
(String) ((ctx == null) ? "nullctx"
: ((ctx.getPrimaryKey() == null ?
"null" : ctx.getPrimaryKey().toString()))) +
"; isDirty = " + isDirty;
}
/**
* 这是本类必须实现的方法,在本例中没有用到
*
*/
public void ejbActivate() {
log("AccountBean.ejbActivate (" + id() + ")");
}
/**
* 这是本类必须实现的方法,在本例中没有用到
*
*/
public void ejbPassivate() {
log("AccountBean.ejbPassivate (" + id() + ")");
}
/**
* 这是本类必须实现的方法,在本例中没有用到
*
*/
public void ejbLoad() {
log("AccountBean.ejbLoad (" + id() + ")");
}
/**
* 设置EJBean的改变标记为false
*
*/
public void ejbStore() {
log("AccountBean.ejbStore (" + id() + ")");
setModified(false);
}
/**
* 这是本类必须实现的方法,在本例中没有用到
*
*/
public void ejbRemove()
throws RemoveException
{
log("AccountBean.ejbRemove (" + id() + ")");
}
/**
* 这个方法和"AccountBean.java"中定义的的Bean的"ejbCreate"方法相对应
* 这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器
* 会找到EJBean的实例,并调用它的"ejbCreate()"方法。
* 对容器管理的ejb,ejbCreate方法返回为null,而bean管理的ejb,返回的是主键类。
* @参数 accountID String 账号ID
* @参数 initialBalance double 初始化结算值
* @参数 type String 账号类型
* @异常 javax.ejb.CreateException
* 创建bean错误时抛出的异常
* @参看 examples.ejb.basic.containerManaged.AccountHome
*/
public String ejbCreate(String accountId, double initialBalance, String type)
throws CreateException
{
log("AccountBean.ejbCreate( id = " + System.identityHashCode(this) + ", PK = " +
accountId + ", " + "initial balance = $ " + initialBalance + ")");
this.accountId = accountId;
this.balance = initialBalance;
this.accountType = type;
return null; // See 9.4.2 of the EJB 1.1 specification
}
/**
* 这是本类必须实现的方法,在本例中没有用到
*/
public void ejbPostCreate(String accountId, double initialBalance, String type)
{
log("AccountBean.ejbPostCreate (" + id() + ")");
}
// 应用程序定义的方法
/**
* 存入一定金额
*
* @参数 amount double 数量
* @返回 double 结算
*/
public double deposit(double amount)
{
log("AccountBean.deposit: Depositing $" + amount + " into '" + accountId + "'");
//业务逻辑计算
balance += amount;
//设置改变标记
setModified(true);
return balance;
}
/**
* 提取一定数量的金额
*
* @参数 amount double 数量
* @返回 double 结算
* @exception ProcessingErrorException
* 如果提取的数量大于结算值
*/
public double withdraw(double amount)
throws ProcessingErrorException
{
log("AccountBean.withdraw: Withdrawing $" + amount + " from '" + accountId + "'");
if (amount > balance) {
//抛出用户定义异常
throw new ProcessingErrorException("Request to withdraw $" + amount +
"; is more than balance $" + balance +
" in account " + accountId);
}
//业务逻辑计算
balance -= amount;
//设置改变标记
setModified(true);
return balance;
}
/**
* 返回当前的结算
*
* @返回 double 结算
*/
public double balance() {
log("AccountBean.balance (" + id() + ")");
return balance;
}
/**
* 返回账号类型
*
* @返回 String 账号类型
*/
public String accountType() {
log("AccountBean.accountType (" + id() + ")");
return accountType;
}
//控制台输出
private void log(String s) {
if (VERBOSE) System.out.println(s);
}
}
4.编写处理异常程序
用文本编辑器编辑文件ProcessingErrorException.java并将它保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。其源文件如下:
//ProcessingErrorException.java
//定义本类在包examples.ejb.basic.containerManaged 中
package examples.ejb.basic.containerManaged;
/**
* 这是用户定义的异常类
*/
//用户定义的异常类必须继承Exception
public class ProcessingErrorException extends Exception {
/**
* 获取没有字符串参数的异常
*
*/
public ProcessingErrorException() {}
/**
* 用特定的字符串构造异常
*
* @参数 message Exception 消息
*/
public ProcessingErrorException(String message) {super(message);}
}
5.编写客户端测试程序
编辑文件Client.java并将它保存到C:\work\src\examples\ejb\basic\containerManaged目录下(或从附带光盘的src\examples\ejb\basic\containerManaged目录拷贝)。其源文件如下:
//Client.java
//定义本类在包examples.ejb.basic.containerManaged 中
package examples.ejb.basic.containerManaged;
//本类用到的其他类
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
//本类用到的EJB类
import javax.ejb.CreateException;
import javax.ejb.DuplicateKeyException;
import javax.ejb.FinderException;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.RemoveException;
//本类用到的名称服务类
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
/**
* 这个类演示了如何调用一个实体EJB,并进行如下操作:
* A:创建一个Account远程对象,存入一些钱。然后试图提取超过当前结算的金额。或抛出用户定义的异常,
* 最后,清除Account远程对象。
* B:创建一些新的账号,它们有不同的结算值。找到所有计算值大于给定数值的账号。找到结算职为0的账号。
* 试图查找账号类型为null的账号。最后,删除所有新创立的账号。
* 这个例子同时演示了怎样在JNDI树查找EJB主接口。
*/
public class Client {
//声明变量
private String url;
private String accountId;
private AccountHome home;
//构造方法
public Client(String url, String accountId)
throws NamingException {
this.url = url;
this.accountId = accountId;
//找找主接口,lookupHome是本例自定义方法。
home = lookupHome();
}
/**
* 在命令行运行这个实例:
* java examples.ejb.basic.containerManaged.Client "t3://localhost:7001"
* 参数是可选的
* @参数 url URL such as "t3://localhost:7001" of Server
* @参数 accountID String Account ID to test, default "10020"
*/
public static void main(String[] args) {
System.out.println("\nBeginning containerManaged.Client...\n");
String url = "t3://localhost:7001";
String accountId = "10020";
// Parse the argument list
switch(args.length) {
case 2:
accountId = args[1];
// fall through
case 1:
url = args[0];
break;
}
Client client = null;
try {
//实例化本类
client = new Client(url, accountId);
} catch (NamingException ne) {
//异常处理
log("Unable to look up the beans home: " + ne.getMessage());
System.exit(1);
}
try {
//运行实例A
client.runExamplePartA();
//运行实例B
client.runExamplePartB();
} catch (Exception e) {
//异常处理
log("There was an exception while creating and using the Accounts.");
log("This indicates that there was a problem communicating with the server: "+e);
}
System.out.println("\nEnd containerManaged.Client...\n");
}
/**
* 执行实例A
*