| |
在ejb环境中实现“观察者”模式 observer模式(“观察者”模式)或许是降低对象结合程度的最佳方法之一。例如,在编写一个典型的应用程序时,你可能决定提供一个工厂或管理器触发适当的事件,以这些事件的一组监听器的形式提供分离的业务逻辑;此后,系统的启动类就在工厂或者管理器创建完毕之后,把这些监听器关联到工厂或者管理器。
在大多数j2ee系统中,这种工厂/管理器都是无状态的会话bean。ejb容器处理对无状态会话bean的请求,根据请求创建无状态会话bean的实例,或重用现有的实例。问题在于,每次初始化一个新的bean实例时都必须伴有一组监听器,这组监听器和为其他实例而运行的监听器完全相同。合理的方案应该是,当一个无状态会话bean实例被创建的时候,它访问某个知识库,通过一定的方法获知相关的监听器,然后建立和这些监听器的关系。在这篇文章中,我要介绍的就是如何实现这一方案。
一种典型的情形 请考虑下面这种典型的情形。一个在线拍卖系统有一个无状态会话bean,名为auctionfactory,这个bean创建拍卖(auction)对象。对于每一个新创建的拍卖对象,业务逻辑要求系统执行一些附加的操作,比如发送email、更新用户摘要文件,等等。在许多系统上,创建拍卖对象和执行这些附加操作的代码如下所示:
public auction createauction(int numofcontainers) throws remoteexception{ someauctionclass auction = new someauctionclass (numofcontainers); // 创建拍卖对象之后,接下来要编写下面这种执行附加操作的代码 //(而不是简单地发送一个“拍卖对象已经创建”的事件) sendemailsaboutnewauction(auction); updateuserprofiles(auction); doothernotificationstuffaboutnewauction(auction); //等等.... return auction;}
之所以要编写这种质量很差的代码,原因就在于初始化各个bean实例时附带一组必需的监听器很困难。如果这个bean是一个事件发布者,而且每一个bean实例初始化的时候都带有一组它需要的监听器,上述代码可以变得更简洁、更强壮,例如:
public auction createauction(int numofcontainers) throws remoteexception{ someauctionclass auction = new someauctionclass (numofcontainers); fireauctioncreated(auction); return auction;}
基本原理说明 实现本文技巧的基本原理其实很简单。一个listenerregistry类实现事件发布者类和必须关联到该类的监听器之间的映射。系统的启动模块初始化listenerregistry,为每一种发布者类型初始化一组必需的监听器。当发布者被创建或激活,它就访问listenerregistry,把它的类传递给listenerregistry,获得一组监听器。然后,发布者把所有这些监听器关联到自身。就这么简单。
你也许会很自然地问,“什么是listenersupplier?”和“为什么不直接注册和使用eventlistener?”确实可以;事实上,该框架的第一个版本就是直接使用事件监听器。但是,如果在listenerregistry中使用监听器,这些监听器必须在注册的时候就存在。另一方面,如果注册的是一个“中介者”listenersupplier(监听器提供者),你就可以自由地把创建/提取监听器延迟到它绝对必需的时候。listenersupplier类似于工厂,但两者的不同之处在于,listenersupplier并非必定要创建新的监听器,它的目标是返回监听器。每次getlistener()方法被调用时,listenersupplier是创建一个新的监听器,还是每次都返回同一实例,这一切由开发者自己决定。
因此,结合运用listenerregistry和监听器提供者,我们可以在事件发布者和观察者(或监听器)不存在的情况下,建立两者之间的关系。可以认为,这个优点很重要,它延迟了发布者和观察者的实例化。
具体实现 在这一部分,你将看到整个框架中所有组成部分的实现代码。我假定你已经了解必要的基础知识,比如ejb、同步,当然还有java核心库。完整的源代码可以从本文最后下载。
下面是listenerregistry接口的代码:
//listenerregistry.javapackage com.jwasp.listener;import java.util.eventlistener;import java.rmi.remoteexception;import com.jwasp.listener.listenersupplier;/*** 框架的核心。实现事件发布者类和监听器提供者之间的映射*/public interface listenerregistry {void addlistenersupplier(listenersupplier listenersupplier, class publisherclass);void removelistenersupplier(listenersupplier listenersupplier, class publisherclass);eventlistener[] getlisteners(class publisherclass) throws remoteexception, listeneractivationexception;}
下面是listenersupplier接口:
//listenersupplier.javapackage com.jwasp.listener; import java.util.eventlistener; /** * 为方便起见而提供的“中介者”,负责创建/提取相应的监听器 */ public interface listenersupplier { /** * 返回和指定发布者类相对应的监听器 */ eventlistener getlistener(class publisherclass) throws java.rmi.remoteexception, listeneractivationexception; }
下面是listenerregistry的缺省实现:
//defaultlistenerregistry.javapackage com.jwasp.listener; import java.util.*; import java.rmi.remoteexception; import com.jwasp.listener.listenerregistry; import com.jwasp.listener.listenersupplier;
/** * listenerregistry的基本实现。该类是一个singleton(singleton模 * 式的主要作用是保证在java应用程序中,一个class只有一个实 * 例存在)。 * 当发布者请求监听器时,这个注册器返回的不仅有显式为 * 指定发布者类所注册的监听器,而且还有为发布者所有父类 * 注册的监听器。例如: * 如果发布者b从发布者a扩展,而且已经有为a注册的监听 * 器提供者,那么,如果你把b类作为参数传递给getlisteners方 * 法,你得到的不仅有显式为b注册的监听器,还有所有为b类的 * 父类(在本例中,它是a)所注册的监听器。 */ public class defaultlistenerregistry implements listenerregistry{ private defaultlistenerregistry(){} public static defaultlistenerregistry getinstance(){ return instance; }
public synchronized void addlistenersupplier(listenersupplier listenersupplier, class publisherclass) { assertnotnull("publisher class is null", publisherclass); assertnotnull("listenersupplierr is null", listenersupplier); collection listenersuppliers = (collection)mylistenersuppliersmap.get(publisherclass); if ( listenersuppliers == null ) { listenersuppliers = new arraylist(); mylistenersuppliersmap.put(publisherclass, listenersuppliers); } listenersuppliers.add(listenersupplier); }
public synchronized void removelistenersupplier(listenersupplier listenersupplier, class publisherclass) { assertnotnull("publisher class is null", publisherclass); assertnotnull("listenersupplierr is null", listenersupplier); collection listenersuppliers = (collection)mylistenersuppliersmap.get(publisherclass); if ( listenersuppliers == null ) { return; } listenersuppliers.remove(listenersupplier); if ( listenersuppliers.isempty() ) { mylistenersuppliersmap.remove(publisherclass); } }
/** * 返回一个为指定发布者类注册的eventlistener的数组。如果注册 * 器包含为该发布者注册的监听器提供者,它将依次访问每一个提供 * 者,调用其listenersupplier.getlistener(publisherclass)方法。
* @param publisherclass发布者类 * @返回eventlistener的数组 */ public eventlistener[] getlisteners(class publisherclass) throws remoteexception,listeneractivationexception { //如最后一个参数设置成false,则禁止继承检查 collection listenersuppliers = getlistenersupplierscopy(publisherclass, true); eventlistener[] array = new eventlistener[listenersuppliers.size()]; iterator i = listenersuppliers.iterator(); int count = 0; while (i.hasnext()){ listenersupplier listenersupplier = (listenersupplier)i.next(); array[count] = listenersupplier.getlistener(publisherclass); count++; } return array; }
/** * 返回当前已经为指定发布者类注册的监听器提供者副本。 * 这是一个同步方法,从而允许getlisteners方法保持非同 * 步。 * @param publisherclass * @param checkinheritance 如为true,则返回为指定发布者类和它的所有父类 *
|
|