网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  在ejb环境中实现“观察者”模式     
  文章作者:未知  文章来源:水木森林  
  查看:70次  录入:管理员--2007-11-17  
 
  在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,则返回为指定发布者类和它的所有父类
*
 
 
上一篇: 在eclipse3.0.x配置基于struts的web开发环境    下一篇: java多线程编程基础之非线程的方法
  相关文档
使用struts+spring+hibernate 组装web应用 11-17
java web应用中如何实现任务有效调度 11-17
方案的重复使用 11-17
[翻译]-windows ce 程序设计 (3rd 版)--5.2 公共控件(七) 11-17
接触 java概述 11-16
java:默认变量初始化 11-17
tomcat4.0中文问题简单解决方法 11-17
java:附加码生成器(图片) 11-17
用jsp实现数据库图片的存储与显示实例 11-16
java中利用散列表实现股票行情的查询 11-17
javamail发送附件的例子 11-17
java也存在2000年问题 11-17
用jbuilder高效率开发java程序 11-17
.net应用自动部署窗体技术详解(4) 11-17
一步一步学习midp2。0游戏编程(三) 11-17
eclipse 的字符串分区共享优化机制 11-17
spring jdbc抽象框架简化web数据库开发 11-17
intellij idea 5.1 发布 11-17
sun国际认证考试指定考试考场 11-17
实例讲解:开发swing的xml框架(2) 11-16
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
技术电话:13616026886
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息