【Spring源码点滴】 @ControllerAdvice

在SpringMVC中,@Controller可以定义一个控制层Bean,其中的方法比较专注于业务,实际在应用中,通常需要对业务前后进行统一的处理,这时会告诉你可以用@ControllerAdvice注解,在其中可以完成统一处理的逻辑,那么@ControllerAdive是怎么实现的?

首先,根据@ControllerAdvice查找到和它相关的类,发现ControllerAdviceBean。

然后,发现方法findAnnotatedBeans,为静态方法,应该是初始化被调用,debug,启动应用,拦截下来,查看代码,基本逻辑就是从容器中查找@ControllerAdvice注解的Bean,然后new一个ControllerAdviceBean,放入List中返回给调用者。

调用者是谁?跟踪返回,来到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<Method> 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<Method> 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);
                }
            }
        }

 

展开阅读全文

没有更多推荐了,返回首页