译:软件学院 黄学
1 简介
.Enterprise Beans 是实现Enterprise JavaBeans(EJB)技术的J2EE的组成部分,它运行于EJB容器中。EJB是一个J2EE服务器的运行时环境(Runtime environment)。虽然EJB容器对于企业级应用开发者来说是透明的,但是它提供了系统层的服务,比如Enterprise Beans的事务处理。这些J2EE核心事务应用服务能让你很快地构建并运用Enterprise Beans。
1.1Enterprise Beans是什么?
Enterprise Beans 是用java语言编写的,用于实现企业级逻辑应用的服务器端组件。企业级逻辑应用都是一些有很强针对性的代码。比如:在一个财务清单应用中,Enterprise Beans必须实现checkInventoryLevel 和 orderProduct 方法。通过调用这些方法,远程客户端能从企业应用服务器端得到相应的服务。
1.2Enterprise Beans 的优点
Enterprise Beans 能使得巨大的分布式应用简单化,有以下几个原因:
第一 EJB容器为Enterprise Beans提供了系统层次的服务,应用程序开发者可以专注于开发应用系统所需的商业逻辑,而不用担心具体服务框架的实现问题。EJB容器负责了系统层次的服务和安全认可机制,而不需要开发者去关心。
第二 是Enterprise Beans 而不是客户端包含了企业应用逻辑,客户端开发者能集中精力处理客户端应用,而不用编写企业逻辑或数据库存取的代码。这样的瘦客户端显著的优点就是客户端能运行在小设备上。
第三 因为Enterprise Beans是一个独立的组件,所以在现有的beans上能构造出新的应用,这些应用能运行于不同的J2EE服务器上。
1.3什么时候我们该用Enterprise Beans?
如果你的系统应用有如下的需求,你可以考虑用Enterprise Beans:
l 系统是可升级的。为了适应越来越多的用户的访问,你需要把系统应用分布在不同的机器上。并不是只有Enterprise Beans能运行在不同的机器上,但是它对于客户端来说是透明的,原来的访问位置还是保持没变。
l 事务处理要求数据完整性。Enterprise Beans支持这样的事务处理机制,就是事务处理可以并发存取一个共用的模块。
l 系统应用拥有多样化的客户端。只需要几行代码,远程客户端就能很容易的访问Enterprise Beans。这样,客户端可以做到多样化,瘦小,数量众多。
1.4Enterprise Beans的类型
下图摘要了Enterprise Beans的三种不同的类型。
Enterprise Beans类型
用途
Session
用于客户端的任务
Entity
描述一个现有的持久的企业实体
Message-Driven
JAVA信息服务API的监听器,处理不同步的信息
2 什么是会话Bean(Session Bean)?
一个Session Bean 代表着一个J2EE服务器中的用户。为了要访问部署在服务器上的应用,客户端要调用Session Bean的方法。Session Bean 通过执行服务器内部的企业级任务,把客户端和复杂的内部实现分离开来,并完成客户端给予的任务。
如它的名字所显示的,一个Session Bean就像一个交互式session(interactive session)。一个Session Bean是不能够共享使用的,它仅仅能够为一个客户端。同样的,一个interactive session也只能一个客户端使用。和交互式session一样,一个Session Bean是不持久的(数据并没有保存到数据库中)。当一个客户端终止会话后,它的Session Bean也将终止,不再和客户端连接。
2.1状态管理模式
Session Bean有两种类型:有状态和无状态
1. 有状态Session Bean
一个对象的状态由它的实例变量的值组成。在一个Session Bean中,它的实例变量描述了一个唯一的客户端bean的会话。因为客户端的相互之间的会话都是通过bean来“交谈”的,所以bean的状态通常也叫做对话状态(conversational state)。
状态是标识一个会话的持续时间。如果客户端移除或者停止一个bean,那么状态就将消失。但是状态的这种短暂性并不是一个缺陷,因为当客户端结束一个会话bean后,就没有必要保留它的状态了。
2. 无状态Session Bean
一个无状态Session Bean不会特别地保存客户端会话的状态。当客户端调用无状态Session Bean的方法时,bean的实例变量就会保存一个状态,但仅仅是在调用方法那段时间内。当方法调用完毕以后,状态就不再存在了。除非在调用Session Bean方法的过程中,所有的无状态Session Bean 都是被EJB容器均等的分配一个实例给任意一个客户端。
因为无状态Session Bean支持多个客户端,所以它们能够提供更好的应用,那些应用需要大量的客户端一起实现。也就是说,为同样多的客户端服务,一个应用需要的无状态Session Bean要少于有状态Session Bean。
同时,EJB容器要把有状态Session Bean中的信息保存到另一个区域,而无状态Session Bean并不需要。因而无状态Session Bean能有更好的表现。
2.2什么时候使用Session Bean?
一般的,在如下的环境下你应该使用Session Bean:
l 无论任何时候,都只有一个客户端访问bean的实例。
l 不需要长久的保存bean的状态,而仅仅是保留一段时间(可能是几个小时)。
有状态Session Bean比较适合以下的这些条件:
l 用bean的状态来描述bean和一个具体的客户端之间的会话。
l bean需要保存客户端访问bean方法时的调用信息。
l bean作为客户端和其他系统应用组件的中间传媒,向客户端展现的是,组件是一个简单的对象。
l bean在后台处理几个企业bean的数据流。举个例子,查看18章的AccountControllerEJB Session Bean应用。
为了改善性能,你应该选择一个无状态Session Bean,如果bean有如下的特性:
l bean的状态并不保存任何一个特定客户端的信息。
l 在一个单一的方法调用中,bean为所有的客户端完成一系列的任务。比如,你可以用一个无状态Session Bean发送一封在线定购验证的邮件。
l bean从数据库中读取那些经常被客户端用到的,属性为只读的数据集。比如,检索出代表这个月产品销售量的行数的bean。
3 什么是Entity Bean?
一个实体Bean(Entity Bean)表示一个是持久运行的企业实体。企业实体比如有:客户,订单和产品。在J2EE的JDK中,持久存储结构就是一个关系模型数据库。有代表性的,每个企业实体在关系模型数据库中都有一个表于它相对应,并且表中的一行(一个元组)就代表实体的一个实例。查看例子,请看第五第六章。
3.1Entity Bean 和 Session Bean有何不同?
Entity Bean 不同于 Session Bean ,有几个方面。实体bean是持久的,它允许共享访问,有自己的标识(关键码),也许还和别的实体bean有联系。如果你经常使用数据库系统,那么应该熟悉永久性数据。数据库中的数据是永久的,因为即便你关闭了数据库系统或者停止了它的应用服务,数据还是存在的。
持久性
因为实体bean的状态存储在持久性的数据库中,所以它是持久的。持久的意思是,当一个应用或者一个J2EE服务器进程结束后,实体bean的状态依然存在。
Entity Bean的永久性有两种模型:bean自管理模式和容器管理模式(bean-managed and container-managed)。在bean自管理模式中,你所写的实体bean的实例要自己管理持久性,因而代码要包括数据库访问的调用。如果你的bean由容器管理,那么EJB容器会自动产生数据库访问的调用。你所写的代码不需要包括数据库访问调用。更多的信息,可以参看容器管理持久性部分。
共享访问
一个实体bean必然可以被多个客户端共享访问。因为多个客户端都需要访问相同的数据,这也就显得实体bean在事务处理中的重要性。典型的,EJB容器提供事务处理的管理。如此,你可以在bean的部署说明书里列举出事务处理的属性。你不必要自己编写事务处理的边界条件,而容器自动为你标记这些边界。更多信息参看14章。
唯一标识
每个实体bean都有一个唯一的标识。比如,一个客户,它用客户的ID号标识。唯一标识,或者叫做有主码,可以让客户端查找到指定的实体bean。更多信息参看bean自管理模式的唯一标识部分。
联系性
就像数据库中的一个表,一个实体bean也和其他的实体bean有着联系。比如,在一个学院学生注册的应用中,StudentEJB 和 CourseEJB 必然有联系,因为学生要注册到一个班级中。
你可以用bean自管理持久性和容器管理持久性来实现实体bean之间的联系。在bean自管理模式中,你要自写代码来实现他们的联系。在容器管理模式中,容器帮你管理实体bean之间的联系。因为这样,人们经常把容器管理模式下的实体bean联系叫做容器管理联系(container-managed relationships)。
3.2容器管理模式
容器管理模式,就是EJB容器控制着所有实体bean对数据库的访问。实体bean的代码中不用指定对数据库的访问调用。因此,bean的代码不必绑定到一个特定的数据库。因为有了这样的柔和性,当你把用样的bean部署到不同的J2EE服务器上时,不需要改动或者重新编译代码。简单来说,你的实体bean更加独立。
为了产生数据库调用,容器需要收集你实体bean中抽象模式的信息。
抽象模式
作为实体bean部署描述的一部分,抽象模式定义了bean的持久性和联系性。“抽象”这个词区别出了这个模式和数据实际存储的物理模式。比如,在一个关系型数据库中,物理模式是由表和属性构成的。
你自己要在部署中指定抽象模式的名称。名称将被用JavaBeans Query Language(“EJB QL”)编写的队列引用。容器管理模式下,你必须为实体bean的所有查找方法(除了findByPrinaryKey)定义一个EJB QL队列。当查找方法被调用的时候,EJB容器就从队列中执行。更多信息请参看第8章。
你也许已经发现,在编写代码之前建立抽象模型是很有用的。表3-1表现三个实体bean中简单的抽象模型。他们之间更多的联系将在下面的章节中介绍。
Figure 3-1 A High-Level View of an Abstract Schema
持久性字段
一个实体bean的持久性字段被保存到的数据库中。总的来说,那些字段构成了bean的状态。在运行时中,EJB容器自动同步数据库中的这些状态。在部署中,EJB容器记录bean到数据库中的表,并且记录记录持久性字段到表中的属性。
例如,一个CustomerEJB实体bean,有这样的持久性字段:firstName, lastName, phone, emailAddress。在持久性容器管理模式中,这些字段是虚拟的。你在抽象模式中声明了这些字段,但是没有在bean代码中编写他们的实例变量。代替的是,这些字段在访问方法被确定。
联系性字段
一个联系性字段就犹如数据库表的外码,它确定一个与自己联系的bean。和持久性字段一样,联系性字段是虚拟的,是在企业bean中的访问方法中被确定的。但不同的是,联系性字段并不表示bean的状态。联系性字段在“ 容器管理模式中联系的方向性 (Direction in Container-Managed Relationships)“一章将被更详细地讨论。
3.3容器管理模式中联系性的多元性
这里,多元性有四种类型:
一对一:(One-to-one) 每一个实体bean的实例都和另一个实体bean的实例有关联。比如,在一个物理仓库存储模型中,每个存储箱都包含一个物品,StorageBinEJB和WidgetEJB就有一对一的关系。
一对多:(One-to-many) 一个实体bean的实例可能和多个其他的bean的实例相关联。比如,一个销售订单,可以有多个元组(多个订单)。在这样的订单应用中,OrderEJB对LineItemEJB有一对多的关系。
多对一:(Many-to-one) 多个实体bean的实例和一个实体bean的实例相关联。这种关联与一对多关联相反。例如,在上面所提到的,LineItemEJB对OrderEJB有多对一的关系。
多对多:(Many-to-many) 实体bean的实体之间相互都有多个联系。比如,在大学中,一个课程有多名学生选修,一名学生同时也选修多门课程。这样的应用中,CourseEJB和StudentEJB是多对多的关系。
3.4容器管理模式中联系的方向性
实体bean之间的联系有单向和双向两种。在双向联系中,每个实体bean都有一个联系字段与对方相对应。通过这联系字段,实体bean的代码就能访问与它相联系的bean。如果一个实体bean有一个联系字段,那么我们经常称之为bean能识别和它联系的bean。举个例子,如果OrderEJB知道LineItemEJB有哪些实例,而且LineItemEJB也知道OrderEJB属于谁,那么它们之间的关系就是双向的。
在单向联系中,仅仅只能其中一个实体bean有一个联系字段和另一个bean对应。例如,LineItemEJB有一个联系字段识别ProductEJB,但是ProductEJB不能有联系字段和LineItemEJB对应。换句话说,LineItemEJB知道ProductEJB,但ProductEJB不知道哪个LineItemEJB和它联系。
EJB QL队列经常用于定位这些联系。联系的方向性,由队列是否能定位一个bean到另一个bean来决定的。比如,一个队列能定位从LineItemEJB到ProductEJB,但是不能定位从ProductEJB到LineItemEJB。如果LineItemEJB和ProductEJB有双向联系,那么队列能双向定位。
3.5什么时候用Entity Beans
你可以在一下的情况下使用实体bean:
l Bean代表一个商业实体,而不是一个过程。比如,CreditCardEJB应为一个实体bean,但CreditCardVerifierEJB应为一个会话bean。
l Bean的状态必需是持久的。如果bean的实例终止或者J2EE服务器停止后,bean的状态仍然保存在持久性存储器中(数据库)。
4什么是消息驱动Bean(Message-Driven Bean)?
注意:这个章节联系到Java 消息服务教程(The Java Message Service Tutorial)。因为消息驱动Bean依赖于Java消息服务(JMS)技术。为了更好的了解Message-Driven Bean,你可以参考一下下面教程URL:http://java.sun.com/products/jms/tutorial/index.html。
消息驱动Bean是允许J2EE服务器异步处理消息的企业级Bean。它扮演着JMS信息监听者的角色,就像一个事件监听器,只不过是接收事件替换成接收信息。这些信息来来自于一些J2EE组件,比如一个应用客户端,其他的企业级Bean,一个web组件,或者一个没有使用J2EE技术的JMS应用,JMS系统。
消息驱动Bean当前只处理JMS消息,也许将来它能够处理其他类型的消息。
实例请参看第7章节。
4.1消息驱动Bean和会话Bean,实体Bean有什么不同?
消息驱动Bean和会话Bean,实体Bean最大的不同在于在客户端消息驱动Bean不用通过接口来访问。接口在章节“接口定义客户端访问”中有描述过。和会话Bean,实体Bean不一样的是,消息驱动Bean仅有一个bean class。
由几个方面考虑,消息驱动Bean类似于一个无状态类型会话Bean。
l 消息驱动Bean的实例不为任何客户端保存数据或会话状态。
l 所有的消息驱动Bean的实例都是平等的,允许EJB容器指派一个消息到任何一个实例中。容器把这些实例形成一个池,使得消息流能够马上被处理掉。
l 一个消息驱动Bean能够处理多个客户端的消息。
消息驱动Bean实例的变量通过操作客户端的消息能够存储一些状态。比如,一个JMS API连接,一个开放数据库的连接,或者一个实体被引用到一个企业Bean实体。
当一个消息到达,容器调用消息驱动Bean的onMessage方法来处理消息。onMessage方法一般把消息映射为五种JMS消息中的一个,并且控制它与应用的企业逻辑保持一致。onMessage方法调用辅助方法,或者可以调用一个会话Bean,一个实体Bean,来处理这些消息中的信息,或者保存到数据库中。
在事务处理的前后,一条消息可能被转换过,因此onMessage方法中的操作都是一个独立的事务处理。如果消息处理被回滚了,那么消息也将回复回原来的样子。更多的信息,请参看第7章。
4.2什么时候使用消息驱动Bean。
会话Bean和实体Bean允许你发送信息,同步接收信息,但不允许异步接收信息。为了避免绑定到多个信息源,你也许更喜欢在不在服务器端组件中使用同步阻塞。为了异步接收信息,使用消息驱动Bean吧。
5.Enterprise Bean的内容
开发一个企业Bean,你必须提供以下的文件:
l 部署描述: 一个XML文件包含部署的信息,比如它的一致性类型和事务处理的属性。使用部署工具可以通过它新Enterprise Bean向导来有效地生成一个部署说明。
l Enterprise Bean类: 实现接口定义的方法。
l 接口: 远程访问,需要远程和本地接口。本地访问,需要本地和本地的接口。请参看“定义客户端访问接口”章节。(注意这些接口都没有被消息驱动Bean使用)
l 辅助类: 企业Bean需要一些其他的类,比如异常和实用类。
你把上面所说的文件打包为EJB JAR文件。EJB JAR是存储企业Bean的模型,它是独立的,可以被用到不同的应用中去。为了构建成一个应用,你必须打包一个或多个模型(比如EJB JAR文件)到EAR文件中去。EAR是一个应用的文档文件。当你部署包含EJB JAR文件的EAT文件时,你也就是把企业Bean部署到J2EE服务器上。
6.Enterprise Bean命名习惯
因为企业Bean由多个部分构成,他们经常遵循下面的命名习惯。表3-2汇集了这个教程里的一些命名习惯。
Table 3-2 Naming Conventions for Enterprise Beans
Item
Syntax
Example
Enterprise bean name(DD)
<name>EJB
AccountEJB
EJB JAR display name(DD)
<name>JAR
AccountJAR
Enterprise bean class
<name>Bean
AccountBean
Home interface
<name>Home
AccountHome
Remote interface
<name>
Account
Local home interface
Local<name>Home
LocalAccountHome
Local interface
Local<name>
LocalAccount
Abstract schema
<name>
Account
DD表示这一项是部署说明中的元素。