Enterprise JavaBeans导论[转]
EJB并不是一个产品。它是Java服务器端服务框架的规范,软件厂商根据它来实现EJB服务器。应用程序开发者可以专注于支持应用所需的商业逻辑,而不用担心周围框架的实现问题。
EJB规范详细地解释了一些最小但是必须的服务,如事务,安全和名字等。软件厂商根据这些规范要求以保证一个enterprise bean能使用某个必需的服务。规范并没有说明厂商如何实现这些服务。这使得通过阅读规范来学习EJB更加困难,因为它允许厂商在不牺牲核心服务的可移植性的前提下来提供一些增强功能。
JavaBeans和Enterprise JavaBeans
JavaBeans是Java的组件模型。在JavaBeans规范中定义了事件和属性等特征。Enterprise JavaBeans也定义了一个Java组件模型,但是Enterprise JavaBeans组件模型和JavaBeans组件模型是不同的。 JavaBeans重点是允许开发者在开发工具中可视化的操纵组件。JavaBeans规范详细地解释了组件间事件登记、传递、识别和属性使用、定制和持久化的应用编程接口和语意。 Enterprise JavaBeans的侧重点是详细地定义了一个可以portably地部署Java组件的服务框架模型。因此,其中并没提及事件,因为enterprise bean通常不发送和接受事件。同样也没有提及属性------属性定制并不是在开发时进行,而是在运行时(实际上在部署时)通过一个部署描述符来描述。
不要寻找JavaBeans和Enterprise JavaBeans之间的相似性。他们都是组件模型规范,但是前者说明了开发工具中应用程序组装的问题,而后者则侧重于部署组件的服务框架的细节。不要错误地认为JavaBeans是用于客户端的开发,Enterprise JavaBeans是用于服务器端的开发。JavaBeans也可作为进行非图形化服务器端Java应用开发的组件模型。区别是当你使用JavaBeans创建服务器应用时,你还得设计整个的服务框架。用Enterprise Javabeans框架是现成的,你只需遵守它的APIs.对于复杂的服务器端应用程序,显然使用Enterprise JavaBeans比重新开发更简单。
Enterprise JavaBeans体系结构
EJB服务器是管理EJB容器的高端进程或应用程序,并提供对系统服务的访问。EJB服务器也可以提供厂商自己的特性,如优化的数据库访问接口,对其他服务(如CORBA服务)的访问,对SSL 3.0的支持等。一个EJB服务器必须提供对可访问JNDI的名字服务和事务服务支持。一些可能的EJB服务器的例子如:
?数据库服务器
?应用服务器
?中间件服务器
EJB容器是一个管理一个或多个EJB类/实例的抽象。它通过规范中定义的接口使EJB类访问所需的服务。容器厂商也可以在容器或服务器中提供额外服务的接口。
现在没有EJB服务器和EJB容器间接口的规范。因为目前容器通常由EJB服务器来提供,所以一旦接口标准化了,厂商就可能提供可以在任何兼容的EJB服务器上运行的容器。
Home接口列出了所有定位、创建、删除EJB 类实例的方法。Home对象是home接口的实现。EJB类开发者必须定义home接口。容器厂商应该提供从home接口中产生home对象实现的方法。
远程接口(remote interface)列出了EJB类中的商业方法。EJBObject实现远程接口,并且客户端通过它访问EJB实例的商业方法。EJB类开发者定义远程接口,容器开发商提供产生相应的EJBObject的方法。客户端不能得到EJB实例的引用,只能得到它的EJBObject实例的引用。当客户端调用一个方法,EJBObject接受请求并把它传给EJB实例,同时提供进程中必要的包装功能。客户端应用程序通过home对象来定位、创建、删除EJB类的实例,通过EJBObject来调用实例中的商业方法。客户端可以用Java来编程,通过Java RMI来访问访问home对象和EJBObject,或用其他语言编程并通过CORBA/IIOP访问,使得部署的服务器端组件可以通过CORBA接口来访问。
上图是Enterprise JavaBeans体系结构的一个描述。下一节详细讨论了每个组件的细节。
**************
理解EJB组件
你现在应该已经熟悉了整个EJB体系结构及其主要的部件。这一节更详细地描述了这些部件,并解释它们运行时的行为语意。 Home接口 EJB库使用enterprise bean的客户端通过它的home接口创建它的实例。Home接口包含一或多个用来创建enterprise bean实例的create()方法。这个home接口不是由bean来现,而是通过称为home object的类来实现。一个home object的实例在服务器中实例,使得客户端可以访问它们。
定位home object 一个home object的引用被放在名字服务中,客户端能通过JNDI访问它。EJB服务器一般提供某种名字空间的实现,虽然有时可以使用外部的名字空间。在这两种情况下客户端都必须知道名字空间的位置以及JNDI的上下文类。例如,一个客户端的applet可能接收名字空间和JNDI上下文类作为applet的参数。除了提供位置和类名,客户端也必须知道在名字树中定位home object.这些必须在客户端启动时提供。当部署者把enterprise bean部署进EJB服务器中时,他必须可以以参数形式指定名字树,如ejb/accounting/AccountsPayable.客户端必须获得这个完整的路径名来定位并获得AccountsPayable home object的引用。并不是说客户端通过JNDI获得容器。客户端使用JNDI查找home接口的实现。Home接口的实现由某个特殊的container来提供,但这是该容器厂商的细节,enterprise bean开发者和客户端应该忽略它。
Home接口中的方法
Enterprise bean开发者定义ejbCreate()方法的同时必须在home接口中声明与其相应的create()方法。实体bean可以包含finder方法以使得客户端能定位已有的实体bean.
Home接口是通过继承javax.ejb.EJBHome来定义的。该接口包含如下的方法:
public interface javax.ejb.EJBHome extends Remote {
public EJBMetaData getEJBMetaData() throws RemoteException;
public void remove(Handle handle) throws
RemoteException,RemoveException;
public void remove(Object primaryKey) throws
RemoteException,RemoveException;
一个bean的home接口可以象下面这样:
public interface myHome extends EJBHome {
public myRem create() throws RemoteException,CreateException;
public myRem create(String str) throws
RemoteException,CreateException;
其中public interface myRem extends EJBObject { … }容器开发商负责提供实现home接口的home对象,因为只有开发商才能实现存贮enterprise bean的库的编码。容器定义容器在理解EJB规范时容器这个术语并不应从字面上简单地理解为类,而是一层代替bean执行相应服务的接口。容器开发商提供运行在EJB服务器中一套完成这些功能的工具和接口。
这些服务包括:?与二级存储中交换(对会话bean)
?持久性管理(对实体bean)
?实现创建和查找服务的home object的可用性
?在可通过JNDI访问的名字空间home object的可视性
?正确的创建、初始化和删除bean
?保证商业方法正确地运行在事务上下文中
?实现某一基本的安全服务
?从home object和EJBObject上的RMI上产生stub和skeleton
容器和EJBObject对规范经常引用由容器或EJBObject提供的服务。这些服务只是用来说明而不暗示特殊类的服务需求。支持enterprise bean的EJBObject和容器类都由容器开发商提供。这些类必须完成bean容器的功能。对bean来说容器和EJBObject是不同的入口点,对某个特殊的服务提供支持独特的能力。例如,容器通过读部署描述符来知道应用于bean方法的事务属性。然而,这些商业方法通过EJBObject调用。EJBObject必须与容器通讯来确定调用商业方法的事务上下文。确定以后,EJBObject在调用商业方法以前建立事务上下文。重要的是EJBObject 和容器的协同工作来实现容器所需的事务。容器厂商提供二者的实现,但对二者的功能分割却是自由的。与home接口的关系
目前厂商提供工具来读home 接口并产生作为容器的home object.在这种情况下厂商对每个enterprise bean类使用不同的容器类。容器厂商可以使用其它的实现策略,如一个容器类实现多个home接口,甚至一个标准的容器类创建独立的home object实现。唯一的必要条件是容器厂商必须使客户端能通过JNDI访问home object. 客户端和bean开发者都不需关心容器和home object的实现细节。Enterprise JavaBeanEnterprise bean是开发者编写的提供应用程序功能的类。开发者可以选择创建会话bean或实体bean,通过实现不同的接口声明其部署描述符来加以区分。
对于会话bean:
public class myBean implements javax.ejb.SessionBean …
对于实体bean:
public class myBean implements javax.ejb.EntityBean …
客户端不会直接访问enterprise bean中的任何方法。客户端通过EJBObject 间接调用bean中的方法,EJBObject就象一个代理一样。在把调用通过EJBObject传递时,容器开发商通过包装编码插入其自己的功能,这称为方法插入。方法插入的一个例子是为每个方法调用创建一个新的事务上下文,当方法返回到EJBObject时提交或回滚事务。当容器厂商的工具在安装bean产生stub和skeleton时,它产生bean的EJBObject一个stub和skeleton.实际上它并不创建bean本身的stub和skeleton,因为bean不会通过网络被访问。EJBObject是真正的网络对象。Bean 是包含应用相关的商业编码的代表。容器也可以调用bean中的某个方法。例如,容器保证当一个bean 实例生成后,homeobject中的create()的任何参数会传递bean相应的ejbCreate()方法。 Enterprisebean还有其它的接口和要求。然而,会话bean和实体bean的要求是不同的。这些在随后详述会话和实体bean的章节中会cover.Remote Interface编写完enterprise bean后开发者创建了一个客户端可访问创建方法的home interface,在home interface中每一个create()方法在相应的bean中都必须有一个ejbcreate()方法。同样,开发者必须创建描述客户端能够访问的商业方法的remoteinterface。因为所有的客户端调用都通过EJBObject,因此实现这个接口的是EJBObject而不是homeobject. Remote interface中列出的方法名和signature必须和实现bean的方法名和signature相同。这不同于home interface--方法signature是一样的,而名字却不同。
以下是一个remote interface的例子:
public interface Account extends javax.ejb.EJBObject {
public void deposit(double amount) throws RemoteException;
public void withdraw(double amount) throws RemoteException;
public double balance() throws RemoteException;
}
所有声明的方法都必须抛出一个RemoteException例外,因为规范要求客户端stub是RMI兼容的。但这并不意味着排除了用其它的传输方式的stub/skeleton实现,如CORBA/IIOP.Remote interface继承javax.ejb.EJBObject接口,增加了额外的方法要求。EJBObjectEJBObject是网络上可视的对象,包含stub和skeleton,作为bean的代理。Bean的remoteinterface继承了EJBObject接口,而EJBObject类实现这个remote interface,使得bean类有自己的EJBObject类。对每个bean类有一个定制的EJBObject类。
如下是EJBObject接口的定义,被bean的remote interface继承:
public interface javax.ejb.EJBObject extends java.rmi.Remote {
public EJBHome getEJBHome() throws RemoteException;
public Object getPrimaryKey() throws RemoteException;
public Handle getHandle() throws RemoteException;
public void remove() throws RemoteException,RemoveException;
public boolean isIdentical(EJBObject other) throws RemoteException;
}
实现这个接口的EJBObject类是一个RMI服务器对象,因为它是他实现了一个RMI remote interface.注意bean本身不是一个remote object,在网络上是不可视的。当容器实例 化了这个EJBObject类时,容器会初始化bean实例的引用,使得它能正确地delegate商业方法调用。厂商的实现是维护EJBObject实例和bean实例的一对一关系。因为remote interface包含EJBObject接口的方法,所以bean不必显式地实现这个接口,虽然它提供了列出的商业方法的实现。因为EJBObject必须正式地实现bean的remote interface,容器在bean安装时产生EJBObject的源代码,这些产生的源代码实现了bean的remote interface.典型 的EJBObject有一个独特的类名,作为EJBObject类和bean的联系。
****************
会话bean
会话bean是一种通过home interface创建并对客户端连接专有的enterprise bean.会话bean实例一般不与其它客户端共享。这允许会话bean维护客户端的状态。会话bean的一个例子是购货车,众多顾客可以同时购货,想他们自己的购货车中加东西,而不是向一个公共的购货车中加私人的货物。
定义一个会话bean可以通过定义一个实现javax.ejb.SessionBean接口的类来创建一个会话bean.该接口定义如下:
public interface javax.ejb.SessionBean extends javax.ejb.EnterpriseBean {
public void ejbActivate() throws RemoteException;
public void ejbPassivate() throws RemoteException;
public void ejbRemove() throws RemoteException;
public void setSessionContext(SessionContext context)
throws RemoteException;
}
javax.ejb.EnterpriseBean是一个空接口,是会话bean和实体bean的超类。
会话bean的交换
容器开发商可以实现把会话bean的实例从主存移到二级存储中的交换机制,这可以增加一段时间内实例化的会话bean的总数。容器维护一个bean的时间期限,当某个bean的不活动状态时间达到这个阙值,容器就把这个bean拷贝到二级存储中并从主存中删除。容器可以使用任何机制来实现bean的持久性存储。最常用的方式是通过bean的串行化。Bean开发者在bean中应避免使用transient fields。EjbActivate()和ejbPassivate()用来维护这个fields值。
活化和钝化
为了支持厂商提供会话bean的交换,规范定义了钝化--把bean从主存转移到二级存储的过程,活化--把bean恢复到主存中去的过程。在SessionBean接口中声明的EjbActivate()和ejbPassivate()方法,允许容器通知已经被活化的bean它将要被钝化。Bean开发者可以用这些方法释放和恢复处于钝化状态的bean所占有的值、引用和系统资源。一个可能的例子是数据库连接,作为有限的系统资源,不能被钝化的bean使
用。
有了这些方法就使得不必在使用transient.事实上,使用transient可能是不安全的,因为串行化机制自动地把值设为null或0。而通过ejbActivate()和ejbPassivate()方法显式地设置这些fields更好一些。依靠Java的串性化机制把transient fields设成null也是不可移植的,因为当bean部署在不使用Java的串性化机制获得持久性的EJB容器中时该行为会发生改变。如果容器不提供交换,那么这些方法将永远不会被调用。 当客户端调用bean的商业方法时钝化的bean被激活。当EJBObject收到方法调用的请求时,它通知容器需要活化的bean.当活化完成时,EJBObject代理对bean的方法调用。 如果bean 参与一个事务,那么它不能被钝化。把bean放在主存中更有效率,因为事务通常在很短的时间内完成。如果bean没有钝化前必须释放或活化前必须重置的状态,那么这些方法可置空。在大多数情况下,bean开发者不必在这些方法中做任何事。
会话bean的状态管理
会话bean的部署描述符必须声明该bean是有状态或无状态的。一个无状态bean是在方法调用间不维护任何状态信息的bean。通常,会话bean的优点是代替客户端维护状态。然而,让会话bean无状态也有一个好处。无状态bean不能被钝化。因为它不维护状态,所以没有需要保存的信息。容器可以删除bean的实例。客户端永远不会知道无状态bean的删除过程。客户端的引用是EJBObject.如果客户端稍后又调用了一个商业方法,则EJBObject通知容器在实例化一个新的会话bean.因为没有状态,因此也没有信息需要恢复。
无状态bean可以在客户端间共享,只是在某一时刻只能有一个客户端执行一个方法。因为在方法调用间没有需要维护的状态,所以客户端可使用任何无状态bean的实例。这使 得容器可以维护一个较小的可服用bean的缓冲池,节省主存。因为无状态bean在方法调 用间不能维护状态,因此从技术上讲在home interface的create()方法不应有参数。在创建时向bean传递参数意味着在ejbCreate()返回时需要维护bean的状态。而且,经由EJBObject调用商业方法的结果使得容器必须能重创建一个无状态的bean.这时在开始创建bean时的参数就不存在了。厂商的安装工具应该能检查home interface的无状态对话bean以保证其不包含带参数的create()方法。
实体bean
实体bean的角色
实体bean用来代表底层的对象。最常用的是用实体bean代表关系库中的数据。一个简单的实体bean可以定义成代表数据库表的一个记录,也就是每一个实例代表一个特殊的记录。更复杂的实体bean可以代表数据库表间关联视图。在实体bean中还可以考虑包含厂商的增强功能,如对象--关系映射的集成。
通常用实体类代表一个数据库表比代表多个相关联的表更简单且更有效。反过来可以轻易地向实体类的定义中增加关联,这样可以最大地复用cache并减小旧数据的表现。
实体bean和对话bean的比较
看起来会话bean好象没什么用处,尤其对于数据驱动的应用程序。当然事实并不是这样。因为实体bean(譬如说)代表底层数据库的一行,则实体bean实例和数据库记录间就是一对一的关系。因为多个客户端必须访问底层记录,这意味着,不同于会话bean,客户端必须共享实体bean。因为是共享的,所以实体bean不允许保存每个客户端的信息。会话bean允许保存客户端的状态信息,客户端和会话bean实例间是一对一的。实体bean允许保存记录的信息,实体bean实例和记录间是一对一的。一个理想的情况是客户端通过会话bean连接服务器,然后会话bean通过实体bean访问数据库。这使得既可以保存客户端的信息又可以保存数据库记录的信息。
同时会话bean也不能提供在相同或不同的EJB类调用间进行全局的事务控制。没有会话bean,应用程序开发者(客户端开发者)就必须理解EJB类的事务要求,并使用客户端的事务划分来提供事务控制。EJB的主要好处就是应用开发者不需知道EJB类的事务需求。一个会话bean可以代表一个商业操作,进行事务控制,不需要客户端进行事务划分。
Finder方法
通过home或remote interface创建和删除bean的实例,对实体bean和会话bean来说有不同的含义。对会话bean来说,删除意味着从容器中删除,不能再使用,并且其状态信息也丢失了。对于实体bean,删除意味着底层数据库记录被删除了。因此,一般不把删除作为实体bean生命周期的一部分。
创建一个实体bean意味着一个记录被插进数据库中。与删除操作类似,创建操作通常也不作为实体bean生命周期的一部分。客户端访问实体bean需要先找到它。除了create()方法,一个实体bean的home interface还有finder方法。客户端需要根据应用程序的限制来识别一个特殊的数据库记录。例如:
public interface AccountHome extends EJBHome {
public Account findByFirstLast(String first, String last)
throws RemoteException,FinderException;
public Account findByAccountNumber(String acctNum)
throws RemoteException,FinderException;
}
当客户端调用home object的任何方法,容器把调用传递到实体bean的相应方法中。
Public class myEntityBean implements EntityBean {
…
public Obejct ejbFindByFirstLast(String first, String last) {
//runs appropriate singleton SELECT statement
//returns primary key for selected row
}
public Obejct ejbFindByAccountNumber(String acctNum) {
//runs appropriate singleton SELECT statement
//returns primary key for selected row
}
}
一个较好的方法是把finder方法当成数据库的SELECT语句,而动态SQL参数相当于方法的参数。注意home interface中的finder方法向客户端返回一个对EJBObject的远程引用。Bean中的Finder方法向容器返回一个唯一的标识符,称为主键。容器用这个主键实例化一个代表选定的记录的EJBObject。不论如何实现finder方法,容器都用这个主键代表这个选定的记录,由实体类来决定如何用唯一的标识符来代表记录。
由可能一个finder方法得到满足SELECT语句条件的多个记录。这种情况下bean的finder方法返回一个主键的枚举类型。Home interface的Finder方法定义成向客户端返回EJBObject引用的枚举类型。
Public interface AccountHome extends EJBHome {
…
public Enumeration findByCompany(String companyName)
throws RemoteException,FinderException;
}
public class myEntityBean implements EntityBean {
…
public Enumeration ejbFindByCompany(String companyName) {
//runs appropriate SELECT statement
//returns an Enumeration of primary keys
}
}
主键
主键这个词有可能被曲解。把它理解为唯一的标识符更恰当些。当实体bean代表一个数据库记录时,主键可能是该记录的组合键。对于每个实体bean的实例,有一个相应的EJBObject.当一个EJBObject与一个实体bean实例对应时,该实例的主键保存在EJBObject中。
这时说该实体bean的实例有一个标识符。当客户端调用home object的finder方法时,容器会用没有标识符的实体bean的实例来执行这个请求。容器可能为此维持一个甚至多个匿名的实例。不论如何实现finder方法,都必须向容器返回底层数据的主键,如数据库的记录。如果多个记录满足条件,那么就返回多个主键。当容器得到主键后,它会用该主键初始化一个EJBObject.容器也可以初始化一个与每个EJBObject关联的实体bean的实例。因为底层记录的标识符在EJBObject中保存,因此在bean实例中没有状态。因此,容器可以在EJBObject上调用商业方法时再实例化bean,以节省内存资源。
当finder方法向容器返回主键时,容器首先会检查该主键的EJBObject是否已经存在。如果该主键的EJBObject已经存在,那么容器不会创建一个新的EJBObject,而是向客户端返回这个已存在的EJBObject的引用。这样就保证了每个记录只有一个EJBObject的实例,所有的客户端共享EJBObject.
主键只是在该类中唯一地标识bean的实例,容器负责保证其范围。应该明确finder方法只是从数据库中取出数据的主键,而不包含其它的数据项。也可能调用finder方法后不产生任何实体bean的实例,只产生包含该主键的EJBObject,当客户端调用EJBObject的方法时在产生并导入实体bean的实例。 Home object保证客户端可以访问以下方法:
public myRem findByPrimaryKey(Obejct key) throws …;
EJBObject提供以下方法的一个实现:
Public Object getPrimaryKey();
客户端能在任何时候获得实体bean的主键,并且以后可以使用该主键通过home interface重建对实体的引用。主键类的类型在部署描述符中指定。Bean开发者可以用任何类类型来表示主键。唯一的要求是类必须实现serializable,因为主键可能在客户和服务器间传递。
*********
实体bean的内外存交换
现在应该来看看javax.ejb.EntityBean接口。
public interface javax.ejb.EntityBean extends EnterpriseBean {
public void ejbActivate() throws RemoteException;
public void ejbPassivate() throws RemoteException;
public void ejbRemove() throws RemoteException,RemoveException;
public void setEntityContext(EntityContext ctx) throws RemoteException;
public void unsetEntityContext() throws RemoteException;
public void ejbLoad() throws RemoteException;
public void ejbStore() throws RemoteException;
}
活化和钝化的过程与会话bean类似。然而,不在事务中的实体bean是无状态的;其状态总是和底层的数据同步的。如果我们象钝化会话bean那样钝化实体bean,则当钝化无状态实体bean时只会删除它。但是因为容器调用finder方法需要匿名的实体bean,容器可 能为此把不活动的实体bean钝化到一个私有内存池中。一旦从EJBObject中删除实体 bean,则同时删除了标识符(主键关联)。 当客户端调用没有相关的实体bean的EJBObject的商业方法时,容器就可能用这个内存池重新分配实体bean. 注意这个内存池中的bean没有标识,可以被任何EJBObject重用。容器可以可以不维护任何有EJBObject的实体bean,除非有一个商业方法在通过EJBObject被调用。如果实体bean在事务中则需保持其与EJBObject的关联。
自管理的持久性
因为实体bean代表底层的数据,因此我们需要把数据从数据从数据库中取出然后放在bean中。当容器第一次把一个实体bean的实例与EJBObject关联时,它就开始了一个事务并调用了这个bean的ejbLoad()方法。在这个方法中开发者必须提供从数据库中取出正确的数据并把它放在bean中。当容器将要提交一个事务它首先调用bean的ejbStrore()方法。这个方法负责向数据库中回写数据。我们称之为自管理持久性,因为bean方法中的代码提供了这种同步。当ejbLoad()方法完成时,bean有可能与底层数据库不一致。商业方法的调用触发了与EJBObject关联的bean的分配,然后在事务中执行的ejbLoad()必须在部署描述符中声明。根据接收到的方法调用请求,EJBObject和容器一起建立一个事务上下文。容器分配EJBObject的bean并调用bean的ejbLoad()方法。这个方法现在运行在事务上下文中。这个事务上下文传递给数据库,根据部署描述符中指定的孤立性级别,这个事务锁定数据库中被访问的数据。只要事务上下文活动,数据库中的数据就一直保持锁定状态。当客户端或容器提交事务时,容器首先调用bean的ejbStore()方法,把bean中的数据回写到数据库中。相应的数据库记录在ejbLoad()和ejbStore()间保持锁定保证了bean和数据库间的同步。其间可以进行不同的商业方法调用。而且,ejbLoad()和ejbStore()明确地区分了事务边界,事务中可以进行任何商业方法调用。事务的持续时间由部署描述符决定,也可能由客户端决定。注意不必使用ejbActivate()和ejbPassivate()方法来执行与数据库间的同步。
容器管理的持久性
如果部署描述符声明bean使用容器管理的持久性,则不用ejbLoad()和ejbStore()来访问数据库。容器会把数据从数据库中导入到bean中,然后调用bean的ejbLoad()方法来完成从数据库中接收数据。同样地,容器调用bean的ejbStore()方法来完成把数据回写到数据库中。这些方法实际 上没有执行任何数据库操作。当开发商用复杂的工具来提供容器管理持久性时,如自动产生能进行对象--关系映射的实体bean类,规范规定了厂商必须提供的容器管理实体持久性的最小需求集。部署描述符可以指定bean的一个public域来实现与数据库列简单映射。容器使用部署描述符读出bean的这个public域并写到相应的列,或从数据库列中读出数据写到public域中。容器管理的持久性对EJB开发者来说是非常好的服务,且不需对象--关系影射等其他复杂的机制,开发者会发现它比自管理的持久性更有效率。
部署描述符
区分EJB开发的角色
EJB开发中两个主要的角色是bean开发者和bean部署者。有很多属性开发者不能预知,如数据库的网络地址,使用的数据库驱动程序等等。部署描述符作为由开发定义的特性表,由部署者添入正确的值。部署描述符有标准的格式,在开发和部署环境中是可移植的,甚至在不同EJB平台间也是可移植的。 Enterprise bean的行为控制除了为开发和部署的协同提供一个标准的属性单,部署描述符也应包含bean应如何执行有关事务和安全的细节信息。一些如访问控制链(ACL)等属性,也应该由部署者来调整以保证适当的用户能在运行时使用bean.其它属性,如事务信息,有可能完全由开发者指定,因为一般由开发者创建数据库访问代码,并熟知bean的方法应如何运行事务。
定义部署描述符
部署描述符是一个标准的Java类。创建一个实例,导入数据,然后串行化。这个串行化的部署描述符放在一个jar文件中并和enterprise bean类一起送到部署环境。部署者读取这个串行化的部署描述符,可能修改一些属性值,然后使用这个修改后的部署描述符来安装enterprise bean.
下面是部署描述符的一部分内容。它是两个其它的部署描述符类的超类。实际上超类是描述这个bean的描述符。
Javax.ejb.deployment.DeploymentDescriptor
?bean home name
?bean class name
?home interface class name
?remote interface class name
?environment properties
?control descriptors
?access control list
DeploymentDescriptor有两个子类:
javax.ejb.deployment.SessionDescriptor
?state management type
?session timeout
javax.ejb.deployment.EntityDescriptor
?list of ocntainer-managed fields
?primary key class name
描述符为实体bean和每个方法定义了事务和安全属性。这些对象的一个数组在
DeploymentDescriptor中指定。
javax.ejb.deployment.ControlDescriptor
?transaction isolation level
?Method object to which this descriptor applies
?run-as mode(for odentity mapping)
?run-as identity(for identity mapping)
?transaction attribute
部署一个enterprise bean时,分配对应的描述符,然后初始化,串行化,再将其与enterprise bean类一起放入到一个jar文件中。不同厂商在定义部署描述符时可能有不同的方式。例如,一个厂商可能使用文本方式,而另一厂商可能提供图形工具。但最后结果的部署描述符是一个标准的格式,并且在不同平台间是可移植的。
EJB Jar文件
为了包装一个enterprise bean,bean的类,接口和串行化的部署描述符放在一个jar文件中。这个jar文件必须有一个manifest文件的入口以声明一个enterprise bean的部署描述符。
Name:AccountDD.ser
Enterprise-Bean:true
在manifest中作为enterprise bean列出的是部署描述符,而不是bean类。部署描述符除了定义enterprise bean,还提供jar文件中所有文件的完整描述。开发者不必关心EJB jar文件的创建。厂商应该提供一个工具来帮助开发者创建部署描述符,然后把所有必须的文件打包进一个jar文件中。
***********
3.事务
CORBA OTS
EJB的事务模型与OTS类似。事实上,CORBA兼容的EJB服务器必须提供一个OTS兼容的事务服务。理解OTS如何工作有助于理解EJB中事务的工作方式。
定义事务
一个事务正式地定义了一个原子工作单位。一个事务中可以包含多个操作,当事务终止时,所有执行的操作或者完全执行或者完全废弃。这称为提交和回滚。
在数据库应用中广泛地使用事务。好的数据库产品对事务提供很强的支持。一个事务中访问的记录在整个事务持续期间保持锁定状态。基于数据库产品在事务开始时可以选定不同的锁定状态。选定的锁定级别应在其它的事务中优化操作的并发访问时保证数据的完整性。网络上的事务可能是分布式的,例如客户端可能在单个事务中访问两个不同的数据库。为了支持分布式事务,大多数事务管理器(包括数据库)支持两段提交。在两段提交协议中,事务管理器在准备提交事务前首先询问所有的事务参与者的工作是否完成。这是协议的第一阶段。一旦每个参与者同意提交,第二阶段才会开始。事务管理器发送独立的提交操作的命令。
OTS中的关键部件
为了更好地理解OTS如何工作,我们需要先看看其关键部件。以下的部件可以直接地映射到EJB,而理解这些部件如何在OTS中工作能使我们更好地理解EJB中的事务。
Control
terminator
Coordinator
Resource
Synchronization
下图示出了这些对象中定义的重要方法,以及在事务体系中这些对象的作用。
虚线框内是一个事务。事务中所有的对象都参与了这个事务,提交和回滚对所有的Resource对象都适用。 Control对象代表一个事务。从该对象我们可以得到Coordinator和Terminator 。EJB开发者不会看到Control对象,容器代表bean用Control对象来管理事务。
当一个bean方法返回且该方法在部署描述符中声明在方法返回前需提交该事务时,容器也用Terminator来提交或回滚事务。提交或回滚事务时,所有事务中的对象都会相应的提交或回滚。
Resource是包含事务状态的对象。例如,它可能是一个数据库连接。在这个对象上调用commit()会更新数据库。一个rollback()调用会恢复该事务开始时通过这个连接对数据作的任何改变。完成提交或回滚后,数据库中相应的记录就会解锁。应用的锁级别会在部署描述符中指定。这个对象的完全的方法集会显示这些对象实现了两段提交协议,使得每一个对象都有权决定整个事务是提交还是回滚。当一个事务完成时,不论是提交还是回滚,都要通知Synchronization对象。与Resource不同,它并不参与两段提交协议,所以无权表决一个事务应该提交还是回滚。在事务中它扮演一个被动的角色。 Coordinator是使这一切工作起作用的对象。Resource和Synchronization通过该对象注册到事务中。Bean不直接访问这个对象。 Transaction-aware objects that are intended for use with EJB will transparently obtain a reference to the current transaction"s Coordinator to register itself.
事务和可恢复的对象
在OTS中事务和可恢复的对象不同。这个区别与EJB有关。在CORBAservice? OTS规范中详细地定义了这些类型,简单地说,可恢复对象有commit()和rollback()方法,允许事务直接地操纵它自己的状态和行为。一个事务对象没有这些方法,不能被事务影响。然而,事务对象有与其关联的事务,以使分配的可恢复对象(或Resources)与事务对象的当前事务相关联。一个enterprise bean是一个事务对象的好例子。容器代表bean维护事务。任何bean分配的可恢复对象在容器的帮助下透明地放置在事务中。Bean没有commit()或rollback()方法,因此事务不能直接操纵bean.让bean作为一个可恢复的Resource并没有什么意义,因为这使得bean开发者必须为每个bean添加额外的代码,而enterprise bean几乎没有内在状态应该影响一个外部的事务。让enterprise bean作为可恢复对象的管理者,让可恢复对象完成这个工作会更好。
注意bean在容器试图提交或回滚之前可以有权表决回滚一个事务。在EJBContext中Bean可以用Coordinator中的rollback_only()方法作为setRollBackOnly()给事务设置标志,以使事务终止时间到达时请求回滚。还可以通过SessionSynchronization接口通知一个bean有关一个事务的结果。
在部署描述符中指定事务控制
bean的部署描述符包含一个ControlDescriptor对象的数组。每个ControlDescriptor描述了与方法关联的事务控制。 Bean开发者指定bean方法中的事务控制。部署者在对方法的事务相关行为没有细致了解的情况下一般不应改变这些值。如下的六个事务控制是在ControlDescriptor类定义的整形常量。除了该类的方法,没有其它的APIs能访问它们。Bean本身不访问事务控制。 Bean本身的方法不能访问其事务属性。容器读取这些控制值来维护bean的相应的事务行为。
?TX_NOT_SUPPORTED
?TX_SUPPORTS
?TX_REQUIRED
?TX_REQUIRES_NEW
?TX_MANDATORY
?TX_BEAN+NANAGED
你可以通过厂商提供的创建部署描述符的工具来为bean设置合适的ControlDescriptor.
TX_NOT_SUPPORTED
该方法不应运行在事务上下文中。如果在一个事务中执行线程,那么这个事务将挂起直到线程从方法中返回。
TX_SUPPORTS
该方法不需要事务,运行该方法时线程可能有一个活动的事务。
TX_REQUIRED
该方法必须运行在事务中。如果线程已经有一个事务,则这个线程允许进入此方法。如果线程没有事务,则容器代表线程启动一个允许线程进入的事务,当线程返回是终止事务。一般应提交事务。如果现成调用setRollbackOnly()方法,则容器相应地执行一个回滚。
TX-REQUIRED_NEW
不论线程是否有一个事务,容器都会在方法调用期间创建一个事务。当线程返回时,容器提交或回滚这个事务。如果线程有一个进行中的事务,则新事务会挂起直到线程返回或方法的事务终止。
TX_MANDATORY
当调用这个方法时线程必须已经在一个事务中。如果线程没有事务,则容器会抛出一个例外。
TX_BEAN_MANAGED
这个与上述几个不同。这种方法表明容器不应在事务管理中起作用。
JTS-Java事务服务
实际上JTS不是一个事务服务--只是底层服务提供者的一层接口。JTS非常简单,由一个接口和几个例外组成。从例外列表很容易能看出它类似OTS,虽然它也可以作为其它服务的接口。对于声明事务控制方式为自管理的bean,可以通过这个接口访问事务服务。厂商也可以用它来提供对客户端划分事务的支持。
如下是UserTransaction接口的定义:
public interface javax.jts.UserTransaction {
public void begin() throws IllegalStateException;
public void commit() throws
TransactionRolledBackException,
HeuristicMixedException,
HeuristicRollbackException,
SecurityException,
IllegalStateException;
Public void rollback() throws
SecurityException,
IllegalStateException;
Public void setRollbackOnly() throws
IllegalStateException;
public void setTransactionTimeout(int seconds);
public int getStatus();
//STATUS_ACTIVE,STATUS_COMMITTING,
//STATUS_COMMITTED,STATUS_MARKED_ROLLBACK
//STATUS_NO_TRANSACTION,STATUS_PREPARED
//STATUS_PREPARING,STATUS_ROLLEDBACK
//STATUS_ROLLING_BACK,STATUS_UNKNOWN
}
*******************
自管理的事务
如果声明一个bean的事务控制为TX_BEAN_MANAGED,则这个bean可以访问事务服务。当事务控制应用于单个的方法时这个控制只能应用于整个的bean. bean访问事务服务的能力不能只对某个方法起作用。因此一个方法声明事务控制为TX_BEAN_MANAGED,而另一个方法声明为其它不同的事务控制是错误的。厂商的安装工具应该能检测到并报告这个错误。Bean分别通过初始化时setSessionContext()或setEntityContext()方法的参数 SessionContext或EntityContext来访问事务服务。这些接口都是EJBContext的子类。
EJBContext的定义如下:
Public interface javax.ejb.EJBContext {
public Identity getCallerIdentity();
public boolean isCallerInRole(Identity other);
public EJBHome getEJBHome();
public Properties getEnvironment();
public UserTransaction getUserTransaction() throwsIllegalStateException;
public boolean getRollbackOnly();
public void set RollbackOnly();
}
一旦bean获得了一个UserTransaction的引用,就可以用这个引用管理自己的事务。有状态的会话bean的方法可以创建一个事务,而且不用终止事务就可以返回。如果还有线程调用bean的方法,容器检测是否有bean创建的活动的事务,如果被调用的事务是同一个事务,容器会允许该线程重新进入这个bean.如果bean在事务中且执行不同事务上下文的线程试图进入bean,容器会阻塞这个线程直到bean的事务终止。如果线程试图进 入事务时bean不在事务中,线程会执行一个自己的事务,容器会挂起线程当前的事务以允许线程进入。一旦线程离开方法就会恢复线程以前的事务,容器不会终止任何方法创建的事务。
对于无状态会话bean和实体bean,当事务活动时bean的方法不允许返回。容器会为此抛出一个例外。
Leaving a tranaction active across method calls is stateful,and is not allowed for stateless session beans.Fro similar reasons,entity beans are also not allowed to maintain an open transaction state across method calls when the bean has declared the TX_BEAN_MANAGED transaction control.
会话同步接口
有状态和无状态的会话bean都可以访问数据库,并且参与一个事务。为了让bean在事务中执行它的任务,bean开发者可以实现在bean中实现 javax.ejb.SessionSynchronization接口。容器能自动检测这个接口,容器会使用这个接口中的方法以使bean得到事务的状态信息。实体bean不支持这个接口。因为实体bean are implicitly transaction aware,所以容器使用不同的方法控制一个事务中的实体 bean.
SessionSynchronization接口定义如下:
public interface javax.ejb.SessionSynchronization {
public void afterBegin() throws RemoteException;
public void beforeCompletion() throws RemoteException;
public void afterCompletion(boolean yn) throws RemoteException;
}
实际上一个事务不属于一个特殊的bean的实例。一个客户端或容器中执行的线程创建一个事务,在执行bean中的代码时执行该事务。如果一个有事务上下文的线程将要进入一个会话bean,容器首先调用它的afterBegin()方法。Bean可以记录所有的商业方法运行在事务中,随后执行事务操作。如果一个操作的内部标志显示这个线程在事务外运行,则会拒绝执行事务操作的请求。直到调用afterCompletion()方法,bean会继续认为商业方法的调用都在事务中执行。Bean将推断性地清除内部标志,以表示随后到来的事务请求将被拒绝。
如果一个事务上下文的线程试图进入一个已经是另一个事务的一部分的Bean时, .Container将封锁入口,直到前一个事务提交或回滚,并且afterCompletion()方法被调用,此时,允许Bean 恢复它的状态。Container负责提供这些行为。当Container发现它将要提交一个事务时,将在这个事务的所有的session Bean上调用beforeCompletion()方法。这就给Bean足够的机会来结束事务的操作,如在提交前将数据写入数据库。反之,当Container 发现,将要回滚一个事务撕,BeforeCompletion()方法将不会被调用,因为将一个将被回滚的事务所产生的数据写入数据库是没有意义 的。
AfterCompletion()是在一个事务即将提交或回滚时被调用,来通知Bean事务操作的最终结果。Bean可以用这个信息来修正自己的内部状态,但它不能用这个信息来维持任何它将要保存的事务。尽管session Bean可以创建,提交和回滚它自己的事务,但通常不推荐这样做。
SessionSynchronization接口不提供整合外部和内部事务的能力。如果一个session bean实现了这个接口,则意味着它在方法调用之间要保持事务的状态。特别地,这也暗示在afterBegin()和afterCompletion()调用之间bean是处于一个事务中。这样,如果一个bean实现了SessionSynchronization接口并且在装配符中声明是无状态的就是一个错误。厂商提供的安装工具应该可以捕捉到并报告这个错误。无状态的session bean可以加入一个事务,但它们不能实现这个接口。事务可以是TX_BEAN_MANAGED,或者container可以在方法入口和从方法的返回上来开始和提交这个事务。Container不可允许在一个现存的事务中有一个线程进入方法,因为无状态的Bean的方法将无法知道正在运行的线程是否正在一个事务中。
解决这个问题的一个方法是使container挂起现存的事务,强迫方法总是认为线程没有在一个事务性的上下文中运行。有状态的Bran可以不实现这个接口而介入事务。但是,装配符必须要认真地配置以使得商务方法总能在正确的事务状态中运行。Bean自己没有通过这个接口来获得自己的事务的状态的权利。
加入事务
EJBContext接口在前面的一节中已经介绍了。其中有两个方法:
public boolean getRollbackOnly();
public void setRoolbackOnly();
这些方法可以有任何bean来使用,而不仅仅是那些声明了其事务控制为bean-managed的bean。事实上,那些处理自己的事务的bean将不会用到这些方法,因为这些方法不是用来和外界的事务管理器进行交流事务状态的。
当一个bean调用了setRollBackOnly()方法时,它是在向事务管理器询问何时结束将要回滚的当前事务。它将给它所参与的事务的结果一个选票。这些方法还存在于UserTransaction接口中,但由于大多数的bean都不访问这个接口,这些方法必须直接地在EJBContext中提供给bean。注意这个方法并不引发回滚操作,它只是简单地设置标志,表示事务在结束时应该回滚。不象JavaBan属性设置方法,这个方法不以boolean值作为参数。这个方法是特意设计成这样,以使得一个bean不能够改变另一个bean的回滚请求。一个bean也许希望使用getRoolBackOnly()方法,来检查当前的事务的状态。如果另一个bean已经标志这个事务为rollback,则正在调用的bean可以推测到并决定不能执行那些在、强制性达到操作,如数据库更新,而这些操作很有可能在事务结束时被反转过来。
客户划分的事务
尽管一个JEB厂商所必须的,大服务器厂商也许决定提供一个类,使得用户可以直接访问事务管理器。当需要在同一个上下文中在两个不同的服务器上调用bean时,用户也许会希望这样做。当然,每个bean的装配符可以允许这样的行为。用户可以创建一个事务,然后在两个不同server上的两个不同的bean上调用商务方法,而将事务的上下文也作为调用的一部分进行传递。一旦调用结束,用户将推测地结束事务。有container厂商产生的stub和skeleton将支持事务上下文的隐式传递。
这里是一个可能的例子:
Current current = new Current();
Current.setServiceProvider(txMgrURL);
Current.create();
Current.begin();
Current.doSomeWork();
RemRef1.doSomeWork();
RemRef2.doMoreWork();
Current.commit();
数据库操作的事务管理
bean当然希望使用JDBC来建立到数据库的连接,并在其上进行操作。但是,为了符合EJB这种container管理事务的模式,连接不能使用自动提交特性,并且不应该在连接上试图提交或回滚。
Container的角色是决定在这个事务中执行的所有行为应该提交还是回滚。这里提这样一个问题很好:container如何看到并管理由bean方法内部创建的数据库连接。尽管在规范中没有明确地提到,EJB将只能使用JDBC驱动,而JDBC也正是用来和EJB配合使用的。在数据库连接的创建时,驱动程序透明地将连接注册到正在执行的线程的当前事务中。之后当container决定结束事务时,数据库连接将自动地结束它。用OTS的术语说,数据库连接是不可恢复的资源,有事务服务在container的协助下,隐式地管理。尽管可以在这种情况下使用非事务感知的JDBC Driver,但开发者必须清楚任何在数据库连接上所做的操作都不属于bean的事务,开发者还必须确保在从方法返回之前结束数据库连接事务。试图使用SessionSynchronization接口来合并数据库连接事务和bean本身的事务是不可靠的,是不应该作的。
分布事务的支持
一个分布事务在下面的情况下是需要的:
. 一个用户使用用户划分的在多个server上的多个bean中创建和调用方法的事务。
. 一个在其他的server上调用其他EJB的方法的bean的方法。
对于这些工作厂商必须为EJBObject生成stub和skeleton来隐式地获得当前事务的上下文,同时将其通过方法调用传到远程bean。当将商务方法调用委派给bean时,远程bean的EJBObject的skeleton必须请求这个事务的上下文。
转自 http://www.yesky.com/33554432/34603008/34668544/34669568/34669920/34669930/www.chinacode.net 中国代码联盟新闻组
EJB技术介绍与研究
一. 什么是EJB
EJB 是由Sun公司提出的基于Java的面向对象的组件标准,和原来的JavaBean不同,EJB组件包含一定的业务规则,运行在服务器端。在目前的企业计算环境中,EJB和com,CORBA并列三大组件标准。
1. EJB体系结构中的六个角色
EJB规范定义了完成一个基于EJB组件的分布式应用所需要的六个角色,这六个角色可以由不同的厂商来担当,也可以某个厂商担当多个角色。这六个角色是:
Enterprise Bean Provider EJB组件开发者负责编写EJB组件,EJB组件开发者是应用领域的专家。
Application Assembler 应用组合者负责将各种EJB组合成一个完整的应用系统。
Deployer 部署者负责将包含EJB组件的ejb-jar文件部署到应用服务器中。
EJB Server Provider EJB服务器提供者负责实现一些底层的系统服务,如交易管理等。 EJB服务器提供者是系统领域的专家。
EJB Container Provider EJB容器提供者负责提供EJB组件的运行环境,EJB容器提供者和EJB服务器提供者一般是由相同的厂商担当,提供的产品叫应用服务器。
System Administrator 系统管理员负责为EJB服务器和容器提供一个企业级的计算和网络环境。
以上角色的划分保证了EJB标准的开放性和兼容性,各个角色互不依赖,也就是说,遵循EJB规范开发的应用不依赖于任何特定的应用服务器,可以部署到任何支持EJB规范的应用服务器中。
2. EJB组件的类型
EJB组件有三种类型:
Stateless Session Bean
Stateful Session Bean
Entity Bean
Stateless Session Bean不能够维持一个调用客户的状态,在一个方法调用中,Stateless Session Bean 可以维持调用客户的状态,当方法执行完,状态不会被保持。在调用完成后,Stateless Session Bean被立即释放到缓冲池中,所以Stateless Session Bean具有很好的伸缩性,可以支持大量用户的调用。
Stateful Session Bean可以一对一的维持某个调用客户的状态,并且在不同的方法调用中维持这个状态, 由于对于每一个并发用户,必须有一个对应的Stateful Session Bean,为了提高系统的效率,Stateful Session Bean可以在一定的客户空闲时间后被写入二级存储设备(如硬盘),在客户发出新的调用请求后,再从二级存储 设备恢复到内存中。
多用户下,Stateless Session Bean运行效率高于Stateful Session Bean。
Entity Bean代表数据库或另外一个企业应用系统中的数据对象,如代表数据库的一行记录。
和Session Bean不同,Entity Bean是持久的(persistent),允许共享访问。
持久性(Persistence)是指Entity Bean的状态不依赖于应用服务器而存在。因为Entity Bean是底层数据库记录的映像,会和数据库记录保持同步,所以,即使当应用服务器崩溃或停止运行,Entity Bean的状态还会保存在数据库中,不会丢失。
按持久性划分,Entity Bean分为以下两种:
Bean-Managed persistence
Container-managed persistence
Bean-managed persistence 指由Bean开发者自己管理Bean和它所代表的数据库记录的同步。
Container-managed persistence 指由Container自动管理Bean和它所代表的数据库记录的同步,不需要Bean开发者写一行Sql语句。
二.EJB的开发部署
开发一个EJB组件,EJB开发者必须提供以下四个文件:
EJB Home Interface
EJB Remote Interface
EJB class
ejb-jar.xml
EJB的home interface定义了一些方法供EJB客户端create, remove和find EJB对象。
EJB remote interface定义了EJB的业务方法,EJB所有的业务方法必须在remote interface定义才能够被客户端访问。
EJB开发者在EJB class中实现在EJB Remote Interface中定义的业务方法。
ejb-jar.xml包含该EJB组件的配置信息。
EJB部署者用应用服务器提供者提供的部署工具将一个开发完整的EJB组件部署到应用服务器中。
Apusic 对EJB的支持
Apusic Application Server完全支持EJB1.1规范,Apusic还提供完整的图形界面部署工具:Apusic Deployer,使您可以方便地调整EJB组件的各种部署参数,并将EJB组件迅速部署到Apusic Application Server中。
EJB 是由Sun公司提出的基于Java的面向对象的组件标准,和原来的JavaBean不同,EJB组件包含一定的业务规则,运行在服务器端。在目前的企业计算环境中,EJB和com,CORBA并列三大组件标准。
EJB体系结构中的六个角色
EJB规范定义了完成一个基于EJB组件的分布式应用所需要的六个角色,这六个角色可以由不同的厂商来担当,也可以某个厂商担当多个角色。这六个角色是:
Enterprise Bean Provider EJB组件开发者负责编写EJB组件,EJB组件开发者是应用领域的专家。
Application Assembler 应用组合者负责将各种EJB组合成一个完整的应用系统。
Deployer 部署者负责将包含EJB组件的ejb-jar文件部署到应用服务器中。
EJB Server Provider EJB服务器提供者负责实现一些底层的系统服务,如交易管理等。EJB服务器提供者是系统领域的专家。
EJB Container Provider EJB容器提供者负责提供EJB组件的运行环境,EJB容器提供者和EJB服务器提供者一般是由相同的厂商担当,提供的产品叫应用服务器。
System Administrator 系统管理员负责为EJB服务器和容器提供一个企业级的计算和网络环境。
以上角色的划分保证了EJB标准的开放性和兼容性,各个角色互不依赖,也就是说,遵循EJB规范开发的应用不依赖于任何特定的应用服务器,可以部署到任何支持EJB规范的应用服务器中。
EJB组件的类型
EJB组件有三种类型:
Stateless Session Bean
Stateful Session Bean
Entity Bean
Stateless Session Bean不能够维持一个调用客户的状态,在一个方法调用中,Stateless Session Bean 可以维持调用客户的状态,当方法执行完,状态不会被保持。在调用完成后,Stateless Session Bean被立即释放到缓冲池中,所以Stateless Session Bean具有很好的伸缩性,可以支持大量用户的调用。
Stateful Session Bean可以一对一的维持某个调用客户的状态,并且在不同的方法调用中维持这个状态, 由于对于每一个并发用户,必须有一个对应的Stateful Session Bean,为了提高系统的效率,Stateful Session Bean可以在一定的客户空闲时间后被写入二级存储设备(如硬盘),在客户发出新的调用请求后,再从二级存储设备恢复到内存中。
多用户下,Stateless Session Bean运行效率高于Stateful Session Bean。
Entity Bean代表数据库或另外一个企业应用系统中的数据对象,如代表数据库的一行记录。
和Session Bean不同,Entity Bean是持久的(persistent),允许共享访问。
持久性(Persistence)是指Entity Bean的状态不依赖于应用服务器而存在。因为Entity Bean是底层数据库记录的映像,会和数据库记录保持同步,所以,即使当应用服务器崩溃或停止运行,Entity Bean的状态还会保存在数据库中,不会丢失。
按持久性划分,Entity Bean分为以下两种:
Bean-Managed persistence
Container-managed persistence
Bean-managed persistence 指由Bean开发者自己管理Bean和它所代表的数据库记录的同步。
Container-managed persistence 指由Container自动管理Bean和它所代表的数据库记录的同步,不需要Bean开发者写一行Sql语句。
EJB的开发部署
开发一个EJB组件,EJB开发者必须提供以下四个文件:
EJB Home Interface
EJB Remote Interface
EJB class
ejb-jar.xml
EJB的home interface定义了一些方法供EJB客户端create, remove和find EJB对象。
EJB remote interface定义了EJB的业务方法,EJB所有的业务方法必须在remote interface定义才能够被客户端访问。
EJB开发者在EJB class中实现在EJB Remote Interface中定义的业务方法。
ejb-jar.xml包含该EJB组件的配置信息。
EJB部署者用应用服务器提供者提供的部署工具将一个开发完整的EJB组件部署到应用服务器中。
Apusic 对EJB的支持
Apusic Application Server完全支持EJB1.1规范,Apusic还提供完整的图形界面部署工具:Apusic Deployer,使您可以方便地调整EJB组件的各种部署参数,并将EJB组件迅速部署到Apusic Application Server中。
三. Java的EJB技术代表的是一种前沿技术,它使得复杂的多层结构应用系统的开发变得容易,下面则分析了EJB构件模型的体系结构、技术特点及应用前景,以及和其它相关技术的比较。
1、EJB{Enterprise JavaBeans}技术
98年3月在San Francisco召开的JavaOne98开发者大会上,Sun公司正式 发布了业界期待已久的EJB1.0版规范说明,在众多的大公司和开发人员中引起了巨大的反应,这标志着用Java开发企业级应用系统将变得简单。这次Ja- vaOne大会也被称之为"EJB展览会",许多公司纷纷表示要推出有关EJB的 产品,已经推出或正准备推出EJB产品的公司有:Sun、IBM、Inprise、BEA、 Gemstone、Informix、NCR、Netscape、Novell、Oracle、Persistence Progress、Secant、Sybase、Symantec等。目前,EJB已成为Java企业计算平台的核心技术,今年5月10日Sun公司发布了EJB1.1版本规范说明草案,对1.0版本中的一些特征作补充说明和改进。
Java平台包含许多用于开发企业级的、多层体系结构的、分布式应用系统的关键技术,如Java RMI JDBC、JNDI、Java管理API(JMAPI)、Java消息服务(JMS)、Java事务服务(JTS)、EJB等,每种技术都有各自不同的特点,本文主要讨论在企业级应用系统中极为重要的EJB技术。
Sun公司发布的EJB规范说明中对EJB的定义是:EJB是用于开发和部署多层结构的、分布式的、面向对象的Java应用系统的跨平台的构件体系结构。采用EJB可以使得开发商业应用系统变得、容易,应用系统可以在一个支持EJB的环境中开发,开发完之后部署在其它的环境中,随着需求的改变,应用系统可以不加修改地迁移到其它功能更强、更复杂的服务器上。
在分布式应用系统的开发中,采用多层体系结构的方法有很多优点,如增加了应用系统的可伸缩性、可靠性、灵活性等。因为服务器端构件可以根据应用需求迅速地加以修改,且构件在网络中的位置和 应用无关,因此系统管理员可以很容易重新配置系统的负载。多层体系结构非常适合于大数据量的商业事务系统,特别是在基于Web的应用中,需要多层体系结构支持瘦客户机及浏览器的快速applet下载。
通常一个多层体系结构的企业级应用系统的开发非常复杂,因为涉及到很多事务处理,姿态管理,多线程,资源调度,安全性操作以及其它许多底层的细节。EJB简化了多层体系结构应用系统的开发过程,使企业计算的开发人员专注于应用系统的解决方案,而不需将过多的精力放在底层的计算细节,而且开发的组件能够运行于所有支持四B的环境之中,具有可复用性。
一个开发商可以开发一个新的支持EJB的执行系统,但通常的做法是供应商对已有的系统进行政进以支持EJB,可以进行改进以支持EJB的系统包括:
· 数据库数理系统,如Oracle,Sybase,DB2等;
· web应用服务器,如Java Web Server, Netscape enterprise Server,Oracle Application Server等;
· CORBA平台,如Iona Orbix/OTM,Borland VisiBroker/IT3等;
· 事务处理监控器,如IBM TXSeries(CICS and Encina),BEA公司的Tuxedo等;
· 构件事务服务器,如Sybase Jaguar CTS 或 Microsoft Transaction Server等。
2、软构件模型
软构件模型的思想是创建可重用的构件并将其组合到容器中以得到新的应用系统,软构件模型定义了构件的基本体系结构、构件界面的结构、和其他构件及容器相互作用的机制等。利用软构件模型规范说明,构件开发人员开发那些实现了应用系统逻辑的构件,而应用系统开发人员把这些预先开发好的构件组合成应用系统。软构件模型思想已经在软件开发界迅速流行,因为它可以达到以下这些目的:复用、高层开发、简化开发过程,降低开发费用,提高所开发产品的质量等。
有两种类型的软构件模型一一客户端构件模型和服务器端构件模型。客户端构件模型如JavaBeans是专门用于处理程序的表示(presentation)及用户界面问题的;服务器端构件模型如EJB则向面向事务的中间件提供基础设施。
服务器端构件模型把构件模型的开发和中间件联系在一起。企业级应用系统的中间件以其复杂性著称,它不仅涉及到应用逻辑、并发性和伸缩性问题,也涉及到如何把不兼容的系统组合在一起的问题。服务器端构件模型解决了中间件开发的复杂性问题,它使得中间件开发人员集中于应用系统的逻辑部分,而不用处理同步、可伸缩性、事务集成、网络、分布式对象框架等一些分布式应用系统中存在的复杂的细节问题。EJB构件模型如图1所示:
EJB Server负责与操作系统有关的底层细节,诸如和其它组件或系统的通讯协议、多线程、负载平衡等,EJB Container提供EJB的生存环境和各种服务(如Transaction Server),EJB Container和Server共同组成了EJB运行环境。
通过使用RMI(Remote Method Invocation),,EJB支持远程的客户端存取。RMI产生一个对象,这个对象被安装在客户机系统中,作为存取服务器对象的代理对象,它使得服务器的位置对于客户机来说是透明的,EJB开发人员为每一个可存取的接口定义一个Java远程接口。
通过使用IIOP协议(Interne InterORB Protocol ),EJB也可以和其他的非Java客户机进行通讯,IIOP允许EJB系统和CORBA的集成,EJB可以存取CORBA服务器,CORBA客户机也可以存取EJB服务器。 EJB构件模型给开发者提供的支持包括以下一些特征:
· 可重用的构件
· 可伸缩性
· 资源管理
· 事务支持
· 并发性管理
· 安全性管理
EJB构件与Container之间有统一的界面,每一个EJB构件都可以运行在所有的运行环境中。在EJB构件模中有两种类型的EJB��session bean和entity bean,这两种类型的EJB代表了两种不同类型的事务逻辑的抽象。Session bean是短暂的对象,运行在服务器端,并执行一些应用逻辑处理,它由客户端应用程序建立,并仅被该应用程序所使用,其数据需要自己来管理,当系统停机后,session bean 不会再被恢复。Entity bean 是持久的对象,可以被其他对象调用,entity bean必须在建立时确定一个唯一的标识,并提供相应的机制允许客户应用程序根据entity bean标识来定位bean实例,多个用户可以并发访问entity bean,当系统停机时,entity bean可以被恢复。Entity bean在EJB1.0规范中可选的特征,但EJB技术发展非常快,在EJB规范说明1.I版本的草案中,已经规定entity bean是必须实现的特征,而不再是可选的特征。
需要注意的是,对于不同的EJB服务器来说,其对客户机的格式的要求是不同的,例如,客户机和服务器建立连接的方式随服务器的不同而不同,但客户机的这些差异并不影响EJB的跨平台性。
3、EJB构件模型的特点
在EJB1.O规范说明中,列出了设计EJB构件模型的目标,其中的一些如下:
· EJB将成为用Java语言开发分布式的、面向对象的企业级应用系统的标准构件体系结构,EJB使得通过组合构件得到分布式应用系统成为可能。
· EJB使得应用系统开发变得容易,应用系统开发人员不需要理解底层的事务处理细节、状态管理、多线程、资源共享管理、以及其它复杂的底层API细节。
· EJB遵循Java的"write once,run anywhere"的思想,一旦一个EJB开发完成之后,就可以部署在任何支持EJB的平台上,而不需要重新编译或对源代码进行修改。
· EJB定义了一个协议,使得用不同供应商提供的工具开发和部署的构件能在运行时互操作。
· EJB体系结构和已有的服务器平台、其它的Java APL、CORBA等兼容。
· EJB将支持enterprise Beans和其它的非Java应用系统的互操作性。
采用EJB开发应用系统有很多优点,如:(1)标准的Java技术便利应用系统可以在许多不同的服务器平台上运行;(2)修改应用系统变得容易,对单个构件进行增加、修改、删除等操作不会对应用系统体系结构产生很大影响;(3)应用系统经过划分之后,使得构件之间相互拙立,又可以相互协作,提供给用户的是该用户所需要的构件:(4)应用系统的开发变得容易,基本上是即插即用的方式;(5)应用系统从本质上说是可伸缩的,可以运行在多线程、多处理机的环境中;(6)UB可以在新的应用系统中得到重用,减少了新系统的开发时间。
当然,和其它的新技术一样,EJB也存在一些缺点,主要有:(1)EJB的数量可能非常多,以致在软件开发库中很难对这些EJB进行跟踪和管理;(2)如果应用开发人员不能正确地使用EJB,可能导致不恰当的应用系统设计,结果使得应用系统的总体性能下降;(3)除非WM及编译器的性能得到提高,否则EJB应用系统的性能仍将是个问题;(4)由于EJB技术出现时间不长,目前可用的EJB还不多,要想得到大量的商业性EJB还需要一段时间。
四、EJB和其它技术的比较
4.1 EJB和JavaBeans的比较
很多人往往把JavaBeans和EJB混淆起来,JavaBeans提供了基于构件的开发机制,JavaBeans可以在多个应用系统中重用,开发者可以通过属性表或通过定制的方法来定制JavaBean。多个JavaBean可以组合在一起构成Java applet或Java应用程序,或建立新的JavaBean,JavaBean容器可以根据JavaBean的属性、方法、事件的定义在设计时或运行时对JavaBean进行操作。
在JavaBean构件模型中,重点是允许开发人员可以在开发工具中可视化地操作构件,为此,JavaBean详细地描述了API的细节,以及构件之间事件注册和发送,属性的识别和利用,定制,永久性等细节。
EJB是一种非可视化的构件,完全位于服务器端,规范说明详细说明了EJB容器需要满足的需求以及如何和EJB构件相互协作。EJB可以和远程的客户端程序通讯,并提供一定的功能,根据规范说明,EJB是client/Server系统的一部分,如果不和客户端程序交互,EJB一般不执行具体的功能,EJB和JavaBean的一个重要区别是EJB必须在网络计算环境下使用才有意义。
EJB的重点是给出服务框架模型,以保证Java构件可以进行可移植性的部署,因此,在EJB规格说明中,并没有提到事件,因为典型的EJB构件不发送和接收事件,EJB规范说明中也没有提到属性。和一般的JavaBean一样,EJB是高度可定制的,对EJB进行定制不需要存取源代码,但对EJB可以进行定制不是在开发阶段,而是在部署阶段用部署描述符进行定制。
需要说明的是,JavaBean不仅可用于客户端应用程序的开发,也可以用于服务器端应用程序的开发,但和EJB的区别是,如果用JavaBean创建服务器端应用程序,还必须同时实现服务框架,在多层结构分布式应用系统中,服务框架的实现是非常繁琐的,对于EJB来说,服务框架已经提供,因此大大简化了系统的开发过程。
4.2 EJB和CORBA
CORBA是目前分布式对象处理的事实工业标准,大部分厂商都宣布支持CORBA标准,同样,在EJB规范中,也考虑到对CORBA的支持。规范主要规定如下:
· 一个CORBA客户机(用CORBA支持的语言写的程序)可以存取基于CORBA的EJB服务器上的构件。
· 一个客户机在一个事务过程中可以同时调用CORBA和EJB对象。
· 一个事务可以同时利用多个由不同开发商提供的,基于CORBA的EJB服务器。
为了保证多个开发商之间的基于CORBA的EJB产品之间的互操作性,规范说明定义了EJB到CORBA的映射,分为四个部分:
1、分布映射--定义了EJB和COR-BA对象之间的关系,以及EJB规范说明中定义的Java RMI到OMG IDL的映射。
2、命名映射--说明了如何利用COS命名服务来确定EJBHome对象。
3、事务映射--定义了EJB的事务支持到OMG Object Transaction Service(OTS)v1.1的映射。
4、安全性映射��定义了EJB中的安全性特征到CORBA安全性的映射。
映射确保了不管哪一种类型的客户机,通过生成相同的字节流,可以和基于CORBA的EJB服务器进行互操作。
从以上的论述中可以知道,对于EJB服务器来说,有两种类型的客户机可以使用EJB:
1.EJB/CORBA客户机��一个使用EJB API的Java客户机。客户机利用JNDI定位对象,利用HOP协议上的JavaRMI来调用远程方法,其中CORBA IDL的使用是隐含的,也就是说,开发人员只使用Java代码,开发客户机程序时可以不必了解CORBA及IDL知识。
2.纯CORBA客户机��用CORBA IDL支持的任何语言写的客户机。客户机用COS命名服务来定位对象,用CORBA IDL来调用远程方法,用对象事务服务OTS来执行事务,其中开发人员要创建一个IDL文件,即CORBA IDL的使用是显式的。
4.3 EJB和网络计算
由Beans构造的应用系统可以根据用户的需求分解成不同的构件,根据用户当前所需要的功能提供相关的构件,并随着用户新的需求随时下载新的构件,而用户没有用到其功能的构件可以驻留在服务器上,这就是网络计算所倡导的概念。
很多人并没有完全理解Java的概念,他们认为为了在一个客户端上运行Java程序,需要把一个庞大的、可能达几兆字节的Java应用程序一次性通过网络传输到客户端,事实上,这也是一些开发人员计划用Java开发应用系统时易犯的错误。
把Java应用于服务器端的应用系统可以真正体现Java的威力,EJB是Java的服务器端构件模型,该模型保证开发出来的构件可以被部署在任何支持EJB规范说明的系统中,即使该系统是由不同的开发商提供的。在网络计算环境中利用Java的最好途径是由EJB提供服务器端的构件,而由JavaBean提供客户端的构件,两者结合在一起,将向"网络就是计算机"之路迈出一大步。
五、总结
对象技术、构件技术、快速应用开发等是计算机界的热门话题,Java的EJB技术的主要思想就是让"恰当的专家做恰当的事情",应用领域的开发人员将开发精力放在应用逻辑方面,而不用考虑底层的计算技术;而计算机专业开发人员去处理底层的计算技术细节,而不用考虑应用领域的专业知识。
EJB计算技术代表的是一种前沿技术,它使得复杂的多层结构应用系统开发变得容易。EJB技术建立在已取得极大成功的Java语言之上,采用EJB技术能有效地进行软件复用,提高开发人员的效率,降低软件的开发和维护成本,提高软件的质量,控制所构建系统的复杂性。EJB技术将使得Java在企业计算中的地位得到加强,为基于Java的应用系统提供了一个框架,和目前的许多系统和模型相比,EJB具有许多优越性,种种迹象表明,EJB有可能成为多层结构分布式应用系统的服务器端构件模型的首要选择。