基于最新Spring 5.x,详细介绍了Spring MVC 初始化流程的源码,主要包括<mvc:annotation-driven >配置标签的源码解析。
我正在参与CSDN《新程序员》有奖征文,活动地址:https://marketing.csdn.net/p/52c37904f6e1b69dc392234fff425442。
此前我们讲过了DispatcherServlet与子容器的初始化以及MVC组件的初始化,我们说过如果IoC容器中存在给定类型的组件,那么DispatcherServlet#onRefresh()
方法中就不会尝试初始化默认组件了。
而在初始化IoC子容器的时候,将会解析Spring MVC的配置文件,在配置文件中就有可能初始化我们自定义的一些组件bean,也有可能会加载其他MVC配置标签,最常见的就是<mvc:annotation-driven >
标签,实际上该标签就会向容器注册一些组件bean,并且还会进行额外的配置。
<mvc:annotation-driven>
标签为基于注解的SpringMVC驱动提供便捷配置,虽然Spring mvc5版本之后Spring MVC会默认加载大部分的默认组件,但是使用该标签仍然能够自动加载某些额外配置,比如自动发现并注册MappingJackson2HttpMessageConverter
转换器以支持JSON数据交互的请求和响应。
mvc系列标签同样属于扩展标签,根据我们此前学过的IoC容器初始化源码,扩展标签将会在IoC容器初始化的parseCustomElement
方法中解析,mvc标签的解析器位于MvcNamespaceHandler
类中:
可以知道<mvc:annotation-driven >
标签是由AnnotationDrivenBeanDefinitionParser
这个解析器来解析的。
下面的源码版本基于5.2.8.RELEASE
。源码解析基于传统的SSM项目,不适用于Spring Boot项目。
Spring MVC源码 系列文章
Spring MVC 初始化源码(1)—ContextLoaderListener与父上下文容器的初始化
Spring MVC 初始化源码(2)—DispatcherServlet与子容器的初始化以及MVC组件的初始化【一万字】
Spring MVC 初始化源码(3)—<mvc:annotation-driven >配置标签的源码解析
Spring MVC 初始化源码(4)—@RequestMapping注解的源码解析
文章目录
- Spring MVC源码 系列文章
- 1 AnnotationDrivenBeanDefinitionParser静态块
- 2 parse执行解析
- 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:annotation-driven/>
标签的核心方法。
在该方法中,将会创建并配置多个mvc组件的bean定义到Spring容器中,这样的话,在后续的DispatcherServlet#onRefresh()
方法中就不会初始化对应类型的默认组件了。
从源码中可以看到,则将会注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter、CompositeUriComponentsContributorFactoryBean、MappedInterceptor、ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver、 BeanNameUrlHandlerMapping、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、HandlerMappingIntrospector
这11
个组件的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的方法
* 解析<mvc:annotation-driven/>标签
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @param context 解析上下文,从中可以获取各种配置
* @return
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext context) {
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();
/*
* 为<mvc:annotation-driven/>标签创建一个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);
/*
* 解析<mvc:message-converters/>子标签,获取并配置消息转换器HttpMessageConverter
* 主要用于处理基于ContentType的请求参数转换、封装
*
* 默认情况下会注册一系列的HttpMessageConverter
* 在这其中,就会尝试自动配置配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖)
*/
ManagedList<?> messageConverters = getMessageConverters(element, source, context);
/*
* 解析<mvc:argument-resolvers/>子标签,获取并配置方法参数解析器HandlerMethodArgumentResolver
* 用于将给定请求的上下文中的数据解析为HandlerMethod方法的参数,相比于HttpMessageConverter,它更加上层
* 即它负责处理Handler方法里的所有入参:包括自动封装、自动赋值、校验等等,
* 具体的实现交给不同的子类来做,比如基于Name、基于ContentType
*
* 默认情况下为null
*/
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
/*
* 解析<mvc:return-value-handlers/>子标签,获取并配置返回值处理器HandlerMethodReturnValueHandler
* 返回值处理器用于处理从处理程序方法调用返回的值
*
* 默认情况下为null
*/
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
/*
* 解析<mvc:async-support/>子标签,获取异步处理的超时时间
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的default-timeout属性
*
* 默认情况下为null
*/
String asyncTimeout = getAsyncTimeout(element);
/*
* 解析<mvc:async-support/>子标签,获取异步处理的线程池
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的task-executor属性
*
* 默认情况下为null
*/
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
/*
* 解析<mvc:async-support/>子标签,获取异步处理CallableProcessingInterceptor类型拦截器
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的<mvc:callable-interceptors/>子标签
*
* 默认情况下为空集合
*/
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
/*
* 解析<mvc:async-support/>子标签,获取异步处理DeferredResultProcessingInterceptor类型拦截器
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的<mvc:deferred-result-interceptors>子标签
*
* 默认情况下为空集合
*/
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
配置一系列路径匹配的参数,比如后缀匹配、斜杠支持等。实际上就是解析此<mvc:annotation-driven/>
标签内部的<mvc:path-matching/>
子标签。
大概步骤为:
- 解析XML标签的
suffix-pattern
属性,配置RequestMappingHandlerMapping的useSuffixPatternMatch
属性。是否启用后缀匹配,默认true,即对url结尾支持".*"匹配,比如/user实际映射到/user.*,因此/user同时匹配/user.html,/user.jsp。 - 解析XML标签的
trailing-slash
属性,配置RequestMappingHandlerMapping的useTrailingSlashMatch
属性。是否启动尾部斜线匹配,默认为true,即对指定的url会新增/,比如/user也会匹配/user/。 - 解析XML标签的
registered-suffixes-only
属性,配置RequestMappingHandlerMapping的useRegisteredSuffixPatternMatch属性。是否启用media type类型的匹配,即对指定的url新增*.json/*.xml等匹配,默认为false。 - 解析XML标签的
path-helper
属性,配置RequestMappingHandlerMapping的urlPathHelper
属性。url路径帮助类,默认为UrlPathHelper类型。 - 解析XML标签的
path-matcher
属性,配置RequestMappingHandlerMapping的pathMatcher
属性。url路径匹配类,默认为AntPathMather类型,支持模式匹配。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 为此RequestMappingHandlerMapping配置一系列路径匹配的参数,比如后缀匹配、斜杠支持等
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:path-matching/>子标签
*
* @param handlerMappingDef 此RequestMappingHandlerMapping的bean定义
* @param element 当前<mvc:annotation-driven/>标签元素
* @param context 解析上下文,从中可以获取各种配置
*/
private void configurePathMatchingProperties(
RootBeanDefinition handlerMappingDef, Element element, ParserContext context) {
/*获取此<mvc:annotation-driven/>标签内部的<mvc:path-matching/>子标签*/
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
//如果配置了<mvc: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
等等。
从这里也能看出<mvc:annotation-driven/>
注解的作用,虽然和默认配置一样都会注册这些组件,但是该标签会进行更加丰富的自动配置
。
/*
* 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);
/*
* 解析<mvc:message-converters/>子标签,获取并配置消息转换器HttpMessageConverter
* 主要用于处理基于ContentType的请求参数转换、封装
*
* 默认情况下会注册一系列的HttpMessageConverter
* 在这其中,就会尝试自动配置配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖)
*/
ManagedList<?> messageConverters = getMessageConverters(element, source, context);
/*
* 解析<mvc:argument-resolvers/>子标签,获取并配置方法参数解析器HandlerMethodArgumentResolver
* 用于将给定请求的上下文中的数据解析为HandlerMethod方法的参数,相比于HttpMessageConverter,它更加上层
* 即它负责处理Handler方法里的所有入参:包括自动封装、自动赋值、校验等等,
* 具体的实现交给不同的子类来做,比如基于Name、基于ContentType
*
* 默认情况下为null
*/
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
/*
* 解析<mvc:return-value-handlers/>子标签,获取并配置返回值处理器HandlerMethodReturnValueHandler
* 返回值处理器用于处理从处理程序方法调用返回的值
*
* 默认情况下为null
*/
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
/*
* 解析<mvc:async-support/>子标签,获取异步处理的超时时间
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的default-timeout属性
*
* 默认情况下为null
*/
String asyncTimeout = getAsyncTimeout(element);
/*
* 解析<mvc:async-support/>子标签,获取异步处理的线程池
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的task-executor属性
*
* 默认情况下为null
*/
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
/*
* 解析<mvc:async-support/>子标签,获取异步处理CallableProcessingInterceptor类型拦截器
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的<mvc:callable-interceptors/>子标签
*
* 默认情况下为空集合
*/
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
/*
* 解析<mvc:async-support/>子标签,获取异步处理DeferredResultProcessingInterceptor类型拦截器
* 就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的<mvc:deferred-result-interceptors>子标签
*
* 默认情况下为空集合
*/
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的方法
* <p>
* 解析"conversion-service"属性获取自定义的转换服务的bean定义
* 如果未指定,那么默认是FormattingConversionServiceFactoryBean,它是一个FactoryBean
* 因此实际默认转换服务就是DefaultFormattingConversionService类型
* 可用于mvc参数数据绑定时的类型转换
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @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-validator
的HibernateValidator
作为provider
。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 解析"validator"属性获取自定义的转换服务的bean定义,可用于mvc参数数据绑定时的数据校验
* 如果未指定,那么自动查找类路径中的JSR-303 provider实现来配置一个类型为
* org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean的Validator
* 通常我们使用hibernate-validator的HibernateValidator作为provider
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @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的方法
* <p>
* 解析"message-codes-resolver"属性获取自定义的消息code解析器的bean定义
* 设置用于将异常解析为消息code的策略,将给定策略应用于此控制器使用的所有数据绑定器。
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @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
的参数转换、封装。就是解析此<mvc:annotation-driven/>
标签内部的<mvc:message-converters/>
子标签。
默认情况下会注册一系列的HttpMessageConverter
。在这其中,就会尝试自动配置MappingJackson2HttpMessageConverter
转换器(前提是项目具有jackson-databind
依赖)。这就是如果我们配置了<mvc:annotation-driven/>
标签并且具有jackson-databind
依赖,那么Spring MVC能够自动处理application/json
的请求和响应的原理。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 获取并配置消息转换器,就是解析此<mvc:annotation-driven/>标签内部的<mvc:message-converters/>子标签
* 在这其中,就会尝试自动配置MappingJackson2HttpMessageConverter转换器(前提是项目具有jackson-databind依赖)
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @param context 解析上下文,从中可以获取各种配置
* @param source 源
* @return 消息转换器集合,默认不为null
*/
private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext context) {
//获取内部的<mvc:message-converters>子标签
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
ManagedList<Object> messageConverters = new ManagedList<>();
/*
* 1 如果存在<mvc:message-converters>子标签
* 那么添加自定义的消息转换器
*/
if (convertersElement != null) {
messageConverters.setSource(source);
//继续获取该标签内部的<bean />和<ref />子标签并遍历,每一个这些标签就表示一个消息转换器的bean
for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) {
//获取消息转换器定义(并非实例)
Object object = context.getDelegate().parsePropertySubElement(beanElement, null);
//加入到集合中
messageConverters.add(object);
}
}
/*
* 2 如果不存在<mvc:message-converters>子标签或者<mvc:message-converters>子标签的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
,就是解析此<mvc:annotation-driven/>
标签内部的<mvc:argument-resolvers/>
子标签。
参数解析器用于将给定请求的上下文中的数据解析为HandlerMethod
方法的参数,相比于HttpMessageConverter
,它更加上层,即它负责处理Handler方法里的所有入参:包括自动封装、自动赋值、校验等等,具体的实现交给不同的子类来做,比如基于Name、基于ContentType。
这里默认情况下为null。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 获取并配置参数解析器HandlerMethodArgumentResolver,就是解析此<mvc:annotation-driven/>标签内部的<mvc:argument-resolvers/>子标签
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @param context 解析上下文,从中可以获取各种配置
* @return 解析的参数解析器集合,默认为null
*/
@Nullable
private ManagedList<?> getArgumentResolvers(Element element, ParserContext context) {
//获取内部的<mvc:argument-resolvers/>子标签
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
/*
* 如果存在<mvc:message-converters>子标签,那么添加自定义的参数解析器
*/
if (resolversElement != null) {
//继续获取该标签内部的<bean />和<ref />子标签并遍历,每一个这些标签就表示一个参数解析器的bean
ManagedList<Object> resolvers = extractBeanSubElements(resolversElement, context);
return wrapLegacyResolvers(resolvers, context);
}
//默认返回null
return null;
}
2.2.4 getReturnValueHandlers获取返回值解析器
获取并配置返回值处理器HandlerMethodReturnValueHandler
,就是解析此<mvc:annotation-driven/>
标签内部的<mvc:return-value-handlers/>
子标签。
返回值处理器用于处理从处理程序方法调用返回的值,这里默认为null。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 获取并配置返回值处理器HandlerMethodReturnValueHandler,就是解析此<mvc:annotation-driven/>标签内部的<mvc:return-value-handlers/>子标签
* <p>
* 返回值处理器用于处理从处理程序方法调用返回的值
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @param context 解析上下文,从中可以获取各种配置
* @return 返回值处理器集合,默认为null
*/
@Nullable
private ManagedList<?> getReturnValueHandlers(Element element, ParserContext context) {
//获取内部的<mvc:return-value-handlers/>子标签
Element handlers = DomUtils.getChildElementByTagName(element, "return-value-handlers");
//继续获取该标签内部的<bean />和<ref />子标签并遍历,每一个这些标签就表示一个参数解析器的bean
//默认返回null
return (handlers != null ? extractBeanSubElements(handlers, context) : null);
}
2.2.5 获取异步处理属性
<mvc:annotation-driven/>
标签内部的<mvc:async-support/>
子标签提供了对Servlet 3
的请求异步处理的常见配置,如果没有这些设置,那么将采用默认配置。
2.2.5.1 getAsyncTimeout获取异步处理超时时间
获取异步处理的超时时间,就是解析此<mvc:annotation-driven/>
标签内部的<mvc:async-support/>
子标签的default-timeout
属性,默认为null。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 获取异步处理的超时时间,就是解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的default-timeout属性
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @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获取异步处理线程池
获取异步处理的线程池,就是解析此<mvc:annotation-driven/>
标签内部的<mvc:async-support/>
子标签的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
类型的拦截器。解析此<mvc:annotation-driven/>
标签内部的<mvc:async-support/>
子标签的<mvc:callable-interceptors/>和<mvc:deferred-result-interceptors>
子标签。
/**
* AnnotationDrivenBeanDefinitionParser的方法
* <p>
* 解析此<mvc:annotation-driven/>标签内部的<mvc:async-support/>子标签的<mvc:callable-interceptors/>子标签
* 获取获取异步处理的callable类型拦截器
*
* @param element 当前<mvc:annotation-driven/>标签元素
* @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<>();
//获取内部的<mvc:async-support/>子标签
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
if (asyncElement != null) {
//获取<mvc:callable-interceptors/>子标签
Element interceptorsElement = DomUtils.getChildElementByTagName(asyncElement, interceptorElementName);
if (interceptorsElement != null) {
interceptors.setSource(source);
//获取此标签内部的<bean/>标签,每一个这些标签就表示一个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定义。作为RequestMappingHandlerAdapter
的requestBodyAdvice、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配置标签,最常见的就是<mvc:annotation-driven >
标签。
<mvc:annotation-driven>
标签为基于注解的SpringMVC驱动提供便捷配置,虽然Spring mvc5版本之后Spring MVC会默认加载大部分的默认组件,但是使用该标签仍然能够自动加载某些额外配置,比如自动发现并注册MappingJackson2HttpMessageConverter
转换器以支持JSON数据交互的请求和响应。
相关文章:
https://spring.io/
Spring Framework 5.x 学习
Spring MVC 5.x 学习
Spring Framework 5.x 源码
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!