Entity Bean与Session Bean的不同表现在如下几个方面:
持久性
在应用或应用服务器的运行时间外,Entity Bean状态数据仍存在于持久数据存储之中。
Entity Bean有两种持久类型:Bean管理持久类型(Bean-managed Persistence,BMP)和容器管理的持久类型(Container-managed Persistence,CMP)。对于Bean管理的持久类型,由组件模型中Enterprise Bean类的代码控制对持久存储中状态数据的访问;容器管理持久性类型的Entity Bean,则由容器生成和管理对应持久存储中状态数据的访问方法。开发者可以不用编写这些方法。
共享访问
相对于Session Bean对应于特定的客户端会话而言,Entity Bean可以在客户端间被共享访问,对于多个并发的客户端访问,由容器提供了完整的事务(transaction)管理机制,保证状态数据的完整性。并且提供了通过修改部署描述,指定事务属性的能力,无需在代码中对事务边界进行控制。
Primary Key
每个Entity Bean实例拥有一个唯一的标识对象,客户端可以使用此标识定位特定的Entity Bean实例。
关系
如存在于关系型数据库中的业务实体数据,Entity Bean之间也可以具有类似的关系。对于Bean管理持久性的Entity Bean,需要在Entity Bean的组件类中对关系进行编码;而对于容器管理持久性的Entity Bean,则由容器对关系进行控制。因此,容器管理持久性的Entity Bean之间的关系,被称为容器管理关系(Container-managed relationship,CMR)。
容器管理持久性(Container-managed Persistence,CMP)
容器管理持久性指由EJB容器处理Entity Bean需要的对数据库的访问。使Entity Bean可以脱离特定类型的数据库,从而具有更高的灵活性。
为使Entity Bean可以由EJB容器对持久性进行管理,需要提供Entity Bean的抽象模式(abstract schema)信息。
抽象模式(Abstract Schema)
抽象模式作为容器管理持久性的Entity Bean部署描述的一部分,提供对Entity Bean持久域和关系的定义。之所以称其为“抽象”模式,是为了与具体的底层数据存储的物理模式区分开来。例如,在关系型数据库中,物理模式由诸如表或列等结构构成。
对于容器管理持久性的Entity Bean,需要在部署描述中定义抽象模式的名字。这些名字将可以通过使用Enterprise JavaBeas™ Query Language(EJB™ QL)编写的查询语句进行引用。例如,必须为每一个finder方法定义一个EJB QL查询语句,通过此语句定义当此finder方法被调用时,容器执行的查询。
持久域(persistent fields)
被定义的Entity Bean的持久域保存在底层的数据存储中,所有这些域构成整个Entity Bean的状态。在运行时,容器自动对这些状态与数据库中的数据进行同步。一般,容器在部署时将Entity Bean与特定的数据库表进行映射,将持久域与数据库表中的列进行映射。
关系域(relationship fields)
关系域可视为数据库表中的外键(foreign key),用于标识Bean之间的关系。
容器管理关系(Container-managed Relationship,CMR)
容器管理持久性的Entity Bean有以下四种容器管理关系:
one-to-one,一个Bean的单个实例关联另一个Bean的单个实例;
one-to-many,一个Bean的单个实例关联另一个Bean的多个实例;
many-to-one,一个Bean的多个实例关联另一个Bean的单个实例;
many-to-many,一个Bean的多个实例关联另一个Bean的多个实例;
容器管理关系的方向
容器管理关系的方向可以是双向或单向。在一个双向的关系中,涉及的Bean都有一个关系域与另外的Bean关联,通过关系域,可以从一个Bean的实例中访问关联的Bean对象,反之亦可。在一个单向的关系中,只有一个Bean拥有关联其他Bean的关系域,只能从这个Bean的实例访问被关联的Bean对象,而不可从被关联的Bean对象访问到这个实例。
EJB QL查询可以通过关系进行定位。关系的方向决定了是否可以从一个Bean定位另一个Bean。如订单作为一个Bean,订单中的项目作为一个Bean,二者拥有双向关系,即订单知道拥有哪些项目,而项目知道自己属于某个订单,因此,通过关系,可以从订单定位订单中的项目,也可以从订单中的项目定位到订单;
Entity Bean的特征
持久性
由于Entity Bean的状态数据保持在持久存储中,因此,即使容器或服务器失效,Entity Bean的状态数据仍然存在。
持久业务数据的对象表示
Entity Bean是持久业务数据的对象表示,更改Entity Bean的实例的状态,数据库中的对应信息也将自动更新。实例状态是数据库数据的视图,而不是两个分离的数据。
表示相同的底层数据的多个Entity Bean实例
在企业应用中,通常出现多个客户对某些业务实体的并发访问,一般,EJB容器通过维护同一个EJB实例的多个拷贝,提供给不同的客户,以此提高对客户请求的响应速度,EJB容器提供保持实例状态的一致性的机制。而这种特性对于客户来说是透明的,因此,客户可以认为操作中的EJB实例是唯一的实例,可以不用考虑EJB实例状态在多个并发客户间的一致性。
可查找的Entity Bean
因为Entity Bean实例拥有其独有的标识,因此,除了可以创建Entity Bean实例外,如使用SQL中的SELECT语句,还可对在数据库中已有的业务数据进行查找。对Entity Bean实例的查找一般通过在Entity Bean的Home接口中定义finder方法实现
数据的对象视图
多层企业应用中,通常有逻辑层和数据层之分,逻辑层中的逻辑组件用于表示特定的业务逻辑或满足特定的业务需求,逻辑组件中一般只封装逻辑,而业务数据则通过数据层中的数据组件提供表示。
业务数据通常以数据库表的方式保存在关系型数据库中,在EJB编程模型成为企业应用开发的标准之前,开发者一般通过JDBC或其他数据库访问机制,将数据映射成为内存中的业务对象,并提供保证这两个数据拷贝之间的一致性的方法,即业务对象知道如何从数据库中获得自身的状态,当自身状态改变时,同步数据库中的对应数据,对于关系型数据,往往需要更复杂的控制。
这样,数据层中的数据组件往往显得非常臃肿,代码中充斥大量的底层服务处理,不能提供业务实体清晰的面向对象表示,即由紧凑的状态和方法构成的对象,而且给开发和维护带来极大的不便。
通过Entity Bean组件模型,开发者可以快速地建立起紧凑、灵活而且具有分布式特性的业务数据的对象视图,通过类似于标准的Java语言中创建、清除对象实例、调用实例的方法,对组件进行操作,组件中只需提供应用的业务逻辑。
组件结构
Entity Bean由以下几部分构成:
· Home接口,客户端通过此接口对Entity Bean对象进行创建、清除、查找等操作;
· 组件接口,客户端通过此接口访问Entity Bean对象,访问对象状态及执行对象业务方法;
· 组件类,开发人员在此类中提供对以上两个接口中定义的方法的实现;
· 部署描述,提供Entity Bean的事务属性、安全等配置信息。
Primary Key
与关系型数据库中的数据类似,每个Entity Bean实例也具有一个标识数据的唯一性的Primary Key对象,Primary Key对象可以具有多个属性。属性可以是任意用于说明此Entity Bean实例的的数据。某些情况下,用于表示复杂关系的Entity Bean,Primary Key甚至可以是整个Entity Bean。
可以通过定义Entity Bean组件中的Primary Key类,来为组件提供可以任何满足要求的Primary Key,但必须保证此Primary Key符合Java编程语言中的串行化要求,即Primary Key必须是合法的RMI类型。
客户端
Entity Bean的客户端按照客户端与Entity Bean所处的JVM是否相同,分为远程客户和本地客户。
JNDI
由于Entity Bean运行于EJB容器中,由容器提供对Entity Bean实例的生存周期管理,客户端不能直接访问容器中的Entity Bean,容器使客户端可以通过JNDI访问Entity Bean的Home接口,客户端通过Home接口取得对Entity Bean对象的引用,通过引用对容器中的Entity Bean实例进行访问。
远程客户
Entity Bean的远程客户端通过Entity Bean的远程Home接口和远程接口访问Entity Bean对象。
Entity Bean的远程客户端与运行客户端的JVM是否与Entity Bean所处JVM是否相同无关,相同或不同JVM中的客户端都可通过远程Home接口和远程接口访问Entity Bean对象。只是远程客户端对Entity Bean进行调用时,其调用通过网络传播,参数与返回值必须是合法的RMI类型,并且都按值传递。
由于网络延迟的原因,客户端通过远程访问比本地访问效率上要差一些,但是,由于远程访问与客户端的位置无关,因此,可以提供Entity Bean的可分布特性,适合粗粒度的对象表示。
Entity Bean的远程客户端可以是用Java语言编写的任意程序类型,如Java应用、applet、Servlet等等,也可以是非Java的客户端。
本地客户
Entity Bean的本地客户通过本地Home接口与本地接口访问Entity Bean对象。
Entity Bean的本地客户端必须位于同一个JVM中。
Entity Bean的本地客户端在对Entity Bean进行调用时,按照标准Java语言中的对象调用方式,其参数和返回值按引用传递。
因为不涉及网络延迟的因素,一般,通过本地访问,效率要高一些,不过,组件的分布式特性就受到了影响。通过定义本地和远程的访问接口,Entity Bean可以同时提供两种访问方式,不过,通常只提供二者之一。
具有容器管理关系的EJB,必须提供本地访问接口
容器与Entity Bean
从Entity Bean实例的产生到清除,它都运行于EJB容器中,容器中可以部署多个Entity Bean,容器提供客户端对Entity Bean实例的访问机制,容器为部署的在其中的Entity Bean提供安全、并发、持久等等服务。对于Entity Bean的客户端而言,容器是透明的。
Entity Bean作为业务数据在应用系统中的对象表示,多个客户通常会并发地访问Entity Bean对象,开发者不必提供对并发访问的支持,通过实例池与事务管理器,EJB容器会保证实例对客户端请求进行进行高效的响应,并保证实例状态与数据库的同步。如果开发者使用了容器管理持久性的Entity Bean,则如何取得与数据库的连接、如何使用SQL语句操作数据、如何利用资源等等,都可以完全由容器进行处理。开发者只需通过部署描述,对组件的事务、安全等进行声明即可。
通过JNDI定位远程Home接口
客户端可通过JNDI定位Entity Bean的远程Home接口,JNDI命名空间中可以包含多个部署在容器中的Entity Bean的远程Home接口。
如下代码段示意如何通过JNDI定位Entity Bean的远程Home接口:
Context initialContext = new InitialContext();
AccountHome accountHome = (AccountHome) javax.rmi.PortableRemoteObject.narrow(
initialContext.lookup(“java:comp/env/ejb/accounts”),
AccountHome.class
);
通过JNDI定位本地Home接口
客户端通过JNDI定位Entity Bean的本地Home接口与定位远程Home接口的方法非常类似,只是没有牵涉到远程访问的API。
如下代码段示意如何通过JNDI定位Entity Bean的本地Home接口:
Context initialContext = new InitialContext();
AccountHome accountHome = (AccountHome) initialContext.lookup(
“java:comp/env/ejb/accounts”
);
组件模型
Home接口
根据Entity Bean是否提供远程或本地访问,Entity Bean组件必须提供本地或远程的Home接口。通过JNDI,容器使Home接口可被客户端访问。
远程Home接口
通过Entity Bean的远程Home接口,开发者向Entity Bean的客户端提供进行如下操作的方法:
· 创建新的Entity Bean实例;
· 查找已存在的Entity Bean实例;
· 清除Entity Bean实例;
· 执行Home接口中的业务方法;
· 取得Entity Bean的javax.ejb.EJBMetaData接口,javax.ejb.EJBMetaData接口用于表示此Entity Bean的信息,降低客户端和服务器的绑定程度和用于支持客户端脚本;
· 取得Home接口句柄(Handler),此句柄可串行化(serialization)到持久存储中,然后,可在其他虚拟机中,从持久存储中,对此串行化对象进行解串行化(deserialization),取得对此远程Home接口句柄的引用;
Entity Bean的远程Home接口必须扩展(extends)javax.ejb.EJBHome接口,并遵循Java语言的远程接口标准。
create方法
Entity Bean的远程Home接口可定义零个或多个create方法,每个create方法提供一种创建Entity Bean实例的方式,create方法中的参数一般被用于初始化Entity Bean实例。每个create方法必须以“create”作为前缀;
远程Home接口中定义的create方法的返回值必须是Entity Bean的远程接口,抛出语句必须包含java.rmi.RemoteException和javax.ejb.CreateException异常,同时可包含任意的应用级的异常。
以下代码段是远程Home接口中三个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;
... }
以下是客户端如何通过create方法创建Entity Bean实例的代码范例:
AccountHome accountHome = ...;
Account account = accountHome.create(“John”, “Smith”, 500.00);.
finder方法
通过Entity Bean的远程Home接口,可以定义一到多个finder方法。所谓finder方法,即是开发者提供给客户端的方法,用于查找某个Entity Bean对象或包含多个Entity Bean对象的集合。远程Home接口中定义的每个finder方法对应一种查找的方式。finder方法的名称必须以“find”前缀开始,如:findLargeAccounts(...)。方法中定义的参数,被Entity Bean组件类中的对应实现方法用于定位需要查找的Entity Bean对象或对象集合。
finder方法的返回值类型必须是Entity Bean的远程接口对象,或是只包含远程接口对象的集合(Collection)。
每个远程Home接口中定义的finder方法的抛出语句必须包含对java.rmi.RemoteException异常和javax.ejb.FinderException异常的抛出。
远程Home接口必须包含一个findByPrimaryKey(primaryKey)方法,客户端可通过此方法使用Entity Bean的Primary Key对Entity Bean对象进行查找。此方法的唯一参数必须与Entity Bean的Primary Key为同一类型,其返回值必须是Entity Bean的远程接口类型。
以下代码范例定义了一个findByPrimaryKey方法:
public interface AccountHome extends javax.ejb.EJBHome {
...
public Account findByPrimaryKey(String AccountNumber) throws RemoteException, FinderException;
}
以下代码范例是客户端调用finder方法的方式:
AccountHome = ...;
Account account = accountHome.findByPrimaryKey(“100-3450-3333”);
Remove方法
javax.ejb.EJBHome接口中定义的方法,由于Entity Bean组件的远程Home接口扩展(extends)javax.ejb.EJBHome接口,因此,客户端可通过调用Entity Bean的远程Home接口中的remove方法清除容器Entity Bean实例。
Home方法
作为应用中业务数据的对象表示,Entity Bean通常表示一类业务实体,如雇员信息、订单、账户等等,通常这些实体都会涉及针对所有或部分已存在数据的操作,如对所有雇员的某些信息进行统计,或者对所有雇员增加花红等等,这些操作不涉及单个的Entity Bean实例。
Entity Bean组件模型中,可以通过在远程Home接口中定义Home方法,提供对不涉及单个特定的Entity Bean实例的操作。
在远程Home接口中定义的Home方法必须抛出java.rmi.RemoteException异常,可抛出任意应用级异常。同时,其参数类型和返回值类型必须是合法的RMI类型。
下面是两个Home方法的范例代码:
public interface EmployeeHome extends javax.ejb.EJBHome {
...
// this method returns a living index depending on
// the state and the base salary of an employee:
// the method is not specific to an instance
public float livingIndex(String state, float Salary) throws RemoteException;
// this method adds a bonus to all of the employees
// based on a company profit-sharing index
public void addBonus(float company_share_index)
throws RemoteException, ShareIndexOutOfRangeException;
...
}
本地Home接口
通过Entity Bean的本地Home接口,开发者向Entity Bean的客户端提供进行如下操作的方法:
· 创建新的Entity Bean实例;
· 查找已存在的Entity Bean实例;
· 清除Entity Bean实例;
· 执行Home接口中的业务方法;
Entity Bean的本地Home接口必须扩展(extends)javax.ejb.EJBLocalHome接口
create方法
Entity Bean的本地Home接口可定义零个或多个create方法,每个create方法提供一种创建Entity Bean实例的方式,create方法中的参数一般被用于初始化Entity Bean实例。每个create方法以“create”作为前缀;
本地Home接口中定义的create方法的返回值必须是Entity Bean的远程接口,抛出语句不可包含java.rmi.RemoteException异常,可包含任意的应用级的异常,必须包含javax.ejb.CreateException异常。
以下代码段是本地Home接口中三个create方法的范例:
public interface AccountHome extends javax.ejb.EJBLocalHome {
public Account create(String firstName, String lastName, double initialBalance)
throws CreateException;
public Account create(String accountNumber, double initialBalance)
throws CreateException, LowInitialBalanceException;
public Account createLargeAccount(String firstname, String lastname, double initialBalance)
throws CreateException;
...
}
以下是客户端如何通过create方法创建Entity Bean实例的代码范例:
AccountHome accountHome = ...;
Account account = accountHome.create(“John”, “Smith”, 500.00);
finder方法
通过Entity Bean的本地Home接口,可以定义一到多个finder方法。所谓finder方法,即是开发者提供给客户端的方法,用于查找某个Entity Bean对象或包含多个Entity Bean对象的集合。本地Home接口中定义的每个finder方法对应一种查找的方式。finder方法的名称必须以“find”前缀开始,如:findLargeAccounts(...)。方法中定义的参数,被Entity Bean组件类中的对应实现方法用于定位需要查找的Entity Bean对象或对象集合。
finder方法的返回值类型必须是Entity Bean的本地接口对象,或是只包含本地接口对象的集合(Collection)。
每个本地Home接口中定义的finder方法的抛出语句必须包含javax.ejb.FinderException异常的抛出,不可包含java.rmi.RemoteException异常。
本地Home接口必须包含一个findByPrimaryKey(primaryKey)方法,客户端可通过此方法使用Entity Bean的Primary Key对Entity Bean对象进行查找。此方法的唯一参数必须与Entity Bean的Primary Key为同一类型,其返回值必须是Entity Bean的本地接口类型。
以下代码范例定义了一个findByPrimaryKey方法:
public interface AccountHome extends javax.ejb.EJBLocalHome {
...
public Account findByPrimaryKey(String AccountNumber) throws FinderException;
}
以下代码范例是客户端调用finder的方式:
AccountHome = ...;
Account account = accountHome.findByPrimaryKey(“100-3450-3333”);
Remove方法
javax.ejb.EJBLocalHome接口中定义的方法,由于Entity Bean组件的本地Home接口扩展(extends)javax.ejb.EJBLocalHome接口,因此,客户端可通过调用Entity Bean的本地Home接口中的remove方法清除容器Entity Bean实例。
Home方法
作为应用中业务数据的对象表示,Entity Bean通常表示一类业务实体,如雇员信息、订单、账户等等,通常这些实体都会涉及针对所有或部分已存在数据的操作,如对所有雇员的某些信息进行统计,或者对所有雇员增加花红等等,这些操作不涉及单个的Entity Bean实例。
Entity Bean组件模型中,可以通过在本地Home接口中定义Home方法,提供对不涉及单个特定的Entity Bean实例的操作。
每个Home方法的抛出语句可以包含任意应用级异常的抛出,不能抛出java.rmi.RemoteException异常。
下面是两个Home方法的范例代码:
public interface EmployeeHome extends javax.ejb.EJBLocalHome {
...
// this method returns a living index depending on
// the state and the base salary of an employee:
// the method is not specific to an instance
public float livingIndex(String state, float Salary);
// this method adds a bonus to all of the employees
// based on a company profit-sharing index
public void addBonus(float company_share_index) throws ShareIndexOutOfRangeException;
...
}
Primary Key
同一个Entity Bean组件的每个实例,都拥有一个用于标识实例的同一类型的Primary Key,如果两个Entity Bean对象拥有相同的Home接口,拥有相同的Primary Key,即可认为这两个Entity Bean对象相等。
Entity Bean的Primary Key可以是任何合法的RMI类型。每个Entity Bean都必须指定其唯一的Primary Key的类型,不同的Entity Bean可以使用相同的primary key类型。客户端可通过Entity Bean实例的组件接口引用,调用getPrimaryKey()方法,取得实例关联的Primary Key对象。
在整个Entity Bean实例的生存周期中,其关联的Primary Key对象不会发生改变,即在生存周期内,客户端调用实例的getPrimaryKey()方法返回的Primary Key对象是相同的。如果实例同时拥有远程接口和本地接口,则这两个接口的getPrimaryKey()方法返回的Primary Key对象也是相同的。
因此,客户端除了可以使用组件接口中的isIdentical方法判断两个Entity Bean实例是否相等之外,也可使用实例关联的Primary Key对象的equals方法进行判断。
下面是使用isIdentical方法判断两个对Entity Bean实例的引用是否相等的代码范例:
Account acc1 = ...;
Account acc2 = ...;
if (acc1.isIdentical(acc2)) {
//acc1 and acc2 are the same entity object
} else {
//acc2 and acc2 are different entity objects
}
知道Entity Bean实例的Primary Key的客户端,可以使用Home接口中定义的findByPrimaryKey方法,取得对Entity Bean实例组件接口的引用。
|
注意
|
当判断两个Entity Bean实例引用是否相等,不可使用“==”运算符,只可使用Primary Key对象的equals方法或组件接口的isIdentical方法进行判断。
|
组件接口
客户端通过Entity Bean提供的组件接口访问Entity Bean对象。开发者必须为组件提供组件接口,并在组件接口中对客户所能调用的业务方法进行定义。
根据Entity Bean是否提供远程或本地访问,组件接口分为远程接口和本地接口。
远程接口
Entity Bean组件中的远程接口必须扩展(extends)javax.ejb.EJBObject接口。并在其中定义可供客户端调用业务方法。业务方法的抛出语句必须包含java.rmi.RemoteException异常,可包含任意的应用级异常。
下面是Entity 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提供为客户端提供对Entity Bean对象引用进行如下操作的方法:
· 取得Entity Bean对象的远程Home接口;
· 清除Entity Bean对象;
· 取得Entity Bean对象的句柄;
· 取得Entity Bean对象的Primary Key。
容器为以上操作提供实现,开发者只需在Entity Bean的组件类中提供对远程接口中定义的业务方法的实现。
本地接口
Entity Bean组件中的本地接口必须扩展(extends)javax.ejb.EJBLocalObject接口。并在其中定义可供客户端调用的业务方法。业务方法的抛出语句不能包含java.rmi.RemoteException异常,可包含任意的应用级异常。
下面是Entity Bean组件本地接口的范例代码:
public interface Account extends javax.ejb.EJBLocalObject {
void debit(double amount) throws InsufficientBalanceException;
void credit(double amount);
double getBalance();
}
javax.ejb.EJBLocalObject提供为客户端提供对Entity Bean对象引用进行如下操作的方法:
· 取得Entity Bean对象的本地Home接口;
· 清除Entity Bean对象;
· 取得Entity Bean对象的Primary Key。
容器为以上操作提供实现,开发者只需在Entity Bean的组件类中提供对本地接口中定义的业务方法的实现。
组件类
由于Entity Bean具有两种不同的持久类型,Bean管理持久性(Bean-managed Persistence,BMP)和容器管理持久性(Container-managed Persistence,CMP),两种持久类型的组件类的开发方式具有较多的不同。因此,将在以下两章中分别对这两种持久性类型的Entity Bean进行介绍,并对不同持久类型的组件类的开发进行描述。
生存周期
Entity Bean对象的生存周期
上图是Entity Bean生存周期内的状态图。
在容器创建了Entity Bean实例之后,调用Entity Bean组件类的setEntityContext方法,将Entity Bean的上下文传递到实例。
实例化之后,Entity Bean被转移到实例池成为可用实例。实例池中的实例没有任何标识,只有在实例进入就绪状态时,容器将为实例分配标识。
实例有两种方式从实例池进入就绪状态。一种方式是客户端调用了Entity Bean的Home接口的create方法,使容器调用Entity Bean的ejbCreate和ejbPostCreate方法;另一种方式是容器调用Entity Bean的ejbActivate方法。
当实例进入就绪状态之后,即可对实例的业务方法进行调用。
同样,实例也有两种方式从就绪状态进入实例池。一种方式是客户端调用了remove方法,使容器调用Entity Bean的ejbRemove方法;另一种方式是容器调用Entity Bean的ejbPassivate方法。
当Entity Bean实例的生命周期结束,容器将Entity Bean从实例池中移出,并调用Entity Bean的unsetEntityContext方法
posted on 2007-10-22 13:44
☜♥☞MengChuChen 阅读(1256)
评论(0) 编辑 收藏 所属分类:
EJB3.0