Uniform exception handling is often encountered in project development. There is a solution in springMVC to use ExceptionHandler. So for example,

@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);
        returnResult.failure(); }}Copy the code

In this code, we can see that there are two exception-handling functions that handle IllegalArgumentException and RuntimeException, but on second thought, one question arises: IllegalArgumentException is a subclass of RuntimeException. Who will handle IllegalArgumentException? At first, I saw some answers on the Internet, and I could set Order, but after a simple test, I found that Order did not work. Although there is speculation in mind, but still hope to be able to find real proof of the idea, so they tried to find this piece of source code.

The source code interpretation

The call stack

After debugging step by step, the call stack is found as follows:

The core code

Decide the choice which is the core of ExceptionHandler code for ExceptionHandlerMethodResolver getMappedMethod method. The code is as follows:

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; }}Copy the code

This first finds all exceptionHandlers that can match the exception, and then sorts them, taking the one with the least depth (that is, the one with the highest degree of match).

As for the depth comparator algorithm shown below, it does a simple recursion, constantly judging whether the parent exception is the target exception to obtain the final depth.

conclusion

The source code is not long, we can easily find the answer we want — the order of ExceptionHandler is determined by the exception match, and there is no other way to specify the order (which is not necessary).