随笔-9  评论-15  文章-1  trackbacks-0

EJB

1EJB体系结构:

     包括客户端、服务器端。

     客户端:包含了调用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接口。实现ejbCreateejbRemove等。

     编写部署文件:完整的beanjava类和描述其特性的ejb-jar.xml文件组成,将其打包,放在jboss中的deploy文件夹中。

3.开发和部署测试程序:

     开发一个Servlet测试程序,将测试程序放在tomcatwebapps中。

4.会话Bean

     分为有状态会话Bean和无状态会话BeanEJB容器通过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()方法回到不存在状态,并触发BeanejbRemove()方法。如果客户长时间不调用Bean或服务器准备释放一些内存资源,则容器调用ejbPassivate()将这些Bean从组件池中钝化,此时释放分配的资源。当请求被钝化Bean时,容器调用ejbActivate()激活BeanBean转到方法现成状态时分配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()方法创建一个BeannewInstance()负责实例化Beanejb容器调用bean类的setSessionContext()方法把运行环境对象SessionContext传递给Bean,然后调用ejbCreate()方法进行初始化和资源分配。

7Jboss

     Jboss来运行EJB,将EJB.jar文件放在jboss deploy文件夹中。这个jboss版本是Jboss2.2.1。将该EJB所有的class文件放在tomcatwebapps中。

配置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——有两个值StatelessStateful

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开发者负责与数据库交互的代码部分。

9EJB 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的实现类。

10Entity 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业务逻辑方法可以被客户调用,在调用setxxgetXx时,容器(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();对于CMPejbCreate()返回为主关键字类型,由于容器来实现,在此方法中只需关联相关的映射字段,然后返回null。必须在类中定义与数据库表相关联的映射字段。

     编写部署文件:部署文件是ejb-jar.xml

     对于CMP Bean来说,当一个Bean实例被客户引用,容器会自动读取Bean的实例字段,然后,通过容器与数据库发生关系,保存改变的数据,执行完后Bean被钝化,并调用ejbPassivate()来通知Bean。然后又调用这个Bean时,Bean先调用ejbActivate()通知BeanBean实例要激活,然后从数据库中提

取数据,并自动将数据值映射到Bean的实例,然后调用ejbLoad(),实例再一次被初始化,最后才开始执行要执行的业务方法。

12.开发BMP Bean

    

     当一个Bean实例被客户引用,并执行一个业务方法后,容器执行ejbStore(),由这个方法把数据保存在数据库中,执行完后Bean被钝化,调用ejbPassivate()通知Bean。当客户又调用这个Bean的某业务方法时,被钝化的Bean又重新激活,EJB对象先调用ejbActivate()通知BeanBean实例要激活,然后调用BeanejbLoad(),此方法负责从数据库中提取数据,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)、部署者(Deployer)、EJB 服务器提供者(EJB Server Provider)、EJB 容器提供者(EJB Container Provider)、系统管理员(System Administrator):

  二、EJB中各角色的分析

  1EJB组件开发者(Enterprise Bean Provider

  EJB组件开发者负责开发执行商业逻辑规则的EJB组件,开发出的EJB组件打包成ejb-jar文件。EJB组件开发者负责定义EJBremotehome接口,编写执行商业逻辑的EJB class,提供部署EJB的部署文件(deployment descriptor)。部署文件包含EJB的名字,EJB用到的资源配置,如JDBC等。EJB组件开发者是典型的商业应用开发领域专家。

  EJB组件开发者不需要精通系统级的编程,因此,不需要知道一些系统级的处理细节,如事务、同步、安全、分布式计算等。

  2、应用组合者(Application Assembler

  应用组合者负责利用各种EJB组合一个完整的应用系统。应用组合者有时需要提供一些相关的程序,如在一个电子商务系统里,应用组合者需要提供JSPJava Server Page)程序。

应用组合者必须掌握所用的EJBhomeremote接口,但不需要知道这些接口的实现。

  3、部署者(Deployer)

  部署者负责将ejb-jar文件部署到用户的系统环境中。系统环境包含某种EJB ServerEJB Container。部署者必须保证所有由EJB组件开发者在部署文件中声明的资源可用,例如,部署者必须配置好EJB所需的数据库资源。

部署过程分两步:部署者首先利用EJB Container提供的工具生成一些类和接口,使EJB Container能够利用这些类和接口在运行状态管理EJB 部署者安装EJB组件和其他在上一步生成的类到EJB Container中。 部署者是某个EJB运行环境的专家。

  某些情况下,部署者在部署时还需要了解EJB包含的业务方法,以便在部署完成后,写一些简单的程序测试。

  4EJB 服务器提供者(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容器的平台上。客户能够通过这些Beanshome接口,定位到某个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里面声明了一个应用程序的方法或者说应用逻辑。也在beansremote接口中声明了这个方法,那么,这两个地方必须要同样的名字。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()方法的返回值类型是不同的。实体beanhome接口还包含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 beanmetadata信息。当开发工具来编译链接应用程序的时候,或者配置工具来配置的时候,可能会用到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规范定义了如下的命名约定。它的返回值是会话beanremote接口的类型。方法的名字只能是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 beanmetadata信息。当开发工具来编译链接应用程序的时候,或者配置工具来配置的时候,可能会用到metadata信息。Javax.ejb.EJBMetadata接口提供了获得javax.ejb.EJBHome接口,home类,remote接口,还有获得主键的方法。也提供了一个isSesson()的方法来确定在放这个home接口的对象是会话bean还是实体beanIsStatelessSession()方法指示这个会话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

  JbuilderEJB Container能够进行无缝连接。JbuilderInprise的应用服务器包括了所有的开发和配置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规范的相应的版本,还要确定它是否正确的支持EJBAPI 

  要确定JD到所支持的EJB容器的版本。可以通过检查Inprise的安装说明来确定EJB容器所支持的支持JDK的版本。 

  在配置Enterprise Bean的时候,你必须使用Inprise的应用服务器所提供的工具。这些工具能够编辑和修改第三方的代理商提供的Inprise配置描述器。还能够验证配置描述器,能够验证bean的源代码。 

  六、一个简单的HELLO例子 

  1、安装Apusic Application Server 

  Note:以下以Linux为例,来说明Apusic Application Server的安装过程。其他平台的安装,可参考Apusic Application Server安装手册。 

  下载JDK1.2Apusic 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源文件并将编译后classejb-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 ClientJSPServlet或别的EJB调用HelloBean 
  调用EJB有以下几个步骤: 
  通过JNDIJava 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 

EJBEnterprise JavaBeans)可不算什么新概念了,但许多人在听到或者看到这个名词的时候还会眼晕。EJB组件在J2EE规范中自成一层,把应用程序的表示层和后端信息系统(比如数据库或者主框架计算机)捆绑了起来。EJB架构既用到了EJB对象的功能又利用了它们所运行的环境。



为什么出来个EJB



从概念上看,EJB对象封装了业务对象及其概念,让开发人员把精力集中于解决方案的细节之上。从设计的角度看,EJB应该轻便而相互影响地合并起来。这一举措可以令单一的EJB,不论其是否为商务应用程序就可能采用一个EJB代表自主开发还是第3方厂商开发却都能用于多种应用程序。比方说,CRM(客户关系管理)工具和电子一位用户。这些已经具有适应性对象的配置由于部署描述符、说明EJBXML文件而变得非常简单。部署描述符允许不经重新编译就可修改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



会话(SessionBeans的作用建立在会话的基础之上。客户在请求并收到bean功能之后,具有特定bean的会话就终止了而且没有留下会话发生的记录。会话Bean类型还可以进一步细分为无状态或者有状态方式。



无状态会话Beans并不知道客户或者涉及到请求的上下文,从而令其成为单一请求/回应应用的理想工具。比方说,一个用户搜索所有公开bugbug跟踪系统就是如此。客户应用程序联系一个无状态会话Bean并给其传递搜索参数。接着,这个bean访问数据库,选择匹配检索条件的条目,并把记录传回客户程序。通讯完成之后,bean不保留交互信息。因此,多个客户程序可以同时访问无状态会话Bean却不会相互影响。



相反,有状态会话Beans会把请求同特定的客户联系起来,在客户和bean之间建立一种一对一的关系。购物车bean就是一例。用户实施标准的电子商务任务,给购物车里加入商品,输入地址信息然后下定单。购物车bean维持状态,因而它知道所有这些变量都关联某一特定客户。



实体Beans



实体(EntityBeans表示会话终止之后持久存在的业务对象或者数据。它们通常作为数据库中的单一记录形式存在,当然,其存储形式也可能采用其他媒质,比如文件等。一个对象就表示一个用户,有名字、联系方式、语言选择等等,这些参数代表了实体Bean的用途。作为持久性最本质的内涵之一,实体Bean的唯一标识或者主键起到了识别和检索正确对象信息的作用。实体beans需要主键作为“辅助类”封装对象的唯一标识符。



消息Beans



以上的两种bean类型以同步方式为EJB客户提供服务。客户发出请求然后等待bean发回结果。消息驱动(Message Driven Beans避免了这一可能的瓶颈问题。采用Java消息服务JMSJava Messaging Service)。客户程序可以产生一个消息并把消息发布给消息队列。消息驱动Bean随之采用或者检索消息执行其内容。这种事件或者数据的通讯就成为异步形式;客户或者bean都无须依赖对方的直接响应了。



比如,伦敦的一位银行官员使用一种应用程序发布最新的汇率消息。这时,部署在波士顿的一个外部交易bean从消息队列中获取这一消息然后更新数据库中的有关记录。在理想的情况下,消息驱动Bean会把信息传递给处理数据库事务的实体Bean。这样,每一种bean把它不能处理的任务转发从而创建出一种真正的分布式组件结构。



EJB
的原理



现在不考虑EJB的类别,以上三种类型组成了EJB对象:本地接口、远程接口和bean的实现。客户程序使用Java命名和目录接口JNDIJava 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容器的类型,另一种部署描述符会告诉容器如何识别和定位采用JNDIbean。以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 的开发人员依赖容器进行事务管理时,就称为容器管理式定界,容器使用在部署时提供的事务属性:



无论客户机何时调用企业级 bean,容器都会介入这个方法调用。这种介入允许容器通过事务属性显式控制事务定界。例如,如果企业级 bean 部署了 TX_REQUIRED 事务属性,则无论何时,只要客户机调用支持事务的企业级 bean,容器就会自动启动事务,而客户机并不与任何事务上下文相关联。”(Enterprise JavaBeans Specification 1.0)



如果开发人员选择在 bean 内支持事务,则他们在部署描述符中指定 TX_BEAN_MANAGED 事务属性,然后就可以在 bean 自身内部自由使用 javax.transaction.UserTransaction 接口划分事务边界。通过认出 TX_BEAN_MANAGED 事务属性,容器就能知道不必介入事务支持。



通过增强 AccessControlEntry 对象和 RunAs 安全标识中指定的限制,容器为 EJB 组件提供安全支持。AccessControlEntry 对象在 bean 级别上或针对单个方法,将 Identity 对象与企业级 bean 相关联。Identity 对象反映允许调用 bean 的方法的用户或角色。当容器试图访问数据源或另一个 bean 时,它们也会将 RunAs 安全身份应用于 EJB 组件。可将 RunAs 身份设置为等同于某个特定用户帐户、有权限的系统帐户或客户机安全身份。访问控制和 RunAs 的信息是 bean 的开发人员在部署描述符中指定的,将影响容器管理 bean 的与安全有关的行为方式。



虽然 EJB 1.0 规范也提到安全问题,但更详细的安全功能定义,见该规范的后续版本。



CORBA
EJB 技术的关系

公用对象请求代理程序体系结构 (CORBA) 为分布式对象的平台中立和语言中立的计算环境奠定了基础。在 CORBA 环境中,功能驻留于对象之中,而客户机可通过对象请求代理程序 (ORB) 访问这些对象。完整的 CORBA 实现提供 ORB,外加称为 CORBA 对象服务和 CORBA 公用工具的几个运行时服务。也可只提供 ORB,不提供相关联的对象服务和公用工具(例如,IBM 就提供这样的两种独立 ORB)。实现基本 ORB 功能的软件称为 ORB 核心。为了支持语言无关性,CORBA 应用程序是用接口定义语言 (IDL) 编写的。该语言在语法上类似于 C++,但不包含语义:IDL 中指定的操作是操作接口,而不是操作实现。由于它对多种平台和多种语言的支持,以及源自其分布式特征的可伸缩性,CORBA 非常适合于管理企业规模的信息系统。



设计 EJB 规范也是为了支持企业信息系统。这样说来,CORBA 是一个竞争者吗?根据 Frequently Asked Questions for Enterprise JavaBeans,答案是否定的:



实际上,EJB 技术很好地补充了 CORBACORBA 提供了一个强大的基于标准的基础结构,可在此结构之上构建 EJB 服务器。EJB 技术使得在 CORBA 基础结构的顶层构建应用程序变得更为容易。”(Enterprise JavaBeans 常见问题解答)



虽然 EJB 规范和 CORBA 规范说明的是不同的技术,但 EJB 实现目前利用 CORBA 技术的某些方面。一个例子就是 RMI/IIOPEJB 规范要求 EJB 组件及其容器使用 Remote Method Invocation (RMI) 技术,实现分布式对象之间的方法调用。 RMI 规定远程方法的语法和语义,但并不规定应使用何种传输协议提供网络连接。CORBA Internet 对象请求代理程序间协议 (IIOP) 基本上定义了通过 TCP/IP 传输 CORBA 消息的一种方法。开发使用 IIOP 消息形式交换 RMI 数据的 EJB 实现,说明了 EJB 应用程序怎样才能有效地使用 CORBA 技术的各部分。这种网络也支持与 CORBA 应用程序的互操作性,后者使用 IIOP 发送本地 CORBA 消息,与 RMI 无关。IBM EJB 实现,即 WebSphere Application Server,优化了 IIOP 的使用,方法是,弄清楚分布式对象何时驻留在同一台服务器上,并且只在对象确实在远程时才调用 IIOP



为了方便既并入 EJB 技术,又并入 CORBA 技术的企业系统的开发,Sun Microsystems EJB 规范和 CORBA 之间创建了一种映射。 EJB 体系结构映射到 CORBA,影响到 EJB 技术的几个方面,包括对象分布、命名和事务。CORBA 映射的主要目的是,保证不同厂商构建的 EJB 服务器之间的互操作性。互操作性提供以下好处:



CORBA
客户机可以访问部署在基于 CORBA EJB 服务器上的 EJB 组件

客户机程序在事务中可以将对 CORBA 对象的调用,与对企业级 bean 的调用混合在一起

事务可以跨多个 bean,而这些 bean 又位于来自不同厂商的基于 CORBA 的多台 EJB 服务器上

使用来自某个厂商的 ORB 的客户机,可以访问另一个厂商基于 CORBA EJB 服务器上的 bean

对于要访问 EJB 组件的 CORBA 客户机来说,bean 接口被映射到 IDL。例如,可将股票交易 bean 中定义的 buy() sell() 方法,指定为 IDL 文件中的 CORBA 操作。非 bean CORBA 客户机,如 C++ 客户机,可以访问这个 bean,并用标准 CORBA 调用来调用 bean 的方法。如果容器使用 IIOP 作为它的分布式对象协议,则该容器的职责是,生成与企业级 bean 及其接口对应的 IDL



EJB
命名服务,它以“CORBA 对象服务”命名服务为基础,使 EJB 组件可用于 CORBA 客户机。Java Naming and Directory Interface (JNDI) 可提供到 CORBA 命名服务的接口,同时,客户机既可以通过 JNDI 调用间接访问基础命名服务,也可以通过“CORBA 对象服务” (COS) 命名 API 直接访问该服务。



EJB 事务支持依赖于 CORBA Transaction Service,即 Object Transaction Service (OTS)Java Transaction Service (JTS) 代表 OTS Java 绑定,它是语言中立的。基于 CORBA EJB 容器必须识别 CORBA 客户机通过 OTS 接口发出的事务边界,以及 EJB 应用程序通过 Java Transaction API (JTA) 接口发出的事务,JTA 是到 JTS 的应用程序级接口。JTA 还代表 Open Group XA 接口的 Java 绑定,以便将应用程序资源连接到外部事务管理器。JIA 中含存的 javax.transaction.UserTransaction 接口,为事务边界的应用程序级控制提供 APIUserTransaction 接口,既可由其事务属性设置为 TX_BEAN_MANAGED bean 使用,以可由 Java 客户机使用。



使用 EJB 组件

因为 EJB 体系结构被设计为高度灵活的,并支持使用任意复杂的方式连接企业级 bean,所以可构建许多不同的方案,来说明应用程序可怎样使用企业级 bean。一个有用的方案提出将 EJB 组件表示为三层信息系统的关键组件,该系统将企业数据、事务和应用程序资源连接到 Web 上。



基于 EJB 的三层编程模型视 Web 浏览器为第一层,视支持应用程序的 Web 服务器为第二层,视企业信息资源为第三层。在此编程模型中,除了 EJB 技术外,还实现了 Java servlet 技术、JavaBeans 技术和 Java Server Page (JSP) 技术。下图显示了各层的排列情况:



第一层是瘦客户机 -- 通常是 Web 浏览器,它可以处理普通 Web 数据类型,如 HTML GIF,并支持 HTTP 通信。第二层是 Web 应用程序服务器,它是用代码扩充的 Web 服务器,用来对能够通过 Web 服务器调用的应用程序提供运行时支持。现有的 Web 应用程序都沿用 CGI-BIN 编程模型,但预计第二层应用程序开发将转向 Java servlet 编程模型,后者提供大幅改善的性能和可移植性。除支持 Java servlet 外,Web 应用程序服务器还将添加 EJB 服务器功能,以支持使用 EJB 组件的应用程序。第三层代表企业级信息资源,可以包括关系数据库和面向对象的数据库、事务监视器和定制的应用程序。EJB 技术在这一设计中扮演着关键角色,因为,它使驻留在第二层上的应用程序组件,与组成第三层的企业资源之间的接口,得以标准化。



Java servletJava beans Java server page 不是 EJB 应用程序方案的必需元素,但它们可与 EJB 组件一起工作,以提供基于 Java 的内聚性的应用程序环境。此处描绘的环境将以下职责指定给参与工作的 Java 组件:



Java servlet 指定了应用程序“控制器”的角色

JSP
页面处理数据表示和用户界面的任务

Java bean
充当“数据封装器”,存储中间结果的数据

EJB
组件提供访问企业信息资源的机制

客户可以使用一个假定的、基于 EJB Web 应用程序更新现有的库存,并用容器管理式持久性和容器管理式事务,将访问库存数据库的位置封装在实体 EJB 组件的内部。库存票据可通过 Web 浏览器输入,浏览器提供一个 HTML 表单来捕获产品编号、供应商,等等,并在提交时调用一个 servletservlet 代码充当应用程序控制器角色,确定哪些企业数据库需要更新,需要用户追加什样的信息。servlet 可通过代表它的实体 bean 访问主库存数据库,并调用 JNDI 接口获取对此 bean 的本地对象的引用,然后使用 finder 方法定位所请求产品编号的远程对象。此时,通过调用远程对象的方法,servlet 可更新库存计数,接着容器将此方法委托给 EJB 组件。因为容器根据数据库更新,以对 bean 透明的方式划分一个事务,而且以对 bean 透明的方式将数据写入数据库来保证数据持久性,所以也就保持了数据的完整性。



EJB 组件返回到 servlet 的任何结果信息,都可以使用 setter 方法存储在一个(非企业的) Java bean 的属性中。此时 servlet 可将控制权转让给一个适当的 JSP 页面,以便将这些结果组合到表示格式中,并将结果返回给用户。JSP 页面很可能主要由静态文本和有关单个事务的可变信息占位符组成。在向浏览器发送表示数据之前,JSP 页面使用 getter 方法从 Java bean 的属性中获得可变数据元素。



基于 EJB 的三层设计提供了几个好处,包括:



访问企业数据的业务逻辑可封装在可重用、可移植的企业级 bean 中。

现有的企业系统只需很少修改或者根本不需要修改,就可以集成为企业级 bean

企业应用程序所需的运行时服务,如事务和持久性,可以从 bean 中分解出来,并指定给此 bean 的容器。

无须更改 EJB 组件,即可修改控制应用程序流程的 Servlet

Servlet
代码可将注意力集中在应用程序控制逻辑上,而无须考虑数据表示。

JSP
页面可将静态和动态内容混合在一起,生成表示信息。

Java 语言编写的系统组件,对于具有 JVM 的任何平台都是可移植的。

结论

在开发能够支持关键任务的企业级信息系统的过程中,EJB 规范代表了 Java 技术的下一个发展阶段。EJB 组件将随 JavaBeans 规范引入的 Java 组件模型,扩展到服务器领域,从而使业务逻辑组件的开发可以跨企业应用程序重用,并且可以跨支持 Java 的平台移植。由于包含了基于 RMI 技术的对象分布,所以支持跨多层的可执行组件的分立,从而允许最大的实现灵活性和高度可伸缩性。如果将常规的企业应用程序运行时服务重新定义为可指定给容器抽象的对象服务,则允许 EJB 组件的开发人员将精力集中在业务逻辑上,从而减小了通常与运行时服务相关的复杂性和平台相关性。



增强 Java 运行环境,以包括命名和目录服务的标准接口、关系数据库访问、事务服务和远程对象访问,使 Java 开发人员能够编写强健的企业应用程序,而不必离开 Java 编程环境。将其它 Java 技术 -- Java servlet JavaServer Pages 技术 -- EJB 组件一起使用,可创建一个对于大型企业系统来说足够强健的紧凑编程模型,但由于使用了巧妙的接口,从而简化了开发工作。而且,因为 EJB 体系结构是 JavaBeans 组件模型的逻辑扩展,所以作为 EJB 组件开发的业务逻辑可跨多个企业应用程序重用。



企业级 bean 体系结构的另一个好处是,提供了现有企业信息系统的直接集成通道,此通道可能与 Java 编程语言或 bean 编程模型毫无共同之处。因为现有的企业信息资源 -- 如关系数据库、事务监视器和业务应用程序的定制新品种 -- 可通过将它们封装在 EJB 组件中连接到 Web 前端,而无须替换应用程序或重写主要代码段,所以,客户可保护其现有的 IT 投资。



考虑到 EJB 技术的巨大前景,IT 业界以相当大的兴趣欢迎 EJB 规范,就不是什么令人惊讶的事了。EJB 体系结构提供的一个最大好处可能是,把业务逻辑编程与将业务逻辑和企业级服务器端运行环境的复杂集成分离开来。如果部署了 EJB 组件的容器承担了管理运行时服务(如持久性、事务和并发数据库访问)的职责,则 bean 的开发人员就可以自由地将精力集中在开发封装业务逻辑的软件组件上。JavaSoft 副总裁表述了 EJB 技术的重要性(引自 Sun Microsystems 网站):



“‘Enterprise JavaBeans API
将为企业开发人员和解决方案提供商提供一种新的战略武器,供他们建立下一代行业领先的、基于关键业务的应用程序,’Sun Microsystems JavaSoft 软件产品部副总裁,Jon Kannegaard 说:‘因为用 Enterprise JavaBeans API 设计的应用程序将与现有的企业系统一起工作,所以企业利用 Java 平台会获得新的竞争优势,同时还保留他们对现有技术的投资,’Kannegaard 继续说。



使用 Enterprise JavaBeans API,开发人员将能够消除应用程序开发过程中的复杂性。这是可能的,因为每个 Enterprise JavaBeans 组件都封装了一个基本的业务功能。目前开发人员必须懂得如何编写业务逻辑和专门的系统级程序,以控制诸如安全性功能部件和处理多个事务的能力 -- 一项既枯燥又复杂的任务。Enterprise JavaBeans API 使全体开发人员能够将精力集中在编写解决业务问题的逻辑上,而不是将精力集中在编写用以简化不同技术间交互作用的代码上。”(新闻稿:Sun Releases Draft Enterprise JavaBeans Specification for Public Review



参考资料



通过 Sun 网站的 associated FAQs 深入了解 Java 技术和 EJB 体系结构。

查阅 Enterprise JavaBeans Specification 1.0

请参阅 Enterprise JavaBeans 规范的完整新闻稿。

请参阅 IBM WebSphere Application Server 如何使用 EJB 技术。

作者简介

Ken Nordby
IBM 软件开发实验室的软件工程师,该实验室位于北卡罗来纳州 Research Triangle Park。作为 SWG Product Affinity Services 业务小组的成员,Ken 与为 IBM WebSphere Application Server Enterprise JavaBeans 技术的 IBM 实现)进行开发和咨询的 IBM 人一起工作。可以通过 nordby@us.ibm.com Ken 联系。

什么是 Enterprise JavaBeans 组件?()

推荐:simon

分类:JAVA

发布时间:2002-04-09

人气:1781

第一部分:EJB 体系结构的历史和目标



本文概述 Enterprise JavaBeans (EJB) 技术,旨在让读者快速理解基本概念。 1 部分讲述 EJB 技术的历史和某些目标、优点和技术。为了简洁明了,有选择地讲述 EJB 技术的一些关键要素。请注意,虽然 EJB 组件依赖于一些基础的 Java 服务(如 Java Transaction Service),但使用 EJB 组件及认识这些组件的好处并不需要掌握这些相关技术的知识。



Enterprise JavaBeans 技术自 1998 3 月问世以来很受好评。下面这段话就是一个例子:



自从两年多以前问世以来,Enterprise JavaBeanstm 技术在平台供应商和企业的开发小组中,同样都保持着空前的发展势头。这是因为 EJBtm 的服务器端组件模型简化了中间件组件的开发,这些中间组件都是事务性的、可伸缩的和可移植的。Enterprise JavaBeans 服务器通过为中间件服务(如事务处理、安全性、数据库连接及其他)提供自动支持,降低了开发中间件的复杂程度。”(Sun Microsystems 网站)



Enterprise JavaBeans
这一名称利用了 Java bean — 这种可移植、可重用的 Java 软件组件的声望。Enterprise JavaBeans 技术把 Java 组件的概念从客户机域扩展到了服务器域:这是 Java 技术成长过程中有重大意义的一步,它使 Java 技术发展成为一种强健的、可伸缩的环境,能够支持以任务为关键的企业信息系统。



服务器上的 Java 应用程序

Java
编程语言最初在 Web 开发人员中获得好评的一个原因是,它支持称为 applet 的可下载 Java 程序。对 Applet 的支持以 Applet 类的形式内置到了 1.0 版的 Java Development Kit (JDK) 中。按照 1.0 版的时间框架,Java 开发是以 applet 和应用程序作为中心的。基于 JDK 1.0 版的 Java 读物都是从 applet 和应用程序的角度来描述 Java 编程的:



“Java
程序由更多的类定义中的某一个组成,每个类定义均已编译成它自已的 Java 虚拟机对象代码的 .class 文件。这些类之一必须定义一个叫做 main() 的方法,程序就是从这个方法开始运行的。想调用一个 Java 程序,需要运行 Java 解释器 java,并指定包含 main() 方法的类的名称。请注意 Java applet 并不是一个应用程序它是一个由已在运行的 Java 应用程序(如 Web 浏览器或 applet 查看器)装入并运行的 Java 类。”(见 Flanagan 所著的 Java in a Nutshell



Java
应用程序可以在服务器上运行,但是不管是在客户机-服务器环境下,还是在基于 Web 的环境下,JDK 中都没有提供让 Java 应用程序专用于服务器机器的接口或包。认识到 Java Web 环境下作为一种服务器语言的潜力,Sun Microsystems 编写了 Java Servlet 规范。servlet 在许多方面与 applet 相似,它是专门为在 Web 服务器机器上运行而设计的 Java 程序:



“servlet
是由容器管理的 Web 组件,可产生动态内容。servlet 是一种小型的、与平台无关的 Java 类,被编译成体系结构中立的字节代码,这种代码可以动态地加载到一个 web 服务器上,并由此 web 服务器运行。servlet 通过一种由 servlet 容器实现的请求-响应模型与 Web 客户机进行交互。这种请求-响应模型建立在超文本传输协议 (HTTP) 行为的基础之上。”(见 JavaSoft 的“Java Servlet API Specification”)



在一台 Web 服务器控制下,在多台服务器上运行若干小型用户程序,这种想法并不新鲜一段时间以来,公共网关接口 (CGI) 程序(常被称为 CGI 脚本)一直起着这种作用,并推动了 Web 的普及。但 Java servlet 可以以更高的效率和可移植性来实现这一目的,因而可望最终会取代 CGI 程序。为 servlet 提供运行时环境的软件(通常被称为 servlet 引擎)可以添加到现有的、本身并不支持 Java 可执行程序的 Web 服务器上。



Java servlet
的出现,为应用程序员使用 Java 来创建 Web 应用程序开辟了新的途径。但是,仅有 servlet 还不能为真正的企业计算提供完整的模型。CGI 应用程序本身往往不是完整的应用程序,在处理接收自 Web 浏览器上用户的信息请求时,CGI 只是整个处理过程中的一个中间步骤。例如,CGI 应用程序的一种常见用途是访问数据库。将它用于这种任务时,CGI 程序提供一种方法,将用户的数据请求连接到能满足这种请求的企业数据库。CGI 程序常常充当一种中间软件,从 Web 浏览器接收请求,决定必须调用哪些计算资源来满足这些请求,并向浏览器发回响应。Java servlet CGI 程序一样,最适合充当连接前端 Web 请求与后端数据资源的中间层组件。



三层体系结构

Web
编程向服务器端 Java 应用程序的演化,也带来了体系结构的演化,使它脱离了常规的客户机-服务器两层模型,而向一种三层方法发展。两层模型当时曾经具有创新意义,因为它将一些计算任务从主处理器上卸载到灵巧的客户机。常规的基于 LAN 的数据库应用程序就是一个例子,其中数据库管理器服务器软件驻留在一个专用的服务器机器上,而用户则通过他们的工作站上的客户机代码来访问数据库。随着客户机-服务器模型成长到能付诸使用,就出现了对服务器可伸缩性和对客户机代码大小和复杂性的关注。于是提出了一种三层的体系结构,以避免在两层模型中已察觉到的弱点,使 Web 能成为一个计算平台:



许多人...断言,传统的客户机/服务器两层体系结构不会有好的可伸缩性,因为用户连接和数据访问的数量无法预测,而且在一些系统管理上也存在问题。为处理两层体系结构的限制,许多开发集体都在转向三层体系结构。这种体系结构大致可以定义为:客户机层上的表示层、中间的服务器和后端的某种数据库。这种设想的目的就是缓和客户机或数据库服务器上的代码膨胀,集中管理业务逻辑,更灵活地使用数据库,而不仅是使用所存储的过程和触发器。”(见 Kim 的“Looking for a 3-Tier App Builder?”)



一个三层结构模型通常被想像成有一个 Web 浏览器作为客户层。Web 浏览器由于有可能成为一种真正的通用客户机,使它从观念上取代了两层结构的“胖客户机”。如果浏览器作为 Web 应用程序体系结构的标准瘦客户机获得认可,那么以前驻留在两层模型的胖客户机中的功能会怎么样呢?现在,应用程序专用的功能并不移植回服务器(例如数据库管理器),而是有意将它驻留在一个新的中间层上。中间层支持应用程序服务器软件,这种软件是中间件的一种形式,它处于第一层上瘦客户机的最小功能和第三层上服务器端业务系统的丰富功能之间。由于三层体系结构与 Web 处理模型有密切关系,所以中间层应用程序服务器常被视为 Web 服务器的一种功能扩展。现有的 Web 应用程序利用 CGI 程序,将来自 Web 浏览器的用户请求传送到不基于 Web 的业务系统,并向浏览器返回响应,就是三层模型的一种实现。这些应用程序逐渐向 servlet 技术的转移说明三层模型正在增强。



JavaBeans 组件

JavaBeans
规范将“组件软件”的概念引入到 Java 编程的领域。组件是自含的、可重用的软件单元;而 JavaBeans 组件,则可以使用可视的应用程序开发工具,可视地将它们编写到 Java 程序中。JavaBeans 规范为 Java 开发人员提供了一种“组件化”其 Java 类的方法:



Bean
是一些 Java 类,可在一个可视的构建器工具中操作它们,并且可以将它们一起编写到应用程序中。任何具有某种特性和事件接口约定的 Java 类都可以是一个 Bean。(见 JavaSoft,“Using the Beans Development Kit 1.0”)



如果软件重用是一个好主意,那么是否应该让每一个 Java 类都成为 Java bean 呢?如果 Java 类满足某些准则,它们就适于充当 bean 的角色:



在开发任何新软件之前,都值得考虑是否用 JavaBean 的形式来开发它。如果软件模块要既能够可视地操作,又能够定制以达到某些效果,则这种软件模块就可能适于做成一个 JavaBean。为帮助您确定要开发的软件是否应该是一个 JavaBean,假定它应该是用 Java 编写的,请向您自已提出以下问题,并相应地作出决定:



是否打算让它可重用?或者,它会是可重用的吗?

是否希望将它与其他可重用的 Java 组件一起使用?

是否预计会在 IDE 工具中使用它?



如果上述问题的答案都是肯定的,则它应该作为 JavaBean 来开发。(见 developerWorks 的“JavaBeans Guidelines”)



JavaBean
概念是为了在 Java 编程环境中支持可重用的组件,它是一种一般性的设计方法,适用于客户机或服务器机器上运行的 Java 程序。由于对可视的构建器工具的强调,也由于许多 Java bean 都是图形用户界面 (GUI) 组件,所以 JavaBean 组件可能被视为一种客户端技术。但是,并不要求 Java bean 都是可视的,并且它们也可以用于服务器环境中。



编码为 Java bean Java 类通常具有以下特征:



使用设计模式。这些模式就是方法和接口的编码约定。

支持可视的软件开发工具。类必须将变量(称为属性)、方法和事件展示出来。

可以定制。定制包括能支持缺省的属性编辑器,或者提供单一的定制规则。定制使开发人员得以在不更改源代码的情况下更改 bean 的行为。

支持自省 (introspection)这指的是将属性、方法和事件公开给其他类,可以通过设计模式或通过创建 BeanInfo 类来完成这种自省。

是持久的。这就允许在一个可视构建器中定制一个 bean,然后以其定制后的状态加以保存。

Java 2 Platform, Enterprise Edition

Sun Microsystems
发起了一项称为 Java 2 Platform, Enterprise Edition (J2EE) 的技术创新,旨在将 Java 平台的范围扩展到大规模服务器环境:



“1997
4 12 日,Sun 宣布了一项为企业环境开发 Java 平台的创新成果。使用开放式的 Java Community ProcessSun 促进了一组标准的 Java 扩展的开发,称为 Enterprise Java API这些应用程序编程接口 (API) 为各种各样的中间件的实现提供了不依赖供应商的编程接口。Enterprise Java API 的要点是 Enterprise JavaBeans API,后者为 Java 应用程序服务器定义了一个服务器端组件模型,以及一个不依赖供应商的编程接口。”(见 Thomas 的“Java 2 Platform, Enterprise Edition: Ensuring Consistency, Portability, and Interoperability”)



J2EE
Enterprise JavaBeans 技术提供了工作环境。事实上,Sun 把若干项软件技术都设想为这样的构件块,它们将使大型企业能够把以任务为关键的业务系统移植到 Java 环境中,而 Enterprise JavaBeans 技术不过是这些技术之一。EJB 组件是按它们自己的规范定义的,但 EJB 技术并不是一项独立的技术。它建立在其他 Java 技术之上,这些技术由 Sun 和其他 IT 公司联合规定,它们一起提供了这个框架的内容,该框架就称为 Java 2 Platform, Enterprise Edition



J2EE 中包括以下技术:



Enterprise JavaBeans (EJB)
技术

Java Interface Definition Language (IDL)

Java Message Service (JMS) API

Java Naming and Directory Interface (JNDI)

Java Remote Method Invocation (RMI)
Object Serialization

Java Servlet API

Java Transaction API (JTA)

Java Transaction Service (JTS)

JavaServer Pages (JSP)
技术

JDBC
数据库访问 API

参与到这个企业 Java 框架中,并不意味着每项技术都依赖于所有其他技术。单独的规范文档指出每项技术的相关性。例如,Enterprise JavaBeans 规范 1.0 发行版就指明了在定位各个组件时与 JNDI 的相关性,以及在编程中启动和停止事务处理时与 JTA 的相关性。



EJB
技术的设计目标

EJB
规范的第一版以初稿形式于 1997 12 月公布,并于 1998 3 月作为 1.0 版发行。规范作者为 EJB 体系结构制定了以下目标:



Enterprise JavaBeans
体系结构将是标准的组件体系结构,用于以 Java 编程语言构建分布式的面向对象的商务应用程序。通过把使用不同供应商提供的工具开发出来的组件组合在一起,Enterprise JavaBeans 体系结构将有可能构建分布式的应用程序。



Enterprise JavaBeans
体系结构将使编写应用程序变得容易:应用程序开发人员将不必了解低层次的事务和状态管理的细节、多线程、资源共享和其他复杂的低级 API。但是,将允许专家级的程序员直接访问低级 API



Enterprise JavaBeans 应用程序将遵循 Java 编程语言的“一次编写,随处运行”的原则。EJB 组件可以只开发一次,然后在多个平台上部署,而不需要重新编译或修改源代码。



Enterprise JavaBeans 体系结构将处理企业应用程序生命周期中的开发、部署和运行等方面。



Enterprise JavaBeans
体系结构将定义一些约定,这些约定使多个供应商提供的工具能够开发并部署可在运行时互操作的组件。



Enterprise JavaBeans
体系结构将与现有的服务器平台兼容。供应商将能够扩展它们的现有产品,以支持 Enterprise JavaBeans 组件。



Enterprise JavaBeans
体系结构将与 Java 编程语言编写的其他 API 兼容。



Enterprise JavaBeans
体系结构将提供 EJB 组件和非 Java 编程语言应用程序之间的互操作性。



Enterprise JavaBeans
体系结构将与 CORBA 兼容。

使用 EJB 技术的好处

这些设计目标会使企业和开发人员得到什么好处呢?下面列出了可望从采用 Enterprise JavaBeans 环境获得的好处:



EJB
组件使编写应用程序更为简单。尽管 EJB 体系结构复杂,但应用程序开发人员一般都不必再编写用于访问系统服务的代码。一种称为 EJB 容器的系统组件使系统服务可用于 EJB 组件的任务。



服务器端商务逻辑可以移植。除了 Java 语言固有的可移植性外,EJB 体系结构还在 bean 和支持该 bean 的容器之间提供了一套标准化的应用程序编程接口。这使开发人员能够将 bean 从一种操作环境移植到另一种操作环境,而无须重新编写其源代码。



可以从现有的软件组件装配出服务器端应用程序,这与从现有的 Java bean 可以装配出客户端应用程序一样,从而使软件能够重用。



EJB
体系结构内置了对典型企业级系统服务的支持,包括分布式对象、事务处理、数据库、安全和全局命名。



多家 IT 供应商都采纳 EJB 体系结构,这是由于有这样的承诺:客户将能够从选定的供应商那里选购软件组件,如 EJB 组件、容器及 EJB 服务器;也由于承诺了不同供应商的产品,只要符合 EJB 体系结构,就都是可互操作的。



EJB 组件构建的应用程序可以从一个服务器移植到另一个服务器,从而支持可伸缩性,这是因为在 EJB 模型中,各个软件组件都是严格分离的。



EJB
体系结构能保障原有的 IT 投资,这是通过允许将现有的信息系统和资产“包裹”在这些应用程序中,而不要求客户更换现有技术。事实上,在关系数据库中存储数据的企业已经有了一套已有雏形的实体 bean,正等着通过 EJB 外壳去访问。



进一步考察 JNDI

Enterprise JavaBeans
组件使用 Java Naming and Directory Interface (JNDI) 来访问各种目录服务。JNDI 分两部分:应用程序编程接口 (API) 和服务供应商接口 (SPI)



“JNDI
体系结构由 JNDI API JNDI SPI 组成。JNDI API 允许 Java 应用程序访问各种命名和目录服务。JNDI SPI 则是设计来供任意一种服务的供应商(也包括目录服务供应商)使用。这使得各种各样的目录服务和命名服务能够透明地插入到使用 JNDI API Java 应用程序中。(见 JavaSoft,“JNDI: Java Naming and Directory Interface”)



JNDI API
并不同某种专用的命名技术或目录技术连在一起,也不同任何供应商的目录服务连在一起,因此它对 EJB 组件的可移植性有所贡献。例如,客户可以从多种不同的技术中选择,来为其 EJB 应用程序提供目录服务,这些技术包括:



LDAP
Sun LDAP 服务供应商支持 LDAP 协议的第 2 版和第 3 版。

NIS
Sun 提供一个 NIS 服务供应商(NIS 即网络信息服务,以前称为黄页)。

COS 命名:Sun COS 命名服务供应商提供对 CORBA 命名服务的访问。

文件系统:Sun 提供一个服务供应商来访问文件系统。

RMI
注册:Sun RMI 注册提供一个服务供应商。

Novell:有几个服务供应商可提供对目录服务 NDS 的访问以及 NetWare 3X 连接库、Novell 文件系统和其他 Novell 服务(如扩展 NCP)的访问。

虽然 JNDI 规范对供应商是中立的,但不应认为,实现 JNDI 接口的应用程序服务器一定要能访问来自多个供应商的服务供应商代码。



JNDI
命名体系结构的关键概念包括:



对象和名称之间的绑定。

若干称为命名上下文的绑定集。

命名系统,即若干组命名上下文。

命名空间,指一个命名系统中的所有名称。

名称分类为原子名称、复合名称和合成名称。原子名称是不可分割的,可以绑定到一个对象上。复合名称是原子名称的组合,而合成名称则跨越多个命名系统。



命名上下文特别重要:所有的命名操作均是在上下文对象上进行的,并且名称解析过程总是从最初的命名上下文开始。



EJB 应用程序是如何使用 JNDI 的呢?JNDI 的主要用途是检索对 EJB 组件的引用。因为 EJB 框架是一个分布式对象框架,所以 EJB 应用程序不应当假定 EJB 组件的位置。JNDI 就是获取对 bean 的起始引用的一种机制。当一个 bean 安装到一个 enterprise bean 服务器上时,一个被称为 EJB 容器的软件组件就负责创建各个名称-对象绑定,使所需的 Java 类文件能使用这个 bean。应用程序使用 JNDI 的查找方法来检索对象引用,如下例所示:



Context initialContext = new InitialContext( );

CartHome cartHome = javax.rmi.PortableRemoteObject.narrow(

initialContext.lookup("applications/shopping_cart"), CartHome.class);



应用程序有责任知道外部名称,应用程序就是通过这个名称才得以引用一个 enterprise bean,并通过 JNDI 来获取对该 bean 的引用的。



进一步考察 JTA

JNDI 以外,Enterprise JavaBeans 体系结构还使用 Java Transaction API (JTA)因为事务对维护数据完整性和可靠性很重要,所以支持事务处理是 EJB 体系结构的一个基本部分。如果企业应用程序是分布式的,事务处理就会更加重要:



事务的概念是一个重要的编程范例,其目的在于简化既要求可靠性又要求可用性的应用程序结构,特别是那些需要同时访问共享数据的应用程序。事务的概念最早是用在商务运作的应用程序中,其中它被用于保护集中式数据库中的数据。后来,事务的概念已扩展到分布式计算的更广泛的环境中。今天,事务是构建可靠的分布式应用程序的关键,这一点已得到广泛承认。”(见对象管理组的“Transaction Service Specification”)



有时将事务描述为具有下列特征的工作单元:



原子性如果因故障而中断,所有结果均撤销

一致性事务的结果保留不变的特性

孤立性中间状态对其他事务是不可见的

持久性已完成的事务的结果是持久的

事务的终止有两种方式:提交一个事务会使其所有的更改永久不变,而回滚 (rolling back) 一个事务则撤销其所有的更改。



对象管理组织 (OMG) 为一种面向对象的事务服务,即对象事务服务 (OTS),创建了一种规范。OTS EJB 体系结构内的事务服务的基础。下列事务规范就是为 enterprise bean 所采用的事务模型而设:



OMG
的对象事务服务 (OTS)

Sun Microsystems
Transaction Service (JTS)

Sun Microsystems
Java Transaction API (JTA)

开放组 (X/Open) XA 接口

这种与语言无关的对象事务服务,为一个强健的分布式事务服务提供了基本概念、定义和功能。



Java Transaction Service OTS Java 映射,在 org.omg.CosTransactions org.omg.CosTSPortability 这两个包中定义。JTS 对事务分界和事务环境的传播之类的服务提供支持。JTS 功能由应用程序通过 Java Transaction API 访问。



Java Transaction API
指定事务管理器与分布式事务中涉及的其他系统组件之间的各种高级接口,这些系统组件有应用程序、应用程序服务器和资源管理器等。JTA 功能允许事务由应用程序本身、由应用程序服务器或由一个外部事务管理器来管理。JTA 接口包含在 javax.transaction javax.transaction.xa 这两个包中。



XA
接口定义了资源管理器和分布式事务环境中外部事务管理器之间的约定。外部事务管理器可以跨多个资源协调事务。XA Java 映射包含在 Java Transaction API 中。



内容预告

“什么是 Enterprise JavaBeans 组件?”的第二部分将讨论 EJB 编程模型。



参考资料



要了解更多有关 Java 技术和 EJB 体系结构的内容,请访问 Sun 的网站

关于从 applet 和应用程序的角度看 Java 编程,请阅读 David Flanagan 所著的 Java in a Nutshell

下载一份 Java Servlet API Specification 的副本。

下载 Java Developer's Journal 3 卷第 1 期中 Tom Kim 所写的“Looking for a 3-Tier App Builder?”(PDF)

参加 JavaSoft “Using the Beans Development Kit 1.0”课程。

“JavaBeans Guidelines”中可以发现一些补充的指导原则,它们使您能开发出性能优良的 Bean,这些 Bean 能够在大多数环境中表现良好,包括流行的各种 IDE 和各种浏览器。

阅读 Patricia Seybold Group Anne Thomas 所写的“Java 2 Platform, Enterprise Edition: Ensuring Consistency, Portability, and Interoperability” 中对 J2EE 的详细说明。

查阅“JNDI: Java Naming and Directory Interface” 中的 JNDI 体系结构和接口的概述,以及各种情况和示例。

了解Java 2 Platform, Enterprise Edition 中包含的以下 Java 技术:

Java IDL

Java Message Service (JMS) API

Java Naming and Directory Interface (JNDI)

Java Remote Method Invocation (RMI)

Java Transaction API (JTA)

Java Transaction Service (JTS)

JavaServer Pages (JSP) 技术

JDBC 数据访问 API

要了解常见问题、与 LDAP 相关的 RFC 以及更多信息,请访问 Mark Wahl LDAP 网站

要了解如何将 Linux 配置为 NIS(YP) NIS+ 客户机及如何安装成 NIS 服务器,请查阅 Linux NIS(YP)/NYS/NIS+ HOWTO

下载 Java IDL 的命名服务 COS naming

详细了解 Java Remote Method Invocation (RMI),包括规范、示例和常见问题。

了解 Novell 提供的大量的产品和解决方案。

访问 Object Management Group (OMG) 的网站

查阅开放组的 XA interface 规范。





作者简介

Ken Nordby
是位于 Research Triangle ParkNorth Carolina IBM 软件开发实验室的软件工程师。作为 SWG Product Affinity Services 工作组的成员,Ken 和他的 IBM 同事从事 IBM WebSphere Application ServerEnterprise JavaBeans IBM 实现)的开发及咨询工作。可以通过 nordby@us.ibm.com Ken 联系。

第二部分:EJB 编程模型



本文的第二部分说明创建 Enterprise JavaBean 组件所需的 Java 接口和类的作用。除了对 bean 类本身进行编码外,EJB 开发人员还必须为 bean 定义一个本地接口和一个远程接口。这些接口的实现类通常由容器生成,因此部署 EJB 组件是开发人员和 EJB 容器的合作行为。第二部分还区分了 enterprise bean 的两种主要类型,即会话 bean 和实体 bean,并说明了 EJB 容器和 EJB 服务器之间的关系。



enterprise bean 的编程模型的三个关键特征是:面向对象、对象的分布式和使用代理对象。由于此编程模型使用 Java 技术,因此它在本质上就是面向对象的。此模型也是分布式的,这是指 bean 在理论上是位置透明的。根据 Enterprise JavaBeans (EJB) 规范,“一般说来,EJB 类和 EJB 容器的实际位置对客户机是透明的。”在客户机想要访问 EJB 组件时使用代理对象。bean 本身对于客户机是不可访问的,对 bean 方法的访问则由 helper 类提供。



接口、委托和代理

Java 程序员编写一个 Enterprise JavaBeans 组件时,他们所创建的类必须实现一个 EJB 接口,并且它必须包含一个名为 ejbCreate() 的方法。一个 EJB 接口 -- 例如 SessionBean 接口 -- 指定了一些方法,它们包括以下各项:



ejbActivate()

ejbPassivate()

ejbRemove()

setSessionContext()



ejbActivate()
ejbPassivate() 方法通知一个 bean,管理该 bean 的容器组件正在主动和被动之间切换 bean 的状态(这通常是指在内存中还是交换到磁盘)。ejbRemove() 方法使 bean 知道它已被从容器中删除。setSessionContext() 方法使 bean 与一个上下文对象相关联,此上下文对象是为了便于 bean 与其容器进行通信。



ejbCreate()
方法并不是从零做起创建 enterprise bean 的。当客户机想要创建新的 enterprise bean 时,bean 的容器将调用这个 bean 的类的 newInstance() 方法,来实例化新的 bean 对象。然后容器调用 setSessionContext() 方法来建立上下文对象,用于与 bean 进行通信。最后,容器调用新 bean 中的 ejbCreate() 方法。像 ejbCreate()ejbActivate() ejbPassivate() 这样的方法有时称为对象生存周期方法,以区别于业务逻辑方法。



当开发人员设计一个新的 EJB 组件时,编写组成 enterprise bean 类的代码本身是不够的。EJB 程序员还必须编写两个将由 helper 类使用的 Java 接口。这些强制性接口必须扩展标准的 EJBObject EJBHome 接口,而这两个接口则都是 java.rmi.Remote marker 接口的扩展。扩展标准 EJBObject 接口的接口被称为 enterprise bean 的远程接口,它指定在 bean 自身中定义的业务方法。当应用程序调用 enterprise bean 中的业务方法时,应用程序并不访问 bean 本身。实际上,方法调用被传递给实现 EJBObject 接口扩展的那个对象。这种做法称为委托,它是 EJB 体系结构中的一个设计要点:





客户机从来不直接访问 enterprise bean 类的实例。客户机总是使用 enterprise bean 的远程接口来访问 enterprise bean 的实例。实现 enterprise bean 的远程接口的类由容器提供。此类所实现的分布式对象称为 EJB 对象。”(Enterprise JavaBeans Specification 1.0)



bean
EJBObject 接口的扩展称为其远程接口,而实现远程接口的对象则称为 EJB 对象。



enterprise bean 还必须具有本地接口。此接口是标准 EJBHome 接口的扩展。实现 bean 的本地接口的对象称为本地对象。本地对象包含一个 create() 方法,此方法由应用程序调用,而应用程序则必须创建一个 bean 实例。本地对象中的 create() 方法创建一个新的 EJB 对象。它并不直接创建新的 enterprise bean 实例,因为不允许直接访问 bean



EJB
对象和本地对象充当 bean 对象的代理,因为它们代表 bean 接收方法调用。EJB 对象主要为 bean 业务方法充当代理;本地对象主要为 bean 生存周期方法充当代理。



EJB 组件使用 create() 方法并不一定要实例化新的 bean。容器确定如何最好地满足创建请求,对于某些类型的 bean,它可以重用现有的实例:





客户机使用会话 bean 本地接口上的 create remove 方法。虽然客户机以为它正在控制着 EJB 实例的生存周期,但是,是容器在处理 create remove 调用,而不一定要创建和删除 EJB 实例。在客户机和...实例之间不存在固定的映射。容器只是将客户机的工作委托给任何一个方法已经就绪的可用实例而已。”(Enterprise JavaBeans Specification 1.0)



创建新的 bean 实例受容器的控制,并可以与客户机发布 create() 方法异步。



当创建一个 EJB 组件时,开发人员负责定义 EJBObject 接口和 EJBHome 接口,但是无需编写实现这些接口的类的代码。EJB 容器软件组件自动创建这些类。



下面的代码段说明客户机应用程序可能怎样使用称为 CartBean enterprise bean 来进行在线购物:



CartHome cartHome = javax.rmi.PortableRemoteObject.narrow(

initialContext.lookup("applications/shopping_cart"), CartHome.class);

Cart cart = cartHome.create();

cart.addItem(item29);

cart.addItem(item67);

cart.addItem(item91);

cart.purchase();

cart.remove();





CartHome
是实现本地接口的类(EJBHome 接口的扩展)。Cart 是实现远程接口的类(EJBObject 接口的扩展)。当客户机调用应用程序方法(如 addItem() purchase())时,它们是在 cart 对象上调用的,此对象接着将这些方法的执行委托给 bean 自身。enterprise bean 的功能是通过其代理 EJB 对象(即 cart)来获得的。如果多台客户机同时访问 cart bean,将会发生什么事情呢?Enterprise bean 开发人员无需编写代码来支持并发访问。并发性由 EJB 容器支持。



下图说明各 EJB 对象之间的关系:



服务器和容器

EJB
体系结构包括 EJB 服务器和 EJB 容器两个概念。EJB 服务器充当一种组件执行系统,正如 EJB 白皮书中所述:



“Enterprise JavaBeans
规范为每个支持完全可移植性的 Java 应用程序服务器定义了一个标准模型。任何厂商都可以使用此模型来实现对 Enterprise JavaBeans 组件的支持。多种系统(如 TP 监视器、CORBA 运行时系统、COM 运行时系统、数据库系统、Web 服务器系统或其它基于服务器的运行时系统)都可以调整到能够支持可移植的 Enterprise JavaBeans 组件。”(Thomas, Enterprise JavaBeans Technology: Server Component Model for the Java Platform)



EJB
服务器为使用 EJB 组件的应用程序提供操作环境,并供应所有必需的服务,来支持 EJB 体系结构。打包 EJB 服务器软件并没有预先规定的方式。一种方法是将它作为一项功能增强包括到应用程序服务器中,这就是在 IBM WebSphere Application Server, Advanced Edition, Version 2.0 中采用的方法。



EJB
组件并不在 EJB 服务器的顶部直接执行。一个称为 EJB 容器的中间软件组件在 EJB 服务器环境中运行,从而又为这些 bean 自身提供操作环境。EJB 容器对 EJB 应用程序是完全透明的,但是在支持 bean 操作方面起着关键性的作用。



为了使 enterprise bean 能充当可重用的软件组件,它们对特定的服务器或平台功能不能有内建的相关性。服务器端功能的几种常见类型已经被从 bean 设计中“分离出去”,而将此功能的责任转移给了容器组件。例如,容器将被用来接管安全性、并发性、事务处理、交换到辅助存储器和其它服务的责任,从而使 bean 免受服务器相关性的制约,并将按业务逻辑来优化,而不是按服务逻辑来优化。



EJB 白皮书这样描述容器的作用:



“EJB
容器管理部署于其中的 enterprise bean。客户机应用程序并不直接与 enterprise bean 进行交互。相反,客户机应用程序通过由容器生成的两个封装接口( EJB Home 接口和 EJB Object 接口)与 enterprise bean 进行交互。当客户机使用封装接口调用各种操作时,容器截获每个方法调用,并插入管理服务。”(Thomas, Enterprise JavaBeans Technology: Server Component Model for the Java Platform)



可以期望 EJB 容器软件一般都会随 EJB 服务器软件一起提供,尽管规范允许分离这些组件。除了提供对运行时服务(如事务处理和安全性)的访问以外,还期望 EJB 容器包括各种必要工具,来支持 enterprise bean 的安装、操作和管理。例如,需要有工具解释 EJB jar 文件的内容,有工具生成数据库访问,来获得容器提供的持久性,有工具监视正在运行的 bean 的行为,以及实现安全性等。



Bean
风格

EJB
组件分为两种主要类别 -- 会话 bean 和实体 bean。根据 bean 处理状态、事务和持久性的方式这些类别还可以进一步细分。会话 bean 通常具有以下属性:



代表单个客户机执行

可以是事务性的

可以更新共享数据库中的数据

生存期相对较短

其生存期通常就是客户机的生存期

任何持久性数据都由 bean 管理

可以依容器的判断予以删除

会在 EJB 服务器失败时被删除

实体 bean 通常具有以下属性:



代表数据库中的数据

是事务性的

允许多个用户共同访问

可以长期存在

持久性数据可以由容器管理

EJB 服务器失败后能继续生存

EJB
规范对会话 bean 和实体 bean 的说明如下:



对于客户机,会话 enterprise bean 是一种非持久性的对象,它实现某些在服务器上运行的业务逻辑。想像一个会话对象的一种方式是:会话对象是运行在服务器上的客户机程序的逻辑扩展。会话对象不在多台客户机之间共享。



对于客户机,实体 enterprise bean 是一种持久性对象,它代表一个存储在持久性存储器(例如,一个数据库)中的实体的对象视图,或者是一个由现有企业应用程序实现的实体。”(Enterprise JavaBeans Specification 1.0)



用一种粗略的说法,会话 bean 代表这样的操作,它检索或存储数据以满足用户请求;而实体 bean 则代表一种数据集,可以访问这些数据集来满足用户请求。



会话 bean

最简单的一种 Enterprise JavaBeans 组件就是无状态的会话 bean因为这些 bean 没有可以区分它们的状态,所有的实例都是完全相同的。容器管理无状态会话 bean 的生存周期,其方式是通过创建足够数目的此种 bean 来适应客户机工作负荷,并在不需要它们时将其删除。钝化,即将闲置的 bean 写到磁盘上,不用于无状态的会话。要调用 bean,客户机程序调用本地接口中的 standard create() 方法,尽管此操作不一定导致实例化新的 bean 实例。容器可以选择将客户机请求发送给现有的对象。反之,容器则可以按它的选择创建新的实例,且独立于由客户机发布的 create() 方法。



EJB 本地对象上发布的 create() 调用返回一个对 EJB 对象的引用,这个 EJB 对象代表 enterprise bean一旦客户机有了 EJB 对象引用,它就可以将业务方法发布到 EJB 对象上,容器随之会将这些方法委托给 bean 自身。负责管理会话 bean 的容器组件无需推断会话 bean 是否是无状态的。会话 bean 是无状态的还是有状态的在安装时声明。



如果会话 bean 在方法调用之间保留状态信息,则它是有状态的。通过调用 ejbPassivate() 方法,容器可以依其判断将有状态会话 bean 钝化,或写到辅助存储器中。EJB 规范并不要求容器在钝化 bean 时使用 Java 串行化协议,但是它们必须提供等价的功能。当容器决定将一个非活动的会话 bean 交换回到内存中时,它会取消被动 bean 的串行化,并调用 ejbActivate() 方法。有状态会话 bean 的开发人员负责确保状态数据是可串行化的。在集群的应用程序服务器环境中实现有状态会话 bean 时务必要小心,因为并不是所有的服务器都支持集群的有状态会话 bean 的同步化。



有状态会话 bean 可以是事务性的。通过使用 javax.transaction.UserTransaction 接口中的方法,如 begin()commit() rollback()bean 可以控制事务;通过实现 javax.ejb.SessionSynchronization 接口,bean 可以接收有关事务状态的通知。EJB 容器无需推断哪些 bean 需要事务支持;UserTransaction 接口仅可用于那些在安装时被标记为事务性的 bean



实体 bean

实体 bean 在体系结构上与会话 bean 类似,但它们提供对企业数据的访问,而不是支持用户会话。一个实体 bean 可以支持多个并发用户,而容器则使访问和事务同步化。实体 bean 还具有支持本地对象中的 finder 方法的主键。知道实体 bean 的主键的客户机可以通过调用本地对象上的 findBy PrimaryKey() 方法获得对象引用。与会话 bean 不同,实体 bean 的本地对象除了具有 create 方法外还具有 finder 方法。



持久性是实体 bean 的一个基本属性。EJB 规范允许两种形式的实体持久性:bean 管理的持久性和容器管理的持久性。对于代表关系数据库中的数据的实体 beanbean 对持久性的管理意味着,对数据库访问的调用是直接编写在企业 bean 的方法中的(使用 JDBC SQLJ)。这种方法是直截了当的,但它降低了可移植性。容器对持久性的管理意味着 bean 不受数据库调用的影响。在安装时告知容器有关 bean 数据所需的持久性,而容器负责生成实现持久性的代码。这种方法允许 bean 的可移植性更高,甚至达到持久性可使用不同数据源的程度。然而,此方法要求容器中要有复杂功能。



当实体 bean 对象与 EJB 对象相关联时,前者处于就绪状态;否则将认为它们处于共享状态。当客户机调用 EJB 对象中的方法时,容器查找关联的实体 bean 的实例(如果存在的话),或者从共享状态中传送出一个实例。处于就绪状态的实体 bean 可以接收到通过委托从客户机传播给它们的业务方法调用。它们还可以在容器请求时执行 ejbLoad() ejbStore() 方法。load 方法和 store 方法旨在维持实体 bean 和基础数据存储之间数据的一致性。



实体 bean 支持多个用户并发地访问数据。EJB 规范声明,维持数据完整性是容器的责任:



“enterprise bean
开发人员在编写业务方法时无需担心来自多个事务的并发访问。enterprise bean 开发人员在编写方法时可以假定,对于被多个事务同时访问的各个实体 bean,将能确保适当的同步化。”(Enterprise JavaBeans Specification 1.0)



容器完成这一任务通常是通过锁定数据库中的数据,并使访问串行化,或通过创建实体 bean 的多个实例,并允许在基础数据存储中使用并发控制,这样来管理访问。



第三部分内容预告

“什么是 Enterprise JavaBeans 组件?”的第三部分将讨论安装 EJB 组件的特殊部署过程。它还将说明 CORBA 是否是 EJB 组件的竞争对手(答案是“否” -- 请参阅 EJB 技术是如何补充 CORBA 的)。最后,您将看到一种基于 EJB 的三层编程模型的使用情况。



参考资料



查阅 Enterprise JavaBeans Specification 1.0

要了解有关 EJB 体系结构的更多内容,请参阅 Anne Thomas Enterprise JavaBeans Technology: Server Component Model for the Java PlatformPatricia Seybold Group

要了解有关 Java 技术和 EJB 体系结构的更多内容,请访问 Sun 的网站



作者简介

Ken Nordby
IBM 软件开发实验室的软件工程师,该实验室位于 Research Triangle ParkNorth Carolina。作为 SWG Product Affinity Services 业务小组的成员,Ken 与这样一些 IBM 人共事,他们为 IBM WebSphere Application Server(即 Enterprise JavaBeans 技术的 IBM 实现)从事开发和咨询工作。可以通过 nordby@us.ibm.com Ken 联系。


原作者:

Ken Nordby

原出处:

ibm

什么是 Enterprise JavaBeans 组件?(三)

推荐:simon

分类:JAVA

发布时间:2002-04-11

人气:1239

第三部分:布署和使用 Enterprise JavaBeans 组件



本文的第 3 部分说明 Enterprise JavaBeans 组件的部署过程,部署并不仅仅是安装,因为它通常还涉及代码生成。部署还使用了一个特殊的部署描述符文件,此文件支持控制企业级 bean 行为(如某个 bean 是否需要事务)的参数。bean 部署的这一特性支持 bean 行为的说明性、纲领性规范的 EJB 目标。第 3 部分还比较了持久性的两种主要类型,bean 管理式持久性和容器管理式持久性,并讨论了 EJB 组件与 CORBA 的关系。同时还给出了一个简单的三层 EJB 应用程序。

部署过程

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 的开发人员依赖容器进行事务管理时,就称为容器管理式定界,容器使用在部署时提供的事务属性:





无论客户机何时调用企业级 bean,容器都会介入这个方法调用。这种介入允许容器通过事务属性显式控制事务定界。例如,如果企业级 bean 部署了 TX_REQUIRED 事务属性,则无论何时,只要客户机调用支持事务的企业级 bean,容器就会自动启动事务,而客户机并不与任何事务上下文相关联。”(Enterprise JavaBeans Specification 1.0)



如果开发人员选择在 bean 内支持事务,则他们在部署描述符中指定 TX_BEAN_MANAGED 事务属性,然后就可以在 bean 自身内部自由使用 javax.transaction.UserTransaction 接口划分事务边界。通过认出 TX_BEAN_MANAGED 事务属性,容器就能知道不必介入事务支持。



通过增强 AccessControlEntry 对象和 RunAs 安全标识中指定的限制,容器为 EJB 组件提供安全支持。AccessControlEntry 对象在 bean 级别上或针对单个方法,将 Identity 对象与企业级 bean 相关联。Identity 对象反映允许调用 bean 的方法的用户或角色。当容器试图访问数据源或另一个 bean 时,它们也会将 RunAs 安全身份应用于 EJB 组件。可将 RunAs 身份设置为等同于某个特定用户帐户、有权限的系统帐户或客户机安全身份。访问控制和 RunAs 的信息是 bean 的开发人员在部署描述符中指定的,将影响容器管理 bean 的与安全有关的行为方式。



虽然 EJB 1.0 规范也提到安全问题,但更详细的安全功能定义,见该规范的后续版本。



CORBA
EJB 技术的关系

公用对象请求代理程序体系结构 (CORBA) 为分布式对象的平台中立和语言中立的计算环境奠定了基础。在 CORBA 环境中,功能驻留于对象之中,而客户机可通过对象请求代理程序 (ORB) 访问这些对象。完整的 CORBA 实现提供 ORB,外加称为 CORBA 对象服务和 CORBA 公用工具的几个运行时服务。也可只提供 ORB,不提供相关联的对象服务和公用工具(例如,IBM 就提供这样的两种独立 ORB)。实现基本 ORB 功能的软件称为 ORB 核心。为了支持语言无关性,CORBA 应用程序是用接口定义语言 (IDL) 编写的。该语言在语法上类似于 C++,但不包含语义:IDL 中指定的操作是操作接口,而不是操作实现。由于它对多种平台和多种语言的支持,以及源自其分布式特征的可伸缩性,CORBA 非常适合于管理企业规模的信息系统。



设计 EJB 规范也是为了支持企业信息系统。这样说来,CORBA 是一个竞争者吗?根据 Frequently Asked Questions for Enterprise JavaBeans,答案是否定的:





实际上,EJB 技术很好地补充了 CORBACORBA 提供了一个强大的基于标准的基础结构,可在此结构之上构建 EJB 服务器。EJB 技术使得在 CORBA 基础结构的顶层构建应用程序变得更为容易。”(Enterprise JavaBeans 常见问题解答)



虽然 EJB 规范和 CORBA 规范说明的是不同的技术,但 EJB 实现目前利用 CORBA 技术的某些方面。一个例子就是 RMI/IIOPEJB 规范要求 EJB 组件及其容器使用 Remote Method Invocation (RMI) 技术,实现分布式对象之间的方法调用。 RMI 规定远程方法的语法和语义,但并不规定应使用何种传输协议提供网络连接。CORBA Internet 对象请求代理程序间协议 (IIOP) 基本上定义了通过 TCP/IP 传输 CORBA 消息的一种方法。开发使用 IIOP 消息形式交换 RMI 数据的 EJB 实现,说明了 EJB 应用程序怎样才能有效地使用 CORBA 技术的各部分。这种网络也支持与 CORBA 应用程序的互操作性,后者使用 IIOP 发送本地 CORBA 消息,与 RMI 无关。IBM EJB 实现,即 WebSphere Application Server,优化了 IIOP 的使用,方法是,弄清楚分布式对象何时驻留在同一台服务器上,并且只在对象确实在远程时才调用 IIOP



为了方便既并入 EJB 技术,又并入 CORBA 技术的企业系统的开发,Sun Microsystems EJB 规范和 CORBA 之间创建了一种映射。 EJB 体系结构映射到 CORBA,影响到 EJB 技术的几个方面,包括对象分布、命名和事务。CORBA 映射的主要目的是,保证不同厂商构建的 EJB 服务器之间的互操作性。互操作性提供以下好处:



CORBA
客户机可以访问部署在基于 CORBA EJB 服务器上的 EJB 组件

客户机程序在事务中可以将对 CORBA 对象的调用,与对企业级 bean 的调用混合在一起

事务可以跨多个 bean,而这些 bean 又位于来自不同厂商的基于 CORBA 的多台 EJB 服务器上

使用来自某个厂商的 ORB 的客户机,可以访问另一个厂商基于 CORBA EJB 服务器上的 bean

对于要访问 EJB 组件的 CORBA 客户机来说,bean 接口被映射到 IDL。例如,可将股票交易 bean 中定义的 buy() sell() 方法,指定为 IDL 文件中的 CORBA 操作。非 bean CORBA 客户机,如 C++ 客户机,可以访问这个 bean,并用标准 CORBA 调用来调用 bean 的方法。如果容器使用 IIOP 作为它的分布式对象协议,则该容器的职责是,生成与企业级 bean 及其接口对应的 IDL



EJB
命名服务,它以“CORBA 对象服务”命名服务为基础,使 EJB 组件可用于 CORBA 客户机。Java Naming and Directory Interface (JNDI) 可提供到 CORBA 命名服务的接口,同时,客户机既可以通过 JNDI 调用间接访问基础命名服务,也可以通过“CORBA 对象服务” (COS) 命名 API 直接访问该服务。



EJB 事务支持依赖于 CORBA Transaction Service,即 Object Transaction Service (OTS)Java Transaction Service (JTS) 代表 OTS Java 绑定,它是语言中立的。基于 CORBA EJB 容器必须识别 CORBA 客户机通过 OTS 接口发出的事务边界,以及 EJB 应用程序通过 Java Transaction API (JTA) 接口发出的事务,JTA 是到 JTS 的应用程序级接口。JTA 还代表 Open Group XA 接口的 Java 绑定,以便将应用程序资源连接到外部事务管理器。JIA 中含存的 javax.transaction.UserTransaction 接口,为事务边界的应用程序级控制提供 APIUserTransaction 接口,既可由其事务属性设置为 TX_BEAN_MANAGED bean 使用,以可由 Java 客户机使用。



使用 EJB 组件

因为 EJB 体系结构被设计为高度灵活的,并支持使用任意复杂的方式连接企业级 bean,所以可构建许多不同的方案,来说明应用程序可怎样使用企业级 bean。一个有用的方案提出将 EJB 组件表示为三层信息系统的关键组件,该系统将企业数据、事务和应用程序资源连接到 Web 上。



基于 EJB 的三层编程模型视 Web 浏览器为第一层,视支持应用程序的 Web 服务器为第二层,视企业信息资源为第三层。在此编程模型中,除了 EJB 技术外,还实现了 Java servlet 技术、JavaBeans 技术和 Java Server Page (JSP) 技术。下图显示了各层的排列情况:





第一层是瘦客户机 -- 通常是 Web 浏览器,它可以处理普通 Web 数据类型,如 HTML GIF,并支持 HTTP 通信。第二层是 Web 应用程序服务器,它是用代码扩充的 Web 服务器,用来对能够通过 Web 服务器调用的应用程序提供运行时支持。现有的 Web 应用程序都沿用 CGI-BIN 编程模型,但预计第二层应用程序开发将转向 Java servlet 编程模型,后者提供大幅改善的性能和可移植性。除支持 Java servlet 外,Web 应用程序服务器还将添加 EJB 服务器功能,以支持使用 EJB 组件的应用程序。第三层代表企业级信息资源,可以包括关系数据库和面向对象的数据库、事务监视器和定制的应用程序。EJB 技术在这一设计中扮演着关键角色,因为,它使驻留在第二层上的应用程序组件,与组成第三层的企业资源之间的接口,得以标准化。



Java servletJava beans Java server page 不是 EJB 应用程序方案的必需元素,但它们可与 EJB 组件一起工作,以提供基于 Java 的内聚性的应用程序环境。此处描绘的环境将以下职责指定给参与工作的 Java 组件:



Java servlet 指定了应用程序“控制器”的角色

JSP
页面处理数据表示和用户界面的任务

Java bean
充当“数据封装器”,存储中间结果的数据

EJB
组件提供访问企业信息资源的机制

客户可以使用一个假定的、基于 EJB Web 应用程序更新现有的库存,并用容器管理式持久性和容器管理式事务,将访问库存数据库的位置封装在实体 EJB 组件的内部。库存票据可通过 Web 浏览器输入,浏览器提供一个 HTML 表单来捕获产品编号、供应商,等等,并在提交时调用一个 servletservlet 代码充当应用程序控制器角色,确定哪些企业数据库需要更新,需要用户追加什样的信息。servlet 可通过代表它的实体 bean 访问主库存数据库,并调用 JNDI 接口获取对此 bean 的本地对象的引用,然后使用 finder 方法定位所请求产品编号的远程对象。此时,通过调用远程对象的方法,servlet 可更新库存计数,接着容器将此方法委托给 EJB 组件。因为容器根据数据库更新,以对 bean 透明的方式划分一个事务,而且以对 bean 透明的方式将数据写入数据库来保证数据持久性,所以也就保持了数据的完整性。



EJB 组件返回到 servlet 的任何结果信息,都可以使用 setter 方法存储在一个(非企业的) Java bean 的属性中。此时 servlet 可将控制权转让给一个适当的 JSP 页面,以便将这些结果组合到表示格式中,并将结果返回给用户。JSP 页面很可能主要由静态文本和有关单个事务的可变信息占位符组成。在向浏览器发送表示数据之前,JSP 页面使用 getter 方法从 Java bean 的属性中获得可变数据元素。



基于 EJB 的三层设计提供了几个好处,包括:



访问企业数据的业务逻辑可封装在可重用、可移植的企业级 bean 中。

现有的企业系统只需很少修改或者根本不需要修改,就可以集成为企业级 bean

企业应用程序所需的运行时服务,如事务和持久性,可以从 bean 中分解出来,并指定给此 bean 的容器。

无须更改 EJB 组件,即可修改控制应用程序流程的 Servlet

Servlet
代码可将注意力集中在应用程序控制逻辑上,而无须考虑数据表示。

JSP
页面可将静态和动态内容混合在一起,生成表示信息。

Java 语言编写的系统组件,对于具有 JVM 的任何平台都是可移植的。

结论

在开发能够支持关键任务的企业级信息系统的过程中,EJB 规范代表了 Java 技术的下一个发展阶段。EJB 组件将随 JavaBeans 规范引入的 Java 组件模型,扩展到服务器领域,从而使业务逻辑组件的开发可以跨企业应用程序重用,并且可以跨支持 Java 的平台移植。由于包含了基于 RMI 技术的对象分布,所以支持跨多层的可执行组件的分立,从而允许最大的实现灵活性和高度可伸缩性。如果将常规的企业应用程序运行时服务重新定义为可指定给容器抽象的对象服务,则允许 EJB 组件的开发人员将精力集中在业务逻辑上,从而减小了通常与运行时服务相关的复杂性和平台相关性。



增强 Java 运行环境,以包括命名和目录服务的标准接口、关系数据库访问、事务服务和远程对象访问,使 Java 开发人员能够编写强健的企业应用程序,而不必离开 Java 编程环境。将其它 Java 技术 -- Java servlet JavaServer Pages 技术 -- EJB 组件一起使用,可创建一个对于大型企业系统来说足够强健的紧凑编程模型,但由于使用了巧妙的接口,从而简化了开发工作。而且,因为 EJB 体系结构是 JavaBeans 组件模型的逻辑扩展,所以作为 EJB 组件开发的业务逻辑可跨多个企业应用程序重用。



企业级 bean 体系结构的另一个好处是,提供了现有企业信息系统的直接集成通道,此通道可能与 Java 编程语言或 bean 编程模型毫无共同之处。因为现有的企业信息资源 -- 如关系数据库、事务监视器和业务应用程序的定制新品种 -- 可通过将它们封装在 EJB 组件中连接到 Web 前端,而无须替换应用程序或重写主要代码段,所以,客户可保护其现有的 IT 投资。



考虑到 EJB 技术的巨大前景,IT 业界以相当大的兴趣欢迎 EJB 规范,就不是什么令人惊讶的事了。EJB 体系结构提供的一个最大好处可能是,把业务逻辑编程与将业务逻辑和企业级服务器端运行环境的复杂集成分离开来。如果部署了 EJB 组件的容器承担了管理运行时服务(如持久性、事务和并发数据库访问)的职责,则 bean 的开发人员就可以自由地将精力集中在开发封装业务逻辑的软件组件上。JavaSoft 副总裁表述了 EJB 技术的重要性(引自 Sun Microsystems 网站):





“‘Enterprise JavaBeans API
将为企业开发人员和解决方案提供商提供一种新的战略武器,供他们建立下一代行业领先的、基于关键业务的应用程序,’Sun Microsystems JavaSoft 软件产品部副总裁,Jon Kannegaard 说:‘因为用 Enterprise JavaBeans API 设计的应用程序将与现有的企业系统一起工作,所以企业利用 Java 平台会获得新的竞争优势,同时还保留他们对现有技术的投资,’Kannegaard 继续说。





“使用 Enterprise JavaBeans API,开发人员将能够消除应用程序开发过程中的复杂性。这是可能的,因为每个 Enterprise JavaBeans 组件都封装了一个基本的业务功能。目前开发人员必须懂得如何编写业务逻辑和专门的系统级程序,以控制诸如安全性功能部件和处理多个事务的能力 -- 一项既枯燥又复杂的任务。Enterprise JavaBeans API 使全体开发人员能够将精力集中在编写解决业务问题的逻辑上,而不是将精力集中在编写用以简化不同技术间交互作用的代码上。”(新闻稿:Sun Releases Draft Enterprise JavaBeans Specification for Public Review



参考资料



通过 Sun 网站的 associated FAQs 深入了解 Java 技术和 EJB 体系结构。

查阅 Enterprise JavaBeans Specification 1.0

请参阅 Enterprise JavaBeans 规范的完整新闻稿

请参阅 IBM WebSphere Application Server如何使用 EJB 技术。



作者简介

Ken Nordby
IBM 软件开发实验室的软件工程师,该实验室位于北卡罗来纳州 Research Triangle Park。作为 SWG Product Affinity Services 业务小组的成员,Ken 与为 IBM WebSphere Application Server Enterprise JavaBeans 技术的 IBM 实现)进行开发和咨询的 IBM 人一起工作。可以通过 nordby@us.ibm.com Ken 联系。




EJBEnterprise JavaBeans)可不算什么新概念了,但许多人在听到或者看到这个名词的时候还会眼晕。EJB组件在J2EE规范中自成一层,把应用程序的表示层和后端信息系统(比如数据库或者主框架计算机)捆绑了起来。EJB架构既用到了EJB对象的功能又利用了它们所运行的环境。



为什么出来个EJB



从概念上看,EJB对象封装了业务对象及其概念,让开发人员把精力集中于解决方案的细节之上。从设计的角度看,EJB应该轻便而相互影响地合并起来。这一举措可以令单一的EJB,不论其是否为商务应用程序就可能采用一个EJB代表自主开发还是第3方厂商开发却都能用于多种应用程序。比方说,CRM(客户关系管理)工具和电子一位用户。这些已经具有适应性对象的配置由于部署描述符、说明EJBXML文件而变得非常简单。部署描述符允许不经重新编译就可修改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



会话(SessionBeans的作用建立在会话的基础之上。客户在请求并收到bean功能之后,具有特定bean的会话就终止了而且没有留下会话发生的记录。会话Bean类型还可以进一步细分为无状态或者有状态方式。



无状态会话Beans并不知道客户或者涉及到请求的上下文,从而令其成为单一请求/回应应用的理想工具。比方说,一个用户搜索所有公开bugbug跟踪系统就是如此。客户应用程序联系一个无状态会话Bean并给其传递搜索参数。接着,这个bean访问数据库,选择匹配检索条件的条目,并把记录传回客户程序。通讯完成之后,bean不保留交互信息。因此,多个客户程序可以同时访问无状态会话Bean却不会相互影响。



相反,有状态会话Beans会把请求同特定的客户联系起来,在客户和bean之间建立一种一对一的关系。购物车bean就是一例。用户实施标准的电子商务任务,给购物车里加入商品,输入地址信息然后下定单。购物车bean维持状态,因而它知道所有这些变量都关联某一特定客户。



实体Beans



实体(EntityBeans表示会话终止之后持久存在的业务对象或者数据。它们通常作为数据库中的单一记录形式存在,当然,其存储形式也可能采用其他媒质,比如文件等。一个对象就表示一个用户,有名字、联系方式、语言选择等等,这些参数代表了实体Bean的用途。作为持久性最本质的内涵之一,实体Bean的唯一标识或者主键起到了识别和检索正确对象信息的作用。实体beans需要主键作为“辅助类”封装对象的唯一标识符。



消息Beans



以上的两种bean类型以同步方式为EJB客户提供服务。客户发出请求然后等待bean发回结果。消息驱动(Message Driven Beans避免了这一可能的瓶颈问题。采用Java消息服务JMSJava Messaging Service)。客户程序可以产生一个消息并把消息发布给消息队列。消息驱动Bean随之采用或者检索消息执行其内容。这种事件或者数据的通讯就成为异步形式;客户或者bean都无须依赖对方的直接响应了。



比如,伦敦的一位银行官员使用一种应用程序发布最新的汇率消息。这时,部署在波士顿的一个外部交易bean从消息队列中获取这一消息然后更新数据库中的有关记录。在理想的情况下,消息驱动Bean会把信息传递给处理数据库事务的实体Bean。这样,每一种bean把它不能处理的任务转发从而创建出一种真正的分布式组件结构。



EJB
的原理



现在不考虑EJB的类别,以上三种类型组成了EJB对象:本地接口、远程接口和bean的实现。客户程序使用Java命名和目录接口JNDIJava 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容器的类型,另一种部署描述符会告诉容器如何识别和定位采用JNDIbean。以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 的开发人员依赖容器进行事务管理时,就称为容器管理式定界,容器使用在部署时提供的事务属性:



无论客户机何时调用企业级 bean,容器都会介入这个方法调用。这种介入允许容器通过事务属性显式控制事务定界。例如,如果企业级 bean 部署了 TX_REQUIRED 事务属性,则无论何时,只要客户机调用支持事务的企业级 bean,容器就会自动启动事务,而客户机并不与任何事务上下文相关联。”(Enterprise JavaBeans Specification 1.0)



如果开发人员选择在 bean 内支持事务,则他们在部署描述符中指定 TX_BEAN_MANAGED 事务属性,然后就可以在 bean 自身内部自由使用 javax.transaction.UserTransaction 接口划分事务边界。通过认出 TX_BEAN_MANAGED 事务属性,容器就能知道不必介入事务支持。



通过增强 AccessControlEntry 对象和 RunAs 安全标识中指定的限制,容器为 EJB 组件提供安全支持。AccessControlEntry 对象在 bean 级别上或针对单个方法,将 Identity 对象与企业级 bean 相关联。Identity 对象反映允许调用 bean 的方法的用户或角色。当容器试图访问数据源或另一个 bean 时,它们也会将 RunAs 安全身份应用于 EJB 组件。可将 RunAs 身份设置为等同于某个特定用户帐户、有权限的系统帐户或客户机安全身份。访问控制和 RunAs 的信息是 bean 的开发人员在部署描述符中指定的,将影响容器管理 bean 的与安全有关的行为方式。



虽然 EJB 1.0 规范也提到安全问题,但更详细的安全功能定义,见该规范的后续版本。



CORBA
EJB 技术的关系

公用对象请求代理程序体系结构 (CORBA) 为分布式对象的平台中立和语言中立的计算环境奠定了基础。在 CORBA 环境中,功能驻留于对象之中,而客户机可通过对象请求代理程序 (ORB) 访问这些对象。完整的 CORBA 实现提供 ORB,外加称为 CORBA 对象服务和 CORBA 公用工具的几个运行时服务。也可只提供 ORB,不提供相关联的对象服务和公用工具(例如,IBM 就提供这样的两种独立 ORB)。实现基本 ORB 功能的软件称为 ORB 核心。为了支持语言无关性,CORBA 应用程序是用接口定义语言 (IDL) 编写的。该语言在语法上类似于 C++,但不包含语义:IDL 中指定的操作是操作接口,而不是操作实现。由于它对多种平台和多种语言的支持,以及源自其分布式特征的可伸缩性,CORBA 非常适合于管理企业规模的信息系统。



设计 EJB 规范也是为了支持企业信息系统。这样说来,CORBA 是一个竞争者吗?根据 Frequently Asked Questions for Enterprise JavaBeans,答案是否定的:



实际上,EJB 技术很好地补充了 CORBACORBA 提供了一个强大的基于标准的基础结构,可在此结构之上构建 EJB 服务器。EJB 技术使得在 CORBA 基础结构的顶层构建应用程序变得更为容易。”(Enterprise JavaBeans 常见问题解答)



虽然 EJB 规范和 CORBA 规范说明的是不同的技术,但 EJB 实现目前利用 CORBA 技术的某些方面。一个例子就是 RMI/IIOPEJB 规范要求 EJB 组件及其容器使用 Remote Method Invocation (RMI) 技术,实现分布式对象之间的方法调用。 RMI 规定远程方法的语法和语义,但并不规定应使用何种传输协议提供网络连接。CORBA Internet 对象请求代理程序间协议 (IIOP) 基本上定义了通过 TCP/IP 传输 CORBA 消息的一种方法。开发使用 IIOP 消息形式交换 RMI 数据的 EJB 实现,说明了 EJB 应用程序怎样才能有效地使用 CORBA 技术的各部分。这种网络也支持与 CORBA 应用程序的互操作性,后者使用 IIOP 发送本地 CORBA 消息,与 RMI 无关。IBM EJB 实现,即 WebSphere Application Server,优化了 IIOP 的使用,方法是,弄清楚分布式对象何时驻留在同一台服务器上,并且只在对象确实在远程时才调用 IIOP



为了方便既并入 EJB 技术,又并入 CORBA 技术的企业系统的开发,Sun Microsystems EJB 规范和 CORBA 之间创建了一种映射。 EJB 体系结构映射到 CORBA,影响到 EJB 技术的几个方面,包括对象分布、命名和事务。CORBA 映射的主要目的是,保证不同厂商构建的 EJB 服务器之间的互操作性。互操作性提供以下好处:



CORBA
客户机可以访问部署在基于 CORBA EJB 服务器上的 EJB 组件

客户机程序在事务中可以将对 CORBA 对象的调用,与对企业级 bean 的调用混合在一起

事务可以跨多个 bean,而这些 bean 又位于来自不同厂商的基于 CORBA 的多台 EJB 服务器上

使用来自某个厂商的 ORB 的客户机,可以访问另一个厂商基于 CORBA EJB 服务器上的 bean

对于要访问 EJB 组件的 CORBA 客户机来说,bean 接口被映射到 IDL。例如,可将股票交易 bean 中定义的 buy() sell() 方法,指定为 IDL 文件中的 CORBA 操作。非 bean CORBA 客户机,如 C++ 客户机,可以访问这个 bean,并用标准 CORBA 调用来调用 bean 的方法。如果容器使用 IIOP 作为它的分布式对象协议,则该容器的职责是,生成与企业级 bean 及其接口对应的 IDL



EJB
命名服务,它以“CORBA 对象服务”命名服务为基础,使 EJB 组件可用于 CORBA 客户机。Java Naming and Directory Interface (JNDI) 可提供到 CORBA 命名服务的接口,同时,客户机既可以通过 JNDI 调用间接访问基础命名服务,也可以通过“CORBA 对象服务” (COS) 命名 API 直接访问该服务。



EJB 事务支持依赖于 CORBA Transaction Service,即 Object Transaction Service (OTS)Java Transaction Service (JTS) 代表 OTS Java 绑定,它是语言中立的。基于 CORBA EJB 容器必须识别 CORBA 客户机通过 OTS 接口发出的事务边界,以及 EJB 应用程序通过 Java Transaction API (JTA) 接口发出的事务,JTA 是到 JTS 的应用程序级接口。JTA 还代表 Open Group XA 接口的 Java 绑定,以便将应用程序资源连接到外部事务管理器。JIA 中含存的 javax.transaction.UserTransaction 接口,为事务边界的应用程序级控制提供 APIUserTransaction 接口,既可由其事务属性设置为 TX_BEAN_MANAGED bean 使用,以可由 Java 客户机使用。



使用 EJB 组件

因为 EJB 体系结构被设计为高度灵活的,并支持使用任意复杂的方式连接企业级 bean,所以可构建许多不同的方案,来说明应用程序可怎样使用企业级 bean。一个有用的方案提出将 EJB 组件表示为三层信息系统的关键组件,该系统将企业数据、事务和应用程序资源连接到 Web 上。



基于 EJB 的三层编程模型视 Web 浏览器为第一层,视支持应用程序的 Web 服务器为第二层,视企业信息资源为第三层。在此编程模型中,除了 EJB 技术外,还实现了 Java servlet 技术、JavaBeans 技术和 Java Server Page (JSP) 技术。下图显示了各层的排列情况:



第一层是瘦客户机 -- 通常是 Web 浏览器,它可以处理普通 Web 数据类型,如 HTML GIF,并支持 HTTP 通信。第二层是 Web 应用程序服务器,它是用代码扩充的 Web 服务器,用来对能够通过 Web 服务器调用的应用程序提供运行时支持。现有的 Web 应用程序都沿用 CGI-BIN 编程模型,但预计第二层应用程序开发将转向 Java servlet 编程模型,后者提供大幅改善的性能和可移植性。除支持 Java servlet 外,Web 应用程序服务器还将添加 EJB 服务器功能,以支持使用 EJB 组件的应用程序。第三层代表企业级信息资源,可以包括关系数据库和面向对象的数据库、事务监视器和定制的应用程序。EJB 技术在这一设计中扮演着关键角色,因为,它使驻留在第二层上的应用程序组件,与组成第三层的企业资源之间的接口,得以标准化。



Java servletJava beans Java server page 不是 EJB 应用程序方案的必需元素,但它们可与 EJB 组件一起工作,以提供基于 Java 的内聚性的应用程序环境。此处描绘的环境将以下职责指定给参与工作的 Java 组件:



Java servlet 指定了应用程序“控制器”的角色

JSP
页面处理数据表示和用户界面的任务

Java bean
充当“数据封装器”,存储中间结果的数据

EJB
组件提供访问企业信息资源的机制

客户可以使用一个假定的、基于 EJB Web 应用程序更新现有的库存,并用容器管理式持久性和容器管理式事务,将访问库存数据库的位置封装在实体 EJB 组件的内部。库存票据可通过 Web 浏览器输入,浏览器提供一个 HTML 表单来捕获产品编号、供应商,等等,并在提交时调用一个 servletservlet 代码充当应用程序控制器角色,确定哪些企业数据库需要更新,需要用户追加什样的信息。servlet 可通过代表它的实体 bean 访问主库存数据库,并调用 JNDI 接口获取对此 bean 的本地对象的引用,然后使用 finder 方法定位所请求产品编号的远程对象。此时,通过调用远程对象的方法,servlet 可更新库存计数,接着容器将此方法委托给 EJB 组件。因为容器根据数据库更新,以对 bean 透明的方式划分一个事务,而且以对 bean 透明的方式将数据写入数据库来保证数据持久性,所以也就保持了数据的完整性。



EJB 组件返回到 servlet 的任何结果信息,都可以使用 setter 方法存储在一个(非企业的) Java bean 的属性中。此时 servlet 可将控制权转让给一个适当的 JSP 页面,以便将这些结果组合到表示格式中,并将结果返回给用户。JSP 页面很可能主要由静态文本和有关单个事务的可变信息占位符组成。在向浏览器发送表示数据之前,JSP 页面使用 getter 方法从 Java bean 的属性中获得可变数据元素。



基于 EJB 的三层设计提供了几个好处,包括:



访问企业数据的业务逻辑可封装在可重用、可移植的企业级 bean 中。

现有的企业系统只需很少修改或者根本不需要修改,就可以集成为企业级 bean

企业应用程序所需的运行时服务,如事务和持久性,可以从 bean 中分解出来,并指定给此 bean 的容器。

无须更改 EJB 组件,即可修改控制应用程序流程的 Servlet

Servlet
代码可将注意力集中在应用程序控制逻辑上,而无须考虑数据表示。

JSP
页面可将静态和动态内容混合在一起,生成表示信息。

Java 语言编写的系统组件,对于具有 JVM 的任何平台都是可移植的。

结论

在开发能够支持关键任务的企业级信息系统的过程中,EJB 规范代表了 Java 技术的下一个发展阶段。EJB 组件将随 JavaBeans 规范引入的 Java 组件模型,扩展到服务器领域,从而使业务逻辑组件的开发可以跨企业应用程序重用,并且可以跨支持 Java 的平台移植。由于包含了基于 RMI 技术的对象分布,所以支持跨多层的可执行组件的分立,从而允许最大的实现灵活性和高度可伸缩性。如果将常规的企业应用程序运行时服务重新定义为可指定给容器抽象的对象服务,则允许 EJB 组件的开发人员将精力集中在业务逻辑上,从而减小了通常与运行时服务相关的复杂性和平台相关性。



增强 Java 运行环境,以包括命名和目录服务的标准接口、关系数据库访问、事务服务和远程对象访问,使 Java 开发人员能够编写强健的企业应用程序,而不必离开 Java 编程环境。将其它 Java 技术 -- Java servlet JavaServer Pages 技术 -- EJB 组件一起使用,可创建一个对于大型企业系统来说足够强健的紧凑编程模型,但由于使用了巧妙的接口,从而简化了开发工作。而且,因为 EJB 体系结构是 JavaBeans 组件模型的逻辑扩展,所以作为 EJB 组件开发的业务逻辑可跨多个企业应用程序重用。



企业级 bean 体系结构的另一个好处是,提供了现有企业信息系统的直接集成通道,此通道可能与 Java 编程语言或 bean 编程模型毫无共同之处。因为现有的企业信息资源 -- 如关系数据库、事务监视器和业务应用程序的定制新品种 -- 可通过将它们封装在 EJB 组件中连接到 Web 前端,而无须替换应用程序或重写主要代码段,所以,客户可保护其现有的 IT 投资。



考虑到 EJB 技术的巨大前景,IT 业界以相当大的兴趣欢迎 EJB 规范,就不是什么令人惊讶的事了。EJB 体系结构提供的一个最大好处可能是,把业务逻辑编程与将业务逻辑和企业级服务器端运行环境的复杂集成分离开来。如果部署了 EJB 组件的容器承担了管理运行时服务(如持久性、事务和并发数据库访问)的职责,则 bean 的开发人员就可以自由地将精力集中在开发封装业务逻辑的软件组件上。JavaSoft 副总裁表述了 EJB 技术的重要性(引自 Sun Microsystems 网站):



“‘Enterprise JavaBeans API
将为企业开发人员和解决方案提供商提供一种新的战略武器,供他们建立下一代行业领先的、基于关键业务的应用程序,’Sun Microsystems JavaSoft 软件产品部副总裁,Jon Kannegaard 说:‘因为用 Enterprise JavaBeans API 设计的应用程序将与现有的企业系统一起工作,所以企业利用 Java 平台会获得新的竞争优势,同时还保留他们对现有技术的投资,’Kannegaard 继续说。



使用 Enterprise JavaBeans API,开发人员将能够消除应用程序开发过程中的复杂性。这是可能的,因为每个 Enterprise JavaBeans 组件都封装了一个基本的业务功能。目前开发人员必须懂得如何编写业务逻辑和专门的系统级程序,以控制诸如安全性功能部件和处理多个事务的能力 -- 一项既枯燥又复杂的任务。Enterprise JavaBeans API 使全体开发人员能够将精力集中在编写解决业务问题的逻辑上,而不是将精力集中在编写用以简化不同技术间交互作用的代码上。”(新闻稿:Sun Releases Draft Enterprise JavaBeans Specification for Public Review



参考资料



通过 Sun 网站的 associated FAQs 深入了解 Java 技术和 EJB 体系结构。

查阅 Enterprise JavaBeans Specification 1.0

请参阅 Enterprise JavaBeans 规范的完整新闻稿。

请参阅 IBM WebSphere Application Server 如何使用 EJB 技术。

作者简介

Ken Nordby
IBM 软件开发实验室的软件工程师,该实验室位于北卡罗来纳州 Research Triangle Park。作为 SWG Product Affinity Services 业务小组的成员,Ken 与为 IBM WebSphere Application Server Enterprise JavaBeans 技术的 IBM 实现)进行开发和咨询的 IBM 人一起工作。可以通过 nordby@us.ibm.com Ken 联系。

什么是 Enterprise JavaBeans 组件?()

推荐:simon

分类:JAVA

发布时间:2002-04-09

人气:1781

第一部分:EJB 体系结构的历史和目标



本文概述 Enterprise JavaBeans (EJB) 技术,旨在让读者快速理解基本概念。 1 部分讲述 EJB 技术的历史和某些目标、优点和技术。为了简洁明了,有选择地讲述 EJB 技术的一些关键要素。请注意,虽然 EJB 组件依赖于一些基础的 Java 服务(如 Java Transaction Service),但使用 EJB 组件及认识这些组件的好处并不需要掌握这些相关技术的知识。



Enterprise JavaBeans 技术自 1998 3 月问世以来很受好评。下面这段话就是一个例子:



自从两年多以前问世以来,Enterprise JavaBeanstm 技术在平台供应商和企业的开发小组中,同样都保持着空前的发展势头。这是因为 EJBtm 的服务器端组件模型简化了中间件组件的开发,这些中间组件都是事务性的、可伸缩的和可移植的。Enterprise JavaBeans 服务器通过为中间件服务(如事务处理、安全性、数据库连接及其他)提供自动支持,降低了开发中间件的复杂程度。”(Sun Microsystems 网站)



Enterprise JavaBeans
这一名称利用了 Java bean — 这种可移植、可重用的 Java 软件组件的声望。Enterprise JavaBeans 技术把 Java 组件的概念从客户机域扩展到了服务器域:这是 Java 技术成长过程中有重大意义的一步,它使 Java 技术发展成为一种强健的、可伸缩的环境,能够支持以任务为关键的企业信息系统。



服务器上的 Java 应用程序

Java
编程语言最初在 Web 开发人员中获得好评的一个原因是,它支持称为 applet 的可下载 Java 程序。对 Applet 的支持以 Applet 类的形式内置到了 1.0 版的 Java Development Kit (JDK) 中。按照 1.0 版的时间框架,Java 开发是以 applet 和应用程序作为中心的。基于 JDK 1.0 版的 Java 读物都是从 applet 和应用程序的角度来描述 Java 编程的:



“Java
程序由更多的类定义中的某一个组成,每个类定义均已编译成它自已的 Java 虚拟机对象代码的 .class 文件。这些类之一必须定义一个叫做 main() 的方法,程序就是从这个方法开始运行的。想调用一个 Java 程序,需要运行 Java 解释器 java,并指定包含 main() 方法的类的名称。请注意 Java applet 并不是一个应用程序它是一个由已在运行的 Java 应用程序(如 Web 浏览器或 applet 查看器)装入并运行的 Java 类。”(见 Flanagan 所著的 Java in a Nutshell



Java
应用程序可以在服务器上运行,但是不管是在客户机-服务器环境下,还是在基于 Web 的环境下,JDK 中都没有提供让 Java 应用程序专用于服务器机器的接口或包。认识到 Java Web 环境下作为一种服务器语言的潜力,Sun Microsystems 编写了 Java Servlet 规范。servlet 在许多方面与 applet 相似,它是专门为在 Web 服务器机器上运行而设计的 Java 程序:



“servlet
是由容器管理的 Web 组件,可产生动态内容。servlet 是一种小型的、与平台无关的 Java 类,被编译成体系结构中立的字节代码,这种代码可以动态地加载到一个 web 服务器上,并由此 web 服务器运行。servlet 通过一种由 servlet 容器实现的请求-响应模型与 Web 客户机进行交互。这种请求-响应模型建立在超文本传输协议 (HTTP) 行为的基础之上。”(见 JavaSoft 的“Java Servlet API Specification”)



在一台 Web 服务器控制下,在多台服务器上运行若干小型用户程序,这种想法并不新鲜一段时间以来,公共网关接口 (CGI) 程序(常被称为 CGI 脚本)一直起着这种作用,并推动了 Web 的普及。但 Java servlet 可以以更高的效率和可移植性来实现这一目的,因而可望最终会取代 CGI 程序。为 servlet 提供运行时环境的软件(通常被称为 servlet 引擎)可以添加到现有的、本身并不支持 Java 可执行程序的 Web 服务器上。



Java servlet
的出现,为应用程序员使用 Java 来创建 Web 应用程序开辟了新的途径。但是,仅有 servlet 还不能为真正的企业计算提供完整的模型。CGI 应用程序本身往往不是完整的应用程序,在处理接收自 Web 浏览器上用户的信息请求时,CGI 只是整个处理过程中的一个中间步骤。例如,CGI 应用程序的一种常见用途是访问数据库。将它用于这种任务时,CGI 程序提供一种方法,将用户的数据请求连接到能满足这种请求的企业数据库。CGI 程序常常充当一种中间软件,从 Web 浏览器接收请求,决定必须调用哪些计算资源来满足这些请求,并向浏览器发回响应。Java servlet CGI 程序一样,最适合充当连接前端 Web 请求与后端数据资源的中间层组件。



三层体系结构

Web
编程向服务器端 Java 应用程序的演化,也带来了体系结构的演化,使它脱离了常规的客户机-服务器两层模型,而向一种三层方法发展。两层模型当时曾经具有创新意义,因为它将一些计算任务从主处理器上卸载到灵巧的客户机。常规的基于 LAN 的数据库应用程序就是一个例子,其中数据库管理器服务器软件驻留在一个专用的服务器机器上,而用户则通过他们的工作站上的客户机代码来访问数据库。随着客户机-服务器模型成长到能付诸使用,就出现了对服务器可伸缩性和对客户机代码大小和复杂性的关注。于是提出了一种三层的体系结构,以避免在两层模型中已察觉到的弱点,使 Web 能成为一个计算平台:



许多人...断言,传统的客户机/服务器两层体系结构不会有好的可伸缩性,因为用户连接和数据访问的数量无法预测,而且在一些系统管理上也存在问题。为处理两层体系结构的限制,许多开发集体都在转向三层体系结构。这种体系结构大致可以定义为:客户机层上的表示层、中间的服务器和后端的某种数据库。这种设想的目的就是缓和客户机或数据库服务器上的代码膨胀,集中管理业务逻辑,更灵活地使用数据库,而不仅是使用所存储的过程和触发器。”(见 Kim 的“Looking for a 3-Tier App Builder?”)



一个三层结构模型通常被想像成有一个 Web 浏览器作为客户层。Web 浏览器由于有可能成为一种真正的通用客户机,使它从观念上取代了两层结构的“胖客户机”。如果浏览器作为 Web 应用程序体系结构的标准瘦客户机获得认可,那么以前驻留在两层模型的胖客户机中的功能会怎么样呢?现在,应用程序专用的功能并不移植回服务器(例如数据库管理器),而是有意将它驻留在一个新的中间层上。中间层支持应用程序服务器软件,这种软件是中间件的一种形式,它处于第一层上瘦客户机的最小功能和第三层上服务器端业务系统的丰富功能之间。由于三层体系结构与 Web 处理模型有密切关系,所以中间层应用程序服务器常被视为 Web 服务器的一种功能扩展。现有的 Web 应用程序利用 CGI 程序,将来自 Web 浏览器的用户请求传送到不基于 Web 的业务系统,并向浏览器返回响应,就是三层模型的一种实现。这些应用程序逐渐向 servlet 技术的转移说明三层模型正在增强。



JavaBeans 组件

JavaBeans
规范将“组件软件”的概念引入到 Java 编程的领域。组件是自含的、可重用的软件单元;而 JavaBeans 组件,则可以使用可视的应用程序开发工具,可视地将它们编写到 Java 程序中。JavaBeans 规范为 Java 开发人员提供了一种“组件化”其 Java 类的方法:



Bean
是一些 Java 类,可在一个可视的构建器工具中操作它们,并且可以将它们一起编写到应用程序中。任何具有某种特性和事件接口约定的 Java 类都可以是一个 Bean。(见 JavaSoft,“Using the Beans Development Kit 1.0”)



如果软件重用是一个好主意,那么是否应该让每一个 Java 类都成为 Java bean 呢?如果 Java 类满足某些准则,它们就适于充当 bean 的角色:



在开发任何新软件之前,都值得考虑是否用 JavaBean 的形式来开发它。如果软件模块要既能够可视地操作,又能够定制以达到某些效果,则这种软件模块就可能适于做成一个 JavaBean。为帮助您确定要开发的软件是否应该是一个 JavaBean,假定它应该是用 Java 编写的,请向您自已提出以下问题,并相应地作出决定:



是否打算让它可重用?或者,它会是可重用的吗?

是否希望将它与其他可重用的 Java 组件一起使用?

是否预计会在 IDE 工具中使用它?



如果上述问题的答案都是肯定的,则它应该作为 JavaBean 来开发。(见 developerWorks 的“JavaBeans Guidelines”)



JavaBean
概念是为了在 Java 编程环境中支持可重用的组件,它是一种一般性的设计方法,适用于客户机或服务器机器上运行的 Java 程序。由于对可视的构建器工具的强调,也由于许多 Java bean 都是图形用户界面 (GUI) 组件,所以 JavaBean 组件可能被视为一种客户端技术。但是,并不要求 Java bean 都是可视的,并且它们也可以用于服务器环境中。



编码为 Java bean Java 类通常具有以下特征:



使用设计模式。这些模式就是方法和接口的编码约定。

支持可视的软件开发工具。类必须将变量(称为属性)、方法和事件展示出来。

可以定制。定制包括能支持缺省的属性编辑器,或者提供单一的定制规则。定制使开发人员得以在不更改源代码的情况下更改 bean 的行为。

支持自省 (introspection)这指的是将属性、方法和事件公开给其他类,可以通过设计模式或通过创建 BeanInfo 类来完成这种自省。

是持久的。这就允许在一个可视构建器中定制一个 bean,然后以其定制后的状态加以保存。

Java 2 Platform, Enterprise Edition

Sun Microsystems
发起了一项称为 Java 2 Platform, Enterprise Edition (J2EE) 的技术创新,旨在将 Java 平台的范围扩展到大规模服务器环境:



“1997
4 12 日,Sun 宣布了一项为企业环境开发 Java 平台的创新成果。使用开放式的 Java Community ProcessSun 促进了一组标准的 Java 扩展的开发,称为 Enterprise Java API这些应用程序编程接口 (API) 为各种各样的中间件的实现提供了不依赖供应商的编程接口。Enterprise Java API 的要点是 Enterprise JavaBeans API,后者为 Java 应用程序服务器定义了一个服务器端组件模型,以及一个不依赖供应商的编程接口。”(见 Thomas 的“Java 2 Platform, Enterprise Edition: Ensuring Consistency, Portability, and Interoperability”)



J2EE
Enterprise JavaBeans 技术提供了工作环境。事实上,Sun 把若干项软件技术都设想为这样的构件块,它们将使大型企业能够把以任务为关键的业务系统移植到 Java 环境中,而 Enterprise JavaBeans 技术不过是这些技术之一。EJB 组件是按它们自己的规范定义的,但 EJB 技术并不是一项独立的技术。它建立在其他 Java 技术之上,这些技术由 Sun 和其他 IT 公司联合规定,它们一起提供了这个框架的内容,该框架就称为 Java 2 Platform, Enterprise Edition



J2EE 中包括以下技术:



Enterprise JavaBeans (EJB)
技术

Java Interface Definition Language (IDL)

Java Message Service (JMS) API

Java Naming and Directory Interface (JNDI)

Java Remote Method Invocation (RMI)
Object Serialization

Java Servlet API

Java Transaction API (JTA)

Java Transaction Service (JTS)

JavaServer Pages (JSP)
技术

JDBC
数据库访问 API

参与到这个企业 Java 框架中,并不意味着每项技术都依赖于所有其他技术。单独的规范文档指出每项技术的相关性。例如,Enterprise JavaBeans 规范 1.0 发行版就指明了在定位各个组件时与 JNDI 的相关性,以及在编程中启动和停止事务处理时与 JTA 的相关性。



EJB
技术的设计目标

EJB
规范的第一版以初稿形式于 1997 12 月公布,并于 1998 3 月作为 1.0 版发行。规范作者为 EJB 体系结构制定了以下目标:



Enterprise JavaBeans
体系结构将是标准的组件体系结构,用于以 Java 编程语言构建分布式的面向对象的商务应用程序。通过把使用不同供应商提供的工具开发出来的组件组合在一起,Enterprise JavaBeans 体系结构将有可能构建分布式的应用程序。



Enterprise JavaBeans
体系结构将使编写应用程序变得容易:应用程序开发人员将不必了解低层次的事务和状态管理的细节、多线程、资源共享和其他复杂的低级 API。但是,将允许专家级的程序员直接访问低级 API



Enterprise JavaBeans 应用程序将遵循 Java 编程语言的“一次编写,随处运行”的原则。EJB 组件可以只开发一次,然后在多个平台上部署,而不需要重新编译或修改源代码。



Enterprise JavaBeans 体系结构将处理企业应用程序生命周期中的开发、部署和运行等方面。



Enterprise JavaBeans
体系结构将定义一些约定,这些约定使多个供应商提供的工具能够开发并部署可在运行时互操作的组件。



Enterprise JavaBeans
体系结构将与现有的服务器平台兼容。供应商将能够扩展它们的现有产品,以支持 Enterprise JavaBeans 组件。



Enterprise JavaBeans
体系结构将与 Java 编程语言编写的其他 API 兼容。



Enterprise JavaBeans
体系结构将提供 EJB 组件和非 Java 编程语言应用程序之间的互操作性。



Enterprise JavaBeans
体系结构将与 CORBA 兼容。

使用 EJB 技术的好处

这些设计目标会使企业和开发人员得到什么好处呢?下面列出了可望从采用 Enterprise JavaBeans 环境获得的好处:



EJB
组件使编写应用程序更为简单。尽管 EJB 体系结构复杂,但应用程序开发人员一般都不必再编写用于访问系统服务的代码。一种称为 EJB 容器的系统组件使系统服务可用于 EJB 组件的任务。



服务器端商务逻辑可以移植。除了 Java 语言固有的可移植性外,EJB 体系结构还在 bean 和支持该 bean 的容器之间提供了一套标准化的应用程序编程接口。这使开发人员能够将 bean 从一种操作环境移植到另一种操作环境,而无须重新编写其源代码。



可以从现有的软件组件装配出服务器端应用程序,这与从现有的 Java bean 可以装配出客户端应用程序一样,从而使软件能够重用。



EJB
体系结构内置了对典型企业级系统服务的支持,包括分布式对象、事务处理、数据库、安全和全局命名。



多家 IT 供应商都采纳 EJB 体系结构,这是由于有这样的承诺:客户将能够从选定的供应商那里选购软件组件,如 EJB 组件、容器及 EJB 服务器;也由于承诺了不同供应商的产品,只要符合 EJB 体系结构,就都是可互操作的。



EJB 组件构建的应用程序可以从一个服务器移植到另一个服务器,从而支持可伸缩性,这是因为在 EJB 模型中,各个软件组件都是严格分离的。



EJB
体系结构能保障原有的 IT 投资,这是通过允许将现有的信息系统和资产“包裹”在这些应用程序中,而不要求客户更换现有技术。事实上,在关系数据库中存储数据的企业已经有了一套已有雏形的实体 bean,正等着通过 EJB 外壳去访问。



进一步考察 JNDI

Enterprise JavaBeans
组件使用 Java Naming and Directory Interface (JNDI) 来访问各种目录服务。JNDI 分两部分:应用程序编程接口 (API) 和服务供应商接口 (SPI)



“JNDI
体系结构由 JNDI API JNDI SPI 组成。JNDI API 允许 Java 应用程序访问各种命名和目录服务。JNDI SPI 则是设计来供任意一种服务的供应商(也包括目录服务供应商)使用。这使得各种各样的目录服务和命名服务能够透明地插入到使用 JNDI API Java 应用程序中。(见 JavaSoft,“JNDI: Java Naming and Directory Interface”)



JNDI API
并不同某种专用的命名技术或目录技术连在一起,也不同任何供应商的目录服务连在一起,因此它对 EJB 组件的可移植性有所贡献。例如,客户可以从多种不同的技术中选择,来为其 EJB 应用程序提供目录服务,这些技术包括:



LDAP
Sun LDAP 服务供应商支持 LDAP 协议的第 2 版和第 3 版。

NIS
Sun 提供一个 NIS 服务供应商(NIS 即网络信息服务,以前称为黄页)。

COS 命名:Sun COS 命名服务供应商提供对 CORBA 命名服务的访问。

文件系统:Sun 提供一个服务供应商来访问文件系统。

RMI
注册:Sun RMI 注册提供一个服务供应商。

Novell:有几个服务供应商可提供对目录服务 NDS 的访问以及 NetWare 3X 连接库、Novell 文件系统和其他 Novell 服务(如扩展 NCP)的访问。

虽然 JNDI 规范对供应商是中立的,但不应认为,实现 JNDI 接口的应用程序服务器一定要能访问来自多个供应商的服务供应商代码。



JNDI
命名体系结构的关键概念包括:



对象和名称之间的绑定。

若干称为命名上下文的绑定集。

命名系统,即若干组命名上下文。

命名空间,指一个命名系统中的所有名称。

名称分类为原子名称、复合名称和合成名称。原子名称是不可分割的,可以绑定到一个对象上。复合名称是原子名称的组合,而合成名称则跨越多个命名系统。



命名上下文特别重要:所有的命名操作均是在上下文对象上进行的,并且名称解析过程总是从最初的命名上下文开始。



EJB 应用程序是如何使用 JNDI 的呢?JNDI 的主要用途是检索对 EJB 组件的引用。因为 EJB 框架是一个分布式对象框架,所以 EJB 应用程序不应当假定 EJB 组件的位置。JNDI 就是获取对 bean 的起始引用的一种机制。当一个 bean 安装到一个 enterprise bean 服务器上时,一个被称为 EJB 容器的软件组件就负责创建各个名称-对象绑定,使所需的 Java 类文件能使用这个 bean。应用程序使用 JNDI 的查找方法来检索对象引用,如下例所示:



Context initialContext = new InitialContext( );

CartHome cartHome = javax.rmi.PortableRemoteObject.narrow(

initialContext.lookup("applications/shopping_cart"), CartHome.class);



应用程序有责任知道外部名称,应用程序就是通过这个名称才得以引用一个 enterprise bean,并通过 JNDI 来获取对该 bean 的引用的。



进一步考察 JTA

JNDI 以外,Enterprise JavaBeans 体系结构还使用 Java Transaction API (JTA)因为事务对维护数据完整性和可靠性很重要,所以支持事务处理是 EJB 体系结构的一个基本部分。如果企业应用程序是分布式的,事务处理就会更加重要:



事务的概念是一个重要的编程范例,其目的在于简化既要求可靠性又要求可用性的应用程序结构,特别是那些需要同时访问共享数据的应用程序。事务的概念最早是用在商务运作的应用程序中,其中它被用于保护集中式数据库中的数据。后来,事务的概念已扩展到分布式计算的更广泛的环境中。今天,事务是构建可靠的分布式应用程序的关键,这一点已得到广泛承认。”(见对象管理组的“Transaction Service Specification”)



有时将事务描述为具有下列特征的工作单元:



原子性如果因故障而中断,所有结果均撤销

一致性事务的结果保留不变的特性

孤立性中间状态对其他事务是不可见的

持久性已完成的事务的结果是持久的

事务的终止有两种方式:提交一个事务会使其所有的更改永久不变,而回滚 (rolling back) 一个事务则撤销其所有的更改。



对象管理组织 (OMG) 为一种面向对象的事务服务,即对象事务服务 (OTS),创建了一种规范。OTS EJB 体系结构内的事务服务的基础。下列事务规范就是为 enterprise bean 所采用的事务模型而设:



OMG
的对象事务服务 (OTS)

Sun Microsystems
Transaction Service (JTS)

Sun Microsystems
Java Transaction API (JTA)

开放组 (X/Open) XA 接口

这种与语言无关的对象事务服务,为一个强健的分布式事务服务提供了基本概念、定义和功能。



Java Transaction Service OTS Java 映射,在 org.omg.CosTransactions org.omg.CosTSPortability 这两个包中定义。JTS 对事务分界和事务环境的传播之类的服务提供支持。JTS 功能由应用程序通过 Java Transaction API 访问。



Java Transaction API
指定事务管理器与分布式事务中涉及的其他系统组件之间的各种高级接口,这些系统组件有应用程序、应用程序服务器和资源管理器等。JTA 功能允许事务由应用程序本身、由应用程序服务器或由一个外部事务管理器来管理。JTA 接口包含在 javax.transaction javax.transaction.xa 这两个包中。



XA
接口定义了资源管理器和分布式事务环境中外部事务管理器之间的约定。外部事务管理器可以跨多个资源协调事务。XA Java 映射包含在 Java Transaction API 中。



内容预告

“什么是 Enterprise JavaBeans 组件?”的第二部分将讨论 EJB 编程模型。



参考资料



要了解更多有关 Java 技术和 EJB 体系结构的内容,请访问 Sun 的网站

关于从 applet 和应用程序的角度看 Java 编程,请阅读 David Flanagan 所著的 Java in a Nutshell

下载一份 Java Servlet API Specification 的副本。

下载 Java Developer's Journal 3 卷第 1 期中 Tom Kim 所写的“Looking for a 3-Tier App Builder?”(PDF)

参加 JavaSoft “Using the Beans Development Kit 1.0”课程。

“JavaBeans Guidelines”中可以发现一些补充的指导原则,它们使您能开发出性能优良的 Bean,这些 Bean 能够在大多数环境中表现良好,包括流行的各种 IDE 和各种浏览器。

阅读 Patricia Seybold Group Anne Thomas 所写的“Java 2 Platform, Enterprise Edition: Ensuring Consistency, Portability, and Interoperability” 中对 J2EE 的详细说明。

查阅“JNDI: Java Naming and Directory Interface” 中的 JNDI 体系结构和接口的概述,以及各种情况和示例。

了解Java 2 Platform, Enterprise Edition 中包含的以下 Java 技术:

Java IDL

Java Message Service (JMS) API

Java Naming and Directory Interface (JNDI)

Java Remote Method Invocation (RMI)

Java Transaction API (JTA)

Java Transaction Service (JTS)

JavaServer Pages (JSP) 技术

JDBC 数据访问 API

要了解常见问题、与 LDAP 相关的 RFC 以及更多信息,请访问 Mark Wahl LDAP 网站

要了解如何将 Linux 配置为 NIS(YP) NIS+ 客户机及如何安装成 NIS 服务器,请查阅 Linux NIS(YP)/NYS/NIS+ HOWTO

下载 Java IDL 的命名服务 COS naming

详细了解 Java Remote Method Invocation (RMI),包括规范、示例和常见问题。

了解 Novell 提供的大量的产品和解决方案。

访问 Object Management Group (OMG) 的网站

查阅开放组的 XA interface 规范。





作者简介

Ken Nordby
是位于 Research Triangle ParkNorth Carolina IBM 软件开发实验室的软件工程师。作为 SWG Product Affinity Services 工作组的成员,Ken 和他的 IBM 同事从事 IBM WebSphere Application ServerEnterprise JavaBeans IBM 实现)的开发及咨询工作。可以通过 nordby@us.ibm.com Ken 联系。

第二部分:EJB 编程模型



本文的第二部分说明创建 Enterprise JavaBean 组件所需的 Java 接口和类的作用。除了对 bean 类本身进行编码外,EJB 开发人员还必须为 bean 定义一个本地接口和一个远程接口。这些接口的实现类通常由容器生成,因此部署 EJB 组件是开发人员和 EJB 容器的合作行为。第二部分还区分了 enterprise bean 的两种主要类型,即会话 bean 和实体 bean,并说明了 EJB 容器和 EJB 服务器之间的关系。



enterprise bean 的编程模型的三个关键特征是:面向对象、对象的分布式和使用代理对象。由于此编程模型使用 Java 技术,因此它在本质上就是面向对象的。此模型也是分布式的,这是指 bean 在理论上是位置透明的。根据 Enterprise JavaBeans (EJB) 规范,“一般说来,EJB 类和 EJB 容器的实际位置对客户机是透明的。”在客户机想要访问 EJB 组件时使用代理对象。bean 本身对于客户机是不可访问的,对 bean 方法的访问则由 helper 类提供。



接口、委托和代理

Java 程序员编写一个 Enterprise JavaBeans 组件时,他们所创建的类必须实现一个 EJB 接口,并且它必须包含一个名为 ejbCreate() 的方法。一个 EJB 接口 -- 例如 SessionBean 接口 -- 指定了一些方法,它们包括以下各项:



ejbActivate()

ejbPassivate()

ejbRemove()

setSessionContext()



ejbActivate()
ejbPassivate() 方法通知一个 bean,管理该 bean 的容器组件正在主动和被动之间切换 bean 的状态(这通常是指在内存中还是交换到磁盘)。ejbRemove() 方法使 bean 知道它已被从容器中删除。setSessionContext() 方法使 bean 与一个上下文对象相关联,此上下文对象是为了便于 bean 与其容器进行通信。



ejbCreate()
方法并不是从零做起创建 enterprise bean 的。当客户机想要创建新的 enterprise bean 时,bean 的容器将调用这个 bean 的类的 newInstance() 方法,来实例化新的 bean 对象。然后容器调用 setSessionContext() 方法来建立上下文对象,用于与 bean 进行通信。最后,容器调用新 bean 中的 ejbCreate() 方法。像 ejbCreate()ejbActivate() ejbPassivate() 这样的方法有时称为对象生存周期方法,以区别于业务逻辑方法。



当开发人员设计一个新的 EJB 组件时,编写组成 enterprise bean 类的代码本身是不够的。EJB 程序员还必须编写两个将由 helper 类使用的 Java 接口。这些强制性接口必须扩展标准的 EJBObject EJBHome 接口,而这两个接口则都是 java.rmi.Remote marker 接口的扩展。扩展标准 EJBObject 接口的接口被称为 enterprise bean 的远程接口,它指定在 bean 自身中定义的业务方法。当应用程序调用 enterprise bean 中的业务方法时,应用程序并不访问 bean 本身。实际上,方法调用被传递给实现 EJBObject 接口扩展的那个对象。这种做法称为委托,它是 EJB 体系结构中的一个设计要点:





客户机从来不直接访问 enterprise bean 类的实例。客户机总是使用 enterprise bean 的远程接口来访问 enterprise bean 的实例。实现 enterprise bean 的远程接口的类由容器提供。此类所实现的分布式对象称为 EJB 对象。”(Enterprise JavaBeans Specification 1.0)



bean
EJBObject 接口的扩展称为其远程接口,而实现远程接口的对象则称为 EJB 对象。



enterprise bean 还必须具有本地接口。此接口是标准 EJBHome 接口的扩展。实现 bean 的本地接口的对象称为本地对象。本地对象包含一个 create() 方法,此方法由应用程序调用,而应用程序则必须创建一个 bean 实例。本地对象中的 create() 方法创建一个新的 EJB 对象。它并不直接创建新的 enterprise bean 实例,因为不允许直接访问 bean



EJB
对象和本地对象充当 bean 对象的代理,因为它们代表 bean 接收方法调用。EJB 对象主要为 bean 业务方法充当代理;本地对象主要为 bean 生存周期方法充当代理。



EJB 组件使用 create() 方法并不一定要实例化新的 bean。容器确定如何最好地满足创建请求,对于某些类型的 bean,它可以重用现有的实例:





客户机使用会话 bean 本地接口上的 create remove 方法。虽然客户机以为它正在控制着 EJB 实例的生存周期,但是,是容器在处理 create remove 调用,而不一定要创建和删除 EJB 实例。在客户机和...实例之间不存在固定的映射。容器只是将客户机的工作委托给任何一个方法已经就绪的可用实例而已。”(Enterprise JavaBeans Specification 1.0)



创建新的 bean 实例受容器的控制,并可以与客户机发布 create() 方法异步。



当创建一个 EJB 组件时,开发人员负责定义 EJBObject 接口和 EJBHome 接口,但是无需编写实现这些接口的类的代码。EJB 容器软件组件自动创建这些类。



下面的代码段说明客户机应用程序可能怎样使用称为 CartBean enterprise bean 来进行在线购物:



CartHome cartHome = javax.rmi.PortableRemoteObject.narrow(

initialContext.lookup("applications/shopping_cart"), CartHome.class);

Cart cart = cartHome.create();

cart.addItem(item29);

cart.addItem(item67);

cart.addItem(item91);

cart.purchase();

cart.remove();





CartHome
是实现本地接口的类(EJBHome 接口的扩展)。Cart 是实现远程接口的类(EJBObject 接口的扩展)。当客户机调用应用程序方法(如 addItem() purchase())时,它们是在 cart 对象上调用的,此对象接着将这些方法的执行委托给 bean 自身。enterprise bean 的功能是通过其代理 EJB 对象(即 cart)来获得的。如果多台客户机同时访问 cart bean,将会发生什么事情呢?Enterprise bean 开发人员无需编写代码来支持并发访问。并发性由 EJB 容器支持。



下图说明各 EJB 对象之间的关系:



服务器和容器

EJB
体系结构包括 EJB 服务器和 EJB 容器两个概念。EJB 服务器充当一种组件执行系统,正如 EJB 白皮书中所述:



“Enterprise JavaBeans
规范为每个支持完全可移植性的 Java 应用程序服务器定义了一个标准模型。任何厂商都可以使用此模型来实现对 Enterprise JavaBeans 组件的支持。多种系统(如 TP 监视器、CORBA 运行时系统、COM 运行时系统、数据库系统、Web 服务器系统或其它基于服务器的运行时系统)都可以调整到能够支持可移植的 Enterprise JavaBeans 组件。”(Thomas, Enterprise JavaBeans Technology: Server Component Model for the Java Platform)



EJB
服务器为使用 EJB 组件的应用程序提供操作环境,并供应所有必需的服务,来支持 EJB 体系结构。打包 EJB 服务器软件并没有预先规定的方式。一种方法是将它作为一项功能增强包括到应用程序服务器中,这就是在 IBM WebSphere Application Server, Advanced Edition, Version 2.0 中采用的方法。



EJB
组件并不在 EJB 服务器的顶部直接执行。一个称为 EJB 容器的中间软件组件在 EJB 服务器环境中运行,从而又为这些 bean 自身提供操作环境。EJB 容器对 EJB 应用程序是完全透明的,但是在支持 bean 操作方面起着关键性的作用。



为了使 enterprise bean 能充当可重用的软件组件,它们对特定的服务器或平台功能不能有内建的相关性。服务器端功能的几种常见类型已经被从 bean 设计中“分离出去”,而将此功能的责任转移给了容器组件。例如,容器将被用来接管安全性、并发性、事务处理、交换到辅助存储器和其它服务的责任,从而使 bean 免受服务器相关性的制约,并将按业务逻辑来优化,而不是按服务逻辑来优化。



EJB 白皮书这样描述容器的作用:



“EJB
容器管理部署于其中的 enterprise bean。客户机应用程序并不直接与 enterprise bean 进行交互。相反,客户机应用程序通过由容器生成的两个封装接口( EJB Home 接口和 EJB Object 接口)与 enterprise bean 进行交互。当客户机使用封装接口调用各种操作时,容器截获每个方法调用,并插入管理服务。”(Thomas, Enterprise JavaBeans Technology: Server Component Model for the Java Platform)



可以期望 EJB 容器软件一般都会随 EJB 服务器软件一起提供,尽管规范允许分离这些组件。除了提供对运行时服务(如事务处理和安全性)的访问以外,还期望 EJB 容器包括各种必要工具,来支持 enterprise bean 的安装、操作和管理。例如,需要有工具解释 EJB jar 文件的内容,有工具生成数据库访问,来获得容器提供的持久性,有工具监视正在运行的 bean 的行为,以及实现安全性等。



Bean
风格

EJB
组件分为两种主要类别 -- 会话 bean 和实体 bean。根据 bean 处理状态、事务和持久性的方式这些类别还可以进一步细分。会话 bean 通常具有以下属性:



代表单个客户机执行

可以是事务性的

可以更新共享数据库中的数据

生存期相对较短

其生存期通常就是客户机的生存期

任何持久性数据都由 bean 管理

可以依容器的判断予以删除

会在 EJB 服务器失败时被删除

实体 bean 通常具有以下属性:



代表数据库中的数据

是事务性的

允许多个用户共同访问

可以长期存在

持久性数据可以由容器管理

EJB 服务器失败后能继续生存

EJB
规范对会话 bean 和实体 bean 的说明如下:



对于客户机,会话 enterprise bean 是一种非持久性的对象,它实现某些在服务器上运行的业务逻辑。想像一个会话对象的一种方式是:会话对象是运行在服务器上的客户机程序的逻辑扩展。会话对象不在多台客户机之间共享。



对于客户机,实体 enterprise bean 是一种持久性对象,它代表一个存储在持久性存储器(例如,一个数据库)中的实体的对象视图,或者是一个由现有企业应用程序实现的实体。”(Enterprise JavaBeans Specification 1.0)



用一种粗略的说法,会话 bean 代表这样的操作,它检索或存储数据以满足用户请求;而实体 bean 则代表一种数据集,可以访问这些数据集来满足用户请求。



会话 bean

最简单的一种 Enterprise JavaBeans 组件就是无状态的会话 bean因为这些 bean 没有可以区分它们的状态,所有的实例都是完全相同的。容器管理无状态会话 bean 的生存周期,其方式是通过创建足够数目的此种 bean 来适应客户机工作负荷,并在不需要它们时将其删除。钝化,即将闲置的 bean 写到磁盘上,不用于无状态的会话。要调用 bean,客户机程序调用本地接口中的 standard create() 方法,尽管此操作不一定导致实例化新的 bean 实例。容器可以选择将客户机请求发送给现有的对象。反之,容器则可以按它的选择创建新的实例,且独立于由客户机发布的 create() 方法。



EJB 本地对象上发布的 create() 调用返回一个对 EJB 对象的引用,这个 EJB 对象代表 enterprise bean一旦客户机有了 EJB 对象引用,它就可以将业务方法发布到 EJB 对象上,容器随之会将这些方法委托给 bean 自身。负责管理会话 bean 的容器组件无需推断会话 bean 是否是无状态的。会话 bean 是无状态的还是有状态的在安装时声明。



如果会话 bean 在方法调用之间保留状态信息,则它是有状态的。通过调用 ejbPassivate() 方法,容器可以依其判断将有状态会话 bean 钝化,或写到辅助存储器中。EJB 规范并不要求容器在钝化 bean 时使用 Java 串行化协议,但是它们必须提供等价的功能。当容器决定将一个非活动的会话 bean 交换回到内存中时,它会取消被动 bean 的串行化,并调用 ejbActivate() 方法。有状态会话 bean 的开发人员负责确保状态数据是可串行化的。在集群的应用程序服务器环境中实现有状态会话 bean 时务必要小心,因为并不是所有的服务器都支持集群的有状态会话 bean 的同步化。



有状态会话 bean 可以是事务性的。通过使用 javax.transaction.UserTransaction 接口中的方法,如 begin()commit() rollback()bean 可以控制事务;通过实现 javax.ejb.SessionSynchronization 接口,bean 可以接收有关事务状态的通知。EJB 容器无需推断哪些 bean 需要事务支持;UserTransaction 接口仅可用于那些在安装时被标记为事务性的 bean



实体 bean

实体 bean 在体系结构上与会话 bean 类似,但它们提供对企业数据的访问,而不是支持用户会话。一个实体 bean 可以支持多个并发用户,而容器则使访问和事务同步化。实体 bean 还具有支持本地对象中的 finder 方法的主键。知道实体 bean 的主键的客户机可以通过调用本地对象上的 findBy PrimaryKey() 方法获得对象引用。与会话 bean 不同,实体 bean 的本地对象除了具有 create 方法外还具有 finder 方法。



持久性是实体 bean 的一个基本属性。EJB 规范允许两种形式的实体持久性:bean 管理的持久性和容器管理的持久性。对于代表关系数据库中的数据的实体 beanbean 对持久性的管理意味着,对数据库访问的调用是直接编写在企业 bean 的方法中的(使用 JDBC SQLJ)。这种方法是直截了当的,但它降低了可移植性。容器对持久性的管理意味着 bean 不受数据库调用的影响。在安装时告知容器有关 bean 数据所需的持久性,而容器负责生成实现持久性的代码。这种方法允许 bean 的可移植性更高,甚至达到持久性可使用不同数据源的程度。然而,此方法要求容器中要有复杂功能。



当实体 bean 对象与 EJB 对象相关联时,前者处于就绪状态;否则将认为它们处于共享状态。当客户机调用 EJB 对象中的方法时,容器查找关联的实体 bean 的实例(如果存在的话),或者从共享状态中传送出一个实例。处于就绪状态的实体 bean 可以接收到通过委托从客户机传播给它们的业务方法调用。它们还可以在容器请求时执行 ejbLoad() ejbStore() 方法。load 方法和 store 方法旨在维持实体 bean 和基础数据存储之间数据的一致性。



实体 bean 支持多个用户并发地访问数据。EJB 规范声明,维持数据完整性是容器的责任:



“enterprise bean
开发人员在编写业务方法时无需担心来自多个事务的并发访问。enterprise bean 开发人员在编写方法时可以假定,对于被多个事务同时访问的各个实体 bean,将能确保适当的同步化。”(Enterprise JavaBeans Specification 1.0)



容器完成这一任务通常是通过锁定数据库中的数据,并使访问串行化,或通过创建实体 bean 的多个实例,并允许在基础数据存储中使用并发控制,这样来管理访问。



第三部分内容预告

“什么是 Enterprise JavaBeans 组件?”的第三部分将讨论安装 EJB 组件的特殊部署过程。它还将说明 CORBA 是否是 EJB 组件的竞争对手(答案是“否” -- 请参阅 EJB 技术是如何补充 CORBA 的)。最后,您将看到一种基于 EJB 的三层编程模型的使用情况。



参考资料



查阅 Enterprise JavaBeans Specification 1.0

要了解有关 EJB 体系结构的更多内容,请参阅 Anne Thomas Enterprise JavaBeans Technology: Server Component Model for the Java PlatformPatricia Seybold Group

要了解有关 Java 技术和 EJB 体系结构的更多内容,请访问 Sun 的网站



作者简介

Ken Nordby
IBM 软件开发实验室的软件工程师,该实验室位于 Research Triangle ParkNorth Carolina。作为 SWG Product Affinity Services 业务小组的成员,Ken 与这样一些 IBM 人共事,他们为 IBM WebSphere Application Server(即 Enterprise JavaBeans 技术的 IBM 实现)从事开发和咨询工作。可以通过 nordby@us.ibm.com Ken 联系。


原作者:

Ken Nordby

原出处:

ibm

什么是 Enterprise JavaBeans 组件?(三)

推荐:simon

分类:JAVA

发布时间:2002-04-11

人气:1239

第三部分:布署和使用 Enterprise JavaBeans 组件



本文的第 3 部分说明 Enterprise JavaBeans 组件的部署过程,部署并不仅仅是安装,因为它通常还涉及代码生成。部署还使用了一个特殊的部署描述符文件,此文件支持控制企业级 bean 行为(如某个 bean 是否需要事务)的参数。bean 部署的这一特性支持 bean 行为的说明性、纲领性规范的 EJB 目标。第 3 部分还比较了持久性的两种主要类型,bean 管理式持久性和容器管理式持久性,并讨论了 EJB 组件与 CORBA 的关系。同时还给出了一个简单的三层 EJB 应用程序。

部署过程

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 的开发人员依赖容器进行事务管理时,就称为容器管理式定界,容器使用在部署时提供的事务属性:





无论客户机何时调用企业级 bean,容器都会介入这个方法调用。这种介入允许容器通过事务属性显式控制事务定界。例如,如果企业级 bean 部署了 TX_REQUIRED 事务属性,则无论何时,只要客户机调用支持事务的企业级 bean,容器就会自动启动事务,而客户机并不与任何事务上下文相关联。”(Enterprise JavaBeans Specification 1.0)



如果开发人员选择在 bean 内支持事务,则他们在部署描述符中指定 TX_BEAN_MANAGED 事务属性,然后就可以在 bean 自身内部自由使用 javax.transaction.UserTransaction 接口划分事务边界。通过认出 TX_BEAN_MANAGED 事务属性,容器就能知道不必介入事务支持。



通过增强 AccessControlEntry 对象和 RunAs 安全标识中指定的限制,容器为 EJB 组件提供安全支持。AccessControlEntry 对象在 bean 级别上或针对单个方法,将 Identity 对象与企业级 bean 相关联。Identity 对象反映允许调用 bean 的方法的用户或角色。当容器试图访问数据源或另一个 bean 时,它们也会将 RunAs 安全身份应用于 EJB 组件。可将 RunAs 身份设置为等同于某个特定用户帐户、有权限的系统帐户或客户机安全身份。访问控制和 RunAs 的信息是 bean 的开发人员在部署描述符中指定的,将影响容器管理 bean 的与安全有关的行为方式。



虽然 EJB 1.0 规范也提到安全问题,但更详细的安全功能定义,见该规范的后续版本。



CORBA
EJB 技术的关系

公用对象请求代理程序体系结构 (CORBA) 为分布式对象的平台中立和语言中立的计算环境奠定了基础。在 CORBA 环境中,功能驻留于对象之中,而客户机可通过对象请求代理程序 (ORB) 访问这些对象。完整的 CORBA 实现提供 ORB,外加称为 CORBA 对象服务和 CORBA 公用工具的几个运行时服务。也可只提供 ORB,不提供相关联的对象服务和公用工具(例如,IBM 就提供这样的两种独立 ORB)。实现基本 ORB 功能的软件称为 ORB 核心。为了支持语言无关性,CORBA 应用程序是用接口定义语言 (IDL) 编写的。该语言在语法上类似于 C++,但不包含语义:IDL 中指定的操作是操作接口,而不是操作实现。由于它对多种平台和多种语言的支持,以及源自其分布式特征的可伸缩性,CORBA 非常适合于管理企业规模的信息系统。



设计 EJB 规范也是为了支持企业信息系统。这样说来,CORBA 是一个竞争者吗?根据 Frequently Asked Questions for Enterprise JavaBeans,答案是否定的:





实际上,EJB 技术很好地补充了 CORBACORBA 提供了一个强大的基于标准的基础结构,可在此结构之上构建 EJB 服务器。EJB 技术使得在 CORBA 基础结构的顶层构建应用程序变得更为容易。”(Enterprise JavaBeans 常见问题解答)



虽然 EJB 规范和 CORBA 规范说明的是不同的技术,但 EJB 实现目前利用 CORBA 技术的某些方面。一个例子就是 RMI/IIOPEJB 规范要求 EJB 组件及其容器使用 Remote Method Invocation (RMI) 技术,实现分布式对象之间的方法调用。 RMI 规定远程方法的语法和语义,但并不规定应使用何种传输协议提供网络连接。CORBA Internet 对象请求代理程序间协议 (IIOP) 基本上定义了通过 TCP/IP 传输 CORBA 消息的一种方法。开发使用 IIOP 消息形式交换 RMI 数据的 EJB 实现,说明了 EJB 应用程序怎样才能有效地使用 CORBA 技术的各部分。这种网络也支持与 CORBA 应用程序的互操作性,后者使用 IIOP 发送本地 CORBA 消息,与 RMI 无关。IBM EJB 实现,即 WebSphere Application Server,优化了 IIOP 的使用,方法是,弄清楚分布式对象何时驻留在同一台服务器上,并且只在对象确实在远程时才调用 IIOP



为了方便既并入 EJB 技术,又并入 CORBA 技术的企业系统的开发,Sun Microsystems EJB 规范和 CORBA 之间创建了一种映射。 EJB 体系结构映射到 CORBA,影响到 EJB 技术的几个方面,包括对象分布、命名和事务。CORBA 映射的主要目的是,保证不同厂商构建的 EJB 服务器之间的互操作性。互操作性提供以下好处:



CORBA
客户机可以访问部署在基于 CORBA EJB 服务器上的 EJB 组件

客户机程序在事务中可以将对 CORBA 对象的调用,与对企业级 bean 的调用混合在一起

事务可以跨多个 bean,而这些 bean 又位于来自不同厂商的基于 CORBA 的多台 EJB 服务器上

使用来自某个厂商的 ORB 的客户机,可以访问另一个厂商基于 CORBA EJB 服务器上的 bean

对于要访问 EJB 组件的 CORBA 客户机来说,bean 接口被映射到 IDL。例如,可将股票交易 bean 中定义的 buy() sell() 方法,指定为 IDL 文件中的 CORBA 操作。非 bean CORBA 客户机,如 C++ 客户机,可以访问这个 bean,并用标准 CORBA 调用来调用 bean 的方法。如果容器使用 IIOP 作为它的分布式对象协议,则该容器的职责是,生成与企业级 bean 及其接口对应的 IDL



EJB
命名服务,它以“CORBA 对象服务”命名服务为基础,使 EJB 组件可用于 CORBA 客户机。Java Naming and Directory Interface (JNDI) 可提供到 CORBA 命名服务的接口,同时,客户机既可以通过 JNDI 调用间接访问基础命名服务,也可以通过“CORBA 对象服务” (COS) 命名 API 直接访问该服务。



EJB 事务支持依赖于 CORBA Transaction Service,即 Object Transaction Service (OTS)Java Transaction Service (JTS) 代表 OTS Java 绑定,它是语言中立的。基于 CORBA EJB 容器必须识别 CORBA 客户机通过 OTS 接口发出的事务边界,以及 EJB 应用程序通过 Java Transaction API (JTA) 接口发出的事务,JTA 是到 JTS 的应用程序级接口。JTA 还代表 Open Group XA 接口的 Java 绑定,以便将应用程序资源连接到外部事务管理器。JIA 中含存的 javax.transaction.UserTransaction 接口,为事务边界的应用程序级控制提供 APIUserTransaction 接口,既可由其事务属性设置为 TX_BEAN_MANAGED bean 使用,以可由 Java 客户机使用。



使用 EJB 组件

因为 EJB 体系结构被设计为高度灵活的,并支持使用任意复杂的方式连接企业级 bean,所以可构建许多不同的方案,来说明应用程序可怎样使用企业级 bean。一个有用的方案提出将 EJB 组件表示为三层信息系统的关键组件,该系统将企业数据、事务和应用程序资源连接到 Web 上。



基于 EJB 的三层编程模型视 Web 浏览器为第一层,视支持应用程序的 Web 服务器为第二层,视企业信息资源为第三层。在此编程模型中,除了 EJB 技术外,还实现了 Java servlet 技术、JavaBeans 技术和 Java Server Page (JSP) 技术。下图显示了各层的排列情况:





第一层是瘦客户机 -- 通常是 Web 浏览器,它可以处理普通 Web 数据类型,如 HTML GIF,并支持 HTTP 通信。第二层是 Web 应用程序服务器,它是用代码扩充的 Web 服务器,用来对能够通过 Web 服务器调用的应用程序提供运行时支持。现有的 Web 应用程序都沿用 CGI-BIN 编程模型,但预计第二层应用程序开发将转向 Java servlet 编程模型,后者提供大幅改善的性能和可移植性。除支持 Java servlet 外,Web 应用程序服务器还将添加 EJB 服务器功能,以支持使用 EJB 组件的应用程序。第三层代表企业级信息资源,可以包括关系数据库和面向对象的数据库、事务监视器和定制的应用程序。EJB 技术在这一设计中扮演着关键角色,因为,它使驻留在第二层上的应用程序组件,与组成第三层的企业资源之间的接口,得以标准化。



Java servletJava beans Java server page 不是 EJB 应用程序方案的必需元素,但它们可与 EJB 组件一起工作,以提供基于 Java 的内聚性的应用程序环境。此处描绘的环境将以下职责指定给参与工作的 Java 组件:



Java servlet 指定了应用程序“控制器”的角色

JSP
页面处理数据表示和用户界面的任务

Java bean
充当“数据封装器”,存储中间结果的数据

EJB
组件提供访问企业信息资源的机制

客户可以使用一个假定的、基于 EJB Web 应用程序更新现有的库存,并用容器管理式持久性和容器管理式事务,将访问库存数据库的位置封装在实体 EJB 组件的内部。库存票据可通过 Web 浏览器输入,浏览器提供一个 HTML 表单来捕获产品编号、供应商,等等,并在提交时调用一个 servletservlet 代码充当应用程序控制器角色,确定哪些企业数据库需要更新,需要用户追加什样的信息。servlet 可通过代表它的实体 bean 访问主库存数据库,并调用 JNDI 接口获取对此 bean 的本地对象的引用,然后使用 finder 方法定位所请求产品编号的远程对象。此时,通过调用远程对象的方法,servlet 可更新库存计数,接着容器将此方法委托给 EJB 组件。因为容器根据数据库更新,以对 bean 透明的方式划分一个事务,而且以对 bean 透明的方式将数据写入数据库来保证数据持久性,所以也就保持了数据的完整性。



EJB 组件返回到 servlet 的任何结果信息,都可以使用 setter 方法存储在一个(非企业的) Java bean 的属性中。此时 servlet 可将控制权转让给一个适当的 JSP 页面,以便将这些结果组合到表示格式中,并将结果返回给用户。JSP 页面很可能主要由静态文本和有关单个事务的可变信息占位符组成。在向浏览器发送表示数据之前,JSP 页面使用 getter 方法从 Java bean 的属性中获得可变数据元素。



基于 EJB 的三层设计提供了几个好处,包括:



访问企业数据的业务逻辑可封装在可重用、可移植的企业级 bean 中。

现有的企业系统只需很少修改或者根本不需要修改,就可以集成为企业级 bean

企业应用程序所需的运行时服务,如事务和持久性,可以从 bean 中分解出来,并指定给此 bean 的容器。

无须更改 EJB 组件,即可修改控制应用程序流程的 Servlet

Servlet
代码可将注意力集中在应用程序控制逻辑上,而无须考虑数据表示。

JSP
页面可将静态和动态内容混合在一起,生成表示信息。

Java 语言编写的系统组件,对于具有 JVM 的任何平台都是可移植的。

结论

在开发能够支持关键任务的企业级信息系统的过程中,EJB 规范代表了 Java 技术的下一个发展阶段。EJB 组件将随 JavaBeans 规范引入的 Java 组件模型,扩展到服务器领域,从而使业务逻辑组件的开发可以跨企业应用程序重用,并且可以跨支持 Java 的平台移植。由于包含了基于 RMI 技术的对象分布,所以支持跨多层的可执行组件的分立,从而允许最大的实现灵活性和高度可伸缩性。如果将常规的企业应用程序运行时服务重新定义为可指定给容器抽象的对象服务,则允许 EJB 组件的开发人员将精力集中在业务逻辑上,从而减小了通常与运行时服务相关的复杂性和平台相关性。



增强 Java 运行环境,以包括命名和目录服务的标准接口、关系数据库访问、事务服务和远程对象访问,使 Java 开发人员能够编写强健的企业应用程序,而不必离开 Java 编程环境。将其它 Java 技术 -- Java servlet JavaServer Pages 技术 -- EJB 组件一起使用,可创建一个对于大型企业系统来说足够强健的紧凑编程模型,但由于使用了巧妙的接口,从而简化了开发工作。而且,因为 EJB 体系结构是 JavaBeans 组件模型的逻辑扩展,所以作为 EJB 组件开发的业务逻辑可跨多个企业应用程序重用。



企业级 bean 体系结构的另一个好处是,提供了现有企业信息系统的直接集成通道,此通道可能与 Java 编程语言或 bean 编程模型毫无共同之处。因为现有的企业信息资源 -- 如关系数据库、事务监视器和业务应用程序的定制新品种 -- 可通过将它们封装在 EJB 组件中连接到 Web 前端,而无须替换应用程序或重写主要代码段,所以,客户可保护其现有的 IT 投资。



考虑到 EJB 技术的巨大前景,IT 业界以相当大的兴趣欢迎 EJB 规范,就不是什么令人惊讶的事了。EJB 体系结构提供的一个最大好处可能是,把业务逻辑编程与将业务逻辑和企业级服务器端运行环境的复杂集成分离开来。如果部署了 EJB 组件的容器承担了管理运行时服务(如持久性、事务和并发数据库访问)的职责,则 bean 的开发人员就可以自由地将精力集中在开发封装业务逻辑的软件组件上。JavaSoft 副总裁表述了 EJB 技术的重要性(引自 Sun Microsystems 网站):





“‘Enterprise JavaBeans API
将为企业开发人员和解决方案提供商提供一种新的战略武器,供他们建立下一代行业领先的、基于关键业务的应用程序,’Sun Microsystems JavaSoft 软件产品部副总裁,Jon Kannegaard 说:‘因为用 Enterprise JavaBeans API 设计的应用程序将与现有的企业系统一起工作,所以企业利用 Java 平台会获得新的竞争优势,同时还保留他们对现有技术的投资,’Kannegaard 继续说。





“使用 Enterprise JavaBeans API,开发人员将能够消除应用程序开发过程中的复杂性。这是可能的,因为每个 Enterprise JavaBeans 组件都封装了一个基本的业务功能。目前开发人员必须懂得如何编写业务逻辑和专门的系统级程序,以控制诸如安全性功能部件和处理多个事务的能力 -- 一项既枯燥又复杂的任务。Enterprise JavaBeans API 使全体开发人员能够将精力集中在编写解决业务问题的逻辑上,而不是将精力集中在编写用以简化不同技术间交互作用的代码上。”(新闻稿:Sun Releases Draft Enterprise JavaBeans Specification for Public Review



参考资料



通过 Sun 网站的 associated FAQs 深入了解 Java 技术和 EJB 体系结构。

查阅 Enterprise JavaBeans Specification 1.0

请参阅 Enterprise JavaBeans 规范的完整新闻稿

请参阅 IBM WebSphere Application Server如何使用 EJB 技术。



作者简介

Ken Nordby
IBM 软件开发实验室的软件工程师,该实验室位于北卡罗来纳州 Research Triangle Park。作为 SWG Product Affinity Services 业务小组的成员,Ken 与为 IBM WebSphere Application Server Enterprise JavaBeans 技术的 IBM 实现)进行开发和咨询的 IBM 人一起工作。可以通过 nordby@us.ibm.com Ken 联系。




EJB的入门教材


温柔飞
2001-10-17 00:00:00
5743
次浏览


1
EJB的开发


先泛泛而论,讲一讲EJB的开发步骤。

1.1 SessionBean的开发
第一步, 写远程接口(remote interface),继承EJBObject接口,把需要调用的public方法写在里面(这些方法将在SessionBean中实现),注意要声明throws java.rmi.RemoteException。
 

例如:

package jsper.ejb;

import java.rmi.*;
import javax.ejb.*;

public interface MyEJB extends EJBObject
 
{

public String sayHello() throws java.rmi.RemoteException;

}

第二步, 写Home接口(生成EJBObject引用的factory)
 
至少生成一个create方法, 注意要声明throws java.rmi.RemoteException和javax.ejb.CreateException。
比如:



package jsper.ejb;

import java.rmi.*;
import javax.ejb.*;


public interface MyEJBHome extends EJBHome
 
{

MyEJB create() throws java.rmi.RemoteException, javax.ejb.CreateException;

}

第三步, 写真正的Session Bean的实现(实现定义在远程接口中的方法), 需要实现javax.ejb.SessionBean接口
注意:不能用implents MyEJB的方式直接实现远程接口,此处不用抛出RemoteException
package jsper.ejb;

import java.rmi.RemoteException;
import javax.ejb.*;
public class MyEJBClass implements SessionBean {

 
 public MyEJBClass() {
 }
 //定义在SessionBean 中的方法
 
 public void ejbCreate() throws RemoteException, CreateException {
 }

 public void ejbActivate() throws RemoteException {
 }

 public void ejbPassivate() throws RemoteException {
 }

 public void ejbRemove() throws RemoteException {
 }

public void setSessionContext(SessionContext ctx)
 
throws RemoteException {

 }

 //此处是具体的实现

 public String sayHello()

 {

  System.out.println("Hello");
 }
}
 
第四步,写一个发布用的配置文件ejb-jar.xml
需要提供的信息:
Bean Home name -- The nickname that clients use to lookup your bean
s home object.
Enterprise bean class name -- The fully qualified name of the enterprise bean class.
  Home interface class name
  Remote interface class name
Re-entrant -- Whether the enterprise bean allow re-entrant calls. This setting must be false for session beans(it applies to entity beans only)
  stateful or stateless
 

  Session timeout -- The length of time (in seconds) before a client should time out when calling methods on your bean.
最后你还可以提供属于自己的配置信息供自己控制EJB的工作方式。

例子:
   
helloEjb
com.jsper.ejb.MyEJBHome
com.jsper.ejb.MyEJB
com.jsper.ejb.MyEJBClass
Stateless
Container
   
 

第五步,将你的所有文件用jar工具生成jar文件

ejb-jar.xml须在顶级的META-INF子目录
这句话比较咬嘴, 举个例子

mylib----META-INF--*.XML
|
 
|com--coucouniu--ejb---EJBClass
   |-EJBHome
   |-EJB
   
在生成.jar文件时

sh>cd mylib  //注意此处所在目录
sh>jar cv0f myejb.jar *

请注意: 到这一步我们做出的东西都是和和特定的EJB Server是无关的, 只是和遵循EJB的标准有关

第六步,使用特定平台的发布工具生成发布使用的jar文件。
不同的中间件产品此步骤非常不同, 产生的结果都是生成只有自己的EJB Server能理解的远程接口和Home接口实现等等东西,打包在一个jar文件中
一般是很简单的
第七步,把.jar文件发布到EJB Server

根据不同的中间件产品此步骤非常不同, 可以分为启动时发布和运行时发布两种,一般是很简单的, 以weblogic为例:
1、在weblogic.properties 文件中配置使weblogic 启动时自动装载。
添加一个条目比如:
weblogic.ejb.deploy=C:/weblogic510/myserver/ejb_basic_beanManaged.jar,\
  C:/weblogic510/myserver/ejb_basic_test.jar
  
2、使用deploy或DeployerTool动态装载/卸载/更新

第八步,写客户端的程序(我迄今为止的理解)
 
在我们使用发布工具把EJB发布到EJB Container的过程中,会绑定一个名字到Container的目录服务中,现在我们要调用时从这个目录服务中把EJBHome对象取出,这里分为从本地和外部两种情况:
一种是客户端本地调用EJB。 比如和EJB引擎和Servlet引擎是整合在同一个Application Server中, 这时当一个Servlet要调用EJB时无须验证,即可得到EJBHome接口的实现
 Context ic = new InitialContext();
   System.out.println("Looking for the EJB published as
hello");
   com.jsper.ejb.MyEJBHome homeInterface = (com.jsper.ejb.MyEJBHome) ic.lookup(
hello
); //发布时绑定的名字是hello
 这样就可从目录服务中得到Home接口的实现, 也是我们最常用的方式, 可移植性很好

外部调用的话首先要经过身份验证,
比如Oracle8i :

String ejbUrl = "sess_iiop://localhost:2481:ORCL/test/MyEJB";
  String username = "scott";
  String password = "tiger";

  // Setup the environment
  Hashtable environment = new Hashtable();
  // Tell JNDI to speak sess_iiop
  environment.put(javax.naming.Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
  // Tell sess_iiop who the user is
  environment.put(Context.SECURITY_PRINCIPAL, username);
  // Tell sess_iiop what the password is
  environment.put(Context.SECURITY_CREDENTIALS, password);
  // Tell sess_iiop to use credential authentication
environment.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
// Lookup the URL
  com.jsper.ejb.MyEJBHome homeInterface = null;
  try {
   System.out.println("Creating an initial context");
   Context ic = new InitialContext(environment);
   System.out.println("Looking for the EJB published as
test/MyEJB
");
   homeInterface = (com.jsper.ejb.MyEJBHome) ic.lookup(ejbUrl);
  }
  catch (ActivationException e) {
   System.out.println("Unable to activate : " + e.getMessage());
   e.printStackTrace();
   System.exit(1);
  }
再比如weblogic的调用方式:
try
{
  // Get an InitialContext
  String url="t3://localhost:7001";
  Properties h = new Properties();
  h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
  h.put(Context.PROVIDER_URL, url);

Context ctx = new InitialContext(h);

  System.out.println("Getting the EJBHome object
");
   com.jsper.ejb.EJBHome tmp= (com.jsper.ejb.EJBHome)ctx.lookup("hello");

//create three element array of COUNT object
  EJB ejb =tmp.create();
  System.out.println(ejb.sayHello());
}
catch(Exception e)
{
e.printStackTrace();
}
由于和具体的目录服务、协议相关,为了达到可移植的目的,只好多做一些工作,幸好一般不需要做这些工作。

Tomcat中怎样设置虚拟目录

作者:jdeveloper


在%Tomcat_Home%\conf\server.xml <ContextManager>中添加如下代码

<Context path="/jdeveloperhjc" docBase="webapps/jdeveloperhjc" debug="0" reloadable="true" > </Context> <Context path="/jdevelopertest" docBase="f:/htdocs/demo/" debug="0" reloadable="true" > </Context>
其中path的值是虚拟目录
docbase若是以\或盘符开始 则是你的硬盘目录的绝对路径。
若不是 则是相对于%Tomcat_Home%的相对路径


启动Tomcat后 可以用如下的方式访问:
http://localhost:8080/jdeveloperhjc
http://localhost:8080/jdevelopertest

入门

JSP 技术中一个重要的特性是它能从 JSP 页面中直接存取可重用的组件,例如 JavaBean。

JavaBean 组件,是用 Java 语言编写的与平台无关的组件,是得到业界各大厂商支持的技术。 JavaBean 组件继承了在 Java 程序中可以看到的平台无关性。开发人员可以编写出可重用的组件,然后在各个平台上运行。

在 JSP 页面中使用 JavaBean 组件的原因是将代码与显示分离。我们在概论中已经讨论了这个概念。您可通过使用 JavaBean 组件来减少 JSP 页面中的代码。

在 JSP 页面中有负责存取内容和显示的标记。生成内容的逻辑和程序代码被包含在可重用的组件中,即 JavaBean 组件。

JavaBean 组件特性

JavaBean 组件是可重用的软件组件,使用标准的 "方法" 命名规则。这使得 JavaBean 组件具有可预测的行为并可在工具中被轻松使用。

JavaBean 组件的公共特性有 属性、方法和事件。

属性是 JavaBean 的组成部分。它们可以是其它的 Java 对象或原始类型。我们可以在下一屏看到,JavaBean 组件的属性是通过一对公用的(public) getter 和 setter 方法来定义。

一个方法是一个 JavaBean 可提供的动作或服务。

事件是 JavaBean 对有事件发生的一个提示。

在后面,我们将具体讨论 bean 的功能。


JSP 环境中的 Bean

使用 JavaBean 组件的一种方法是将其作为一个数据封装器。JavaBean 的一个属性只是 bean 的数据(状态)。属性可以由两种方法来存取:getter 和 setter。属性的值可通过 getter 方法存取。如果属性可被修改,它的值可通过 setter 方法修改。

看看在下面提供的样本代码。这对方法定义了一个名为 time 的 bean 属性,而它的存取类型是 Date (java.util.Date)。

public Date getTime()

public void setTime(Date newTime)

JavaBean 中的属性和方法是交换数据和提供服务的 API。 对 bean 的存取只需要将消息发送到 bean 实例。大多数企业级开发工具,例如 VisualAge® for Java,可自动依据 JavaBean 规范生成 Java 类。

在 JSP 页面中使用 JavaBean 组件

让我们看看在 JSP 页面中使用 JavaBean 组件的优点。

当在一个应用服务器中与 servlet 和 JSP 页面一起使用时,JavaBean 组件代表一个应用的业务逻辑。它们提供:

  • 属性,用来配置它们的行为

  • 方法,用来提供业务逻辑

  • 属性,封装生成的动态内容

当用户通过浏览器发出一个请求时,它可能是要求静态或是动态的信息。如果是动态的,一个 servlet 将按下列步骤处理请求:

1.      servlet 找到一个或多个来处理请求的 JavaBean 组件。

2.      它将请求的参数传递给 bean,接着调用业务逻辑方法。

3.      然后 servlet 保存 result bean 的引用,并将其提供给 JSP 页面。

4.      JSP 页面使用存放在 result bean 中的动态内容来返回响应到浏览器中。

JavaBean 组件如何工作

我们曾经提到过 servlet 和后端应用程序,例如数据库,通过一个 result bean 提供动态内容。

JSP 页面通过一个标记来存取 result bean 对象。该标记指明如何查找或创建一个 bean。

  • 如果要访问现存的 bean,它将从会话或请求中存取。

  • 如果需要创建 bean,它从一个序列化的 bean 中被实例化,或一个新的 bean 被创建。

 

posted on 2005-08-05 09:25 jam 阅读(2222) 评论(1)  编辑  收藏

评论:
# re: EJB介绍 2011-07-04 15:36 | 笨程序员
太强大了,谢谢你。能交个朋友吗,我的QQ是:343827585,希望能有机会跟你交流技术相关的东西。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: