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实现图片橡皮擦和快速染色的具体代码,供大家参考,具体内容如下源码地址:Eraselmg1.染色 &n
- excel对于下拉框较多选项的,需要使用隐藏工作簿来解决,使用函数取值来做选项选项较少(一般少于5个):private static Dat
- 前言:回顾之前的微信公众号配置和消息处理的内容,我们已经掌握了如何配置服务器与微信公众号建立连接,也掌握了通过消息管理的方式,对用户的信息进
- 问题描述我在接受 mq 消息的时候,需要做一个重试次数限制,如果超过 maxNum 就发邮件告警,不再重试。所以我需要对 consumer
- 上篇文章中介绍了聊天功能,这里介绍通讯录是如何实现的。首先要加载公司的所有部门,树形结构,然后点击进入部门的人员列表,点击人员能查看详细信息
- spring中的bean依赖有大体上可以分为两类,共3中形式,下面简单介绍一下。第一类是构造方法中的循环依赖,这种会报错@Servicepu
- 目录Maven依赖配置示例Maven依赖要开始使用咖啡因Caffeine和Spring Boot,我们首先添加spring-boot-sta
- 静态成员变量与非静态成员变量的区别以下面的例子为例说明package cn.galc.test;public class Cat {/**
- 前言在有些业务场景中,系统对于响应时间有一定的要求,而一个方法里面同步执行的业务逻辑太多势必会影响响应速度,带来不好的用户体验。比如登录时记
- 实现二分法查找二分法查找,需要数组内是一个有序的序列二分查找比线性查找:数组的元素数越多,效率提高的越明显二分查找的效率表示:O(log2N
- java引用传递的三种类型我这里使用了mldn视频里的例子,只用于学习交流。第一种结果:调用前:50调用后:1000分析:理解:好理解第二种
- 在谈 Volatile 之前,我们先回顾下 Java 内存模型 的三要素:原子性、可见性、有序性,也就是大家常提到的并发编程三要素。并发编程
- 本文实例讲述了Android获取SD卡及手机ROM容量的方法。分享给大家供大家参考,具体如下:这里通过一个简单的小例子,来获取SD卡的容量和
- Unity Shader学习:玻璃材质,供大家参考。主要是通过反射和折射来达到透明的效果,用菲涅尔来混叠。shader部分:Shader &
- 一、Bundle进行IPC介绍四大组件中的三大组件(Activity、Service、Receiver)都是支持在Intent中传递Bund
- Interceptor 介绍 * (Interceptor)同 Filter 过滤器一样,它俩都是面向切面编程—&
- springboot配置文件中属性变量引用@@这种属性应用方式是field_name=@field_value@。两个@符号是springb
- 一问道StringBuffer与StringBuilder的区别,张口就来StringBuffer是线程安全的,因为它相关方法都加了sync
- gRPCgRPC是由 google开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多
- 前言自从国产之光fastjson频频暴雷,jackson json的使用是越来越广泛了。尤其是spring家族把它搞成了默认的JSON处理包