SpringBoot利用切面注解及反射实现事件监听功能
作者:mabo_9704@163.com 发布时间:2022-09-25 16:55:00
前言
当某个事件需要被监听的时候,我们需要去做其他的事前,最简单的方式就是将自己的业务 方法追加到该事件之后。
但是当有N多个这样的需求的时候我们都这样一个个去添加修改事件的源码吗?
这篇文章将告诉你如何用一个注解,就可以将你的业务代码通过切面的方式添加到事件的前后,而不需要修改事件的代码
效果图
如下图所示,add方法内并没有调用其他的方法,但是其他方法仍然被执行了。
只要给监听方法加@AddEventListener()注解就可以让它在事件前后执行了
监听原理
该方法是利用切面、注解、反射来实现SpringBoot的事件监听的
1.通过Aspect的切面,切入事件方法
首先使用Aspec的Around(也可以用before或者after,但是比较麻烦)注解,切入AddEvent的方法中,around注解的方法中,可以在事件方法的执行前后添加业务代码。但是我们不直接加入需要添加的业务,进入第二步骤。
2.利用反射获取被AddEventAop注解的类和方法
利用反射Class.forName(class),获取被AddEventAop注解的类(当然你也可以修改一下,获取所有的类),该类哪个方法被AddEventListener注解了,就执行该方法,则监听执行成功。
method.invoke(o, args);
注意(非常重要)
AddEventListener使用的类上,必须被AddEventAop注解了,否则反射的时候方法不会被执行。
事件的类必须是bean,否则切面失败。
监听方法和(被监听方法)事件方法的参数数量,类型,顺序必须一致,否则可能导致反射执行方法失败
核心源码
@Around("@annotation(event)")
public Object addEventListener(ProceedingJoinPoint joinPoint, AddEventAop event) throws Throwable {
Object[] args = joinPoint.getArgs();
//存储需要在方法执行之后再执行的类
List<Method> afterEventMethod = new ArrayList<>();
//反射获取AddEventListener修饰的方法并执行
//获取自定义注解的配置
final Map<String, Object> beans = applicationContext.getBeansWithAnnotation(AddEventAop.class);
for (String key : beans.keySet()) {
//Spring 代理类导致Method无法获取,这里使用AopUtils.getTargetClass()方法
Object o = beans.get(key);
Class<?> aClass = beans.get(key).getClass();
String name = aClass.getName();
//aop切面会导致方法注解丢失,在这里处理获取原类名
if (name.contains("$$")){
String[] names = name.split("\\$\\$");
name=names[0];
aClass = Class.forName(name);
}
Method[] methods = aClass.getMethods();
for (Method method : methods) {
//获取指定方法上的注解的属性
AddEventListener annotation = method.getAnnotation(AddEventListener.class);
if (annotation!=null){
//执行所有的注解了该类的方法
EventType value = annotation.value();
if (value.equals(EventType.BEFOREEVENT)){
method.invoke(o, args);
}else{
afterEventMethod.add(method);
}
}
}
}
//执行被切面的方法
Object proceed = joinPoint.proceed(args);
//执行需要在方法执行之后再执行的方法
for (Method method : afterEventMethod) {
Class<?> aClass = method.getDeclaringClass();
Object o = aClass.newInstance();
method.invoke(o, args);
}
return proceed;
}
源码地址
Github项目地址
来源:https://blog.csdn.net/weixin_47053123/article/details/125812796


猜你喜欢
- 本文实例讲述了Android实现手机壁纸改变的方法。分享给大家供大家参考。具体如下:main.xml布局文件:<?xml versio
- Required String parameter xxx is not present类型异常异常报错学习Spring Boot的时候做一
- Android 自定义阴影效果详解及实例Android5.X中,Google为其增加了两个属性 android:elevation=” ”
- 上一篇博文《Android中Handler使用浅析》通过实现倒计时闪屏页面的制作引出了Handler的使用方法以及实现原理,博文末尾也提到了
- 前言我们在对英文句子分词的时候,一般采用采用的分词器是WhiteSpaceTokenizerFactory,有一次因业务要求,需要根据某一个
- 在android中,LayoutInflater有点类似于Activity的findViewById(id),不同的是LayoutInfla
- 概述:通过自定义ImageView控件,在xml布局里面调用自定的组件实现图片的缩放。/*** 自定义的ImageView控制,可对图片进行
- 本文实例讲述了Android控件Tween动画(补间动画)实现方法。分享给大家供大家参考,具体如下:Android动画中的Tween动画:是
- 本文为大家分享了Android ViewPager实现图片滑动预览效果展示的具体代码,供大家参考,具体内容如下效果图:滑动前:滑动后:代码非
- 解析得到的代码能通过XHTML 1.0 STRICT验证;包含了标题,链接,字体,对齐,图片,引用,列表等方面的功能.&
- 背景今天我们来谈一下我们自定义的一组WPF控件Form和FormItem,然后看一下如何自定义一组完整地组合WPF控件,在我们很多界面显示的
- 今天写Tab的时候由于TAB的跳转问题去查资料,倒反而发现更有趣的问题,就是如何将TAB放置在屏幕的底端。 <?xml version
- using System.Drawing;using System.Drawing.Drawing2D;using System.Drawi
- 实践过程效果代码public partial class frmSend : Form{ public frmSe
- 学习目的:1、掌握在Android中如何建立EditText2、掌握EditText的常用属性3、掌握EditText焦点的事件、按键的事件
- 概述在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。也就是说,程序的流程对运行结果有直接的影响。所以,我们必须清楚每条
- 一、场景public class OrderModel {private List<String> favorableDescL
- 1、深度总结引用一位网友的话,说的非常好,如果别人问你static的作用;如果你说静态修饰 类的属性 和 类的方法 别人认为你是合格的;如果
- 本文实例讲述了C#获取文件创建时间的方法。分享给大家供大家参考。具体如下:C#获取文件创建时间,主要用到了FileInfo的Creattio
- maven插件主要是为maven中生命周期中的阶段服务的,maven中只是定义了3套生命周期,以及每套生命周期中有哪些阶段,具体每个阶段中执