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();