背景:最近項目中使用了@ControllerAdvice+@ExceptionHandler註解組合,實現全局異常處理器,處理代碼中手動向上拋出的異常(throws和throw)和自動向上拋出的異常(默認),代碼全局異常處理器代碼本身寫的沒問題,但不知道爲啥就是不起作用,下面看我怎麼解決的吧!
前言:
我們都知道java中異常處理方式有兩種
1、就地解決
即用try-catch塊包裹住容易發生異常的代碼片段,這樣當該代碼片段真正發生異常後,就會立即被catch塊捕捉並在catch塊中處理,從而使代碼繼續往下執行,不影響其他代碼的執行。
2、向上拋出
如果不想立馬就地處理,可以選擇將該異常向上拋出,讓方法的調用者處理。若方法的調用者也不行處理,同樣可以繼續向上拋出該異常,以此類推,直到將該異常拋給JVM處理。可是JVM懶啊,一看你們該處理的都不處理是吧,好,我也不處理,我還要把你們方法的調用過程給曬出來,結果就可以在控制檯看到方法調用的堆棧信息了。
1、爲啥要使用全局異常處理器?
總是用try-catch塊包裹代碼塊也不好,影響性能不說代碼看着不是很美觀,所以我們選擇用第二種——向上拋出的方式。向上拋出沒問題,但總要有一個地方處理該異常,在web系統當中還應該將該異常以一個用戶可以接受的方式返回給前端,不但在接口對接的時候讓前端小姐姐知道是我們後臺接口出現了問題,不至於摸不着頭腦;而且我們後端開發人員也能根據接口返回的結果快速的知道到底是哪裏出現了問題,才能快速解決問題。
2、我的@RestControllerAdvice標註的全局異常處理器
先看下我的全局異常處理器寫的沒問題是吧:
@RestControllerAdvice //等於@ControllerAdvice+@ResponseBody,和@RestController一個道理
public class OaExpHandler {
/**
* 處理所有的異常和Throwable類
* @param e
* @return
*/
@ExceptionHandler({Exception.class,Throwable.class})
public Map<String,Object> testExceptionHandler1(Exception e){
System.out.println("進來了");
Map<String, Object> map = new HashMap<>();
map.put("code",400);
map.put("msg","出錯啦");
return map;
}
}
很簡單也沒啥問題對吧,但是爲啥不行呢?
3、無效的原因
網上有好多是說沒有被掃描到,即沒有納入IOC容器中,這確實是一個原因,但我怎麼會犯這個錯誤呢?
其實還有一個原因,@ControllerAdvice全局異常處理器是處理controller中向上拋出後沒有被處理的異常,若異常在到達該異常處理器前就已經被處理了,自然就不會到達@ExceptionHandler標註的方法處理。我的就是這個原因...
我看了下controller中沒有try-catch塊,但是我有兩個切面,對所有的controller方法進行了環繞通知——找到原因了啊。
一起看看罪魁禍首:
@Around("controllerPointcutExpress() || actControllerPointcutExpress()")
public Object execTimeAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
long start = System.currentTimeMillis();
/*try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}*/
result = joinPoint.proceed();
//獲取目標方法的全類名
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method targetMethod = signature.getMethod();
System.out.println("目標方法:"+targetMethod +"執行總時長爲------- {"+(System.currentTimeMillis() - start)+"}毫秒");
return result;
}
被註釋的代碼就是那段有罪的代碼,可以看到我用try-catch塊對proceed()方法進行了包裹,所以一旦目標方法出現了異常,這裏的catch塊就會非常勤快的捕捉到異常並處理掉,自然沒有向上拋出去,也就無法到達@ControllerAdvice標註的全局異常處理器中。看到這裏不禁會問,嗯?難道Aspect切面的執行順序在@ControllerAdvice之前?但是事實上就是這個樣子的。
4、根本原因
一張圖足以說明一切:
看完本篇文章只要能學到兩點就可以了
1、理解java異常處理的機制。
2、知道filter、interceptor、controllerAdvice、Aspect、controller在springMVC中的執行順序。
好了,今天就到這裏吧,希望看完本篇文章能解決你的問題,若能學點東西就更好了。
另外,祝你每天開心、升職加薪、生活幸福!