【Spring源码点滴】 @ControllerAdvice

在SpringMVC中,@Controller可以定义一个控制层Bean,其中的方法比较专注于业务,实际在应用中,通常需要对业务前后进行统一的处理,这时会告诉你可以用@ControllerAdvice注解,在其中可以完成统一处理的逻辑,那么@ControllerAdive是怎么实现的?
首先,根据@ControllerAdvice查找到和它相关的类,发现ControllerAdviceBean。
然后,发现方法findAnnotatedBeans,为静态方法,应该是初始化被调用,debug,启动应用,拦截下来,查看代码,基本逻辑就是从容器中查找@ControllerAdvice注解的Bean,然后new一个ControllerAdviceBean,放入List中返回给调用者。
【【Spring源码点滴】 @ControllerAdvice】调用者是谁?跟踪返回,来到RequestMappingHandlerAdapter.initControllerAdviceCache方法,在获取返回List之后,首先排序,然后遍历List。如果项目中有多个ControllerAdive,是需要排序的,可以实现Ordered接口,或者在类上面注解@Order,默认排序值为INT最大值,优先级最低。
阅读遍历的逻辑,会发现其实只是获取ControllerAdviceBean中的对应注解的方法,然后放入RequestMappingHandlerAdapter对应的缓存中,到这就明了了,这个统一处理的其实还是通过RequestMappingHandlerAdapter实现的,只是再抽象了一层MVC的模式,使开发者可以关注@ControllerAdvice注解的Bean本身。
有四种可被读取的方式,代码在最下方:
1.MODEL_ATTRIBUTE_METHODS,方法上注解RequestMapping或ModelAttribute;
2.INIT_BINDER_METHODS,方法上注解InitBinder;
3.继承RequestBodyAdvice;
4.继承ResponseBodyAdvice;
这4种方法分别有什么作用,网上的资料有很多,就不赘述了,本人偏向于分析设计思想。至于RequestMappingHandlerAdapter,放另一篇文章吧。

for (ControllerAdviceBean adviceBean : adviceBeans) { Class beanType = adviceBean.getBeanType(); if (beanType == null) { throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean); } Set attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS); if (!attrMethods.isEmpty()) { this.modelAttributeAdviceCache.put(adviceBean, attrMethods); if (logger.isInfoEnabled()) { logger.info("Detected @ModelAttribute methods in " + adviceBean); } } Set binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(adviceBean, binderMethods); if (logger.isInfoEnabled()) { logger.info("Detected @InitBinder methods in " + adviceBean); } } if (RequestBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); if (logger.isInfoEnabled()) { logger.info("Detected RequestBodyAdvice bean in " + adviceBean); } } if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); if (logger.isInfoEnabled()) { logger.info("Detected ResponseBodyAdvice bean in " + adviceBean); } } }


    推荐阅读