EJB是J2EE中最核心的技术之一,是一种服务器端组件的体系结构。它封装了应用程序中的事务逻辑,允许进程建立分布式对象,简化企业级程序的开发。EJB的提出为EJB组件在何时如何与它们的容器进行交互作用做出了规范。下面我们就来了解一下EJB的体系结构到底是怎样的。
EJB的体系结构主要由四部分组成。他们分别是EJB组件,不可见的EJB对象,定义客户访问以及EJB容器职责。这四部分分别对各自内容进行了规范。接下来我们将对这三部分做较为详细的介绍。
1. EJB组件。一个企业Bean的实现应该由多个EJB组件协同工作完成。EJB组件又分为以下三种:
a) Bean类。Bean类是包含了企业应用事务逻辑实现细节的一个Java类。为了实现JAVA“WriteOnce,Run AnyWhere”的理念,Bean类必须实现一个定义完好的接口并且遵守一定的规则,从而能够使得Bean类能够在各个EJB服务器上运行。EJB规范定义了许多Bean类必须实现的标准接口,这些接口强制Bean类公开EJB组件模型中定义并实现的所有方法。EJB容器就是通过调用这些必须的方法来对EJB Beans进行管理的。
首先所有的Bean类必须实现的最基本接口是javax.ejb.EnterPriseBean接口。所有实现了该接口的java类都是一个真正的企业Bean类。同时该接口又继承了java.io.Seralizable接口,这标志着所有的企业Bean都可以转化为序列流,具有序列化对象的一切特征。但是特定的企业Bean并不需要直接实现javax.ejb.EnterPriseBean接口,它们只需要实现相应的Bean类型的接口就可以了。例如会话Bean类实现javax.ejb.SessionBean接口,实体Bean类实现javax.ejb.EntityBean接口,消息驱动Bean实现javax.ejb.MessageDrivenBean接口。至于这三种Bean类我会在下一篇博客中进行较为详细的讲解。
b) 远程接口。企业Bean的远程接口定义了相应Bean类公开的所有的事务方法。这些事务方法仅对客户程序是可见的,其他的方法就对EJB容器是可见的。远程接口必须遵循EJB规范定义的特定规则,如所有的远程接口必须继承javax.ejb.EJBObject接口,并且该接口又继承了java.rmi.Remote接口。
c) 引导接口。引导接口定义了Bean生命周期的方法。这些方法用来创建Bean,删除Bean以及查找Bean。所有的引导接口必须从一个公共接口javax.ejb.EJBHome接口派生出来,并且该接口也继承了java.rmi.Remote接口。
2. 不可见的EJB对象。在介绍不可见的EJB对象之前我们需要先了解客户端程序是如何与EJB应用服务器进行交互的。
当一个客户程序要调用EJBBean类的方法实现某一功能的时候,它并不是直接调用EJB类的实例的方法,实际上客户端永远不会直接调用EJB Bean的实例上的方法,该过程的实现是通过EJB容器截获客户端的请求,然后EJB容器再将该请求委托给Bean实例。通过解释该请求,EJB容器可以自动执行服务器端必要的系统级服务。EJB容器处于于客户端程序和Bean之间,起间接层的作用。
那在EJB容器中有哪些不可见对象呢?实际上在EJB容器中的不可见对象有两个,一个就是上面提到的EJB对象,另外一个是引导对象。这两个对象在实现客户端请求的过程中起着非常重要的作用。
下面我们就来介绍一下这两个隐形对象。EJB对象是EJB容器根据Bean类和部署描述提供的信息为每一个Bean类生成的,EJB对象和EJB容器一起工作,在运行期间向Bean提供系统级的服务。实际上就相当于.net中new出的对象,只不过这个new的过程是容器帮我们做的,程序员只要调用就可以了而不用再去手动编写实例化的代码,功能的实现说到底也是由EJB对象实现的,只不过形式上更像是直接调用的Bean类的方法。那么当客户端要完成一个功能,这个功能说到底是要有某一或几个EJB对象完成的,但是客户端是怎样找到这些隐形的EJB对象的呢?这时候就需要我们的另外一个隐形对象---引导对象了。客户端发送一个请求给EJB应用服务器,在该请求中客户端代码使用JNDI在EJB容器中查找引导对象(即实现了上图中引导接口的对象)然后客户端代码再向EJB引导对象查询EJB对象。引导对象负责EJB对象的创建,删除和查找。
3. 定义客户访问。客户访问主要介绍三个方面的知识。他们分别是使用JNDI查找Bean,远程访问或本地访问,以及本地接口。他们所介绍的分别是客户端如何查找自己所需要的Bean,Bean的访问方式以及如何以更有效的方式调用企业Bean。
a) 使用JNDI查找Bean。JNDI是Java命名和目录服务的简称,它被用来在EJB容器中查找引导对象。它像访问不同关系数据库的JDBC那样,为光宇服务访问提供一个标准的API。JNDI具有两个重要的特点,一是虚拟性,另外一个是动态性。它的虚拟性主要体现在它允许通过简单的文件,打印机,EJB引导对象和其他任何资源的目录,实现目录服务的彼此互联。目录和子目录可以放在相同或不同的地方以实现EJB Bean的分布式部署,但是用户不需要知道。而他的动态性主要是JNDI允许在运行时根据不同类型的目录服务来装载不同的JNDI驱动程序。一个驱动程序将特定的目录服务映射到标准JNDI类接口中。
b) 远程访问或本地访问。我们在设计一个企业应用的时候面临的首要决策就是企业Bean允许那种方式来进行访问。根据实际需要我们可以选择使用远程访问方式也可以选择本地访问模式。如果你客户程序与将要被访问的企业Bean在不同的机器或虚拟机上运行此时我们应该选择的是远程访问方式,如果客户程序和将要被访问的企业Bean在相同的JVM上运行此时我们选择的是本地访问方式。本地访问方式与远程访问方式相比具有更高的执行性能。
c) 本地接口。当我们编写了一个以本地方式访问的企业Bean的时候,我们必须要同时编写本地接口和本地引导接口。通过本地对象实现本地接口,而本地接口也将被EJB视为是本地引导对象,这样我们就可以用一种快速方式创建Bean,而不是使用引导接口和引导对象。
4. EJB容器的职责
顾名思义EJB容器是用来盛放EJB Bean的地方,同时也是容器控制客户程序对企业Bean的访问。EJB容器通过截获客户端请求,通过对请求的解释再制定EJB对象执行客户请求。那EJB容器主要有哪些职责呢/
a. 容器管理的事务
事务是将完成一个功能的各个步骤聚合在一起形成一个执行单元,只有该单元中的所有步骤均执行完毕才说明完成了功能,否则会实现回滚,退回到一步未执行前的状态。在J2EE中事务由EJB容器进行自动管理,只需在部署时简单的声明事务属性,来告诉容器如何在运行时管理Bean事务。剩下的事务控制均由容器执行,极大地方便了开发人员。但是EJB容器管理的事务也具有一定的局限性,比如现在的EJB容器只支持单层的分布式事务,不支持嵌套的事务。
b. 持久性
当企业Bean的状态由持久性服务自动管理后,EJB容器就负责企业Bean的实例域与数据库中的数据同步,这成为容器管理持久,也就是我们所说的CMP(如果企业Bean自身状态的管理是由Bean自身来管理的,则成为Bean管理持久,即BMP)。
c. 安全性
EJB容器为分布式对象的安全性提供了一个完整框架。使用容器的安全角色,可以对Bean用户想要完成的任务进行授权,通过存取控制表来实现。EJB容器允许Bena作为安全身份标识来自动运行,这样将比安全编入Bean的事务方法更简单。