EJB 介绍
EJB
1.EJB体系结构:
?
???? 包括客户端、服务器端。
?
???? 客户端:包含了调用EJB组件特定业务所需的EJB接口(包括本地和远程EJB接口);服务器端处理对象的句柄。
?
???? 服务器端:包含了EJB组件实现的实例;用来在客户端和EJB组件之间进行映射的容器代码。
?
???? EJB客户应用程序使用JNDI来查找对本地接口的实例引用,通过EJB接口来调用和引用EJB组件的全部方法和属性。
?
2.开发EJB程序的步骤:
?
???? 开发主接口、开发组件接口、开发Bean实现类、编写部署文件。
?
???? 开发主接口:bean的主接口程序,命名为<bean-name>Home,继承EJBHome,负责bean的生命周期(生成、删除、查找bean)。只需提供主接口,类方法的实现由容器完成。其方法有create,remove,search等。
?
???? 开发组件接口:命名为<bean_name>,继承EJBObject,当远程用户调用主接口方法create时,得到一个组件的远程引用,为这个bean的所有方法提供一个接口类,类和主接口的实现是由容器在部署时自动生成。
?
???? 开发Bean的实现类:命名为<bean_name>EJB,实现SessionBean接口。实现ejbCreate、ejbRemove等。
?
???? 编写部署文件:完整的bean由java类和描述其特性的ejb-jar.xml文件组成,将其打包,放在jboss中的deploy文件夹中。
?
3.开发和部署测试程序:
?
???? 开发一个Servlet测试程序,将测试程序放在tomcat的webapps中。
?
4.会话Bean:
?
???? 分为有状态会话Bean和无状态会话Bean。EJB容器通过ejb-jar.xml来判断是否为一个SessionBean提供保存状态的服务。
?
所有SessionBean的寿命周期由容器控制,Bean的客户不拥有Bean的直接引用。部署一个EJB时,容器为这个Bean分配几个实例到Component Pooling,当客户请求一个Bean时,J2EE服务器将一个预先实例化的Bean分配出去,在客户的一次会话中,可以只引用一次Bean,就可以执行这个Bean的多个方法。如果另一个客户请求同一个Bean,容器检查池中空闲的Bean(不在方法和事务中,如果一个客户长时间引用一个Bean,单执行一个方法后需等待一段事件执行另一个方法,则这段时间也是空闲的),如果全部的实例都已用完,则会自动生成一个新的实例放在池中,并分配给请求者。当负载减少时,池会自动管理Bean实例的数量,将多余的实例从池中释放。
?
5.有状态会话Bean:
?
???? 在客户访问之间保存数据,在客户引用期间维护Bean中的所有实例数据的状态值。
?
???? 有四种状态:不存在、方法现成、事务中方法现成、钝化。
?
???? 不存在:有状态SessionBean的初始化状态为不存在,当客户引用一个Bean时,按照下图中初始化一个Bean。??? 方法现成:如果客户调用remove()方法回到不存在状态,并触发Bean的ejbRemove()方法。如果客户长时间不调用Bean或服务器准备释放一些内存资源,则容器调用ejbPassivate()将这些Bean从组件池中钝化,此时释放分配的资源。当请求被钝化的Bean时,容器调用ejbActivate()激活Bean,Bean转到方法现成状态时分配Bean所需的资源。
?
???? Bean本身可以管理事务(BMT Bean-Managed Transactions),也可由容器管理事务(CMT Container-Managed Transactions)。对于CMT,容器在方法开始时打开事务,在方法结束时实现事务。通过afterBegin()、beforeCompletion()、afterCompletion()来获取事务的各个状态,afterCompletion(true)表示事务完成,afterCompletion(false)表示事务被撤消。
?
????
?
???? setSessionContext()将对象的语境放到对象变量中,容器在结束会话Bean或自动超时死亡之前自动调用ejbRemove()方法,此方法中可以用来释放资源,
?
6.无状态会话Bean:
?
???? 不会在客户访问之间保存数据,不能申明实例变量,方法只能操作传来的参数。
?
如果数据是数据的瞬像,则用无状态会话Bean。弊端:本该存储在服务器端的数据被保存在客户中,每次调用这些数据要以参数的方式传递给Bean。如果数据状态非常敏感,则不要使用无状态会话Bean。
?
有两种状态:存在、不存在。
?
?
只对客户提供业务逻辑,服务器端不保存客户端的任何数据状态,这些状态被保存在客户端。
?
当客户端不存在一个无状态Session Bean时,通过远程主接口的create()方法创建一个Bean,newInstance()负责实例化Bean,ejb容器调用bean类的setSessionContext()方法把运行环境对象SessionContext传递给Bean,然后调用ejbCreate()方法进行初始化和资源分配。
?
7.Jboss:
?
???? 用Jboss来运行EJB,将EJB的.jar文件放在jboss deploy文件夹中。这个jboss版本是Jboss2.2.1。将该EJB所有的class文件放在tomcat的webapps中。
?
配置ejb-jar.xml文件:
?
???? <?xml version="1.0" encoding="UTF-8"?>
?
<ejb-jar>
?
????????? <description>This is Hello Ejb</description>
?
????????? <display-name>HelloBean</display-name>
?
????????? <enterprise-beans>
?
????????????? <session>
?
?????????????????? <ejb-name>Hello</ejb-name>
?
?????????????????? <home>hello.HelloHome</home>
?
?????????????????? <remote>hello.Hello</remote>
?
?????????????????? <ejb-class>hello.HelloEJB</ejb-class>
?
?????????????????? <session-type>Stateless</session-type>
?
?????????????????? <transaction-type>Container</transaction-type>
?
????????????? </session>
?
????????? </enterprise-beans>
?
</ejb-jar>
?
ejb-name——是EJB的接口类名称。这里的接口类是Hello。
?
home ——是主接口,包括完整的包名。
?
ejb-class ——是EJB的类实例,包括完整的包名。
?
remote ——是EJB的接口类名称,包括完整的包名。
?
session-type——有两个值Stateless、Stateful。
?
8.实体Bean:
?
???? 用来代表底层的对象,常用来映射关系数据库中的纪录。关系数据库的字段可以被一对一的映射到一个Entity Bean中,表之间的关系可以看成是Entity Bean之间的关系,一个Entity Bean实例可能会对应表中的一条纪录或一个查询结果。
?
???? 持久性:数据库纪录的任何改变也应该被同步组件池中相关的Bean中。这一过程是持久性,是Entity Bean最重要的特征。可分为:容器管理持久性(CMP Container-Managed Persistence)和Bean管理持久性(BMP Bean-Managed Persistence)。
?
???? 容器管理者:是在Bean与基础数据库表纪录值之间负责同步工作的操作者。CMP Bean的持久性由EJB容器负责,与数据库的操作在部署EJB时由EJB部署者描述,由容器实现SQL操作和同步工作。BMP Bean的持久性由Bean负责,由Bean开发者负责与数据库交互的代码部分。
?
9.EJB 1.1规范中的CMP:
?
???? 用CMP方式编写的Bean对于数据库的操作是在部署时由部署者映射
?
到实际的数据库字段,这样增强程序的移植性。不必考虑CMP Bean如何连接到数据库,者在部署Bean时由部署者为CMP Bean指定一个数据库连接池的JNDI名。
?
???? 在设计一个CMP Bean时,Bean被固定映射一个实体表,表中的每个指定字段被映射成Bean的一个public 型类变量,在实际开发中,只需在Bean的实现类中,申明这些变量,映射操作和SQL处理由部署者和容器自动完成。
?
???? 只有Entity Bean有主键,每个Entity Bean的实例代表一行纪录。主键类型一般对应于数据表主关键字类型。在Bean的实现类中ejbCreate(),CMP Bean返回一个NULL类型的值,BMP Bean返回一个主键类型对象;在Bean的远程主接口中,create()用来插入一条数据,并根据ejbCreate()返回一个Bean的引用。
?
???? CMP Bean和会话Bean一样需要设计:远程主接口、组件接口和Bean的实现类。
?
10.Entity Bean的寿命周期:
?
?
???? 客户在调用完一个Entity Bean且释放资源后,Entity Bean的实例仍然存在于组件池中,与映射的数据库纪录保持持久性。
?
???? Entity Bean的开始状态为不存在,不引用,当客户直接向数据库插入纪录后,新的纪录将被映射Bean的实例放到组件池中等待引用,状态为存在,不引用,可以通过主接口的find方法查找这些对象到存在、引用状态,也可通过Home.remove()将其删除,回到初始状态。在初始状态通过Home.create()可以到存在、引用状态,引用的句柄由create方法返回。只有在存在、引用时可以调用组件的业务方法。用set null可以将存在、引用状态的Bean释放资源,使用主接口和组件接口的remove()将删除被映射的数据纪录,释放Entity Bean资源,但引用资源仍未释放,只用set null才可以释放引用资源。当数据库纪录被其他应用程序或进程直接插入数据后,容器将自动维持其持久性,在客户端执行完一个Entity Bean后,一定要释放其引用的资源。
?
????
?
???? 当远程客户调用远程主接口的create()时,容器调用newInstance()来创建一个Bean实例,调用setEntityContext()将当前的情境传递给Bean,进入池共享阶段。调用ejbCreate()、ejbPostCreate()来完全初始化Bean并进入准备阶段,进入准备阶段的Bean业务逻辑方法可以被客户调用,在调用setxx或getXx时,容器(CMP)或Bean(BMP)会多次调用更新(ejbStore())和提取(ejbLoad())来维护组件的持久性。
?
11.开发CMP Bean:
?
???? 开发主接口:继承EJBHome,
?
???? 开发组件接口:继承EJBObject,组件接口中申明的方法必须在Bean类中实现,组件的主键有默认的操作方法,所以可以不用在组件接口中申明,使用getPrimary()可以获取组件的主键,返回一个Object类型,在客户端程序中通过上溯造型成合适的类型。
?
???? 开发Bean的实现类:实现了EntityBean接口,ejbLoad()从数据库中读取数据纪录,ejbStore()提交当前数据状态到纪录,ejbRemove()释放实例对象并删除相关映射的数据纪录,setEntityContext()使当前Bean实例访问Bean情境,unsetEntityContext()释放特定的情境资源。Entity Bean激活时的调用顺序:ejbActivate()—ejbLoad();钝化时的顺序:ejbStore()—ejbPassivate();对于CMP的ejbCreate()返回为主关键字类型,由于容器来实现,在此方法中只需关联相关的映射字段,然后返回null。必须在类中定义与数据库表相关联的映射字段。
?
???? 编写部署文件:部署文件是ejb-jar.xml。
?
???? 对于CMP Bean来说,当一个Bean实例被客户引用,容器会自动读取Bean的实例字段,然后,通过容器与数据库发生关系,保存改变的数据,执行完后Bean被钝化,并调用ejbPassivate()来通知Bean。然后又调用这个Bean时,Bean先调用ejbActivate()通知Bean,Bean实例要激活,然后从数据库中提
?
取数据,并自动将数据值映射到Bean的实例,然后调用ejbLoad(),实例再一次被初始化,最后才开始执行要执行的业务方法。
?
?
12.开发BMP Bean:
?
????
?
???? 当一个Bean实例被客户引用,并执行一个业务方法后,容器执行ejbStore(),由这个方法把数据保存在数据库中,执行完后Bean被钝化,调用ejbPassivate()通知Bean。当客户又调用这个Bean的某业务方法时,被钝化的Bean又重新激活,EJB对象先调用ejbActivate()通知Bean,Bean实例要激活,然后调用Bean的ejbLoad(),此方法负责从数据库中提取数据,Bean实例被初始化,最后才执行要执行的业务方法。
?
???? 要求所有的数据库操作由Bean实例完成。
?
???? setXxx():来设置字段的值;getXxx():来获取Bean字段的值;ejbCreate():由开发者实现,返回创建纪录的主键值;ejbLoad():以实现组件非持久性状态缓存持久性信息;ejbStore():将信息从组件的非持久性状态转到持久性状态;ejbRemove():必须由开发者实现;unsetEntityContext():释放在setEntityContext()中缓存的情境资源和取得的资源;setEntityContext():设置情境资源,初始化数据库连接对象;ejbActivate():通过情境参数设置主键值;ejbPassivate():取消Bean与数据库记录的持久性工作,进入钝化状态。
?
???? 开发主接口:与开发CMP Bean的主接口一样。
?
???? 开发组件接口:与开发CMP Bean的主件接口一样。
?
???? 开发Bean的实现类:Bean不在声明全局的类变量,类变量的映射改教给Bean来管理。需要声明一个EntityContext情境变量,通过这个变量的getPrimaryKey()得到保存在情境中的主关键字,以便在Bean激活时重新初始化Bean的数据。因为要对数据库直接操作,所以定义一个DataSource的对象,在Bean初始化从连接池中取得一个有效数据库的对象。定义的Connect对象将在获取一个数据库连接时被引用。定义一个String类型的static变量存放一个获得数据库资源的JNDI名。
?EJB核心技术及其应用 [转帖]
?
文章摘要:?
?
EJB的全称是Enterprise java bean。是JAVA中的商业应用组件技术。EJB结构中的角色 EJB 组件结构是基于组件的分布式计算结构,是分布式应用系统中的组件...?
?
一、EJB技术简介
?
EJB的全称是Enterprise java bean。是JAVA中的商业应用组件技术。EJB结构中的角色 EJB 组件结构是基于组件的分布式计算结构,是分布式应用系统中的组件。
?
一个完整的基于EJB的分布式计算结构由六个角色组成,这六个角色可以由不同的开发商提供,每个角色所作的工作必须遵循Sun公司提供的EJB规范,以保证彼此之间的兼容性。这六个角色分别是EJB组件开发者(Enterprise Bean Provider) 、应用组合者(Application Assembler)、部署者—eployer)、EJB 服务器提供者(EJB Server Provider)、EJB 容器提供者(EJB Container Provider)、系统管理员(System Administrator):
?
二、EJB中各角色的分析
?
1、EJB组件开发者(Enterprise Bean Provider)
?
EJB组件开发者负责开发执行商业逻辑规则的EJB组件,开发出的EJB组件打包成ejb-jar文件。EJB组件开发者负责定义EJB的remote和home接口,编写执行商业逻辑的EJB class,提供部署EJB的部署文件(deployment descriptor)。部署文件包含EJB的名字,EJB用到的资源配置,如JDBC等。EJB组件开发者是典型的商业应用开发领域专家。
?
EJB组件开发者不需要精通系统级的编程,因此,不需要知道一些系统级的处理细节,如事务、同步、安全、分布式计算等。
?
2、应用组合者(Application Assembler)
?
应用组合者负责利用各种EJB组合一个完整的应用系统。应用组合者有时需要提供一些相关的程序,如在一个电子商务系统里,应用组合者需要提供JSP(Java Server Page)程序。
?
应用组合者必须掌握所用的EJB的home和remote接口,但不需要知道这些接口的实现。
?
3、部署者—eployer)
?
部署者负责将ejb-jar文件部署到用户的系统环境中。系统环境包含某种EJB Server和EJB Container。部署者必须保证所有由EJB组件开发者在部署文件中声明的资源可用,例如,部署者必须配置好EJB所需的数据库资源。
?
部署过程分两步:部署者首先利用EJB Container提供的工具生成一些类和接口,使EJB Container能够利用这些类和接口在运行状态管理EJB。 部署者安装EJB组件和其他在上一步生成的类到EJB Container中。 部署者是某个EJB运行环境的专家。
?
某些情况下,部署者在部署时还需要了解EJB包含的业务方法,以便在部署完成后,写一些简单的程序测试。
?
4、EJB 服务器提供者(EJB Server Provider)
?
EJB 服务器提供者是系统领域的专家,精通分布式交易管理,分布式对象管理及其它系统级的服务。EJB 服务器提供者一般由操作系统开发商、中间件开发商或数据库开发商提供。
?
在目前的EJB规范中,假定EJB 服务器提供者和EJB 容器提供者来自同一个开发商,所以,没有定义EJB 服务器提供者和EJB容器提供者之间的接口标准。
?
5、EJB 容器提供者(EJB Container Provider)
?
EJB 容器提供者提供以下功能:
?
提供EJB部署工具为部署好的EJB组件提供运行环境 。EJB容器负责为EJB提供交易管理,安全管理等服务。
?
EJB 容器提供者必须是系统级的编程专家,还要具备一些应用领域的经验。EJB 容器提供者的工作主要集中在开发一个可伸缩的,具有交易管理功能的集成在EJB 服务器中的容器。EJB 容器提供者为EJB组件开发者提供了一组标准的、易用的API访问EJB 容器,使EJB组件开发者不需要了解EJB服务器中的各种技术细节。
?
EJB容器提供者负责提供系统监测工具用来实时监测EJB容器和运行在容器中的EJB组件状态。
?
6、系统管理员(System Administrator)
?
系统管理员负责为EJB服务器和容器提供一个企业级的计算和网络环境。
?
系统管理员负责利用EJB 服务器和容器提供的监测管理工具监测EJB组件的运行情况。
?
三、EJB的体系结构:
?
EJB分布式应用程序是基于对象组件模型的,低层的事务服务用了API技术。EJB技术简化了用JAVA语言编写的企业应用系统的开发,配置。EJB技术定义了一组可重用的组件:Enterprise Beans。你可以利用这些组件,象搭积木一样的建立你的分布式应用程序。当你把代码写好之后,这些组件就被组合到特定的文件中去。每个文件有一个或多个Enterprise Beans,在加上一些配置参数。最后,这些Enterprise Beans被配置到一个装了EJB容器的平台上。客户能够通过这些Beans的home接口,定位到某个beans,并产生这个beans的一个实例。这样,客户就能够调用Beans的应用方法和远程接口。
?
EJB服务器作为容器和低层平台的桥梁管理着EJB容器和函数。它向EJB容器提供了访问系统服务的能力。例如:数据库的管理和事务的管理,或者对于其它的Enterprise的应用服务器。所有的EJB 实例都运行在EJB容器中。
?
容器提供了系统级的服务,控制了EJB的生命周期。EJB中的有一些易于使用的管理工具如:Security--配置描述器(The Deployment descriptor)定义了客户能够访问的不同的应用函数。容器通过只允许授权的客户访问这些函数来达到这个效果。Remote Connectivity--容器为远程链接管理着低层的通信issues,而且对Enterprise Beas的开发者和客户都隐藏了通信细节。EJB的开发者在编写应用方法的时候,就象是在条用本地的平台一样的。客户也不清楚他们调用的方法可能是在远程被处理的。Life Cycle managment--客户简单的创建一个Enterprise beans的实例,并通常取消一个实例。而容器管理着Enterprise Beans的实例,使Enterprise Beans实现最大的效能和内存利用率。容器能够这样来激活和使Enterprise Beans失效,保持众多客户共享的实例池。等等。
?
Trasction management-配置描述器定义了Enterprise beans 的事务处理的需求。容器管理着那些管理分布式事务处理的复杂的issues。这些事务可能要在不同的平台之间更新数据库。容器使这些事务之间互相独立,互不干扰。保证所有的更新数据库都是成功发生的,否者,就回滚到事务处理之前的状态。
?
EJB 组件是基于分布式事务处理的企业级应用程序的组件。所有的EJB都有如下的特点:EJB包含了处理企业数据的应用逻辑。定义了EJB的客户界面。这样的界面不受容器和服务器的影响。于是,当一个EJB被集合到一个应用程序中去时,不用更改代码和重新编译。EJB能够被定制 各种系统级的服务,例如安全和事务处理的特性,都不是属于EJB类的。而是由配置和组装应用程序的工具来实现。 有两种类型的EJB: Session beans 和 entity beans.Session beans是一种作为单用户执行的对象。作为对远程的任务请求的相应,容器产生一个Session beans 的实例。一个Session beans有一个用户.从某种程度上来说,一个Session bean 对于服务器来说就代表了它的那个用户.Session beans 也能用于事务,它能够更新共享的数据,但它不直接描绘这些共享的数据。Session beans 的生命周期是相对较短的。典型的是,只有当用户保持会话的时候,Session beans 才是活着的。一旦用户退出了,Session beans 就不再与用户相联系了。Session beans被看成是瞬时的,因为如果容器崩溃了,那么用户必须重新建立一个新的Session对象来继续会话。
?
Session bean典型的声明了与用户的互操作或者会话。也就是说,Session bean了在客户会话期间,通过方法的调用,掌握用户的信息。一个具有状态的Session bean称为有状态的Session bean.当用户终止与Session beans互操作的时候.会话终止了,而且,bean 也不再拥有状态值。Session bean也可能是一个无状态的 session bean.无状态的Session beans并不掌握它的客户的信息或者状态。用户能够调用beans的方法来完成一些操作。但是,beans只是在方法调用的时候才知道用户的参数变量。当方法调用完成以后,beans并不继续保持这些参数变量。这样,所有的无状态的session beans的实例都是相同的,除非它正在方法调用期间。这样,无状态的Session beans就能够支持多个用户.容器能够声明一个无状态的Session beans.能够将任何Session beans指定给任何用户.
?
Entity Beans对数据库中的数据提供了一种对象的视图。例如:一个Entity bean能够模拟数据库表中一行相关的数据。多个client能够共享访问同一个Entity bean.多个client也能够同时的访问同一个Entity bean.Entity beans通过事务的上下文来访问或更新下层的数据。这样,数据的完整性就能够被保证。Entity Beans能存活相对教长的时间,并且状态是持续的。只要数据库中的数据存在,Entity beans就一直存活。而不是按照应用程序或者服务进程来说的。即使EJB容器崩溃了,Entity beans也是存活的。Entity Beans生命周期能够被容器或者 Beans自己管理。如果由容器控制着保证 Entity beans持续的issus。如果由Beans自己管理,就必须写Entity beans的代码,包括访问数据库的调用。
?
Entity Beans是由主键(primary key 一种唯一的对象标识符)标识的。通常,主键与标识数据库中的一块数据,例如一个表中的一行,的主键是相同的。主键是client能够定位特定的数据块。
?
四、开发EJB
?
1、类介绍:
?
开发EJB的主要步骤一般来说,整个的开发步骤(开发,配置,组装)包括如下几个方面。开发:首先要定义三个类:Bean类本身,Bean的本地和远程接口类。 配置:配置包括产生配置描述器--这是一个XML文件、声明了Enterprise Bean的属性、绑定了bean的class文件(包括stub文件和skeleton文件)。最后将这些配置都放到一个jar文件中。还需要在配置器中定义环境属性。组装应用程序:包括将Enterprise beans安装到Server服务器中,测试各层的连接情况。程序组装器将若干个Enterprise Beans与其它的组件结合起来。组合成一个完整的应用程序。或者将若干个Enterprise beans组合成一个复杂的Enterprise Bean。管理Enterprise Bean。
我们必须定义和编写一些EJB中的基本类。如Enterprise bean类:这是Enterprise bean内部应用逻辑的实现。编写Enterprise bean的远程接口类。编写Enterprise bean的本地接口类。说明主键类,主键类只是对于Entity bean才需要的。在Enterprise bean的配置描述器中指定主键的名字。Enterprise beans提供者定义了远程接口和本地接口,实现了EJB类本身。Remote接口中提供了客户调用EJB实现的应用逻辑函数的接口。而home接口提供了产生和定位remote接口实例的方法。?
?
在Enterprise bean本身类的实现,本地home接口,远程remote接口之间并没有正式的联系(例如继承关系)。但是,在三个类里声明的方法却必须遵守EJB里面定义的规范。例如: 你在Enterprise bean里面声明了一个应用程序的方法或者说应用逻辑。也在beans的remote接口中声明了这个方法,那么,这两个地方必须要同样的名字。Bean的实现里面必须至少有一个Create()方法:ejbCreate()。但是可以有多个带有不同参数的create()方法。
?
在home接口中,也必须有相同的方法定义(参数的个数相同)。EjbCreate()方法返回的一个容器管理的持久对象。它们都返回一个容器管理持久性的主键值。但是,在home的相应的Create()方法中返回值的类型是remote接口。
?
注意:实体bean的实现的ejbCreate方法有点不同。实体bean可以不定义ejbCreate方法。如果实体只是通过应用程序或通过数据库管理程序的途径被加到数据库中,实体bean就省略了ejbCreate方法。EjbCreate返回的值是主键类型。如果ejbCreate方法是容器管理持久性的实体bean的方法,它的返回值就是NULL类型。如果实体bean实现了Bean管理的持久性,ejbCreate方法就返回值类型就是主键类型。容器的任务是把各接口和Enterprise bean的实现类结合起来。保证在编译时和运行时,各接口和实现类是相对应的。?
?
EJB的实现类,各接口要从不同的基类中继承下来。一个会话bean必须实现基类javax.ejb.SessionBean。而实体bean必须实现基类javax.ejb.EntiyBean。这些EJB的基类都是从javax.ejb.EnterpriseBean继承而来。而javax.ejb.EnterpriseBean又是从java.io.Serializable继承而来。每一个Enterprise Bean都必须有一个remote接口。Remote接口定义了应用程序规定客户可以调用的逻辑操作。这些是一些可以由客户调用的公共的方法,通常由Enterprise beans类来实现。注意,Enterprise bean的客户并不直接访问Bean。而是通过remote接口来访问。Enterprise bean类的remote接口扩展了javax.ejb.EJBObject类的公共java接口。而Javax.ejb.EJBObject是所有remote接口的基类。其代码如下:?
?
package javax.ejb;
public interface EJBObject extends java.rmi.Remote{
public EJBHome getEJBHome() throws java.rmi.RemoteException;
public Object getPrimaryKey() throws java.rmi.RemoteException;
public void Remove() throws java.rmi.RemtoeException, java.rmi.RemoveException
public Handle getHandle() throws java.rmi.RemoteException;
boolean isIdentical (EJBObject p0) throws java.rmi.RemoteException;
}??
?
getEJBHome()方法允许你取得一个相关的Home接口。对于 实体Bean,用getPrimaryKey()方法获得实体Bean的主键值。Remove()可以删除一个Enterprise bean。具体的语义在各种不同类型的enterprise beans的生命周期中,由上下文中解释的。方法getHandle()返回了一个Enterprise bean实例的持久的句柄。IsIndentical()方法允许你去比较Enterprise beans是否相同。
?
2、方法:
?
所有的remote接口中的方法必须声明为公共(public)的,并必须抛出java.rmi.RemotException异常。另外,所有的remote接口中的方法定义的参数和都必须是在RMI-IIOP中有效的。对每一个在remote接口中定义的方法,在Enterprise bean 类里面都要有相应的方法。相应的方法必须要有同样的名字,同样类型和数量的参数,同样的返回值,而且还要抛出同样的例外。 如下代码显示了一个ATM例子的会话bean的remote接口Atm,。里面声明了一个应用方法transfer()。黑体部分表示EJB规范中必须要有的内容。Remote接口必须扩展javax.ejb.EJBObject类。从客户端调用的Enterprise bean的每一个方法都必须在remote接口中声明。Transfer()方法抛出了两个意外。其中InSufficientFundsException例外是应用程序定义的意外。
?
Public interface Atm extends javax.ejb.EJBObject{
Public void transfer(String Source, String Target, float amount)
Throws java.rmi.RemoteException, InSufficientFundsException;
}??
?
Home接口必须定义一个或多个的Create()方法。每一个这样的Create()方法都必须命名为Create。并且,它的参数,不管是类型还是数量都必须与bean类里面的ejbCreate()方法对应。注意,home接口中的Create()方法和bean类中ejbCreate()方法的返回值类型是不同的。实体bean的home接口还包含find()方法。 每一个Home接口都扩展了javax.ejb.EJBHome接口。如下代码显示了javax.ejb.EJBHome接口的定义:?
?
package javax.ejb;
public interface EJBHome extends java.rmi.Remote() {
void remove(Handle handle) throws java.rmi.RemoteException,RemoveException;
void remove(Object primarykey) throws java.rmi.RemoteException,RemoveException;
EJBMetaData getEJBMetaData() throws RemoteException;
Homehandle getHomeHandle() throws RemoteException;
}?
?
这里提供了两个remove()方法来删除Enterprise bean的实例。第一个remove方法是通过句柄来删除一个Enterprise bean的实例。第二个remove方法通过主键来删除一个Enterprise bean的实例。 在众多的Enterprise bean实例中,句柄唯一的标识一个实例。一个句柄与它引用的Enterprise bean有相同的生命期。考虑一个实体对象,客户可以通过一个句柄来重新获得相应的Enterprise bean的实例。一个句柄能够对应一个Enterprise bean对象的多个实例。例如,即使当Enterprise bean对象所在的主机崩溃了,或者Enterprise bean对象在不同的机器之间移动,句柄仍是有效的。这里的句柄是Serialized句柄,与CORBA中的字符串化的CORBA对象的引用是相似的概念。在EJBHome接口中的第二个remove操作通过其主键来决定要删除的Enterprise bean。主键可以是扩展了Java Object类的任何类型,但是,必须要实现Java的Serializable接口。主键是标识实体bean的主要的方法。通常,主键是数据库中的一个关键字,唯一的定义了由实体bean代表的数据。?
?
方法getEJBMetaData()返回了Enterprise bean对象的metadata接口。这个接口允许客户获得Enterprise bean的metadata信息。当开发工具来编译链接应用程序的时候,或者配置工具来配置的时候,可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口,home类,remote接口,还有获得主键的方法。也提供了一个isSesson()的方法来确定在放这个home接口的对象是会话bean还是实体bean。
?
IsStatelessSession()方法指示这个会话bean是有状态还是无状态的。如下代码显示了javax.ejb.EJBMetadata接口的定义部分的代码。
?
Public javax.ejb; Public interface EJBMetaData{
EJBHome getEJBHome();
Class getHomeInterfaceClass();
Class getRemoteInterfaceClasss();
Class getPrimaryKeyClass();
Boolean isSession();
Boolean isStatelesssSession();
}??
?
对每一个Create()方法,EJB规范定义了如下的命名约定。它的返回值是会话bean的remote接口的类型。方法的名字只能是Create()。对会话bean类中的每一个ejbCreate()方法都必须有一个Create()与之对应。 对于每一个Create()方法的参数的类型和数量都必须与会话bean类中的ejbCreate()方法相对应。方法必须抛出java.rmi.RemoteException例外。 方法必须抛出javax.rmi.CreateExeption例外。 Create()方法的参数是用来初始化新的会话bean对象的。 如下代码显示了一个会话bean对象的不同的Create()方法,其中必须的部分用粗体显示:?
?
public interface AtmHome extends javax.ejb.EJBHome{
Atm create() throws java.rmi.RemoteException,javax.ejb.CreateException;
Atm create(Profile preferredProfile)
Throws java.rmi.RemoteExeption,javax.ehrows java.rmi.RemoteException,RemoveException;
EJBMetaData getEJBMetaData() throws RemoteException;
Homehandle getHomeHandle() throws RemoteException;
}?
?
这里提供了两个remove()方法来删除Enterprise bean的实例。第一个remove方法是通过句柄来删除一个Enterprise bean的实例。第二个remove方法通过主键来删除一个Enterprise bean的实例。在众多的Enterprise bean实例中,句柄唯一的标识一个实例。一个句柄与它引用的Enterprise bean有相同的生命期。考虑一个实体对象,客户可以通过一个句柄来重新获得相应的Enterprise bean的实例。一个句柄能够对应一个Enterprise bean对象的多个实例。例如,即使当Enterprise bean对象所在的主机崩溃了,或者Enterprise bean对象在不同的机器之间移动,句柄仍是有效的。这里的句柄是Serialized句柄,与CORBA中的字符串化的CORBA对象的引用是相似的概念。?
?
在EJBHome接口中的第二个remove操作通过其主键来决定要删除的Enterprise bean。主键可以是扩展了Java Object类的任何类型,但是,必须要实现Java的Serializable接口。主键是标识实体bean的主要的方法。通常,主键是数据库中的一个关键字,唯一的定义了由实体bean代表的数据。方法getEJBMetaData()返回了Enterprise bean对象的metadata接口。这个接口允许客户获得Enterprise bean的metadata信息。当开发工具来编译链接应用程序的时候,或者配置工具来配置的时候,可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口,home类,remote接口,还有获得主键的方法。也提供了一个isSesson()的方法来确定在放这个home接口的对象是会话bean还是实体bean。IsStatelessSession()方法指示这个会话bean是有状态还是无状态的。如下代码显示了javax.ejb.EJBMetadata接口的定义部分的代码。
?
Public javax.ejb;
Public interface EJBMetaData{
EJBHome getEJBHome();
Class getHomeInterfaceClass();
Class getRemoteInterfaceClasss();
Class getPrimaryKeyClass();
Boolean isSession();
Boolean isStatelesssSession();
}?
?
五、EJB的编程环境:
?
1、 使用Jbuilder
?
Jbuilder与EJB Container能够进行无缝连接。Jbuilder和Inprise的应用服务器包括了所有的开发和配置Enterprise Beans的工具以及所需要的库:运行和管理Enterprise Bean的容器、命名服务、 事务服务、Java数据库、开发Enterprise Beans所需要的API、一个增强的java-to-iiop编译器,支持值类型和RMI信号等等。?
?
Jbuilder还提供了一个快速开发应用程序Enterprise Beans的工具和向导。通过简单而且直观的步骤,向导帮助你建立一个Enterprise Bean。自己设定某些缺省值,产生了bean的模板,在上面,我们可以增加我们自己的应用逻辑。Jbuilder也提供了一个EJB的接口生成向导。向导在Enterprise Bean的公共方法基础上生成了Remote接口和Home接口。Jbuilder还提供一个配置器的向导帮助我们逐步的建立XML描述器文件。并将生成的Stubs集中到一个jar文件中。
?
2、使用Jbuilder之外的集成环境:?
?
如果你使用其它的除了别的集成环境(IDE)。要确定使用了集成环境IDE所带的容器工具。也要验证IDE是否支持EJB规范的相应的版本,还要确定它是否正确的支持EJB的API。?
?
要确定JD到所支持的EJB容器的版本。可以通过检查Inprise的安装说明来确定EJB容器所支持的支持JDK的版本。?
?
在配置Enterprise Bean的时候,你必须使用Inprise的应用服务器所提供的工具。这些工具能够编辑和修改第三方的代理商提供的Inprise配置描述器。还能够验证配置描述器,能够验证bean的源代码。?
?
六、一个简单的HELLO例子?
?
1、安装Apusic Application Server?
?
Note:以下以Linux为例,来说明Apusic Application Server的安装过程。其他平台的安装,可参考Apusic Application Server安装手册。?
?
下载JDK1.2,Apusic Application Server必须运行在JDK1.2以上环境中。可从以下站点下载最新JDK。
http://java.sun.com?
?
下载Apusic Application Server
Apusic Application Server 试用版可从以下网址得到:
http://www.apusic.com/download/enter.jsp?
?
在下载完成后,你可以得到一个包裹文件apusic.zip,选定安装目录,假设安装到/usr下,则用以下命令:?
?
cd /usr
jar xvf apusic.zip
/usr下会出现一个目录apusic,Apusic Application Server的所有程序都被解压到/usr/apusic下。
将以下路径加入到CLASSPATH中
/usr/apusic/lib/apusic.jar
$JAVA_HOME/lib/tools.jar??
?
用以下命令运行Apusic Application Server?
?
java -Xms64m com.apusic.server.Main -root /usr/apusic?
?
2、定义EJB远程接口(Remote Interface)
?
任何一个EJB都是通过Remote Interface被调用,EJB开发者首先要在Remote Interface中定义这个EJB可以被外界调用的所有方法。执行Remote Interface的类由EJB生成工具生成
?
以下是HelloBean的Remote Inteface程序:?
?
package ejb.hello;
?
import java.rmi.RemoteException;
import java.rmi.Remote;
import javax.ejb.*;
?
public interface Hello extends EJBObject, Remote {
?
//this method just get "Hello World" from HelloBean.
public String getHello() throws RemoteException;
}
?
?
3、定义Home Interface
?
EJB容器通过EJB的Home Interface来创建EJB实例,和Remote Interface一样,执行Home Interface的类由EJB生成工具生成。?
?
以下是HelloBean 的Home Interface程序:
?
package ejb.hello;?
?
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 HelloHome extends EJBHome {
?
public Hello create() throws CreateException,
RemoteException;
?
}
?
?
4、写EJB类
?
在EJB类中,编程者必须给出在Remote Interface中定义的远程方法的具体实现。EJB类中还包括一些 EJB规范中定义的必须实现的方法,这些方法都有比较统一的实现模版,编程者只需花费精力在具体业务方法的实现上。?
?
以下是HelloBean的代码:
?
package ejb.hello;
?
import javax.ejb.*;
import java.util.*;
import java.rmi.*;
?
public class HelloBean implements SessionBean {
static final boolean verbose = true;
?
private transient SessionContext ctx;
?
// 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;
}
?
/**
* This method corresponds to the create method in
* the home interface HelloHome.java.
* The parameter sets of the two methods are
* identical. When the client calls
* HelloHome.create(), the container allocates an
* instance of the EJBean and calls ejbCreate().
*/
public void ejbCreate () {
if (verbose)
System.out.println("ejbCreate called");
}
/**
* **** HERE IS THE BUSINESS LOGIC *****
* the getHello just return a "Hello World" string.
*/
public String getHello()
throws RemoteException
{
return("Hello World");
}
}
?
?
5、创建ejb-jar.xml文件
?
ejb-jar.xml文件是EJB的部署描述文件,包含EJB的各种配置信息,如是有状态Bean(Stateful Bean) 还是无状态Bean(Stateless Bean),交易类型等。ejb-jar.xml文件的详细信息请参阅EJB规范。以下是HelloBean的配置文件:
?
<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems Inc.//DTD Enterprise JavaBeans 1.2//EN" " http://java.sun.com/j2ee/dtds/ejb-jar_1_2.dtd";>
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Hello</ejb-name>
<home>ejb.hello.HelloHome</home>
<remote>ejb.hello.Hello</remote>
<ejb-class>ejb.hello.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Hello</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>?
?
6、编译和部署
?
编译Java源文件并将编译后class和ejb-jar.xml打包到Hello.jar?
?
mkdir build
mkdir build/META-INF
cp ejb-jar.xml build/META-INF
javac -d build *.java
cd build
jar cvf Hello.jar META-INF ejb
cd ..??
?
用EJB工具生成可部署到Apusic Application Server中运行的jar文件:?
?
java com.apusic.ejb.utils.EJBGen -d /usr/apusic/classes/Hello.jar build/Hello.jar?
?
增加/usr/apusic/classes/Hello.jar到CLASSPATH中?
?
将Hello.jar加入到Apusic Application Server配置文件中。在/usr/apusic/config/server.xml 加入以下几行:?
?
<module>
<ejb>
<ejb-uri>classes/Hello.jar</ejb-uri>
<bean>
<ejb-name>Hello</ejb-name>
<jndi-name>HelloHome</jndi-name>
</bean>
</ejb>
</module>?
?
启动服务器?
?
java -Xms64m com.apusic.server.Main -root /usr/apusic
?
7、写客户端调用程序
?
您可以从Java Client,JSP,Servlet或别的EJB调用HelloBean。
调用EJB有以下几个步骤:
通过JNDI(Java Naming Directory Interface)得到EJB Home Interface
通过EJB Home Interface 创建EJB对象,并得到其Remote Interface
通过Remote Interface调用EJB方法?
?
以下是一个从Java Client中调用HelloBean的例子:
?
package ejb.hello;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;
import javax.ejb.*;
import java.rmi.RemoteException;
?
/**
* @author Copyright (c) 2000 by Apusic, Inc. All Rights Reserved.
*/
public class HelloClient{
public static void main(String args[]){
String url = "rmi://localhost:6888";
Context initCtx = null;
HelloHome hellohome = null;
try{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.apusic.jndi.InitialContextFactory");
env.put(Context.PROVIDER_URL, url);
initCtx = new InitialContext(env);
}catch(Exception e){
System.out.println("Cannot get initial context: " + e.getMessage());
System.exit(1);
}
try{
hellohome = (HelloHome)initCtx.lookup("HelloHome");
Hello hello = hellohome.create();
String s = hello.getHello();
System.out.println(s);
}catch(Exception e){
System.out.println(e.getMessage());
System.exit(1);
}
}
?
}
?
?
运行HelloClient,可得到以下输出:
?
Hello World?
?
?
?
EJB(Enterprise JavaBeans)可不算什么新概念了,但许多人在听到或者看到这个名词的时候还会眼晕。EJB组件在J2EE规范中自成一层,把应用程序的表示层和后端信息系统(比如数据库或者主框架计算机)捆绑了起来。EJB架构既用到了EJB对象的功能又利用了它们所运行的环境。
?
为什么出来个EJB
?
从概念上看,EJB对象封装了业务对象及其概念,让开发人员把精力集中于解决方案的细节之上。从设计的角度看,EJB应该轻便而相互影响地合并起来。这一举措可以令单一的EJB,不论其是否为商务应用程序就可能采用一个EJB代表自主开发还是第3方厂商开发却都能用于多种应用程序。比方说,CRM(客户关系管理)工具和电子一位用户。这些已经具有适应性对象的配置由于部署描述符、说明EJB的XML文件而变得非常简单。部署描述符允许不经重新编译就可修改EJB属性和行为。
?
EJB的处所
?
EJB对象驻留在EJB容器内,后者是向开发者提供各类服务的环境。容器根据具体的配置可能负责处理安全、事务和实例管理。由于程序员无须再亲自完成这些任务从而令开发时间大大节约。
?
J2EE服务器和EJB容器这两个概念之间存在显著差别, EJB容器可能属于J2EE服务器的一部分,但却并不一定是必需的组成部分。在作为J2EE服务器组成部分的情况下,EJB客户程序通常会采取Java servlet或者JSP的形式。不过,由于取消了对J2EE Web层的依附性,标准的EJB容器服务可以接受多种类型客户程序、用Java或其他各种语言编写的应用程序所发出的请求。同EJB容器的通讯才是客户操作的先决条件。
?
?
EJB的内容
?
EJB对象分为以下三种类别:
?
?
? 会话Beans
?
? 实体Beans
?
? 消息驱动Beans
根据所需要的bean行为,某些特性决定了所采用的Bean类型。
?
会话Beans
?
会话(Session)Beans的作用建立在会话的基础之上。客户在请求并收到bean功能之后,具有特定bean的会话就终止了而且没有留下会话发生的记录。会话Bean类型还可以进一步细分为无状态或者有状态方式。
?
无状态会话Beans并不知道客户或者涉及到请求的上下文,从而令其成为单一请求/回应应用的理想工具。比方说,一个用户搜索所有公开bug的bug跟踪系统就是如此。客户应用程序联系一个无状态会话Bean并给其传递搜索参数。接着,这个bean访问数据库,选择匹配检索条件的条目,并把记录传回客户程序。通讯完成之后,bean不保留交互信息。因此,多个客户程序可以同时访问无状态会话Bean却不会相互影响。
?
相反,有状态会话Beans会把请求同特定的客户联系起来,在客户和bean之间建立一种一对一的关系。购物车bean就是一例。用户实施标准的电子商务任务,给购物车里加入商品,输入地址信息然后下定单。购物车bean维持状态,因而它知道所有这些变量都关联某一特定客户。
?
实体Beans
?
实体(Entity)Beans表示会话终止之后持久存在的业务对象或者数据。它们通常作为数据库中的单一记录形式存在,当然,其存储形式也可能采用其他媒质,比如文件等。一个对象就表示一个用户,有名字、联系方式、语言选择等等,这些参数代表了实体Bean的用途。作为持久性最本质的内涵之一,实体Bean的唯一标识或者主键起到了识别和检索正确对象信息的作用。实体beans需要主键作为“辅助类”封装对象的唯一标识符。
?
消息Beans
?
以上的两种bean类型以同步方式为EJB客户提供服务。客户发出请求然后等待bean发回结果。消息驱动(Message Driven) Beans避免了这一可能的瓶颈问题。采用Java消息服务JMS(Java Messaging Service)。客户程序可以产生一个消息并把消息发布给消息队列。消息驱动Bean随之采用或者检索消息执行其内容。这种事件或者数据的通讯就成为异步形式;客户或者bean都无须依赖对方的直接响应了。
?
比如,伦敦的一位银行官员使用一种应用程序发布最新的汇率消息。这时,部署在波士顿的一个外部交易bean从消息队列中获取这一消息然后更新数据库中的有关记录。在理想的情况下,消息驱动Bean会把信息传递给处理数据库事务的实体Bean。这样,每一种bean把它不能处理的任务转发从而创建出一种真正的分布式组件结构。
?
EJB的原理
?
现在不考虑EJB的类别,以上三种类型组成了EJB对象:本地接口、远程接口和bean的实现。客户程序使用Java命名和目录接口JNDI(Java Naming and Directory Interface)定位bean的本地接口(JNDI)。本地接口随后返回远程接口的实例,同时暴露必要的bean实现方法。客户程序再调用适当的这些方法。程序清单A所示的代码说明了以上过程。
?
Listing A
First comes the EJB client class—in this case, a very simple stand-alone user interface:
?
import javax.ejb.*;
import javax.naming.*;
import java.util.*;
import org.shifter.ejb.*;
public class VerySimpleClient
{
public static void main( String[] args ) {
try {
Context ctx = getInitialContex(); VerySimpleHome home = ( VerySimpleHome )ctx.lookup( "simpleton" );
VerySimple ejb = home.create();
ejb.setName( "Fredrick" );
System.out.println( "My name is " + ejb.getName() );
ejb.remove();
} catch (Exception e) {
e.printStackTrace();
} }
public static Context getInitialContext() throws NamingException {
// Retrieve the Context via JNDI lookup
} }
Now, we define the Home and Remote interfaces. The client interacts directly with these classes:
?
package org.shifter.ejb;
// The home interface import javax.ejb.*; import java.rmi.RemoteException;
public interface VerySimpleHome extends EJBHome {
public VerySimple create() throws CreateException, RemoteException; }
package org.shifter.ejb;
// The remote interface import javax.ejb.*;
import java.rmi.RemoteException;
?
public interface VerySimple extends EJBObject {
public String getName() throws RemoteException;
public void setName( String n ) throws RemoteException; }
?
Finally, we have the implementation of the EJB, where all functionality occurs:
package org.shifter.ejb;
import javax.ejb.*;
public class testertwoEJB implements javax.ejb.SessionBean{
// Member variables private String name; private SessionContext ctx;
// Default constructor
public testertwoEJB() { }
// Called by the create() method of the home interface.
public void ejbCreate() { }
?
// Called by the remove() method of the home interface.
public void ejbRemove() { }
?
// Called when the EJB container makes this bean active.
public void ejbActivate() {
// Resource allocation might go here.
}
// Called when the EJB container makes this bean inactive. public void ejbPassivate() {
// Resource clean up might go here. }
?
// Set the runtime context
public void setSessionContext(SessionContext ctx) { this.ctx = ctx; }
// *****
// The following methods are the only ones visible
// to EJB clients through this bean’s remote interface.
// *****
public String getName() {
return name; }
public void setName( String n ){
name = ( n != null ) ? n : "Igor"; } }
?
?
你可能需要根据bean的类型实现其他方法。比方说,假如客户需要定位实体Bean,那么你的本地接口就要包括findByPrimaryKey()方法,由它把主键类作为其参数以返回适当的对象。
?
早先提到过,每一个EJB对象所包装的部署描述符会告诉EJB容器对象的行为如何。描述符之一,也就是所谓的ejb-jar.xml就是完成以上功能的,它是具有容器管理事务所有方法的无状态会话Bean,如程序清单B所示。
?
Listing B
?
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>VerySimple</ejb-name> <home>org.shifter.ejb.VerySimpleHome</home> <remote>org.shifter.ejb.VerySimple</remote>
<ejb-class>org.shifter.ejb.VerySimpleEJB</ejb-class> <session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>VerySimple</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
?
?
根据EJB容器的类型,另一种部署描述符会告诉容器如何识别和定位采用JNDI的bean。以WebLogic服务器为例,起这一作用的就是weblogic-ejb-jar.xml,情形如程序清单C所示。
?
Listing C
?
<weblogic-ejb-jar>
<weblogic-enterprise-bean>
<ejb-name>VerySimple</ejb-name>
<jndi-name>simpleton</jndi-name>
</weblogic-enterprise-bean>
</weblogic-ejb-jar>
?
?
喜忧掺半
?
EJB的使用会涉及到某些内在的危险和可能的问题。程序员在给EJB对象编码的时候必须遵守大量的语法和行为规则。它们还必须确定到底是采用bean自身还是EJB容器的持久性管理;选择错误就可能都是数据。容器甚至可能崩溃从而破坏活动的会话Beans。容器还可能在尝试回滚事务的时候失败而丧失信息。部署EJB对象是一个单调反复的过程,在没有容器源代码的情况下进行调试工作几乎是不可能的。
?
不过,EJB的组件天性却令其代码的重用性优势凸显,从而节约了开发过程中的大量时间和金钱。开发人员可以把关注点集中于业务逻辑本身,而把安全和事务回滚等任务交付给EJB 容器。可靠的对象实例管理和方便的配置更是EJB的突出优点。学习和掌握EJB的设计规则确实是一件很费时间和精力的工作,但其结构本身在应用程序的开发过程中会产生非常有益的好处。
?
?
?
?
?
原作者:
?BUILDER.COM
?
?
?
?
?
?
?
?
部署过程
Enterprise JavaBeans (EJB) 组件是在称为部署的特定过程中安装的。由容器组件提供对部署过程的支持。在高级别上,部署由下列步骤组成:
?
bean 的开发人员创建必需的类文件、接口文件和控制信息。
容器分析输入文件并生成必要的类。
容器将条目添加到指向本地对象的 JNDI 命名空间中。
EJB 组件的开发人员编写 bean 的 Java 源文件,此文件包含为这个 bean 提供功能的业务逻辑方法,还包括 ejbCreate() 方法。bean 类还必须实现 javax.ejb.SessionBean 接口或 javax.ejb.EntityBean 接口。此外,bean 的开发人员编写接口文件,定义对 javax.ejb.EJBHome 接口和 javax.ejb.EJBObject 接口的扩展。EJBHome 接口的扩展,称为 bean 的本地接口,包含一个创建方法,并且如果 bean 是一个实体 bean,它还会包含一个 finder 方法。EJBObject 接口的扩展,称为 bean 的远程接口,指定在 bean 本身中定义的业务逻辑方法。
?
bean 的开发人员提供由部署描述符、环境属性和清单式文件组成的控制信息。
?
部署描述符是 javax.ejb.deployment.SessionDescriptor 对象或 javax.ejb.deployment.EntityDescriptor 对象的序列化实例。
环境属性作为键-值对存储在一个文件中,可通过 java.util.Properties 对象访问此文件。
清单式文件是标识企业级 bean 及其相关文件所必需的。
企业级 bean 的类文件、这两个接口的类文件、部署描述符文件、环境属性文件和清单式文件都是使用名为 ejb-jar 的文件格式归档的。所生成的 ejb-jar 文件提供给容器,作为部署过程的输入。
?
在部署时,容器分析 ejb-jar 文件的内容,并采取必要的操作使此 bean 可用。这些操作包括:生成实现 bean 的本地和远程接口的新 Java 类,将本地接口实现绑定到 JNDI 命名空间中,生成桩模块和 skeleton helper 类,后者是支持 RMI 通信所必需的。容器也可以生成 bean 的子类,并入容器专用的代码,以方便对 bean 的管理。部署时由容器生成的类通常是容器专用的,而不像 EJB 组件本身那样具有可移植性。
?
持久性、事务和安全
在为 EJB 组件提供持久性、事务和安全服务方面,EJB 容器可扮演主要角色。是将这些服务的职责指定给容器,还是假定职责由 bean 自身负责,EJB 规范为 bean 的开发人员提供了灵活性。例如,对实体 bean 的持久性支持既可以由 bean 管理,也可以由容器管理。如果 EJB 组件开发人员选择使用容器管理式持久性,他们就会在部署描述符中添加一个称为 containerManagedFields 的属性。根据 EJB 规范:
?
“containerManagedFields 属性的值是一个实例字段列表,企业级 bean 提供者希望,容器通过从数据库加载或将其存储到数据库,来管理这些实例字段。企业级 bean 代码不应该包含任何数据库访问调用 -- 数据库访问调用将由容器工具在部署时生成。
?
“专用于提供容器管理式持久性支持的容器,通常将提供丰富的部署时工具,以允许企业级 bean 部署者建立实例字段到基础数据源的映射。一般认为,尽管容器提供者的工具简化了映射进程,但映射进程仍可能涉及到 bean 部署者(即映射进程不是全自动的)。”(Enterprise JavaBeans Specification 1.0)
?
除了支持容器管理式持久性以外,EJB 体系结构还支持容器对事务的管理。该规范规定:
?
“Enterprise JavaBeans 是一种高级组件框架,它试图使应用程序开发人员不面对系统的复杂性。因此,大多数企业级 bean 及其客户机不需要通过程序访问事务管理。”(Enterprise JavaBeans Specification 1.0)
?
当 bean 的开发人员依赖容器进行事务管理时,就称为容器管理式定界