• mvc 异常处理源码解析(3)


    准备

    1. 准备一个controller类, 里面抛出一个异常
    @RestController
    @RequestMapping("/hello")
    public class HelloController {
    
    
        @GetMapping("/h")
        public String hello(HttpServletResponse response) throws ArithmeticException {
    
            try {
                int a = 1 / 0;
            } catch (Exception e) {
                throw e;
            }
            return "hello";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1. 配置一个全局异常处理类
    /**
     * 异常处理器
     */
    @RestControllerAdvice
    public class BDExceptionHandler {
    
        /**
         * 参数异常
         * @param e 异常
         * @return BaseResult
         */
        @ExceptionHandler(ArithmeticException.class)
        public R doBaseExceptionHandler(ArithmeticException e) {
            return R.error(e.getMessage());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 接下来访问url, 跟踪源码

    源码跟踪

    进入到mvc的入口类DispatcherServlet的 doDispatch方法, 可以发现整体逻辑被try catch包围, 当第3步抛出异常之后就会被捕获, dispatchException对象则不为空,最后进入processDispatchResult方法进行处理

    	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		HttpServletRequest processedRequest = request;
    		HandlerExecutionChain mappedHandler = null;
    		boolean multipartRequestParsed = false;
    
    		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
    		try {
    			ModelAndView mv = null;
    			Exception dispatchException = null;
    
    			try {
    				//1.获取处理器链路
    				//2.执行拦截器前置方法
    				//3.调用controller方法, 返回结果集
    				//4.执行拦截器后置方法
    			}
    			catch (Exception ex) {
    			//
    				dispatchException = ex;
    			}
    			catch (Throwable err) {
    				dispatchException = new NestedServletException("Handler dispatch failed", err);
    			}
    			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    		}
    		catch (Exception ex) {
    			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    		}
    		catch (Throwable err) {
    			triggerAfterCompletion(processedRequest, response, mappedHandler,
    					new NestedServletException("Handler processing failed", err));
    		}
    		finally {
    			if (asyncManager.isConcurrentHandlingStarted()) {
    				// Instead of postHandle and afterCompletion
    				if (mappedHandler != null) {
    					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    				}
    			}
    			else {
    				// Clean up any resources used by a multipart request.
    				if (multipartRequestParsed) {
    					cleanupMultipart(processedRequest);
    				}
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    进入processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

    	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
    			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
    			@Nullable Exception exception) throws Exception {
    
    		boolean errorView = false;
    		//判断异常是否为空, 如果不是空则处理
    		if (exception != null) {
    			//处理ModelAndViewDefiningException异常
    			if (exception instanceof ModelAndViewDefiningException) {
    				logger.debug("ModelAndViewDefiningException encountered", exception);
    				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
    			}
    			else {
    				//处理其他所有的异常
    				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
    				mv = processHandlerException(request, response, handler, exception);
    				errorView = (mv != null);
    			}
    		}
    		//省略下面代码
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    进入mv = processHandlerException(request, response, handler, exception);

    	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
    			@Nullable Object handler, Exception ex) throws Exception {
    
    		// Success and error responses may use different content types
    		request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    
    		// Check registered HandlerExceptionResolvers...
    		ModelAndView exMv = null;
    		if (this.handlerExceptionResolvers != null) {
    			//this.handlerExceptionResolvers里面默认有两个处理异常的类
    			for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
    				// 遍历,判断使用那个类来处理
    				exMv = resolver.resolveException(request, response, handler, ex);
    				if (exMv != null) {
    					break;
    				}
    			}
    		}
    		if (exMv != null) {
    			//省略代码
    			return exMv;
    		}
    
    		throw ex;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    看一下上面for循环里面的this.handlerExceptionResolvers对象的结构 :
    DefaultErrorAttributes : 没做任何处理, 只是将异常设置到request对象的属性当中;

    HandlerExceptionResolverComposite : 里面有三个异常处理类, 分别的作用是 :

    ExceptionHandlerExceptionResolver:基于 @ExceptionHandler 配置 HandlerMethod 的 HandlerExceptionResolver 实现类。例如通过 @ControllerAdvice 注解自定义异常处理器,加上@ExceptionHandler注解指定方法所需要处理的异常类型

    ResponseStatusExceptionResolver:基于 @ResponseStatus 提供错误响应的 HandlerExceptionResolver 实现类。例如在方法上面添加 @ResponseStatus 注解,指定该方法发生异常时,需要设置的 code 响应码和 reason 错误信息

    DefaultHandlerExceptionResolver:默认 HandlerExceptionResolver 实现类,针对各种异常,设置错误响应码。例如 HTTP Method 不支持,则在这个实现类中往响应中设置错误码和错误信息

    原文链接:https://blog.csdn.net/Running666/article/details/130786561

    在这里插入图片描述
    进入HandlerExceptionResolverComposite类的resolveException(); 遍历上面的三种异常处理类, 判断应该使用哪个处理

    	public ModelAndView resolveException(
    			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
    
    		if (this.resolvers != null) {
    			//获取, 遍历
    			for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
    				ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
    				if (mav != null) {
    					return mav;
    				}
    			}
    		}
    		return null;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    由于只设置了第一种异常处理方式, 所以异常会由ExceptionHandlerExceptionResolver来处理, 进入handlerExceptionResolver.resolveException()

    	public ModelAndView resolveException(
    			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
    
    		if (shouldApplyTo(request, handler)) {
    			prepareResponse(ex, response);
    			//主要的异常处理逻辑
    			ModelAndView result = doResolveException(request, response, handler, ex);
    			if (result != null) {
    				// Print debug message when warn logger is not enabled.
    				if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
    					logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
    				}
    				
    				logException(ex, request);
    			}
    			return result;
    		}
    		else {
    			return null;
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    进入doResolveException(request, response, handler, ex)方法;

    	@Override
    	@Nullable
    	protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
    			HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
    			
    		//根据controller类和异常来判断由哪个类来处理这个异常
    		ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
    		if (exceptionHandlerMethod == null) {
    			return null;
    		}
    		//填充参数处理器
    		if (this.argumentResolvers != null) {
    			exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    		}
    		//填充返回结果处理器
    		if (this.returnValueHandlers != null) {
    			exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    		}
    
    		ServletWebRequest webRequest = new ServletWebRequest(request, response);
    		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    		ArrayList<Throwable> exceptions = new ArrayList<>();
    		try {
    			//省略代码
    			Object[] arguments = new Object[exceptions.size() + 1];
    			exceptions.toArray(arguments);  // efficient arraycopy call in ArrayList
    			arguments[arguments.length - 1] = handlerMethod;
    			//反射调用异常处理类
    			exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, arguments);
    		}
    		catch (Throwable invocationEx) {
    			// Any other than the original exception (or a cause) is unintended here,
    			// probably an accident (e.g. failed assertion or the like).
    			if (!exceptions.contains(invocationEx) && logger.isWarnEnabled()) {
    				logger.warn("Failure in @ExceptionHandler " + exceptionHandlerMethod, invocationEx);
    			}
    			// Continue with default processing of the original exception...
    			return null;
    		}
    		//省略
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    主要逻辑就是看如何找到处理对应异常的方法, 进入getExceptionHandlerMethod(handlerMethod, exception);

    进入到了ExceptionHandlerExceptionResolver类中, 在这个类里面有两个关键的属性,exceptionHandlerCache和exceptionHandlerAdviceCache, 两个都是map, exceptionHandlerAdviceCache的初始化下面再说,exceptionHandlerCache的初始化想知道的自己去查一下吧

    	private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache =
    			new ConcurrentHashMap<>(64);
    
    	private final Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerAdviceCache =
    			new LinkedHashMap<>();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    exceptionHandlerCache里面存的就是在当前controller里面包含@ExceptionHandler注解的方法, key: controller类, value : 方法包装类

    exceptionHandlerAdviceCache里面存的就是标注了@ControllerAdvice注解的类,里面带有@ExceptionHandler注解的方法, key:
    @RestControllerAdvice注解标注的类, value: 方法包装类

    	@Nullable
    	protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
    			@Nullable HandlerMethod handlerMethod, Exception exception) {
    
    		Class<?> handlerType = null;
    		//从exceptionHandlerCache获取异常对应的处理方法, 由于没有配置, 肯定获取不到
    		if (handlerMethod != null) {
    			handlerType = handlerMethod.getBeanType();
    			ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
    			if (resolver == null) {
    				resolver = new ExceptionHandlerMethodResolver(handlerType);
    				this.exceptionHandlerCache.put(handlerType, resolver);
    			}
    			Method method = resolver.resolveMethod(exception);
    			if (method != null) {
    				return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
    			}
    			if (Proxy.isProxyClass(handlerType)) {
    				handlerType = AopUtils.getTargetClass(handlerMethod.getBean());
    			}
    		}
    		//遍历全局的异常处理类, 看是否可以获取到对应的处理方法
    		for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {
    			ControllerAdviceBean advice = entry.getKey();
    			if (advice.isApplicableToBeanType(handlerType)) {
    				ExceptionHandlerMethodResolver resolver = entry.getValue();
    				Method method = resolver.resolveMethod(exception);
    				if (method != null) {
    					return new ServletInvocableHandlerMethod(advice.resolveBean(), method);
    				}
    			}
    		}
    
    		return null;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    进入Method method = resolver.resolveMethod(exception);, 最终进入到resolveMethodByExceptionType()方法, 在ExceptionHandlerMethodResolver类中

    ExceptionHandlerMethodResolver中有两个关键属性mappedMethods,和exceptionLookupCache, 两个也都是map, 两个都是根据异常获取对应的异常处理方法, mappedMethods在程序启动时候初始化, exceptionLookupCache相当于一个缓存,为了提高查询速度

    	@Nullable
    	public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {
    		//从缓存中获取处理方法, 如果获取不到,返回null(第一次执行此方法肯定获取不到)
    		Method method = this.exceptionLookupCache.get(exceptionType);
    		if (method == null) {
    			//如果获取不到, 则去mappedMethods获取
    			method = getMappedMethod(exceptionType);
    			//将获取的结果缓存到exceptionLookupCache中
    			this.exceptionLookupCache.put(exceptionType, method);
    		}
    		return (method != NO_MATCHING_EXCEPTION_HANDLER_METHOD ? method : null);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    进入getMappedMethod(exceptionType);

    	private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
    		List<Class<? extends Throwable>> matches = new ArrayList<>();
    		//遍历所有可以处理的异常, 判断与抛出的异常是否匹配
    		for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
    			if (mappedException.isAssignableFrom(exceptionType)) {
    				matches.add(mappedException);
    			}
    		}
    		if (!matches.isEmpty()) {
    			//如果有多个方法可以匹配来处理异常,则进行排序
    			if (matches.size() > 1) {
    				matches.sort(new ExceptionDepthComparator(exceptionType));
    			}
    			//获取第一个方法来处理异常,返回方法
    			return this.mappedMethods.get(matches.get(0));
    		}
    		else {
    			return NO_MATCHING_EXCEPTION_HANDLER_METHOD;
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    到此为止, 已经获取到对应的处理异常的方法了, 在上面的doResolveHandlerMethodException方法中, 最后通过反射调用该方法, 处理异常

    接下来讨论一下ExceptionHandlerExceptionResolver类里面的exceptionHandlerCache和exceptionHandlerAdviceCache初始化和
    ExceptionHandlerMethodResolver类中的mappedMethods初始化

    ExceptionHandlerExceptionResolver初始化

    ExceptionHandlerExceptionResolver实现了InitializingBean接口, 猜测初始化肯定在afterPropertiesSet()方法中, 我们至于要查找ExceptionHandlerExceptionResolver是如何注入到springboot容器中的, 及afterPropertiesSet()方法逻辑即可
    在这里插入图片描述

    ExceptionHandlerExceptionResolver注入

    实际上,ExceptionHandlerExceptionResolver并不会成为bean交给Spring容器管理。但是在WebMvcConfigurationSupport初始化过程中,会手动调用afterPropertiesSet()进行默认初始化

    还记得上面HandlerExceptionResolverComposite类里面有三个异常处理类吗? 看一下他们是如何注入的

    在WebMvcConfigurationSupport类里面的handlerExceptionResolver()方法:

    	@Bean
    	public HandlerExceptionResolver handlerExceptionResolver(
    			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
    		List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
    		configureHandlerExceptionResolvers(exceptionResolvers);
    		//如果是空, 在下面的if里面将三个异常处理类添加到集合中
    		if (exceptionResolvers.isEmpty()) {
    			addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
    		}
    		extendHandlerExceptionResolvers(exceptionResolvers);
    		HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
    		composite.setOrder(0);
    		//赋值属性, 最后返回
    		composite.setExceptionResolvers(exceptionResolvers);
    		return composite;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    进入到addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);

    	protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers,
    			ContentNegotiationManager mvcContentNegotiationManager) {
    		//创建ExceptionHandlerExceptionResolver 对象
    		ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
    		exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
    		exceptionHandlerResolver.setMessageConverters(getMessageConverters());
    		exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
    		exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
    		if (jackson2Present) {
    			exceptionHandlerResolver.setResponseBodyAdvice(
    					Collections.singletonList(new JsonViewResponseBodyAdvice()));
    		}
    		if (this.applicationContext != null) {
    			exceptionHandlerResolver.setApplicationContext(this.applicationContext);
    		}
    		//手动调用afterPropertiesSet()给属性初始化
    		exceptionHandlerResolver.afterPropertiesSet();
    		//添加第一个
    		exceptionResolvers.add(exceptionHandlerResolver);
    
    		ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
    		responseStatusResolver.setMessageSource(this.applicationContext);
    		//添加第二个
    		exceptionResolvers.add(responseStatusResolver);
    		//添加第三个
    		exceptionResolvers.add(new DefaultHandlerExceptionResolver());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    所以我们只需要看WebMvcConfigurationSupport是如何注入的就可以了, 实际上他是通过WebMvcAutoConfiguration类来间接注入的
    在这里插入图片描述
    而WebMvcAutoConfiguration类的注入是通过自动装配来注册的
    在这里插入图片描述

    ExceptionHandlerExceptionResolver中exceptionHandlerAdviceCache初始化

    	@Override
    	public void afterPropertiesSet() {
    		// Do this first, it may add ResponseBodyAdvice beans
    		initExceptionHandlerAdviceCache();
    
    		if (this.argumentResolvers == null) {
    			List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
    			this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    		}
    		if (this.returnValueHandlers == null) {
    			List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
    			this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    进入initExceptionHandlerAdviceCache()方法

    	private void initExceptionHandlerAdviceCache() {
    		if (getApplicationContext() == null) {
    			return;
    		}
    		//获取带有ControllerAdvice注解的类
    		List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
    		for (ControllerAdviceBean adviceBean : adviceBeans) {
    			Class<?> beanType = adviceBean.getBeanType();
    			if (beanType == null) {
    				throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
    			}
    			//构建value对象, 存入到exceptionHandlerAdviceCache中
    			//ExceptionHandlerMethodResolver中mappedMethods初始化逻辑也在其中
    			ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
    			if (resolver.hasExceptionMappings()) {
    				this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
    			}
    			if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
    				this.responseBodyAdvice.add(adviceBean);
    			}
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ExceptionHandlerMethodResolver中mappedMethods初始化

    mappedMethods的初始化逻辑很简单, 在上面的initExceptionHandlerAdviceCache()方法中我们已经找到了带有ControllerAdvice的所有类, 将类的类型作为参数创建了ExceptionHandlerMethodResolver对象, mappedMethods的初始化就在构造方法中

    进入ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType) 方法

    	public ExceptionHandlerMethodResolver(Class<?> handlerType) {
    		//获取到handlerType类中所有的带有ExceptionHandler注解的方法,
    		for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
    			//解析ExceptionHandler注解中的属性, 因为可以配置多个异常类型, 所有返回的是集合, 进行遍历
    			for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
    				//将异常类型作为key, 方法作为value, 存入到mappedMethods中
    				addExceptionMapping(exceptionType, method);
    			}
    		}
    	}
    
    	private List<Class<? extends Throwable>> detectExceptionMappings(Method method) {
    		List<Class<? extends Throwable>> result = new ArrayList<>();
    		//获取method上的ExceptionHandler注解的所有的异常类型,存入到result中, 返回
    		detectAnnotationExceptionMappings(method, result);
    		if (result.isEmpty()) {
    			for (Class<?> paramType : method.getParameterTypes()) {
    				if (Throwable.class.isAssignableFrom(paramType)) {
    					result.add((Class<? extends Throwable>) paramType);
    				}
    			}
    		}
    		if (result.isEmpty()) {
    			throw new IllegalStateException("No exception types mapped to " + method);
    		}
    		return result;
    	}
    
    
    	private void addExceptionMapping(Class<? extends Throwable> exceptionType, Method method) {
    		Method oldMethod = this.mappedMethods.put(exceptionType, method);
    		if (oldMethod != null && !oldMethod.equals(method)) {
    			throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for [" +
    					exceptionType + "]: {" + oldMethod + ", " + method + "}");
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    结尾

    上面已经说了到逻辑代码发生异常之后, 我们自定义的异常处理类如何加载处理这些异常(同时包括系统启动时的一些系统异常), 但是如果抛出一种没有处理类的异常会怎么样呢? 下篇文章在讨论一下

  • 相关阅读:
    一个重要的问题:怎么寻找自己的终身事业呢?
    函数式编程-Stream流
    js中this总结
    运用 Elastic Stack 收集 docker 容器日志
    JAVA毕业设计vue学习视频课程网站计算机源码+lw文档+系统+调试部署+数据库
    【DevOps】Git 图文详解(五):远程仓库
    使用接口根据关键词取视频列表详情
    折腾LINUX复古终端
    【多线程】Java如何实现多线程?如何保证线程安全?如何自定义线程池?
    MPC Multisig TSS TEE
  • 原文地址:https://blog.csdn.net/hc1428090104/article/details/132618213