在項目開發中常常會遇到統一異常處理的問題,在springMVC中有一種解決方式,使用ExceptionHandler。舉個例子,java
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler({IllegalArgumentException.class})
@ResponseBody
public Result handleIllegalArgumentException(IllegalArgumentException e) {
logger.error(e.getLocalizedMessage(), e);
return Result.fail(e.getMessage());
}
@ExceptionHandler({RuntimeException.class})
@ResponseBody
public Result handleRuntimeException(RuntimeException e) {
logger.error(e.getLocalizedMessage(), e);
return Result.failure();
}
}
複製代碼
在這段代碼中,咱們能夠看到存在兩個異常處理的函數分別處理IllegalArgumentException和RuntimeException,可是轉念一想,就會想到一個問題,IllegalArgumentException是RuntimeException的子類,那麼對IllegalArgumentException這個異常又會由誰來處理呢?起初在網上看到一些答案,能夠經過Order設置,可是通過簡單的測試,發現Order並不起任何做用。雖然心中已有猜想,但仍是但願可以找到真正能夠證實想法的證據,因而便嘗試找到這一塊的源碼。算法
排出掉緩存的狀況,主動觸發一個IllegalArgumentException異常,通過一步步調試,發現調用棧以下:spring
決定最終選擇哪一個ExceptionHandler的核心代碼爲ExceptionHandlerMethodResolver的getMappedMethod方法。代碼以下:緩存
private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
List<Class<? extends Throwable>> matches = new ArrayList<Class<? extends Throwable>>();
for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
if (mappedException.isAssignableFrom(exceptionType)) {
matches.add(mappedException);
}
}
if (!matches.isEmpty()) {
Collections.sort(matches, new ExceptionDepthComparator(exceptionType));
return this.mappedMethods.get(matches.get(0));
}
else {
return null;
}
}
複製代碼
這個首先找到能夠匹配異常的全部ExceptionHandler,而後對其進行排序,取深度最小的那個(即匹配度最高的那個)。app
至於深度比較器的算法以下圖,就是作了一個簡單的遞歸,不停地判斷父異常是否爲目標異常來取得最終的深度。函數
源碼不長,咱們也能夠很容易地就找到咱們想要的答案——ExceptionHandler的處理順序是由異常匹配度來決定的,且咱們也沒法經過其餘途徑指定順序(其實也沒有必要)。測試