SpringMVC异常解析器初始化原理

文章详细描述了SpringMVC框架中ExceptionHandlerExceptionResolver的初始化过程,包括查找带有@ControllerAdvice注解的类,以及如何处理带有@ExceptionHandler注解的方法,涉及到参数解析器和返回值处理器的配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver{
    public void afterPropertiesSet() {
		// 初始化被@ControllerAdvice标注的类,在HandlerAdapter中也做过这件事
        initExceptionHandlerAdviceCache();{
			 List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());{
                // 保存添加了@ControllerAdvice注解的类信息
                List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
                // 找到所有的beanName
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class);
                for (String name : beanNames) {
                    // 判断是否是代理的Bean,添加了@Scoped的标识,添加了返回true
                    if (!ScopedProxyUtils.isScopedTarget(name)) {
                        // 找到Bean中带有@ControllerAdvice的类
                        ControllerAdvice controllerAdvice = beanFactory.findAnnotationOnBean(name, ControllerAdvice.class);
                        if (controllerAdvice != null) {
                            // 将这些信息包装成ControllerAdviceBean对象,避免后续再次找相同的Bean
                            adviceBeans.add(new ControllerAdviceBean(name, beanFactory, controllerAdvice));
                        }
                    }
                }
                // 对这些bean进行排序
                OrderComparator.sort(adviceBeans);
                return adviceBeans;
            }
			// 遍历找到的adviceBean
			for (ControllerAdviceBean adviceBean : adviceBeans) {
				// 获取Bean的类型
				Class<?> beanType = adviceBean.getBeanType();
				// 创建一个ExceptionHandlerMethodResolver对象,是为了处理标注了@ExceptionHandler的方法
				// 因为标注了@ExceptionHandler就有点类似于@RequestMapping
				// 一个是异常情况下的执行方法,一个是正常情况下的执行方法
				ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);{
					// 找到标注了ExceptionHandler的方法
					// EXCEPTION_HANDLER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, ExceptionHandler.class);
					for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
						// detectExceptionMappings: 遍历在方法中的异常参数,例如NullE,Ex,Th等等异常
						for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method){
																			ExceptionHandler ann = AnnotatedElementUtils.findMergedAnnotation(method, ExceptionHandler.class);
																			result.addAll(Arrays.asList(ann.value()));
																			// 如果没有在@ExceptionHandler添加异常参数
																			if (result.isEmpty()) {
																				// 找到参数中为Throwable的异常对象,保存到result中
																				// 如果没有,就会抛出异常
																				for (Class<?> paramType : method.getParameterTypes()) {
																					if (Throwable.class.isAssignableFrom(paramType)) {
																						result.add((Class<? extends Throwable>) paramType);
																					}
																				}
																			}
																		}) {
							// 保存异常方法和数据,将异常类型作为Key,Method方法作为value本身
							addExceptionMapping(exceptionType, method);{
								Method oldMethod = this.mappedMethods.put(exceptionType, method);
								// 如果存在两种一样的的Exception的方法,就要报错了
								if (oldMethod != null && !oldMethod.equals(method)) {
									throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for");
								}
							}
						}
					}
				}
				// 上面如果保存了异常数据,这里就符合条件mappedMethods有值
				if (resolver.hasExceptionMappings(){
								return !this.mappedMethods.isEmpty();
							}) {
					// 保存到当前ExceptionResolver的缓存中exceptionHandlerAdviceCache
					this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
				}
				// 如果当前bean的类型是ResponseBodyAdvice这个类型
				if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
					// 还要保存到responseBodyAdvice这里
					this.responseBodyAdvice.add(adviceBean);
				}
			}
		}

        if (this.argumentResolvers == null) {
			// 获取处理异常方法的参数解析器
            List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();{
				List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
				// 处理@SessionAttribute和@RequestAttribute的参数解析器
				resolvers.add(new SessionAttributeMethodArgumentResolver());
				resolvers.add(new RequestAttributeMethodArgumentResolver());

				// 处理参数为req,resp,model,RedirectAttributes的处理器
				resolvers.add(new ServletRequestMethodArgumentResolver());
				resolvers.add(new ServletResponseMethodArgumentResolver());
				resolvers.add(new RedirectAttributesMethodArgumentResolver());
				resolvers.add(new ModelMethodProcessor());

				// 自定义的参数解析器
				if (getCustomArgumentResolvers() != null) {
					resolvers.addAll(getCustomArgumentResolvers());
				}
				// 兜底的参数解析器
				resolvers.add(new PrincipalMethodArgumentResolver());

				return resolvers;
			}
			// 将参数解析器包装到HandlerMethodArgumentResolverComposite内
            this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
        }
		// 返回值处理器
        if (this.returnValueHandlers == null) {
			// 获取默认的返回值处理器
            List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(){
				List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();

				// 处理ModeAndView,Model,View,httpEntity的返回值
				handlers.add(new ModelAndViewMethodReturnValueHandler());
				handlers.add(new ModelMethodProcessor());
				handlers.add(new ViewMethodReturnValueHandler());
				handlers.add(new HttpEntityMethodProcessor(
						getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));

				// 处理返回值为req,resp的
				handlers.add(new ServletModelAttributeMethodProcessor(false));
				handlers.add(new RequestResponseBodyMethodProcessor(
						getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));

				// 处理返回值为String的视图
				handlers.add(new ViewNameMethodReturnValueHandler());
				// 返回Map的处理器
				handlers.add(new MapMethodProcessor());

				// 自定义的返回值处理器
				if (getCustomReturnValueHandlers() != null) {
					handlers.addAll(getCustomReturnValueHandlers());
				}

				// 兜底的返回值处理器
				handlers.add(new ServletModelAttributeMethodProcessor(true));

				return handlers;
			};
			// 将参数解析器包装到HandlerMethodReturnValueHandlerComposite内
            this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值