论坛首页 Java企业应用论坛

自己做的事件监听处理小框架

浏览 12186 次
精华帖 (0) :: 良好帖 (10) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2009-11-22   最后修改:2009-11-22
3、注解版实现:
1、定义注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)    
@Retention(RetentionPolicy.RUNTIME)
public @interface HandleEvent {
	Class<? extends BaseEvent>[] events();
}


2、在顶层接口IBaseService增加一个方法getRealClass,此方法用于返回真正的业务类字节码引用,此方法在抽象业务类用统一实现即可。本来不需要此方法,但由于使用了SPRING的AOP,一时没有找到取得真正业务类字节码引用的方法,所以才定义这么个接口,代码
/**
 * 业务层顶层接口,自定义的小框架里可以在顶层业务接口中直接继承事件接口,不影响性能
 * 因为在初始化事件监听器时,已经过滤了没有真正实现接口方法的类,所以不会造成多余的调用
 */
public interface IBaseService extends IBaseEventListener{
	public Class<? extends IBaseService> getRealClass();
}

抽象业务类的代码
/**
 * 实现顶层接口的抽象类
 */
public abstract class AbstractBaseService implements IBaseService{
	/**
	 * 发布事件 2008-9-18
	 */
	protected void publishEvent(BaseEvent event) {
		EventController.publishEvent2(event);
	}
	//具体子类中不需要再实现
	public Class<? extends IBaseService> getRealClass(){
		return this.getClass();
	}
	
	public void onBaseEvent(BaseEvent event){
		//这里空实现,且没有注解,这样,如果具体业务类没有重写方法,
		//初始化事件监听器时就会被过滤掉,不会造成多余调用
	}
}


改写IBaseEventListener接口,删除getEventClasses方法,因为使用注解来定义要处理事件,所以此方法不再需要。本来onBaseEvent方法也可以去除,直接由注解来定义即可,但由于以下原因,还是要保留:1、如果没有任何接口定义onBaseEvent方法,那么SPRING的代理类也不会有此方法,这样就无法使用AOP的种种好处了;2、为规范事件处理的方法名和参数,更易于后续维护,所以还是要有个接口定义为好。
/**
 * 事件处理接口,实现此接口并且getEventClasses方法的返回结果条数大于0,方可处理对应的事件
 */
public interface IBaseEventListener {
	/**
	 * 事件处理的方法
	 */
	public void onBaseEvent(BaseEvent event);
}


事件处理工具类
/**
 * 事件处理相关操作工具类
 */
public class EventController {
	private static Map<String,List<LisenerInfo>> listeners2 = new LinkedHashMap<String, List<LisenerInfo>>();
	/**
	 * 扫瞄所有bean,进行事件监听
	 */
	public static void initBaseEventListener2(){
		//取得所有业务类
		Map<String,IBaseService> beans = SysContext.getBeansOfType(IBaseService.class);
		if(beans==null || beans.size()==0)
			return;
		Collection<IBaseService> values = beans.values();
		for (IBaseService listener : values) {
			//注意这里不能使用listener.getClass()方法,因此方法返回的只是SPRING的代理类,此代理类的方法没有注解信息
			Method[] methods = listener.getRealClass().getDeclaredMethods();
	        for (Method method : methods) {
	             //判断方法中是否有指定注解类型的注解   
	            boolean hasAnnotation = method.isAnnotationPresent(HandleEvent.class);    
	            if (hasAnnotation) {
	                //根据注解类型返回方法的指定类型注解   
	            	HandleEvent annotation = method.getAnnotation(HandleEvent.class);    
	            	Class<? extends BaseEvent>[] events = annotation.events();
	            	if(events==null || events.length==0){//这里过滤掉没有真正实现事件监听的业务类
	            		continue;
	            	}
	            	for (int i = 0; i < events.length; i++) {
	            		try {
		            		if(listeners2.containsKey(events[i].getName())){
		            			//注意这里要用代理类的方法,即listener.getClass().getMethod(method.getName()),不能直接使用method变量,下同
								listeners2.get(events[i].getName()).add(new LisenerInfo(listener,listener.getClass().getMethod(method.getName())));
		            		}else{
		            			listeners2.put(events[i].getName(),Arrays.asList(new LisenerInfo[]{new LisenerInfo(listener,listener.getClass().getMethod(method.getName()))}));
		            		}
	            		} catch (Exception e) {
							throw new UnknowException("初始化事件监听器时出错:",e);
						}
					}
	            }
			}
		}
	}
	/**
	 * 发布事件
	 */
	public static void publishEvent2(BaseEvent event){
		List<LisenerInfo> list = listeners2.get(event.getClass().getName());
		if(list!=null && list.size()>0){
			for (LisenerInfo listener : list) {
				try {
					listener.getMethod().invoke(listener.getService(), event);
				} catch (Exception e) {
					//此处不能捕捉异常,因为任何一个处理类实例出错都应该全部回滚
					throw new UnknowException(e);
				} 
			}
		}
	}
}

//此类记录目标方法和目标类
class LisenerInfo{
	private Method method;//目标方法
	private Object service;//业务类实例
	public LisenerInfo(Object service,Method method){
		this.method = method;
		this.service = service;
	}
	public Method getMethod() {
		return method;
	}
	public Object getService() {
		return service;
	}
}


好了,框架完成,事件发布还和以前那样,来看看事件处理的实现,同样也不再需要getEventClasses方法了
//不再需要每个具体业务都实现IBaseEventListener接口
public class OtherServiceImpl extends AbstractBaseService implements OtherService{   
    private IBaseDAO otherDao;   
  
    /**  
     * 重写父类的方法,处理用户删除事件  
     */
    @HandleEvent(events={UserDeleteEvent.class,UserUpdateEvent.class})
    public void onBaseEvent(BaseEvent baseEvent){   
        if(baseEvent instanceof UserDeleteEvent){//如果是用户删除事件   
            otherDao.deleteOtherData(((User)baseEvent.getSource()).getId());   
        }else{
        	//....
        }
    }   
}  


全部完成
0 请登录后投票
   发表时间:2009-12-04  
呵呵,想弄个良好贴还真有点难啊...
0 请登录后投票
   发表时间:2010-03-30  
写的不错,考虑一下再进一步,加上具备异步处理能力的事件框架

良好贴若干年前容易,现在难了:)
0 请登录后投票
   发表时间:2010-03-30  
itstarting 写道
写的不错,考虑一下再进一步,加上具备异步处理能力的事件框架

嗯,加个多线程处理倒是简单得很,可要考虑事务同步的问题上麻烦一些,最近都有没有这个时间去做啊,呵呵,有空还是要完善一下
0 请登录后投票
   发表时间:2010-06-21  
java 事件监听
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics