SpringMVC源码分析-HandlerAdapter(2)-RequestMappingHandlerAdapter的初始化

RequestMappingHandlerAdapter继承结构:

这里写图片描述

RequestMappingHandlerAdapter继承自AbstractHandlerMethodAdapter


AbstractHandlerMethodAdapter

源码:

package org.springframework.web.servlet.mvc.method;

public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator 
implements HandlerAdapter, Ordered {

    private int order = Ordered.LOWEST_PRECEDENCE;

    public AbstractHandlerMethodAdapter() {
        super(false);
    }

    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public int getOrder() {
        return this.order;
    }

    @Override
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }

    // 模板方法,由子类实现
    protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

    @Override
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return handleInternal(request, response, (HandlerMethod) handler);
    }

    // 模板方法,由子类实现
    protected abstract ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;

    @Override
    public final long getLastModified(HttpServletRequest request, Object handler) {
        return getLastModifiedInternal(request, (HandlerMethod) handler);
    }

    // 模板方法,由子类实现
    protected abstract long getLastModifiedInternal(HttpServletRequest request, 
    HandlerMethod handlerMethod);

}
AbstractHandlerMethodAdapter实现了HandlerAdapter接口
HandlerAdapter三个接口方法分别调用了三个模板方法
1)supportsInternal,
2)handleInternal,
3)getLastModifiedInternal
具体逻辑由其子类(RequestMappingHandlerAdapter)实现

我们注意到AbstractHandlerMethodAdapter#support中有一个条件:

Handler必须是HandlerMethod类型

另外还实现了Order接口,可以在配置时设置顺序,默认优先级最低


RequestMappingHandlerAdapter

RequestMappingHandlerAdapter可以说是整个SpringMVC最复杂的一个组件

RequestMappingHandlerAdapter继承自AbstractHandlerMethodAdapter
实现了三个模板方法1)supportsInternal,2)handlerInternal,3)getLastModifiedInternal

supportsInternal实现:

@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
    return true;
}
supportsInternal:直接返回true,也就是没有添加任何判断逻辑
所以只需要满足父类的HandlerMethod类型的要求就可以了

getLastModifiedInternal实现:

@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
    return -1;
}
直接返回了-1

最重要的是handlerInternal方法,正是这个方法实际使用了Handler来处理请求


handlerInternal具体实现

handlerInternal使用Handler处理请求,处理过程分为3步:

扫描二维码关注公众号,回复: 2245660 查看本文章
1,准备处理器需要的数据
2,使用处理器处理请求
3,处理返回值,将不同类型的返回值统一处理成ModelAndView类型

第一步,根据处理器的需要设置参数,而参数的类型,数量都不确定,
这个过程中使用了大量组件,使代码不容器理解,所以这一步是最为复杂的

关于绑定参数的一些问题:

1,都有哪些参数需要绑定
2,参数值的来源有哪些
3,具体进行绑定的方法

需要绑定的参数是根据方法确定的
除了实际处理请求的处理器,还有注释了@ModelAttribute和注释了@InitBinder的方法

参数的来源有6个:

1,request中的相关参数,包含url参数,post参数,请求头参数
2,cookie中的参数
3,session中的参数
4,设置到FlashMap中的参数,这类参数用于redirect的参数传递
5,SessionAttributes传递的参数,这类参数通过@SessionAttributes注解传递
6,注释了@ModelAttribute的方法进行设置的参数

前三种参数通过request进行管理
后三种参数通过Model进行管理
第四种参数,在请求处理前将之前保存的设置到Model,处理完如果需要将model中的值设置到FlashMap
第五,六种参数使用ModelFactory管理

参数的解析:

参数具体解析是使用HandlerMethodArgumentResolve类型的组件完成
不同类型的参数使用不同的ArgumentResolve来解析

有的Resolve内部使用了WebDataBinder,可以通过注释了@InitBinder的方法来初始化
注释了@InitBinder的方法需要绑定参数,也是不确定的,
它使用的和Handler使用的不是一套ArgumentResolve

注释了@ModelAttribute的方法也需要绑定参数,
它使用的和Handler使用的是同一套ArgumentResolve

RequestMappingHandlerAdapter的初始化

RequestMappingHandlerAdapter的创建是在afterPropertiesSet方法中实现的

afterPropertiesSet源码:

@Override
public void afterPropertiesSet() {
    //@ControllerAdvice注释的类相关的
    //  modelAttributeAdviceCache,
    //  initBinderAdviceCache,
    //  requestResponseBodyAdvice
    // Do this first, it may add ResponseBody advice beans
    initControllerAdviceCache();

    // 初始化argumentResolvers
    if (this.argumentResolvers == null) {
        List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    // 初始化initBinderArgumentResolvers
    if (this.initBinderArgumentResolvers == null) {
        List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
        this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    // 初始化returnValueHandlers
    if (this.returnValueHandlers == null) {
        List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
}

afterPropertiesSet方法主要初始化了:

除去initControllerAdviceCache方法(下面说)

1)HandlerMethodArgumentResolverComposite argumentResolvers;
    从返回类型可以看出这是一个给处理器方法解析参数的解析器集合
    用于给处理器方法和注释了@ModelAttribute的方法设置参数

2)HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
    从返回类型可以看出这是一个给处理器方法解析参数的解析器集合
    用于给注释了@InitBinder的方法设置参数

3)HandlerMethodReturnValueHandlerComposite returnValueHandlers;
    用于将处理器的返回值处理成ModelAndView的类型

另外,从返回类型XXXComposite可以看出,这里用到了一个组合模式,其中封装了多种组件

initControllerAdviceCache方法:初始化了@ControllerAdvice注释类相关的集合

1)Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache
    用于缓存@ControllerAdvice注解的类中注解了@ModelAttribute的方法

2)Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache
    用于缓存@ControllerAdvice注解的类中注解了@InitBinder的方法

3)List<Object> requestResponseBodyAdvice
    用于保存实现了RequestBodyAdvice和ResponseBodyAdvice接口的类

initControllerAdviceCache源码:

private void initControllerAdviceCache() {
    if (getApplicationContext() == null) {
        return;
    }
    if (logger.isInfoEnabled()) {
        logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
    }

    // 获取所有注释了@ControllerAdvice注解的Bean,并根据Order排序
    List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
    AnnotationAwareOrderComparator.sort(beans);

    List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();

    // 遍历所有@ControllerAdvice注解的Bean
    for (ControllerAdviceBean bean : beans) {
        // 获取添加了@ModelAttribute注解且没有@RequestMapping注解的方法
        Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
        if (!attrMethods.isEmpty()) {
            this.modelAttributeAdviceCache.put(bean, attrMethods);
            if (logger.isInfoEnabled()) {
                logger.info("Detected @ModelAttribute methods in " + bean);
            }
        }
        // 获取添加了@InitBinder注解的方法
        Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
        if (!binderMethods.isEmpty()) {
            this.initBinderAdviceCache.put(bean, binderMethods);
            if (logger.isInfoEnabled()) {
                logger.info("Detected @InitBinder methods in " + bean);
            }
        }
        // 获取实现了RequestBodyAdvice接口的bean
        if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
            requestResponseBodyAdviceBeans.add(bean);
            if (logger.isInfoEnabled()) {
                logger.info("Detected RequestBodyAdvice bean in " + bean);
            }
        }
        // 获取实现了ResponseBodyAdvice接口的bean
        if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
            requestResponseBodyAdviceBeans.add(bean);
            if (logger.isInfoEnabled()) {
                logger.info("Detected ResponseBodyAdvice bean in " + bean);
            }
        }
    }

    // 将实现了RequestBodyAdvice和ResponseBodyAdvice接口的类放入requestResponseBodyAdviceBeans
    // 这里是放入顶部,说明通过@@ControllerAdvice注解实现接口的处理优先级最高
    if (!requestResponseBodyAdviceBeans.isEmpty()) {
        this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
    }
}

这里需要注意:

requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans)
RequestBodyAdvice和ResponseBodyAdvice的实现有两种注册方法
1,注解注册到RequestMappingHandlerAdapter
2,通过@Controller注解SpringMVC自己发现并注册
所以使用@Controller注解注册的方式优先级要更高一些

MODEL_ATTRIBUTE_METHODS和INIT_BINDER_METHODS是两个静态过滤器
用于传入MethodIntrospector.selectMethods过滤包含某注解的方法

// 判断方法是否有@InitBinder注解
public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() {
    @Override
    public boolean matches(Method method) {
        return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
    }
};

// 判断方法是否有@ModelAttribute注解且不具有@RequestMapping注解
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = new MethodFilter() {
    @Override
    public boolean matches(Method method) {
        return ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) &&
                (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null));
    }
};

为什么要找有@ModelAttribute注解且不具有@RequestMapping注解的方法?

@ModelAttribute和@RequestMapping同时存在的方法
只是将返回值设置到Model而不是作为View使用了,但不会提前执行

argumentResolvers,initBinderArgumentResolversreturnValueHandlers属性的初始化

这三个属性的初始化都是调用了getDefaultXXX得到相应的值.然后设置对应的属性

以getDefaultArgumentResolvers为例:

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

    // 1,基于注解的参数解析器
    // Annotation-based argument resolution
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    resolvers.add(new PathVariableMethodArgumentResolver());
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new SessionAttributeMethodArgumentResolver());
    resolvers.add(new RequestAttributeMethodArgumentResolver());

    // 2,基于类型的参数解析器
    // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    resolvers.add(new ModelMethodProcessor());
    resolvers.add(new MapMethodProcessor());
    resolvers.add(new ErrorsMethodArgumentResolver());
    resolvers.add(new SessionStatusMethodArgumentResolver());
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

    // 3,自定义参数解析器
    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }

    // 4,可解析所有类型的解析器
    // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));

    return resolvers;
}
getDefaultArgumentResolvers中有四类解析器:

    1,基于注解的参数解析器
    2,基于类型的参数解析器
    3,自定义参数解析器
    4,可解析所有类型的解析器

从源码中可以看出,自定义的解析器是在前面两种都无法解析是才会使用到,这个顺序是无法改变的
例如如果想自己写一个解析器来解析@PathVariable注释的PathVariable参数,是无法实现的
即使写出来并注册到RequestMappingHanderAdapter中也不会被调用

关于RequestMappingHanderAdapter的初始化,主要就是初始化了这6个属性


RequestMappingHanderAdapter处理请求的入口方法是handleInternal,
后面就要针对这个具体处理请求的方法进行分析了

猜你喜欢

转载自blog.csdn.net/abap_brave/article/details/80955612
今日推荐