`

自己做的事件监听处理小框架(注解版实现)

阅读更多
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(),createList(new LisenerInfo(listener,listener.getClass().getMethod(method.getName()))));
		            		}
	            		} catch (Exception e) {
							throw new UnknowException("初始化事件监听器时出错:",e);
						}
					}
	            }
			}
		}
	}

private static List<LisenerInfo> createList(LisenerInfo li){
		List<LisenerInfo> list = new ArrayList<LisenerInfo>(5);
		list.add(li);
		return list;
	}

	/**
	 * 发布事件
	 */
	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{
        	//....
        }
    }   
}  


全部完成
2
0
分享到:
评论

相关推荐

    Maven整合ssm框架.zip

    创建springMVC.xml配置,配置注解扫描,注解驱动,视图解析器 4.编写controller 第四步:spring和springmvc整合 整合的要点:就是让springmvc从servletContext中获取spring容器即可 1.在web.xml中配置spring的...

    springboot 和一些主流框架的整合的各个基本demo

    Springboot-mybatis-annotation 这是mybatis 的注解版 Springboot-mail 这是springboot 发邮件 Springboot-redis springboot 之使用redis数据库 Springboot-editor.md springboot 与editor.md 整合 Springboot-...

    springboot知识点整理

    6.3.1 注解版 123 6.3.2 配置文件版 124 6.4 整合SpringData JPA 125 6.4.1 SpringData简介 125 6.4.2 整合 126 7 Spring Boot启动配置原理 128 7.1 启动流程(Springboot 1.50版本) 128 7.1.1 创建...

    JAVA上百实例源码以及开源项目源代码

    util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以...

    Spring3.x企业应用开发实战(完整版) part1

    12.2.4 添加Hibernate事件监听器 12.2.5 使用原生Hibernate API 12.2.6 使用注解配置 12.2.7 事务处理 12.2.8 延迟加载的问题 12.3 在Spring中使用myBatis 12.3.1 配置SqlMapClient 12.3.2 在Spring配置myBatis ...

    Spring.3.x企业应用开发实战(完整版).part2

    12.2.4 添加Hibernate事件监听器 12.2.5 使用原生Hibernate API 12.2.6 使用注解配置 12.2.7 事务处理 12.2.8 延迟加载的问题 12.3 在Spring中使用myBatis 12.3.1 配置SqlMapClient 12.3.2 在Spring配置myBatis ...

    Springboot:springboot和一些主流框架的整合的各个基本demo

    兄Dei,有用能不能给个Star呀兄Dei,有用能不能给个Star呀兄Dei,有用能不能给个Star呀项目目录介绍最简单的版本 web版本的是给项目添加日志管理这个是mybatis的配置版这是mybatis的注解版这是springboot发邮件 ...

    JAVA上百实例源码以及开源项目

    util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以...

    easyble-x:Android蓝牙低功耗(BLE)的简单框架

    Android BLE开发框架基于此库编写的BLE调试助手——BLE调试宝,各大应用市场都已上架,欢迎下载使用。下面放两个常用的应用市场地址第一次进入是主页的话,重新再进一次就是应用详情页了最新版本功能支持多设备同时...

    smartTable-2.2.0.zip

    支持其他刷新框架SmartRefreshLayout; 可配置表格最小宽度(小于该宽度自动适配); 支持直接List或数组字段转列; 支持Json数据直接转换成表格; 支持表格网格指定行列显示; 支持自动生成表单。

    还在死记硬背面试题,面试官问我题的时候,我哭了,试试这一套,精心提炼核心重点内容简化实战应用面试宝典10秒钟搞定一道面试题!

    最新版Java面试宝典,精心提炼核心重点内容简化应用面试实战10秒一道,Java初级,高级,框架,底层原理,数据库,操作系统,微服务,IO,并发,JVM,容器,SpringBoot,SpringCloud,linx,面向对象,常用类,多线程,...

    Spring in Action(第2版)中文版

    3.5.5程序事件的解耦 3.5.6让bean了解容器 3.6脚本化的bean 3.6.1给椰子上lime 3.6.2脚本化bean 3.6.3注入脚本化bean的属性 3.6.4刷新脚本化bean 3.6.5编写内嵌的脚本化bean 3.7小结 第4章通知bean 4.1aop...

    Spring in Action(第二版 中文高清版).part2

    3.5.5 程序事件的解耦 3.5.6 让Bean了解容器 3.6 脚本化的Bean 3.6.1 给椰子上Lime 3.6.2 脚本化Bean 3.6.3 注入脚本化Bean的属性 3.6.4 刷新脚本化Bean 3.6.5 编写内嵌的脚本化Bean 3.7 小结 第4章 通知...

    Spring in Action(第二版 中文高清版).part1

    3.5.5 程序事件的解耦 3.5.6 让Bean了解容器 3.6 脚本化的Bean 3.6.1 给椰子上Lime 3.6.2 脚本化Bean 3.6.3 注入脚本化Bean的属性 3.6.4 刷新脚本化Bean 3.6.5 编写内嵌的脚本化Bean 3.7 小结 第4章 通知...

    从零开始学Spring Boot

    1.6 Spring Boot使用别的json解析框架 1.7 全局异常捕捉 1.8 Spring Boot datasource - mysql 1.9 JPA - Hibernate 1.10 使用JPA保存数据 1.11 使用JdbcTemplate 1.12 Spring Boot修改端口号 1.13 Spring Boot配置...

    annotaction

    2. 新增的注解支持:该版本新增了若干注解,用于简化 Servlet、过滤器(Filter)和监听器(Listener)的声 明,这使得 web.xml 部署描述文件从该版本开始不再是必选的了。 3. 可插性支持:熟悉 Struts2 的开发者一定...

    java基础案例与开发详解案例源码全

    14.2.1 事件监听器366 14.2.2 事件适配器(EventAdapter)370 14.3 AWT常用组件372 14.3.1 界面组件372 14.3.2 菜单组件377 14.3.3 其他组件382 14.4 Swing简介383 14.4.1 Swing体系图383 14.4.2 Swing组件应用384 ...

    Yin.RPC:我的梦想RPC

    本人学习Netty后决定自己写1个基于Netty、Zookeeper、Spring的轻量级RPC框架,收获颇丰,不过本人才疏学浅,难免有所疏漏,若有批评和建议请发到邮箱 Features 支持长连接 支持异步调用 支持心跳检测 支持JSON序列化...

Global site tag (gtag.js) - Google Analytics