通过阅读该篇博客,你可以了解了java的解反射机制,可以了解如何基于春天生命周期使用自定义注解解决日常研发问题。具体源码可以点击链接。
在日常研发中,经常会遇见业务一的某个行动被触发后,同时触发业务B的行动的行为,这种单对单的形式可以直接在业务的行动执行结束后直接调用业务B的行动,那么如果是单对多的情况呢?
这里提供一种在日常研发中经常使用到的机制,基于春天实现的事件驱动,即在业务的行动执行完,抛出一个事件,而业务B, C, D等监听到该事件后处理相应的业务。
这里提供一个场景范例,该范例基于springboot空壳项目实现,具体可以查看源码,此处只梳理关键步骤。
<强>步骤一:强>
定义一个注解,标志接收事件的注解,即所有使用了该注解的函数都会在对应事件被抛出的时候被调用,该注解实现比较简单,代码如下
/* * * @author xifanxiaxue * @date 3/31/19 * @desc接收事件的注解 */@Documented @Retention (RetentionPolicy.RUNTIME) @Target ({ElementType.METHOD}) 公共@ interface ReceiveAnno {//监听的事件 类clz (); }
如果想了解注解多个参数的意义是什么的可以点击链接查看博主之前写过文章。
定义事件接口
/* * * @author xifanxiaxue * @date 3/31/19 * @desc */公共接口IEvent { }
所有事件都需要实现该接口,主要是为了后面泛型和类型识别。
定义MethodInfo
/* * * @author xifanxiaxue * @date 3/31/19 * @desc */公开课MethodInfo { 公共对象obj; 公共方法方法; 公共静态MethodInfo返回对象的值(方法方法,对象obj) { MethodInfo信息=new MethodInfo (); 信息。方法=方法; 信息。obj=obj; 返回信息; } 公共对象getObj () { 返回obj; } 公共方法getMethod () { 回归方法; } }
该类只是做了对象和方法的封装,没有其他作用。
<强>步骤二:强>
实现一个事件容器,该容器的作用是存放各个事件以及需要触发的各个业务的方法的对应关系。
/* * * @author xifanxiaxue * @date 3/31/19 * @desc事件容器 */公开课EventContainer { 私有静态Map比;,eventListMap=new HashMap<的在(); 公共静态孔隙addEventToMap(类clz、方法方法,对象obj) { List methodInfos=eventListMap.get (clz); 如果(methodInfos==null) { ,methodInfos=new ArrayList<的在(); eventListMap。把(clz methodInfos); } methodInfos.add (MethodInfo。返回对象的值(方法、obj)); } 公共静态空提交(类clz) { List methodInfos=eventListMap.get (clz); 如果(methodInfos==null) { 返回; } (MethodInfo MethodInfo: methodInfos) { 方法方法=methodInfo.getMethod (); 尝试{ method.setAccessible(真正的); method.invoke (methodInfo.getObj ()); }捕捉(IllegalAccessException e) { e.printStackTrace (); }捕捉(InvocationTargetException e) { e.printStackTrace (); } } } }
其中的addEventToMap函数的作用是将对应的事件,事件触发后需要触发的对应业务内的方法存放在eventListMap内;而提交函数会在其他业务类内抛出事件的时候被调用,而作用是从eventListMap中取出对应的方法,并通过反射触发。
<强>步骤三:
强>
实现事件处理器,该事件处理器的作用是在bean被春容器实例化后去判断对应的bean是否有相应函数加了@ReceiveAnno注解,如果有则从中取出对应的事件并放入EventContainer中。
/* * * @author xifanxiaxue * @date 3/31/19 * @desc事件处理器 */@ component 公开课EventProcessor延伸InstantiationAwareBeanPostProcessorAdapter { @Override 公共布尔postProcessAfterInstantiation(对象bean,字符串beanName)抛出BeansException { 新ReflectionUtils.MethodCallback ReflectionUtils.doWithLocalMethods (bean.getClass (), () { @Override 公共空间研究方法(方法)抛出IllegalArgumentException, IllegalAccessException { ReceiveAnno伊斯兰教纪元=method.getAnnotation (ReceiveAnno.class); 如果(伊斯兰教纪元==null) { 返回; } 类clz=anno.clz (); 尝试{ 如果(! IEvent.class.isInstance (clz.newInstance ())) {=messageformat FormattingTuple消息。格式(“{}没有实现IEvent接口”,clz); 把新RuntimeException (message.getMessage ()); } }捕捉(InstantiationException e) { e.printStackTrace (); } EventContainer。addEventToMap (clz、方法、豆); } }); 超级回报。postProcessAfterInstantiation (bean, beanName); } }基于春天如何实现事件驱动实例代码