SpringBoot利用切面注解及反射實(shí)現(xiàn)事件監(jiān)聽(tīng)功能
前言
當(dāng)某個(gè)事件需要被監(jiān)聽(tīng)的時(shí)候,我們需要去做其他的事前,最簡(jiǎn)單的方式就是將自己的業(yè)務(wù) 方法追加到該事件之后。
但是當(dāng)有N多個(gè)這樣的需求的時(shí)候我們都這樣一個(gè)個(gè)去添加修改事件的源碼嗎?
這篇文章將告訴你如何用一個(gè)注解,就可以將你的業(yè)務(wù)代碼通過(guò)切面的方式添加到事件的前后,而不需要修改事件的代碼
效果圖
如下圖所示,add方法內(nèi)并沒(méi)有調(diào)用其他的方法,但是其他方法仍然被執(zhí)行了。
只要給監(jiān)聽(tīng)方法加@AddEventListener()注解就可以讓它在事件前后執(zhí)行了


監(jiān)聽(tīng)原理
該方法是利用切面、注解、反射來(lái)實(shí)現(xiàn)SpringBoot的事件監(jiān)聽(tīng)的
1.通過(guò)Aspect的切面,切入事件方法
首先使用Aspec的Around(也可以用before或者after,但是比較麻煩)注解,切入AddEvent的方法中,around注解的方法中,可以在事件方法的執(zhí)行前后添加業(yè)務(wù)代碼。但是我們不直接加入需要添加的業(yè)務(wù),進(jìn)入第二步驟。
2.利用反射獲取被AddEventAop注解的類和方法
利用反射Class.forName(class),獲取被AddEventAop注解的類(當(dāng)然你也可以修改一下,獲取所有的類),該類哪個(gè)方法被AddEventListener注解了,就執(zhí)行該方法,則監(jiān)聽(tīng)執(zhí)行成功。
method.invoke(o, args);
注意(非常重要)
- AddEventListener使用的類上,必須被AddEventAop注解了,否則反射的時(shí)候方法不會(huì)被執(zhí)行。
- 事件的類必須是bean,否則切面失敗。
- 監(jiān)聽(tīng)方法和(被監(jiān)聽(tīng)方法)事件方法的參數(shù)數(shù)量,類型,順序必須一致,否則可能導(dǎo)致反射執(zhí)行方法失敗
核心源碼
@Around("@annotation(event)")
public Object addEventListener(ProceedingJoinPoint joinPoint, AddEventAop event) throws Throwable {
Object[] args = joinPoint.getArgs();
//存儲(chǔ)需要在方法執(zhí)行之后再執(zhí)行的類
List<Method> afterEventMethod = new ArrayList<>();
//反射獲取AddEventListener修飾的方法并執(zhí)行
//獲取自定義注解的配置
final Map<String, Object> beans = applicationContext.getBeansWithAnnotation(AddEventAop.class);
for (String key : beans.keySet()) {
//Spring 代理類導(dǎo)致Method無(wú)法獲取,這里使用AopUtils.getTargetClass()方法
Object o = beans.get(key);
Class<?> aClass = beans.get(key).getClass();
String name = aClass.getName();
//aop切面會(huì)導(dǎo)致方法注解丟失,在這里處理獲取原類名
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){
//執(zhí)行所有的注解了該類的方法
EventType value = annotation.value();
if (value.equals(EventType.BEFOREEVENT)){
method.invoke(o, args);
}else{
afterEventMethod.add(method);
}
}
}
}
//執(zhí)行被切面的方法
Object proceed = joinPoint.proceed(args);
//執(zhí)行需要在方法執(zhí)行之后再執(zhí)行的方法
for (Method method : afterEventMethod) {
Class<?> aClass = method.getDeclaringClass();
Object o = aClass.newInstance();
method.invoke(o, args);
}
return proceed;
}源碼地址
到此這篇關(guān)于SpringBoot利用切面注解及反射實(shí)現(xiàn)事件監(jiān)聽(tīng)功能的文章就介紹到這了,更多相關(guān)SpringBoot事件監(jiān)聽(tīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot 事件監(jiān)聽(tīng)的實(shí)現(xiàn)方法
- SpringBoot Application事件監(jiān)聽(tīng)的實(shí)現(xiàn)方案
- springboot+redis過(guò)期事件監(jiān)聽(tīng)實(shí)現(xiàn)過(guò)程解析
- SpringBoot加載應(yīng)用事件監(jiān)聽(tīng)器代碼實(shí)例
- springboot?事件監(jiān)聽(tīng)器的案例詳解
- SpringBoot ApplicationListener事件監(jiān)聽(tīng)接口使用問(wèn)題探究
- SpringBoot中的ApplicationListener事件監(jiān)聽(tīng)器使用詳解
- Springboot事件監(jiān)聽(tīng)與@Async注解詳解
- Java?Springboot異步執(zhí)行事件監(jiān)聽(tīng)和處理實(shí)例
- SpringBoot實(shí)現(xiàn)事件監(jiān)聽(tīng)(異步執(zhí)行)的示例代碼
相關(guān)文章
SpringBoot如何返回頁(yè)面的實(shí)現(xiàn)方法
SpringBoot中使用Controller和頁(yè)面的結(jié)合能夠很好地實(shí)現(xiàn)用戶的功能及頁(yè)面數(shù)據(jù)的傳遞。本文介紹了如何實(shí)現(xiàn)頁(yè)面的返回以及這里面所包含的坑,感興趣的可以了解一下2021-07-07
Spring之ShutDown?Hook死鎖現(xiàn)象解讀
這篇文章主要介紹了Spring之ShutDown?Hook死鎖現(xiàn)象解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
Java中使用BigDecimal進(jìn)行精確運(yùn)算
這篇文章主要介紹了Java中使用BigDecimal進(jìn)行精確運(yùn)算的方法,非常不錯(cuò),需要的朋友參考下2017-02-02
SpringBoot項(xiàng)目修改訪問(wèn)端口和訪問(wèn)路徑的方法
這篇文章主要介紹了SpringBoot項(xiàng)目修改訪問(wèn)端口和訪問(wèn)路徑的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Spring中@PathVariable注解的簡(jiǎn)單使用
這篇文章主要介紹了Spring中@PathVariable注解的簡(jiǎn)單使用,@PathVariable 是 Spring Framework 中的注解之一,用于處理 RESTful Web 服務(wù)中的 URL 路徑參數(shù),它的作用是將 URL 中的路徑變量綁定到方法的參數(shù)上,需要的朋友可以參考下2024-01-01
rabbitmq使用springboot實(shí)現(xiàn)direct模式(最新推薦)
這篇文章主要介紹了rabbitmq使用springboot實(shí)現(xiàn)direct模式,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07

