SpringBoot RestControllerAdvice异常处理适配原理

         在项目中我们经常通过RestControllerAdvice+ExceptionHandler一起来实现全局的异常处理。

        以下是示例代码:

     

package com.xulu.monitor.test;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ParentException.class)
    public Response handlerChildrenException(){
        Response res = new Response();
        System.out.println("1111");
        return res;
    }

    @ExceptionHandler(ChildrenException.class)
    public Response handlerParentException(){
        Response res = new Response();
        System.out.println("2222");
        return res;
    }

    @ExceptionHandler(Throwable.class)
    public Response handlerThrowable(){
        Response res = new Response();
        System.out.println("3333");
        return res;
    }
}
package com.xulu.monitor.test;

public class ChildrenException extends ParentException{
}
package com.xulu.monitor.test;

public class ParentException extends RuntimeException{
}

 在GlobalExceptionHandler我们看到异常处理器会处理ParentException、ChildrenException、Throwable这种异常。其中ChildrenException继承于ParentException,而ParentException继承了

RuntimeException,而RuntimeException的父父类就是Throwable。

       当系统抛出一个ChildrenException时,按照全局的异常处理机制三处异常处理代码都有执行的可能性。那在springboot中是怎么匹配异常处理代码的。在springboot中上面的全局异常处理是在SpringMvc源码中执行的。当请求出现异常时,

ExceptionHandlerMethodResolver中的resolveMethod方法会获取匹配的异常处理方法。跟踪resolveMethod方法,发现在该类的getMappedMethod方法中找到了匹配的源码。
private Method getMappedMethod(Class exceptionType) {
		List> matches = new ArrayList<>();
		for (Class mappedException : this.mappedMethods.keySet()) {
			if (mappedException.isAssignableFrom(exceptionType)) {
				matches.add(mappedException);
			}
		}
		if (!matches.isEmpty()) {
			matches.sort(new ExceptionDepthComparator(exceptionType));
			return this.mappedMethods.get(matches.get(0));
		}
		else {
			return null;
		}
	}

重点关注上面的的代码我们发现是先排序再取第一条数

matches.sort(new ExceptionDepthComparator(exceptionType));这段代码。在这段代码中针对ExceptionDepthComparator做了排序。

SpringBoot RestControllerAdvice异常处理适配原理_第1张图片

在上面的排序类中 发现匹配规则是先匹配类型,如果类型不匹配则匹配其父类,一直匹配到深度最浅的父类。如果一直匹配不到则匹配到Throwable。

所以如果抛出了ChildrenException异常则优先匹配异常处理器里的ChildrenException异常,如果异常处理里没有声明ChildrenException的异常处理,则匹配异常处理器里的ParentException异常处理器,ParentException没有声明再匹配Throwable。

你可能感兴趣的:(SpringMvc源码学习,spring,boot,java,后端)