解決@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)文件復(fù)制、剪切文件和刪除示例
這篇文章主要介紹了java實(shí)現(xiàn)文件復(fù)制、剪切文件和刪除示例,需要的朋友可以參考下2014-04-04
Java簡(jiǎn)易學(xué)生成績(jī)系統(tǒng)寫法實(shí)例
在本篇文章里小編給大家分享的是關(guān)于Java簡(jiǎn)易學(xué)生成績(jī)系統(tǒng)寫法實(shí)例以及相關(guān)知識(shí)點(diǎn),有需要的朋友們可以學(xué)習(xí)下。2019-09-09
基于Java SSM實(shí)現(xiàn)Excel數(shù)據(jù)批量導(dǎo)入
這篇文章主要為大家詳細(xì)介紹了基于Java SSM如何實(shí)現(xiàn)excel數(shù)據(jù)批量導(dǎo)入,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
Spring定時(shí)任務(wù)注解@Scheduled詳解
這篇文章主要介紹了Spring定時(shí)任務(wù)注解@Scheduled詳解,@Scheduled注解是包org.springframework.scheduling.annotation中的一個(gè)注解,主要是用來(lái)開(kāi)啟定時(shí)任務(wù),本文提供了部分實(shí)現(xiàn)代碼與思路,需要的朋友可以參考下2023-09-09
JDBC的擴(kuò)展知識(shí)點(diǎn)總結(jié)
這篇文章主要介紹了JDBC的擴(kuò)展知識(shí)點(diǎn)總結(jié),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)JDBC的小伙伴們有很好地幫助,需要的朋友可以參考下2021-05-05

