Spring MVC 初始化源码(3)—<mvc:annotation-driven >配置标签的源码解析

  基于最新Spring 5.x,详细介绍了Spring MVC 初始化流程的源码,主要包括配置标签的源码解析。

  我正在参与CSDN《新程序员》有奖征文,活动地址:https://marketing.csdn.net/p/52c37904f6e1b69dc392234fff425442。

  此前我们讲过了DispatcherServlet与子容器的初始化以及MVC组件的初始化,我们说过如果IoC容器中存在给定类型的组件,那么DispatcherServlet#onRefresh()方法中就不会尝试初始化默认组件了。
  而在初始化IoC子容器的时候,将会解析Spring MVC的配置文件,在配置文件中就有可能初始化我们自定义的一些组件bean,也有可能会加载其他MVC配置标签,最常见的就是标签,实际上该标签就会向容器注册一些组件bean,并且还会进行额外的配置。
  标签为基于注解的SpringMVC驱动提供便捷配置,虽然Spring mvc5版本之后Spring MVC会默认加载大部分的默认组件,但是使用该标签仍然能够自动加载某些额外配置,比如自动发现并注册MappingJackson2HttpMessageConverter转换器以支持JSON数据交互的请求和响应。
  mvc系列标签同样属于扩展标签,根据我们此前学过的IoC容器初始化源码,扩展标签将会在IoC容器初始化的parseCustomElement方法中解析,mvc标签的解析器位于MvcNamespaceHandler类中:
Spring MVC 初始化源码(3)—<mvc:annotation-driven >配置标签的源码解析_第1张图片
  可以知道标签是由AnnotationDrivenBeanDefinitionParser这个解析器来解析的。

  下面的源码版本基于5.2.8.RELEASE。源码解析基于传统的SSM项目,不适用于Spring Boot项目。

Spring MVC源码 系列文章

Spring MVC 初始化源码(1)—ContextLoaderListener与父上下文容器的初始化

Spring MVC 初始化源码(2)—DispatcherServlet与子容器的初始化以及MVC组件的初始化【一万字】

Spring MVC 初始化源码(3)—配置标签的源码解析

Spring MVC 初始化源码(4)—@RequestMapping注解的源码解析

Spring MVC 请求执行流程的源码深度解析【两万字】

文章目录

  • Spring MVC源码 系列文章
  • 1 AnnotationDrivenBeanDefinitionParser静态块
  • 2 parse执行解析
    • 2.1 注册RequestMappingHandlerMapping
      • 2.1.1 configurePathMatchingProperties配置路径匹配
    • 2.2 注册RequestMappingHandlerAdapter
      • 2.2.1 配置ConfigurableWebBindingInitializer
        • 2.2.1.1 getConversionService获取转换服务
        • 2.2.1.2 getValidator获取校验器
        • 2.2.1.3 getMessageCodesResolver
      • 2.2.2 getMessageConverters获取消息转换器
      • 2.2.3 getArgumentResolvers获取参数解析器
      • 2.2.4 getReturnValueHandlers获取返回值解析器
      • 2.2.5 获取异步处理属性
        • 2.2.5.1 getAsyncTimeout获取异步处理超时时间
        • 2.2.5.1 getAsyncExecutor获取异步处理线程池
        • 2.2.5.1 getInterceptors获取异步处理拦截器
      • 2.2.6 支持@JsonView注解解析
  • 3 总结

1 AnnotationDrivenBeanDefinitionParser静态块

  首先我们能看到AnnotationDrivenBeanDefinitionParser具有静态代码块,其内部的代码主要是查找是否具有某些依赖,用于后续parse方法中的一些自动配置,比如自动注册MappingJackson2HttpMessageConverter,用于支持application/json请求和响应。

//AnnotationDrivenBeanDefinitionParser的属性

private static final boolean javaxValidationPresent;

private static boolean romePresent;

private static final boolean jaxb2Present;

private static final boolean jackson2Present;

private static final boolean jackson2XmlPresent;

private static final boolean jackson2SmilePresent;

private static final boolean jackson2CborPresent;

private static final boolean gsonPresent;

static {
    ClassLoader classLoader = AnnotationDrivenBeanDefinitionParser.class.getClassLoader();
    //项目是否具有javax.validation.Validator接口,即validation-api的依赖
    javaxValidationPresent = ClassUtils.isPresent("javax.validation.Validator", classLoader);
    romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
    //项目是否具有javax.xml.bind.Binder接口,这位于rt.jar核心包中
    jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
    //项目是否具有jackson-databind依赖,主要用于支持application/json请求和响应,实现JSON的序列化和反序列化
    jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
            ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
    //项目是否具有jackson-dataformat-xml依赖,主要用于支持XML的请求和响应,实现XML的序列化和反序列化
    jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
    //项目是否具有jackson-dataformat-smile依赖
    jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
    //项目是否具有jackson-dataformat-cbor依赖
    jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
    //项目是否具有gson依赖
    gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
}

2 parse执行解析

  AnnotationDrivenBeanDefinitionParser的方法就是解析标签的核心方法。
  在该方法中,将会创建并配置多个mvc组件的bean定义到Spring容器中,这样的话,在后续的DispatcherServlet#onRefresh()方法中就不会初始化对应类型的默认组件了。
  从源码中可以看到,则将会注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter、CompositeUriComponentsContributorFactoryBean、MappedInterceptor、ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver、 BeanNameUrlHandlerMapping、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、HandlerMappingIntrospector11个组件的bean定义到容器中。
  如果只存在该标签而没有其他子标签配置,则还会注册ContentNegotiationManagerFactoryBean、FormattingConversionServiceFactoryBean、OptionalValidatorFactoryBean、LinkedHashMap(用于CORS配置)4个bean定义到容器中。
  该方法的源码很多,我们拆分开来讲解。最重要最常见的就是RequestMappingHandlerMapping和RequestMappingHandlerAdapter这两个bean定义了,因为它们用于支持基于注解的Spring MVC处理。

/**
 * 自动配置的RequestMappingHandlerMapping的beanName
 */
public static final String HANDLER_MAPPING_BEAN_NAME = RequestMappingHandlerMapping.class.getName();

/**
 * 自动配置的RequestMappingHandlerAdapter的beanName
 */
public static final String HANDLER_ADAPTER_BEAN_NAME = RequestMappingHandlerAdapter.class.getName();

public static final String CONTENT_NEGOTIATION_MANAGER_BEAN_NAME = "mvcContentNegotiationManager";

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 解析标签
 *
 * @param element 当前标签元素
 * @param context 解析上下文,从中可以获取各种配置
 * @return
 */
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext context) {
    Object source = context.extractSource(element);
    XmlReaderContext readerContext = context.getReaderContext();
    /*
     * 为标签创建一个CompositeComponentDefinition类型的bean定义组件
     * 该类型的bean定义,内部可以包含多个bean定义,因此又称为复合bean定义
     */
    CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
    //存入解析上下文内部的containingComponents集合中,入栈顶
    context.pushContainingComponent(compDefinition);

    /*内容协商处理,默认会注册ContentNegotiationManagerFactoryBean的bean定义*/
    RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, context);

    /*
     * 1 向容器注册RequestMappingHandlerMapping的bean定义
     * 该类可以处理基于注解的映射
     */
    RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
    handlerMappingDef.setSource(source);
    handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //添加order属性,使其位于handlerMappings集合链首位
    handlerMappingDef.getPropertyValues().add("order", 0);
    handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

    /*
     * 路径矩阵变量的配置
     */
    //如果具有enable-matrix-variables属性,即是否支持矩阵变量的属性
    if (element.hasAttribute("enable-matrix-variables")) {
        //获取该属性的值
        Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
        //添加removeSemicolonContent属性
        handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
    }
    /*
     * 一系列路径匹配参数的配置
     */
    configurePathMatchingProperties(handlerMappingDef, element, context);
    //当前的RequestMappingHandlerMapping的bean定义注册到子容器中
    //注册此RequestMappingHandlerMapping的bean定义到容器中,名为"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"
    readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);

    /*
     * cors跨域解决的配置
     * 默认会注册LinkedHashMap的bean定义
     */
    RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
    handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);

    /*
     * 2 创建ConfigurableWebBindingInitializer的bean定义
     * 该类用于在Spring应用程序上下文中基于声明式的配置WebDataBinder,允许与多个控制器/处理程序一起重用预配置的初始化程序。
     */

    /*
     * 解析"conversion-service"属性获取转换服务,
     * 默认会注册FormattingConversionServiceFactoryBean的bean定义,这是一个FactoryBean,实际是DefaultFormattingConversionService类型
     */
    RuntimeBeanReference conversionService = getConversionService(element, source, context);
    /*
     * 解析"validator"属性获取校验器
     * 默认会注册OptionalValidatorFactoryBean的bean定义,内部使用一种provider实现,通常是hibernate-validator依赖中的HibernateValidator
     */
    RuntimeBeanReference validator = getValidator(element, source, context);
    /*解析"message-codes-resolver"属性获取响应码解析器,默认是null*/
    RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

    /*新建ConfigurableWebBindingInitializer的bean定义*/
    RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
    bindingDef.setSource(source);
    bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //设置conversionService属性
    bindingDef.getPropertyValues().add("conversionService", conversionService);
    //设置validator属性
    bindingDef.getPropertyValues().add("validator", validator);
    //设置messageCodesResolver属性
    bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
    /*
     * 解析子标签,获取并配置消息转换器HttpMessageConverter
     * 主要用于处理基于ContentType的请求参数转换、封装
     *
     * 默认情况下会注册一系列的HttpMessageConverter
     * 在这其中,就会尝试自动配置配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖)
     */
    ManagedList<?> messageConverters = getMessageConverters(element, source, context);
    /*
     * 解析子标签,获取并配置方法参数解析器HandlerMethodArgumentResolver
     * 用于将给定请求的上下文中的数据解析为HandlerMethod方法的参数,相比于HttpMessageConverter,它更加上层
     * 即它负责处理Handler方法里的所有入参:包括自动封装、自动赋值、校验等等,
     * 具体的实现交给不同的子类来做,比如基于Name、基于ContentType
     *
     * 默认情况下为null
     */
    ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
    /*
     * 解析子标签,获取并配置返回值处理器HandlerMethodReturnValueHandler
     * 返回值处理器用于处理从处理程序方法调用返回的值
     *
     * 默认情况下为null
     */
    ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
    /*
     * 解析子标签,获取异步处理的超时时间
     * 就是解析此标签内部的子标签的default-timeout属性
     *
     * 默认情况下为null
     */
    String asyncTimeout = getAsyncTimeout(element);
    /*
     * 解析子标签,获取异步处理的线程池
     * 就是解析此标签内部的子标签的task-executor属性
     *
     * 默认情况下为null
     */
    RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
    /*
     * 解析子标签,获取异步处理CallableProcessingInterceptor类型拦截器
     * 就是解析此标签内部的子标签的子标签
     *
     * 默认情况下为空集合
     */
    ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
    /*
     * 解析子标签,获取异步处理DeferredResultProcessingInterceptor类型拦截器
     * 就是解析此标签内部的子标签的子标签
     *
     * 默认情况下为空集合
     */
    ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");

    /*
     * 3 向容器注册RequestMappingHandlerAdapter的bean定义
     * 该类可以帮助调用找到的Handler
     */
    RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
    handlerAdapterDef.setSource(source);
    handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //内容协商处理
    handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
    //WebDataBinder的初始化器
    handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
    //消息转换器
    handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
    /*
     * 如果具有jackson-databind依赖
     * 那么新建一个JsonViewRequestBodyAdvice、JsonViewResponseBodyAdvice类型的bean定义
     * 作为RequestMappingHandlerAdapter的requestBodyAdvice、responseBodyAdvice属性
     *
     * 用于支持具有Spring MVC的 @RequestMapping 或者 @ExceptionHandler的 方法上的@JsonView注解的解析
     */
    addRequestBodyAdvice(handlerAdapterDef);
    addResponseBodyAdvice(handlerAdapterDef);

    /*
     * 解析"ignore-default-model-on-redirect"属性,设置给RequestMappingHandlerAdapter的ignoreDefaultModelOnRedirect属性
     * 该属性用于确定在重定向中是否永远不会使用默认model属性,即使控制器方法中未声明RedirectAttributes参数也是如此。
     * 将其设置为 false 意味着如果控制器方法不声明RedirectAttributes参数,则默认model可能在重定向中使用,默认值为false。
     */
    if (element.hasAttribute("ignore-default-model-on-redirect")) {
        Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
        handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
    }
    //设置各种属性

    if (argumentResolvers != null) {
        handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
    }
    if (returnValueHandlers != null) {
        handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
    }
    if (asyncTimeout != null) {
        handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
    }
    if (asyncExecutor != null) {
        handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
    }

    handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
    handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
    //注册此RequestMappingHandlerAdapter的bean定义到容器中,名为"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
    readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);

    /*
     * 4 向容器注册CompositeUriComponentsContributorFactoryBean的bean定义
     *
     * 该类是一个FactoryBean,可以获取CompositeUriComponentsContributor
     * 用于辅助MvcUriComponentsBuilder构建UriComponentsBuilder
     */
    RootBeanDefinition uriContributorDef =
            new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
    uriContributorDef.setSource(source);
    uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
    uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
    String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
    readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);

    /*
     * 5 新建一个ConversionServiceExposingInterceptor的bean定义
     *
     * 这是一个Spring MVC的拦截器HandlerInterceptor的实现
     * 该拦截器用于在preHandle方法中将已配置的ConversionService放置在请求request的属性中(request.setAttribute)
     * 以便在请求处理期间可用。请求属性名称是"org.springframework.core.convert.ConversionService"
     */
    RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
    csInterceptorDef.setSource(source);
    //加入转换服务
    csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
    /*
     * 5 向容器注册一个MappedInterceptor的bean定义
     *
     * 这是一个Spring MVC的拦截器HandlerInterceptor的实现
     * 该拦截器内部还包含一个拦截器,并利用内部的拦截器真正的执行功能
     * MappedInterceptor它仅仅提供了匹配的功能以测试拦截器是否适用于给定的请求路径。
     */
    RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
    mappedInterceptorDef.setSource(source);
    mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //设置构造器参数
    //第一个参数includePatterns为null
    mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
    //第二个参数HandlerInterceptor为上面定义的ConversionServiceExposingInterceptor
    mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
    /*将MappedInterceptor注册到IoC容器中*/
    String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);

    /*
     * 6 向容器注册一个ExceptionHandlerExceptionResolver的bean定义
     *
     * 这是一个Spring MVC的异常处理器HandlerExceptionResolver的实现
     * 该异常处理器可以解析基于@ExceptionHandler注解的异常处理方法
     */
    RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
    methodExceptionResolver.setSource(source);
    methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //内容协商处理
    methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
    //消息转换器
    methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
    //期望排在handlerExceptionResolvers异常处理器集合链的首位
    methodExceptionResolver.getPropertyValues().add("order", 0);
    /*
     * 如果具有jackson-databind依赖
     * 那么新建一个JsonViewResponseBodyAdvice类型的bean定义
     * 作为RequestMappingHandlerAdapter的responseBodyAdvice属性
     *
     * 用于支持具有Spring MVC的 @RequestMapping 或者 @ExceptionHandler的 方法上的@JsonView注解的解析
     *
     * 这些通知应用于在使用@ResponseBody注释的控制器方法执行或返回ReturnEntity之后,
     * 但在将主体使用选定的HttpMessageConverter写入响应之前,添加一个或多个要调用的组件。
     */
    addResponseBodyAdvice(methodExceptionResolver);
    if (argumentResolvers != null) {
        methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
    }
    //返回值处理器
    if (returnValueHandlers != null) {
        methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
    }
    /*将ExceptionHandlerExceptionResolver注册到IoC容器中*/
    String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);

    /*
     * 7 向容器注册一个ResponseStatusExceptionResolver的bean定义
     *
     * 这是一个Spring MVC的异常处理器HandlerExceptionResolver的实现
     * 该异常处理器可以解析使用@ResponseStatus注解表示的异常,将注解中的值映射到HTTP状态代码并返回给客户端。
     */
    RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
    statusExceptionResolver.setSource(source);
    statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //期望排在handlerExceptionResolvers异常处理器集合链的第二位
    statusExceptionResolver.getPropertyValues().add("order", 1);
    /*将ResponseStatusExceptionResolver注册到IoC容器中*/
    String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);

    /*
     * 7 向容器注册一个DefaultHandlerExceptionResolver的bean定义
     *
     * 这是一个Spring MVC的异常处理器HandlerExceptionResolver的实现
     * 该异常处理器可以解析Spring MVC 引发的异常,将它们映射到HTTP状态代码并返回给客户端。
     */
    RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
    defaultExceptionResolver.setSource(source);
    defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //期望排在handlerExceptionResolvers异常处理器集合链的第三位
    defaultExceptionResolver.getPropertyValues().add("order", 2);
    /*将ResponseStatusExceptionResolver注册到IoC容器中*/
    String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);

    context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
    context.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
    context.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
    context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
    context.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
    context.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
    context.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));

    // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
    /*
     * 8 尝试注册其他默认组件
     * 包括BeanNameUrlHandlerMapping、HttpRequestHandlerAdapter
     * SimpleControllerHandlerAdapter、HandlerMappingIntrospector
     */
    MvcNamespaceUtils.registerDefaultComponents(context, source);

    context.popAndRegisterContainingComponent();

    return null;
}

2.1 注册RequestMappingHandlerMapping

  RequestMappingHandlerMapping是最常用的一个HandlerMapping,因为它支持查找通过@RequestMapping注解或者@RequestMapping作为元注解的方式实现的Handler。从spring3.1版本开始,废除了DefaultAnnotationHandlerMapping的使用。

/*
 * 1 向容器注册RequestMappingHandlerMapping的bean定义
 * 该类可以处理基于注解的映射
 */
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//添加order属性,使其位于handlerMappings集合链首位
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

/*
 * 路径矩阵变量的配置
 */
//如果具有enable-matrix-variables属性,即是否支持矩阵变量的属性
if (element.hasAttribute("enable-matrix-variables")) {
    //获取该属性的值
    Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
    //添加removeSemicolonContent属性
    handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
/*
 * 一系列路径匹配参数的配置
 */
configurePathMatchingProperties(handlerMappingDef, element, context);
//当前的RequestMappingHandlerMapping的bean定义注册到子容器中
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);

/*
 1. cors跨域解决的配置
 */
RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);

2.1.1 configurePathMatchingProperties配置路径匹配

  为此RequestMappingHandlerMapping配置一系列路径匹配的参数,比如后缀匹配、斜杠支持等。实际上就是解析此标签内部的子标签。
  大概步骤为:

  1. 解析XML标签的suffix-pattern属性,配置RequestMappingHandlerMapping的useSuffixPatternMatch属性。是否启用后缀匹配,默认true,即对url结尾支持".*"匹配,比如/user实际映射到/user.*,因此/user同时匹配/user.html,/user.jsp。
  2. 解析XML标签的trailing-slash属性,配置RequestMappingHandlerMapping的useTrailingSlashMatch属性。是否启动尾部斜线匹配,默认为true,即对指定的url会新增/,比如/user也会匹配/user/。
  3. 解析XML标签的registered-suffixes-only属性,配置RequestMappingHandlerMapping的useRegisteredSuffixPatternMatch属性。是否启用media type类型的匹配,即对指定的url新增*.json/*.xml等匹配,默认为false。
  4. 解析XML标签的path-helper属性,配置RequestMappingHandlerMapping的urlPathHelper属性。url路径帮助类,默认为UrlPathHelper类型。
  5. 解析XML标签的path-matcher属性,配置RequestMappingHandlerMapping的pathMatcher属性。url路径匹配类,默认为AntPathMather类型,支持模式匹配。
/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 为此RequestMappingHandlerMapping配置一系列路径匹配的参数,比如后缀匹配、斜杠支持等 * 就是解析此标签内部的子标签 * * @param handlerMappingDef 此RequestMappingHandlerMapping的bean定义 * @param element 当前标签元素 * @param context 解析上下文,从中可以获取各种配置 */ private void configurePathMatchingProperties( RootBeanDefinition handlerMappingDef, Element element, ParserContext context) { /*获取此标签内部的子标签*/ Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching"); //如果配置了标签 if (pathMatchingElement != null) { Object source = context.extractSource(element); //解析XML标签的suffix-pattern属性,配置RequestMappingHandlerMapping的useSuffixPatternMatch属性 //是否启用后缀匹配,默认true,即对url结尾支持".*"匹配,比如/user实际映射到/user.*,因此/user同时匹配/user.html,/user.jsp if (pathMatchingElement.hasAttribute("suffix-pattern")) { Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern")); handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch); } //解析XML标签的trailing-slash属性,配置RequestMappingHandlerMapping的useTrailingSlashMatch属性 //是否启动尾部斜线匹配,默认为true,即对指定的url会新增/,比如/user也会匹配/user/ if (pathMatchingElement.hasAttribute("trailing-slash")) { Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash")); handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch); } //解析XML标签的registered-suffixes-only属性,配置RequestMappingHandlerMapping的useRegisteredSuffixPatternMatch属性 //是否启用media type类型的匹配,即对指定的url新增*.json/*.xml等匹配,默认为false if (pathMatchingElement.hasAttribute("registered-suffixes-only")) { Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only")); handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch); } //解析XML标签的path-helper属性,配置RequestMappingHandlerMapping的urlPathHelper属性 //url路径帮助类,默认为UrlPathHelper类型 RuntimeBeanReference pathHelperRef = null; if (pathMatchingElement.hasAttribute("path-helper")) { pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper")); } pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, context, source); handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef); //解析XML标签的path-matcher属性,配置RequestMappingHandlerMapping的pathMatcher属性 //url路径匹配类,默认为AntPathMather类型,支持模式匹配 RuntimeBeanReference pathMatcherRef = null; if (pathMatchingElement.hasAttribute("path-matcher")) { pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher")); } pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source); handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef); } }

2.2 注册RequestMappingHandlerAdapter

  处理器适配器用于帮助DispatcherServlet调用找到的Handler,但是不管Handler实际如何调用。通常一种类型的Handler需要一种对应的HandlerAdapter。RequestMappingHandlerAdapter主要是适配注解处理器,注解处理器就是我们经常使用@RequestMapping注解及其作为元注解的方法处理器HandlerMethod。
  相比于默认加载的RequestMappingHandlerAdapter,在此创建的RequestMappingHandlerAdapter,将会作为bean定义存入容器中,并且进行了更加丰富的自定义过程。比如配置ConfigurableWebBindingInitializer、ConversionService、MappingJackson2HttpMessageConverter等等。
  从这里也能看出注解的作用,虽然和默认配置一样都会注册这些组件,但是该标签会进行更加丰富的自动配置

/*
 * 2 创建ConfigurableWebBindingInitializer的bean定义
 * 该类用于在Spring应用程序上下文中基于声明式的配置WebDataBinder,允许与多个控制器/处理程序一起重用预配置的初始化程序。
 */

/*解析"conversion-service"属性获取转换服务,默认是FormattingConversionServiceFactoryBean,实际是DefaultFormattingConversionService类型*/
RuntimeBeanReference conversionService = getConversionService(element, source, context);
/*解析"validator"属性获取校验器,默认是OptionalValidatorFactoryBean,内部使用一种provider实现,通常是hibernate-validator依赖中的HibernateValidator*/
RuntimeBeanReference validator = getValidator(element, source, context);
/*解析"message-codes-resolver"属性获取响应码解析器,默认是null*/
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

/*新建ConfigurableWebBindingInitializer的bean定义*/
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//设置conversionService属性
bindingDef.getPropertyValues().add("conversionService", conversionService);
//设置validator属性
bindingDef.getPropertyValues().add("validator", validator);
//设置messageCodesResolver属性
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
/*
 * 解析子标签,获取并配置消息转换器HttpMessageConverter
 * 主要用于处理基于ContentType的请求参数转换、封装
 *
 * 默认情况下会注册一系列的HttpMessageConverter
 * 在这其中,就会尝试自动配置配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖)
 */
ManagedList<?> messageConverters = getMessageConverters(element, source, context);
/*
 * 解析子标签,获取并配置方法参数解析器HandlerMethodArgumentResolver
 * 用于将给定请求的上下文中的数据解析为HandlerMethod方法的参数,相比于HttpMessageConverter,它更加上层
 * 即它负责处理Handler方法里的所有入参:包括自动封装、自动赋值、校验等等,
 * 具体的实现交给不同的子类来做,比如基于Name、基于ContentType
 *
 * 默认情况下为null
 */
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
/*
 * 解析子标签,获取并配置返回值处理器HandlerMethodReturnValueHandler
 * 返回值处理器用于处理从处理程序方法调用返回的值
 *
 * 默认情况下为null
 */
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
/*
 * 解析子标签,获取异步处理的超时时间
 * 就是解析此标签内部的子标签的default-timeout属性
 *
 * 默认情况下为null
 */
String asyncTimeout = getAsyncTimeout(element);
/*
 * 解析子标签,获取异步处理的线程池
 * 就是解析此标签内部的子标签的task-executor属性
 *
 * 默认情况下为null
 */
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
/*
 * 解析子标签,获取异步处理CallableProcessingInterceptor类型拦截器
 * 就是解析此标签内部的子标签的子标签
 *
 * 默认情况下为空集合
 */
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
/*
 * 解析子标签,获取异步处理DeferredResultProcessingInterceptor类型拦截器
 * 就是解析此标签内部的子标签的子标签
 *
 * 默认情况下为空集合
 */
ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");

/*
 * 3 向容器注册RequestMappingHandlerAdapter的bean定义
 * 该类可以帮助调用找到的Handler
 */
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//内容协商处理
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
//WebDataBinder的初始化器
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
//消息转换器
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
/*
 * 如果具有jackson-databind依赖
 * 那么新建一个JsonViewRequestBodyAdvice、JsonViewResponseBodyAdvice类型的bean定义
 * 作为RequestMappingHandlerAdapter的requestBodyAdvice、responseBodyAdvice属性
 *
 * 用于支持具有Spring MVC的 @RequestMapping 或者 @ExceptionHandler的 方法上的@JsonView注解的解析
 */
addRequestBodyAdvice(handlerAdapterDef);
addResponseBodyAdvice(handlerAdapterDef);

/*
 * 解析"ignore-default-model-on-redirect"属性,设置给RequestMappingHandlerAdapter的ignoreDefaultModelOnRedirect属性
 * 该属性用于确定在重定向中是否永远不会使用默认model属性,即使控制器方法中未声明RedirectAttributes参数也是如此。
 * 将其设置为 false 意味着如果控制器方法不声明RedirectAttributes参数,则默认model可能在重定向中使用,默认值为false。
 */
if (element.hasAttribute("ignore-default-model-on-redirect")) {
    Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
    handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
}
//设置各种属性

if (argumentResolvers != null) {
    handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
    handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
if (asyncTimeout != null) {
    handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
}
if (asyncExecutor != null) {
    handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
}

handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
//注册此RequestMappingHandlerAdapter的bean定义到容器中,名为"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);

2.2.1 配置ConfigurableWebBindingInitializer

  ConfigurableWebBindingInitializer用于在Spring应用程序上下文中基于声明式的配置WebDataBinder,允许与多个控制器/处理程序一起重用预配置的初始化程序。
  简单的说该类可以对每次请求的WebDataBinder进行初始化,而初始化的属性我们可以通过XML文件进行配置。
  下面的conversionService、validator、messageCodesResolver属性都是ConfigurableWebBindingInitializer的属性,而ConfigurableWebBindingInitializer又会被设置为RequestMappingHandlerAdapter的属性。

2.2.1.1 getConversionService获取转换服务

  解析"conversion-service"属性获取转换服务,默认是FormattingConversionServiceFactoryBean,该类是一个FactoryBean,因此实际的转换服务是DefaultFormattingConversionService类型。
  这里的ConversionService是一个全局的转换服务,主要用于Spring MVC的DataBinder,可以将基于字符串的请求值(例如请求参数,路径变量,请求头,Cookie等)转换为控制器方法参数的目标类型。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 解析"conversion-service"属性获取自定义的转换服务的bean定义 * 如果未指定,那么默认是FormattingConversionServiceFactoryBean,它是一个FactoryBean * 因此实际默认转换服务就是DefaultFormattingConversionService类型 * 可用于mvc参数数据绑定时的类型转换 * * @param element 当前标签元素 * @param source 来源 * @param context 解析上下文,从中可以获取各种配置 * @return 转换服务的bean定义,默认是DefaultFormattingConversionService类型 */ private RuntimeBeanReference getConversionService(Element element, @Nullable Object source, ParserContext context) { RuntimeBeanReference conversionServiceRef; //如果存在conversion-service属性 if (element.hasAttribute("conversion-service")) { //解析该属性为指定的转换服务的bean定义 conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service")); } else { //默认的转换服务,FormattingConversionServiceFactoryBean是一个FactoryBean //实际上的转换服务是DefaultFormattingConversionService类型 RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); conversionDef.setSource(source); conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); //注册bean定义并且获取beanName String conversionName = context.getReaderContext().registerWithGeneratedName(conversionDef); context.registerComponent(new BeanComponentDefinition(conversionDef, conversionName)); conversionServiceRef = new RuntimeBeanReference(conversionName); } return conversionServiceRef; }

2.2.1.2 getValidator获取校验器

  解析"validator"属性获取自定义的转换服务的bean定义,可用于mvc参数数据绑定时的基于注解的数据校验。
  如果未指定,那么自动查找类路径中的JSR-303 provider实现来配置一个类型为,org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean的Validator,通常我们使用hibernate-validatorHibernateValidator作为provider

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 解析"validator"属性获取自定义的转换服务的bean定义,可用于mvc参数数据绑定时的数据校验 * 如果未指定,那么自动查找类路径中的JSR-303 provider实现来配置一个类型为 * org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean的Validator * 通常我们使用hibernate-validator的HibernateValidator作为provider * * @param element 当前标签元素 * @param source 来源 * @param context 解析上下文,从中可以获取各种配置 * @return 转换服务的bean定义,默认是DefaultFormattingConversionService类型 */ @Nullable private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext context) { //如果存在validator属性 if (element.hasAttribute("validator")) { //解析该属性为指定的校验器的bean定义 return new RuntimeBeanReference(element.getAttribute("validator")); //如果具有validation-api的依赖 } else if (javaxValidationPresent) { //尝试创建OptionalValidatorFactoryBean类型的bean定义 RootBeanDefinition validatorDef = new RootBeanDefinition( "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean"); validatorDef.setSource(source); validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); String validatorName = context.getReaderContext().registerWithGeneratedName(validatorDef); context.registerComponent(new BeanComponentDefinition(validatorDef, validatorName)); return new RuntimeBeanReference(validatorName); } else { return null; } }

2.2.1.3 getMessageCodesResolver

  解析"message-codes-resolver"属性获取自定义的消息code解析器的bean定义。设置用于将异常解析为消息code的策略,将给定策略应用于此控制器使用的所有数据绑定器。默认为null。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 解析"message-codes-resolver"属性获取自定义的消息code解析器的bean定义 * 设置用于将异常解析为消息code的策略,将给定策略应用于此控制器使用的所有数据绑定器。 * * @param element 当前标签元素 * @return 转换服务的bean定义,默认是DefaultFormattingConversionService类型 */ @Nullable private RuntimeBeanReference getMessageCodesResolver(Element element) { //如果存在message-codes-resolver属性 if (element.hasAttribute("message-codes-resolver")) { //解析该属性为指定的校验器的bean定义 return new RuntimeBeanReference(element.getAttribute("message-codes-resolver")); } else { //返回null return null; } }

2.2.2 getMessageConverters获取消息转换器

  获取并配置消息转换器HttpMessageConverter,主要用于处理基于ContentType的参数转换、封装。就是解析此标签内部的子标签。

  默认情况下会注册一系列的HttpMessageConverter。在这其中,就会尝试自动配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖)。这就是如果我们配置了标签并且具有jackson-databind依赖,那么Spring MVC能够自动处理application/json的请求和响应的原理。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 获取并配置消息转换器,就是解析此标签内部的子标签 * 在这其中,就会尝试自动配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖) * * @param element 当前标签元素 * @param context 解析上下文,从中可以获取各种配置 * @param source 源 * @return 消息转换器集合,默认不为null */ private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext context) { //获取内部的子标签 Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters"); ManagedList<Object> messageConverters = new ManagedList<>(); /* * 1 如果存在子标签 * 那么添加自定义的消息转换器 */ if (convertersElement != null) { messageConverters.setSource(source); //继续获取该标签内部的子标签并遍历,每一个这些标签就表示一个消息转换器的bean for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) { //获取消息转换器定义(并非实例) Object object = context.getDelegate().parsePropertySubElement(beanElement, null); //加入到集合中 messageConverters.add(object); } } /* * 2 如果不存在子标签或者子标签的register-defaults属性为true(默认为true) * 那么添加默认的消息转换器 */ if (convertersElement == null || Boolean.parseBoolean(convertersElement.getAttribute("register-defaults"))) { messageConverters.setSource(source); //ByteArrayHttpMessageConverter messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source)); //StringHttpMessageConverter RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source); stringConverterDef.getPropertyValues().add("writeAcceptCharset", false); messageConverters.add(stringConverterDef); //ResourceHttpMessageConverter messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source)); //ResourceRegionHttpMessageConverter messageConverters.add(createConverterDefinition(ResourceRegionHttpMessageConverter.class, source)); //SourceHttpMessageConverter messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source)); //AllEncompassingFormHttpMessageConverter messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source)); if (romePresent) { messageConverters.add(createConverterDefinition(AtomFeedHttpMessageConverter.class, source)); messageConverters.add(createConverterDefinition(RssChannelHttpMessageConverter.class, source)); } /* * 如果具有jackson-dataformat-xml依赖 * 那么添加MappingJackson2XmlHttpMessageConverter,主要用于支持XML的请求和响应,实现XML的序列化和反序列化 */ if (jackson2XmlPresent) { //MappingJackson2XmlHttpMessageConverter Class<?> type = MappingJackson2XmlHttpMessageConverter.class; RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source); //Jackson2ObjectMapperFactoryBean,用于获取ObjectMapper GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source); jacksonFactoryDef.getPropertyValues().add("createXmlMapper", true); jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef); messageConverters.add(jacksonConverterDef); //否则如果具有javax.xml.bind.Binder接口,这位于rt.jar核心包中,一般都有 } else if (jaxb2Present) { //Jaxb2RootElementHttpMessageConverter messageConverters.add(createConverterDefinition(Jaxb2RootElementHttpMessageConverter.class, source)); } /* * 如果具有jackson-databind依赖 * 那么添加MappingJackson2HttpMessageConverter,主要用于支持application/json请求和响应,实现JSON的序列化和反序列化 */ if (jackson2Present) { //MappingJackson2HttpMessageConverter Class<?> type = MappingJackson2HttpMessageConverter.class; RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source); //Jackson2ObjectMapperFactoryBean,用于获取ObjectMapper GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source); jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef); messageConverters.add(jacksonConverterDef); //否则如果具有gson依赖,那么使用GsonHttpMessageConverter } else if (gsonPresent) { messageConverters.add(createConverterDefinition(GsonHttpMessageConverter.class, source)); } /* * 如果具有jackson-dataformat-smile依赖 */ if (jackson2SmilePresent) { Class<?> type = MappingJackson2SmileHttpMessageConverter.class; RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source); GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source); jacksonFactoryDef.getPropertyValues().add("factory", new SmileFactory()); jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef); messageConverters.add(jacksonConverterDef); } /* * 如果具有jackson-dataformat-cbor依赖 */ if (jackson2CborPresent) { Class<?> type = MappingJackson2CborHttpMessageConverter.class; RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source); GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source); jacksonFactoryDef.getPropertyValues().add("factory", new CBORFactory()); jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef); messageConverters.add(jacksonConverterDef); } } return messageConverters; }

2.2.3 getArgumentResolvers获取参数解析器

  获取并配置方法参数解析器HandlerMethodArgumentResolver,就是解析此标签内部的子标签。
  参数解析器用于将给定请求的上下文中的数据解析为HandlerMethod方法的参数,相比于HttpMessageConverter,它更加上层,即它负责处理Handler方法里的所有入参:包括自动封装、自动赋值、校验等等,具体的实现交给不同的子类来做,比如基于Name、基于ContentType。
  这里默认情况下为null。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 获取并配置参数解析器HandlerMethodArgumentResolver,就是解析此标签内部的子标签 * * @param element 当前标签元素 * @param context 解析上下文,从中可以获取各种配置 * @return 解析的参数解析器集合,默认为null */ @Nullable private ManagedList<?> getArgumentResolvers(Element element, ParserContext context) { //获取内部的子标签 Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers"); /* * 如果存在子标签,那么添加自定义的参数解析器 */ if (resolversElement != null) { //继续获取该标签内部的子标签并遍历,每一个这些标签就表示一个参数解析器的bean ManagedList<Object> resolvers = extractBeanSubElements(resolversElement, context); return wrapLegacyResolvers(resolvers, context); } //默认返回null return null; }

2.2.4 getReturnValueHandlers获取返回值解析器

  获取并配置返回值处理器HandlerMethodReturnValueHandler,就是解析此标签内部的子标签。
  返回值处理器用于处理从处理程序方法调用返回的值,这里默认为null。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 获取并配置返回值处理器HandlerMethodReturnValueHandler,就是解析此标签内部的子标签 *

* 返回值处理器用于处理从处理程序方法调用返回的值 * * @param element 当前标签元素 * @param context 解析上下文,从中可以获取各种配置 * @return 返回值处理器集合,默认为null */ @Nullable private ManagedList<?> getReturnValueHandlers(Element element, ParserContext context) { //获取内部的子标签 Element handlers = DomUtils.getChildElementByTagName(element, "return-value-handlers"); //继续获取该标签内部的子标签并遍历,每一个这些标签就表示一个参数解析器的bean //默认返回null return (handlers != null ? extractBeanSubElements(handlers, context) : null); }

2.2.5 获取异步处理属性

  标签内部的子标签提供了对Servlet 3的请求异步处理的常见配置,如果没有这些设置,那么将采用默认配置。

2.2.5.1 getAsyncTimeout获取异步处理超时时间

  获取异步处理的超时时间,就是解析此标签内部的子标签的default-timeout属性,默认为null。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 获取异步处理的超时时间,就是解析此标签内部的子标签的default-timeout属性 * * @param element 当前标签元素 * @return default-timeout属性值 */ @Nullable private String getAsyncTimeout(Element element) { Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support"); return (asyncElement != null ? asyncElement.getAttribute("default-timeout") : null); }

2.2.5.1 getAsyncExecutor获取异步处理线程池

  获取异步处理的线程池,就是解析此标签内部的子标签的task-executor属性,默认为null。

@Nullable
private RuntimeBeanReference getAsyncExecutor(Element element) {
   Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
   if (asyncElement != null && asyncElement.hasAttribute("task-executor")) {
      return new RuntimeBeanReference(asyncElement.getAttribute("task-executor"));
   }
   return null;
}
2.2.5.1 getInterceptors获取异步处理拦截器

  获取异步处理的CallableProcessingInterceptor和DeferredResultProcessingInterceptor类型的拦截器。解析此标签内部的子标签的子标签。

/**
 * AnnotationDrivenBeanDefinitionParser的方法
 * 

* 解析此标签内部的子标签的子标签 * 获取获取异步处理的callable类型拦截器 * * @param element 当前标签元素 * @param source 源 * @param context 解析上下文,从中可以获取各种配置 * @param interceptorElementName 拦截器标签名"callable-interceptors" * @return 异步处理的callable类型拦截器集合,默认为空集合 */ private ManagedList<?> getInterceptors( Element element, @Nullable Object source, ParserContext context, String interceptorElementName) { ManagedList<Object> interceptors = new ManagedList<>(); //获取内部的子标签 Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support"); if (asyncElement != null) { //获取子标签 Element interceptorsElement = DomUtils.getChildElementByTagName(asyncElement, interceptorElementName); if (interceptorsElement != null) { interceptors.setSource(source); //获取此标签内部的标签,每一个这些标签就表示一个callable类型拦截器的bean for (Element converter : DomUtils.getChildElementsByTagName(interceptorsElement, "bean")) { BeanDefinitionHolder beanDef = context.getDelegate().parseBeanDefinitionElement(converter); if (beanDef != null) { beanDef = context.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef); interceptors.add(beanDef); } } } } return interceptors; }

2.2.6 支持@JsonView注解解析

  如果具有jackson-databind依赖,那么新建一个JsonViewRequestBodyAdvice、JsonViewResponseBodyAdvice类型的bean定义。作为RequestMappingHandlerAdapterrequestBodyAdvice、responseBodyAdvice属性,用于支持具有Spring MVC的@RequestMapping 或者 @ExceptionHandler的方法上的@JsonView注解的解析。

protected void addRequestBodyAdvice(RootBeanDefinition beanDef) {
    if (jackson2Present) {
        beanDef.getPropertyValues().add("requestBodyAdvice",
                new RootBeanDefinition(JsonViewRequestBodyAdvice.class));
    }
}

protected void addResponseBodyAdvice(RootBeanDefinition beanDef) {
    if (jackson2Present) {
        beanDef.getPropertyValues().add("responseBodyAdvice",
                new RootBeanDefinition(JsonViewResponseBodyAdvice.class));
    }
}

3 总结

  在初始化IoC子容器的时候,将会解析Spring MVC的配置文件,在配置文件中就有可能初始化我们自定义的一些组件bean,也有可能会加载其他MVC配置标签,最常见的就是标签。
  标签为基于注解的SpringMVC驱动提供便捷配置,虽然Spring mvc5版本之后Spring MVC会默认加载大部分的默认组件,但是使用该标签仍然能够自动加载某些额外配置,比如自动发现并注册MappingJackson2HttpMessageConverter转换器以支持JSON数据交互的请求和响应。

相关文章:
  https://spring.io/
  Spring Framework 5.x 学习
  Spring MVC 5.x 学习
  Spring Framework 5.x 源码

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

你可能感兴趣的:(Spring,MVC,5.x,源码,新星计划,java,springmvc初始化,springmvc源码)