解決@Around對(duì)靜態(tài)方法不生效的問(wèn)題
場(chǎng)景:
在處理定時(shí)任務(wù)時(shí),由于這幾個(gè)方法都是靜態(tài)方法,在aop的切面中使用@Around注解,進(jìn)行監(jiān)控方法調(diào)用是否有異常。
發(fā)現(xiàn)aop沒(méi)有生效。
代碼如下:
/*切面類*/ @Aspect @Component public class RetryAop { private static Logger logger = LoggerFactory.getLogger(RetryAop.class); @Around(value = "@annotation(TechlogRetry)") public Object monitorAround(ProceedingJoinPoint pjp) throws Throwable { } } /*對(duì)應(yīng)的注解,在需要的方法上進(jìn)行標(biāo)注*/ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface TechlogRetry { long waitMsec() default 0; Class[] retryThrowable() default {}; } /*對(duì)應(yīng)的測(cè)試方法*/ @Component @EnableScheduling public class TimerWork { // 成員方法可以成功調(diào)用 @Scheduled(cron = "*/5 * * * * ?") @TechlogRetry(waitMsec = 3000,retryThrowable = Exception.class) public void work1() { System.out.println("定時(shí)方法1.。。。。。。"); throw new NullPointerException("拋出異常"); } // 靜態(tài)方法不會(huì)進(jìn)行重試 @Scheduled(cron = "*/5 * * * * ?") @TechlogRetry(waitMsec = 3000,retryThrowable = Exception.class) public static void work2() { System.out.println("定時(shí)方法2.。。。。。。"); throw new NullPointerException("拋出異常"); } // 通過(guò)這種方式生效 @Scheduled(cron = "*/5 * * * * ?") @TechlogRetry(waitMsec = 3000,retryThrowable = Exception.class) public void work4() { System.out.println("這是work4.。。。"); TimerWork.work2();// 調(diào)用work2時(shí),注釋掉方法2上面的相關(guān)注解 } }
產(chǎn)生原因:
可能是由于靜態(tài)方法是屬于類的,而非靜態(tài)方法是屬于Bean的,該類會(huì)被加載到容器中。具體原因需要查資料,后續(xù)進(jìn)行補(bǔ)充。
解決:
如work4,把你需要調(diào)用的靜態(tài)方法放到非靜態(tài)方法中進(jìn)行調(diào)用。
補(bǔ)充:記錄一次@Around使用不正確造成的StackOverflowError
同事發(fā)了一個(gè)底層服務(wù)后。我負(fù)責(zé)的某個(gè)上層服務(wù)突然掛了,有點(diǎn)慌,馬上查看上層服務(wù)的日志。
查看日志特別長(zhǎng)。沒(méi)找到從哪兒報(bào)的。
跳到最上開(kāi)始找,結(jié)果: StackOverflowError。就想到了遞歸調(diào)用。
隨即找到相關(guān)代碼一看:
由于doSomething方法也被@Around攔截,因此,一旦service下某個(gè)方法被攔截進(jìn)入doAround,就會(huì)調(diào)用other.doSomething(),就又會(huì)觸發(fā)doAround
導(dǎo)致一直遞歸調(diào)用且無(wú)法退出。
解決:
在@Around攔截的時(shí)候, 排除掉doSomething方法即可解決。
ps: @Around中不要用到被攔截方法。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Java實(shí)現(xiàn)warcraft?java版游戲的示例代碼
致敬經(jīng)典的warcraft,《warcraft?java版》是一款即時(shí)戰(zhàn)略題材單機(jī)游戲,采用魔獸原味風(fēng)格和機(jī)制。本文將用java語(yǔ)言實(shí)現(xiàn),采用了swing技術(shù)進(jìn)行了界面化處理,感興趣的可以了解一下2022-09-09Java 動(dòng)態(tài)生成類和實(shí)例, 并注入方法操作示例
這篇文章主要介紹了Java 動(dòng)態(tài)生成類和實(shí)例, 并注入方法操作,結(jié)合實(shí)例形式分析了Java 動(dòng)態(tài)生成類和實(shí)例以及動(dòng)態(tài)注入相關(guān)操作技巧,需要的朋友可以參考下2020-02-02Java split函數(shù)拆分后變成null問(wèn)題解決方案
這篇文章主要介紹了Java split函數(shù)拆分后變成null問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java notify和notifyAll的區(qū)別和相同
本文主要介紹Java notify和notifyAll的知識(shí),這里整理詳細(xì)的資料來(lái)說(shuō)明notify 和NotifAll的區(qū)別,有需要的小伙伴可以參考下2016-09-09Java Lock接口實(shí)現(xiàn)原理及實(shí)例解析
這篇文章主要介紹了Java Lock接口實(shí)現(xiàn)原理及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04關(guān)于@OnetoMany關(guān)系映射的排序問(wèn)題,使用注解@OrderBy
這篇文章主要介紹了關(guān)于@OnetoMany關(guān)系映射的排序問(wèn)題,使用注解@OrderBy,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12如何利用IDEA搭建SpringBoot項(xiàng)目整合mybatis實(shí)現(xiàn)簡(jiǎn)單的登錄功能
這篇文章主要介紹了如何利用IDEA搭建SpringBoot項(xiàng)目整合mybatis實(shí)現(xiàn)簡(jiǎn)單的登錄功能,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08