spring基本使用(18)-springMVC2-SpringMVC九大组件的初始化原理分析

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核心组件的工作原理。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值