锁定老帖子 主题:自己做的事件监听处理小框架
精华帖 (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{ //.... } } } 全部完成 |
|
返回顶楼 | |
发表时间:2009-12-04
呵呵,想弄个良好贴还真有点难啊...
|
|
返回顶楼 | |
发表时间:2010-03-30
写的不错,考虑一下再进一步,加上具备异步处理能力的事件框架
良好贴若干年前容易,现在难了:) |
|
返回顶楼 | |
发表时间:2010-03-30
itstarting 写道 写的不错,考虑一下再进一步,加上具备异步处理能力的事件框架
嗯,加个多线程处理倒是简单得很,可要考虑事务同步的问题上麻烦一些,最近都有没有这个时间去做啊,呵呵,有空还是要完善一下 |
|
返回顶楼 | |
发表时间:2010-06-21
java 事件监听
|
|
返回顶楼 | |