1、上篇博客讲到了SpringMVC的九大组件初始化,我们只看到了在什么时候初始化,并没有进行详细的原理分析,今天我们就来分析一下SpringMVC的九大组件是如何初始化的??????。
在DispatcherServelt中:
protected void initStrategies(ApplicationContext context) {
1、初始化文件上传解析器
this.initMultipartResolver(context);
2、初始化本地信息解析器(国际化组件)
this.initLocaleResolver(context);
3、初始化主题解析器
this.initThemeResolver(context);
4、初始化处理器映射器
this.initHandlerMappings(context);
5、初始化处理器适配器
this.initHandlerAdapters(context);
6、初始化异常解析器
this.initHandlerExceptionResolvers(context);
7、初始化请求跟视图名称的翻译器
this.initRequestToViewNameTranslator(context);
8、初始化视图解析器
this.initViewResolvers(context);
9、初始化动画映射管理器
this.initFlashMapManager(context);
}
先达成一个共识,在初始化九大组件的时候,Spring root webApplicationContext + SpringMVC webApplicationContext都是已经刷新完成的了,也就说我们的Service 业务bean + Controller业务bean都已经实例化+初始化完成,我们可以直接从容器中去获取到实例的。
2、初始化文件上传解析器MultipartResolver
源码如下:
private void initMultipartResolver(ApplicationContext context) {
try {
此处的context入参是SpringMVC的应用上下文,此处的初始化就是去SpringMVC的应用上下文中
获取一个beanName = multipartResolver 类型=MultipartResolver.class的bean实例,如果获取到就设置
当前的DispatcherServlet的multipartResolver属性=获取的文件上传解析器。如果没有获取到就表示没有配置
文件上传解析器。
this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
} catch (NoSuchBeanDefinitionException var3) {
this.multipartResolver = null;
if (this.logger.isDebugEnabled()) {
this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
}
}
}
初始化文件上传解析器MultipartResolver就完成了。
3、初始化本地信息解析器LocaleResolver
源码如下:
private void initLocaleResolver(ApplicationContext context) {
try {
还是老规矩先从SpringMVC的应用上下文中获取beanName = localeResolver,类型=LocaleResolver.class的bean,如果获取到了就设置给当前的DispatcherServlet的localeResolver属性。
this.localeResolver = (LocaleResolver)context.getBean("localeResolver", LocaleResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
} catch (NoSuchBeanDefinitionException var3) {
如果在SpringMVC上下文中没有获取到localeResolver,那就获取一个默认的localeResolver,如何获取默认的localeResolver,这个是重点???
获取到后设置到当前的DispatcherServlet的localeResolver中。
this.localeResolver = (LocaleResolver)this.getDefaultStrategy(context, LocaleResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Unable to locate LocaleResolver with name 'localeResolver': using default [" + this.localeResolver + "]");
}
}
}
获取默认的SpringMVC组件,入参为一个Class类型,表示需要获取什么类型的默认组件。
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
获取默认组件
List<T> strategies = this.getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1) {
throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
} else {
如果获取到多个那就返回集合中的第一个。
return strategies.get(0);
}
}
获取默认的组件
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
这个地方是重点,此处的defaultStrategies是DispatcherServlet的一个静态变量: private static final Properties defaultStrategies;
那么这个指是在什么时候加载的呢???我们在DispatcherServlet找到了一段静态代码块
/*
static {
try {
从类路径下加载名称为DispatcherServlet.properties的 文件,然后设置到静态变量
defaultStrategies中。
ClassPathResource resource = new ClassPathResource("DispatcherServlet.properties", DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException var1) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + var1.getMessage());
}
}
*/
从静态变量defaultStrategies中通过接口名称获取一个实现类的类全名字符串。
String value = defaultStrategies.getProperty(key);
if (value == null) {
如果没有获取到默认的组件策略,就返回一个空集合。
return new LinkedList();
} else {
如果获取到了就使用反射来实例化每一个默认的组件实现,组件是可以配置多个的。
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList(classNames.length);
String[] var7 = classNames;
int var8 = classNames.length;
for(int var9 = 0; var9 < var8; ++var9) {
String className = var7[var9];
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = this.createDefaultStrategy(context, clazz);
strategies.add(strategy);
} catch (ClassNotFoundException var13) {
throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13);
} catch (LinkageError var14) {
throw new BeanInitializationException("Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", var14);
}
}
return strategies;
}
}
这个就是初始化本地信息解析器LocaleResolver的原理,在我们没有配置SpringMVC组件的时候,SpringMVC会默认的提供一些组件的默认实现,提供的方式是在类路径下的DispatcherServlet.properties文件中指定,类似于spi。我们来看看SpringMVC为我们提供了那些默认的组件实现,我们找到DispatcherServlet.properties文件:
文件内容如下:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
如果开发者没有在SpringMVC中配置LocaleResolver,那么SpringMVC就会装载AcceptHeaderLocaleResolver在上下文中。
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
如果开发者没有在SpringMVC中配置ThemeResolver,那么SpringMVC就会装载FixedThemeResolver在上下文中。
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
如果开发者没有在SpringMVC中配置HandlerMapping,那么SpringMVC就会装载BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping 2个HandlerMapping在上下文中。
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
如果开发者没有在SpringMVC中配置HandlerAdapter,那么SpringMVC就会装载
HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、AnnotationMethodHandlerAdapter 3个HandlerAdapter在上下文中。
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
如果开发者没有在SpringMVC中配置HandlerExceptionResolver,那么SpringMVC就会装载
AnnotationMethodHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver 3个HandlerExceptionResolver在上下文中。
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
如果开发者没有在SpringMVC中配置RequestToViewNameTranslator,那么SpringMVC就会装载DefaultRequestToViewNameTranslator在上下文中
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
如果开发者没有在SpringMVC中配置ViewResolver,那么SpringMVC就会装载InternalResourceViewResolver在上下文中
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
如果开发者没有在SpringMVC中配置FlashMapManager,那么SpringMVC就会装载SessionFlashMapManager在上下文中
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
文件中SpringMVC帮我们设置了很多组件的一个默认实现,因为就算我们不配置SpringMVC组件,我们也能顺利的使用SpringMVC的功能。
4、初始化主题解析器ThemeResolver
源码如下:
private void initThemeResolver(ApplicationContext context) {
try {
一样的实现,先去SpringMVC上下文中获取,如果没有获取到就使用
DispatcherServlet.properties文件中默认的实现指定。
this.themeResolver = (ThemeResolver)context.getBean("themeResolver", ThemeResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
}
} catch (NoSuchBeanDefinitionException var3) {
this.themeResolver = (ThemeResolver)this.getDefaultStrategy(context, ThemeResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Unable to locate ThemeResolver with name 'themeResolver': using default [" + this.themeResolver + "]");
}
}
}
5、初始化处理器映射器HandlerMappings
源码如下:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
如果需要发现所有的HandlerMapping,默认的true
if (this.detectAllHandlerMappings) {
先从SpringMVC容器中查找所有类型为HandlerMapping的bean。
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
如果找到了先进行排序赋值给当前的DispatcherServlet
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
如果通过类型没有找到,那就在通过beanName=handlerMapping 类型=HandlerMapping.class去找,如果找到了就赋值给当前的DispatcherServlet。
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
;
}
}
if (this.handlerMappings == null) {
如果SpringMVC上下文中都没找到,那就使用默认的DispatcherServlet.properties文件中指定的实现。
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default");
}
}
}
6、初始化处理器适配器HandlerAdapters
套路都清楚了,那就 跟初始化处理器映射器HandlerMappings一致。
7、初始化异常处理解析器HandlerExceptionResolvers
套路都清楚了,那就 跟初始化处理器映射器HandlerMappings一致。
8、其他组件我们都不在一 一说明,都大同小异。
9、<mvc:annotation-driven /> mvc注解驱动原理
目前我们使用SpringMVC都是使用器注解功能,我们使用注解@Controller来进行组件添加,使用@RequestMapping来指定一个处理器映射等。。。这写都是注解驱动的功劳。
我们在传统的SpringMVC项目中,必须在SpringMVC的配置文件中添加注解驱动<mvc:annotation-driven />,我们才能使用注解来进行资源的映射处,那么<mvc:annotation-driven />的原理是啥呢???
我们先找到mvc命名空间的处理器MvcNameSpaceHandler:
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
public MvcNamespaceHandler() {
}
public void init() {
解析mvc的注解驱动
this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
this.registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
this.registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
this.registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
this.registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
this.registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
this.registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
this.registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
this.registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
我们找到SpringMVC的AnnotationDrivenBeanDefinitionParser注解驱动bean定义解析器,其源码如下:
BeanDefinition parse(Element element, ParserContext parserContext) 方法是核心:注册了很多SpringMVC运行的必要组件
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
XmlReaderContext readerContext = parserContext.getReaderContext();
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
1、配置一个内容协调器,用法:<mvc:annotation-driven content-negotiation-manager="xxxx"/>,如果指定了内容协调器就向SpringMVC容器注册内容协调器的bean定义,
如果没有指定内容协调器就注册一个类型为ContentNegotiationManagerFactoryBean.class的内容协调器,这个ContentNegotiationManagerFactoryBean实现了初始化接口InitializingBean
在初始化的时候会new一个ContentNegotiationManager并且添加一些默认的内容协调策略类如下:
ServletPathExtensionContentNegotiationStrategy(this.servletContext, this.mediaTypes) 根据媒体类型进行响应内容协调
HeaderContentNegotiationStrategy:根据请求头来进行响应内容协调
在此步骤中,SpringMVC会给ServletPathExtensionContentNegotiationStrategy内容协调器这是默认发媒体类型,设置默认的媒体类型方式如下:
1.1、如果类装器装载了“com.rometools.rome.feed.WireFeed”这个类,就添加atom=application/atom+xml、rss=application/rss+xml两个媒体类型。
1.2、如果类装器装载了“javax.xml.bind.Binder” 或者 "com.fasterxml.jackson.dataformat.xml.XmlMapper" 类, 就添加xml=application/xml媒体类型
1.3、如果类装器装载了“com.fasterxml.jackson.databind.ObjectMapper” 或者 "com.google.gson.Gson" 类,就添加json=application/json媒体类型。
RuntimeBeanReference contentNegotiationManager = this.getContentNegotiationManager(element, source, parserContext);
2、注册一个处理器映射器HandlerMapping,类型是RequestMappingHandlerMapping,这个映射器处理器是专门用来解析@RequestMapping的,
也是我们目前使用最多的处理器映射器,对于HandlerMapping我们只需要关注RequestMappingHandlerMapping就好,其他的基本上都已经过时了。
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(2);
设置注册的RequestMappingHandlerMapping的排序为0,表示优先使用,即在DispatcherServlet中的handlerMappings的集合中RequestMappingHandlerMapping在集合第一位。
handlerMappingDef.getPropertyValues().add("order", 0);
设置RequestMappingHandlerMapping处理器映射器的内容协调管理器属性。
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
Boolean enableMatrixVariables;
if (element.hasAttribute("enable-matrix-variables")) {
是否开启矩阵参数,很少使用,不用太多关注
enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
} else if (element.hasAttribute("enableMatrixVariables")) {
enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
配置RequestMappingHandlerMapping映射器处理器,配置处理器映射器的常用属性,如pathMatcher、urlPathHelper、useRegisteredSuffixPatternMatch等
this.configurePathMatchingProperties(handlerMappingDef, element, parserContext);
注册的RequestMappingHandlerMapping的名称是RequestMappingHandlerMapping.class.getName()即类的全类名。
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
设置RequestMappingHandlerMapping的跨域属性
RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations((Map)null, parserContext, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);
3、注册类型转换服务,用于请求参数与Controller方法的入参类型转换,
我们可以如下配置 <mvc:annotation-driven conversion-service="conversionService"/>指定类型转换服务,
如果我们没有进行明确是定,SpringMVC将会使用注册一个默认的类型为FormattingConversionServiceFactoryBean的类型转换服务类。
RuntimeBeanReference conversionService = this.getConversionService(element, source, parserContext);
4、获取参数校验器,我们可以这样配置 <mvc:annotation-driven validator="xxx"/>,配置的话就能获取到一个运行时期的bean应用,
如果我们没有配置的话SpringMVC将会注册一个默认的类型是org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean的参数校验器
RuntimeBeanReference validator = this.getValidator(element, source, parserContext);
5、获取消息code是解析器,同样我们可以在 <mvc:annotation-driven 标签中指定
RuntimeBeanReference messageCodesResolver = this.getMessageCodesResolver(element);
6、注册一个ConfigurableWebBindingInitializer数据绑定初始化组件
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(2);
设置数据绑定初始化组件的conversionService属性为上面已经注册的数据类型转换服务
bindingDef.getPropertyValues().add("conversionService", conversionService);
设置数据绑定初始化组件的validator属性为上面以及注册的校验器
bindingDef.getPropertyValues().add("validator", validator);
设置数据绑定初始化组件的messageCodesResolver属性为上面以及注册的消息code解析器
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
7、获取默认的MessageConverters消息转换器,我们依旧可以使用如下进行指定:
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true"> 默认就是true 会注册默认的messageConverters
<bean class="com.wzy.springmvc.customerconverter.UserConverter" />//此处是自定义的MessageConverters
<bean class="xxxx1"/>
</mvc:message-converters>
</mvc:annotation-driven>
如果我们没有进行指定,SpringMVC也会注册默认的MessageConverters。
ManagedList<?> messageConverters = this.getMessageConverters(element, source, parserContext);
8、获取参数解析器,我们依旧可以进行指定:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="xxxx"/>
<bean class="xxxx1"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
如果我们不指定的话,SpringMVC不会创建默认的参数解析器。
ManagedList<?> argumentResolvers = this.getArgumentResolvers(element, parserContext);
9、获取返回值处理器ReturnValueHandlers,我们同样可以指定:
<mvc:annotation-driven>
<mvc:return-value-handlers>
<bean class="xxxx"/>
<bean class="xxxx1"/>
</mvc:return-value-handlers>
</mvc:annotation-driven>
如果我们不指定的话,SpringMVC不会创建默认的返回值处理器。
ManagedList<?> returnValueHandlers = this.getReturnValueHandlers(element, parserContext);
10、异步处理器,我们也是可以配置的:
<mvc:annotation-driven>
<mvc:async-support default-timeout="1000" task-executor="taskExecuterBean">
<mvc:callable-interceptors>
<bean></bean>
</mvc:callable-interceptors>
<mvc:deferred-result-interceptors>
<bean></bean>
</mvc:deferred-result-interceptors>
</mvc:async-support>
</mvc:annotation-driven>
String asyncTimeout = this.getAsyncTimeout(element);
RuntimeBeanReference asyncExecutor = this.getAsyncExecutor(element);
ManagedList<?> callableInterceptors = this.getCallableInterceptors(element, source, parserContext);
ManagedList<?> deferredResultInterceptors = this.getDeferredResultInterceptors(element, source, parserContext);
11、注册一个HanderAdapter,类型是RequestMappingHandlerAdapter.class
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(2);
设置RequestMappingHandlerAdapter的内容协调器contentNegotiationManager
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
设置RequestMappingHandlerAdapter的web参数绑定初始化组件
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
设置RequestMappingHandlerAdapter的消息转换器列表
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
如果类装载器装载了“com.fasterxml.jackson.databind.ObjectMapper” 类,那就设置RequestMappingHandlerAdapter的requestBodyAdvice 请求体增强为一个JsonViewRequestBodyAdvice
this.addRequestBodyAdvice(handlerAdapterDef);
如果类装载器装载了“com.fasterxml.jackson.databind.ObjectMapper” 类,那就设置RequestMappingHandlerAdapter的responseBodyAdvice响应体增强为一个JsonViewResponseBodyAdvice
this.addResponseBodyAdvice(handlerAdapterDef);
Boolean ignoreDefaultModel;
if (element.hasAttribute("ignore-default-model-on-redirect")) {
ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
} else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
}
设置RequestMappingHandlerAdapter的自定义参数解析器属性customArgumentResolvers为之前注册的argumentResolvers
if (argumentResolvers != null) {
handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
设置RequestMappingHandlerAdapter的自定义返回值处理器属性customReturnValueHandlers为之前注册的returnValueHandlers
if (returnValueHandlers != null) {
handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
设置RequestMappingHandlerAdapter的异步请求超时时间属性asyncRequestTimeout为之前解析到的asyncTimeout
if (asyncTimeout != null) {
handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
}
设置RequestMappingHandlerAdapter的异步任务处理器属性taskExecutor为之前解析到的asyncExecutor
if (asyncExecutor != null) {
handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
}
设置RequestMappingHandlerAdapter的回调拦截器为上面解析到的callableInterceptors
handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
设置RequestMappingHandlerAdapter的延迟结果拦截器为上面解析到的deferredResultInterceptors
handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
最终把属性设置完成的处理器适配器RequestMappingHandlerAdapter注册到SpringMVC的应用上下文中。
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
12、注册一个复合的uri组件构建器,并设置其属性handlerAdapter = 之前注册的handlerAdapter,conversionService为之前注册的conversionService
RootBeanDefinition uriContributorDef = new RootBeanDefinition(AnnotationDrivenBeanDefinitionParser.CompositeUriComponentsContributorFactoryBean.class);
uriContributorDef.setSource(source);
uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
String uriContributorName = "mvcUriComponentsContributor";
readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);
13、注册一个属性转换暴露的拦截器,用于将之前注册的类型转换服务conversionService 设置到请求中 request.setAttribute(ConversionService.class.getName(), this.conversionService);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
14、注册一个映射拦截器,将其代理的真正拦截器设置为上一步注册的属性转换暴露的拦截器csInterceptorDef,用于可配置根据请求的path来决定是否给当前的请求暴露类型转换服务conversionService
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(source);
mappedInterceptorDef.setRole(2);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object)null);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);
15、注册一个异常里处理解析器,就是一个能够处理异常+解析异常资源的类,这个类的作用跟HandlerAdapter有点类似
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(2);
设置异常处理解析器的内容协调器contentNegotiationManager为之前注册的contentNegotiationManager
methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
设置异常处理解析器的消息转换器列表messageConverters为之前注册的messageConverters
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
methodExceptionResolver.getPropertyValues().add("order", 0);
this.addResponseBodyAdvice(methodExceptionResolver);
if (argumentResolvers != null) {
设置异常处理解析器的参数解析列表customArgumentResolvers为之前注册的argumentResolvers
methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
设置异常处理解析器的自定义返回值处理器列表customReturnValueHandlers为之前注册的returnValueHandlers
methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);
16、注册一个响应状态异常的解析器,用于根据响应的状态码 来从消息源messageSource中获取到错误的详细信息,然后设置到响应状态实例的错误原因属性里面。
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
statusExceptionResolver.setSource(source);
statusExceptionResolver.setRole(2);
statusExceptionResolver.getPropertyValues().add("order", 1);
String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);
17、注册一个默认的异常处理解析器,用于处理SpringMVC本省定义的一些异常。
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(2);
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
parserContext.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
18、最后在注册一些SprinMVC默认的一下组件,如下:
registerBeanNameUrlHandlerMapping(parserContext, source);
registerHttpRequestHandlerAdapter(parserContext, source);
registerSimpleControllerHandlerAdapter(parserContext, source);
registerHandlerMappingIntrospector(parserContext, source);
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
parserContext.popAndRegisterContainingComponent();
return null;
}
10、@EnableWebMvc注解
此注解的作用跟我们在xml里面配置<mvc:annotation-driven />的作用几乎是一样的,就是通过委派类DelegatingWebMvcConfiguration 向容器中注册SpringMVC的必要组件。
11、总结:我们主要讲解了SpringMVC的九大组件的初始化原理,一共有三种方式如下:
1、我们不做配置,SpringMVC会在类路径下的DispatcherServlet.properties中提供默认的配置,在DispatcherServlet初始化的时候实例化+初始化这些组件
2、通过在xml中开启SpringMVC的注解驱动<mvc:annotation-driven />,在SpringMVC应用上下文解析xml期间会实例化+初始化定义的组件,然后在DispatcherServlet初始化组件策略的方法中直接从SpringMVC的应用上下文中获取并赋值到DispatcherServlet的对象属性中。
3、使用@EnableWebMvc注解,其原理跟在xml中添加<mvc:annotation-driven />是一样的,这个只是Spring推从注解驱动的一种简化配置的方式而已。
在后面的博文中,我们会一 一介绍SpringMVC核心组件的工作原理。