SpringMVC深度探险(四)——SpringMVC核⼼配置⽂件详解
在上⼀篇⽂章中,我们从DispatcherServlet谈起,最终为读者详细分析了SpringMVC的初始化主线的全部过程。整个初始化主线的研究,其实始终围绕着DispatcherServlet、WebApplicationContext和组件这三⼤元素之间的关系展开。
在⽂章写完之后,也陆续收到了⼀些反馈,其中⽐较集中的问题,是有关WebApplicationContext对组件进⾏初始化的过程交代的不够清楚。所以,本⽂作为上⼀篇⽂章的续⽂,就试图来讲清楚这个话题。
SpringMVC的核⼼配置⽂件
SpringMVC的核⼼配置⽂件,我们从整个专栏的第⼀篇⽂章就开始接触。所以,我们在这⾥⾸先对SpringMVC的核⼼配置⽂件做⼀些概括性的回顾。
downpour 写道
结论 SpringMVC的核⼼配置⽂件是构成SpringMVC应⽤程序的必要元素之⼀。
这是我们在讲有关SpringMVC的构成要素时就曾经提到过的⼀个重要结论。当时我们所说的另外两⼤必要元素就是DispatcherServlet和Controller。因⽽,SpringMVC的核⼼配置⽂件在整个应⽤程序中所起到的作⽤也是举⾜轻重的。这也就是我们在这⾥需要补充对这个⽂件进⾏详细分析的原因。
downpour 写道
结论 SpringMVC的核⼼配置⽂件与传统的Spring Framework的配置⽂件是⼀脉相承的。
这个结论很容易理解。作为Spring Framework的⼀部分,我们可以认为SpringMVC是整个Spring Framework的⼀个组件。因⽽两者的配置体系和管理体系完全相同也属情理之中。实际上,SpringMVC所采取的策略,就是借⽤Spring Framework强⼤的容器(ApplicationContext)功能,⽽绝⾮⾃⾏实现。
downpour 写道
结论 SpringMVC的核⼼配置⽂件是架起DispatcherServlet与WebApplicationContext之间的桥梁。
我们在l中指定SpringMVC的⼊⼝程序DispatcherServlet时,实际上蕴含了⼀个对核⼼配置⽂件的指定过程([servlet-name]-l)。当然,我们也可以明确指定这个核⼼配置⽂件的位置。这些配置选项,我们已经在上⼀篇⽂章中详细介绍过,这⾥不再重复。
⽽上⾯这⼀结论,除了说明两者之间的配置关系之外,还包含了⼀层运⾏关系:DispatcherServlet负责对WebApplicationContext进⾏初始化,⽽初始化的依据,就是这个SpringMVC的核⼼配置⽂件。所以,SpringMVC的核⼼配置⽂件的内容解读将揭开整个SpringMVC初始化主线的全部秘密。
如果我们把这个结论与上⼀个结论结合起来来看,也正因为SpringMVC的核⼼配置⽂件使⽤了与Spring Framework相同的格式,才使其成为DispatcherServlet驾驭Spring的窗⼝。downpour 写道
结论 SpringMVC的核⼼配置⽂件是SpringMVC中所有组件的定义窗⼝,通过它我们可以指定整个SpringMVC的⾏为⽅式。
这个结论告诉了我们SpringMVC核⼼配置⽂件在整个框架中的作⽤。组件⾏为模式的多样化,决定了我们必须借助⼀个容器(WebApplicationContext)来进⾏统⼀的管理。⽽SpringMVC的核⼼配置⽂件,就是我们进⾏组件管理的窗⼝。
核⼼配置⽂件概览
说了那么多有关SpringMVC核⼼配置⽂件的结论,我们不妨来看⼀下这个配置⽂件的概况:
<?xml version="1.0" encoding="UTF-8"?>
2.<beans xmlns="/schema/beans"
3.      xmlns:mvc="/schema/mvc"
4.      xmlns:context="/schema/context"
5.      xmlns:xsi="/2001/XMLSchema-instance"
6.      xsi:schemaLocation="/schema/beans
7.            /schema/beans/spring-beans-3.1.xsd
8.            /schema/context
9.            /schema/context/spring-context-3.1.xsd
10.            /schema/mvc
11.            /schema/mvc/spring-mvc-3.1.xsd">
12.
13.    <!-- Enables the Spring MVC @Controller programming model -->
14.    <mvc:annotation-driven />
15.
16.    <context:component-scan base-package="com.demo2do.ller"/>
17.
18.    <!-- Handles HTTP GET requests for /static/** by efficiently serving up static resources in the ${webappRoot}/static/ directory -->
19.    <mvc:resources mapping="/static/**" location="/static/"/>
20.
21.    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
22.        <property name="prefix" value="/"/>
23.        <property name="suffix" value=".jsp"/>
24.    </bean>
25.
26.</beans>
这是⼀个⾮常典型的SpringMVC核⼼配置⽂件。虽然我们在这⾥⼏乎对每⼀段重要的配置都做了注释,不过可能对于毫⽆SpringMVC开发经验的读者来说,这段配置基本上还⽆法阅读。所以接下来,我们就试图对这个⽂件中的⼀些细节加以说明。
配置⽂件中⾸先进⼊我们眼帘的是它的头部的⼀⼤段声明:
1.<?xml version="1.0" encoding="UTF-8"?>
2.<beans xmlns="/schema/beans"
3.      xmlns:mvc="/schema/mvc"
4.      xmlns:context="/schema/context"
5.      xmlns:xsi="/2001/XMLSchema-instance"
6.      xsi:schemaLocation="/schema/beans
7.            /schema/beans/spring-beans-3.1.xsd
8.            /schema/context
9.            /schema/context/spring-context-3.1.xsd
10.            /schema/mvc
11.            /schema/mvc/spring-mvc-3.1.xsd">
12.      ......
13.</beans>
这个部分是整个SpringMVC核⼼配置⽂件的关键所在。这⼀段声明,被称之为Schema-based XML的声明部分。有关Schema-based XML的概念,读者可以参考Spring官⽅的reference:
为了帮助读者快速理解,我们稍后会专门开辟章节针对Schema-based XML的来龙去脉进⾏讲解。
【组件定义】
除了头部声明部分的其他配置部分,就是真正的组件定义部分。在这个部分中,我们可以看到两种不同类型的配置定义模式:
1. 基于Schema-based XML的配置定义模式
1.<mvc:annotation-driven />
2. 基于Traditional XML的配置定义模式
1.<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
2.      <property name="prefix" value="/"/>
3.      <property name="suffix" value=".jsp"/>
4.l</bean>
两种不同的组件定义模式,其⽬的是统⼀的:对SpringMVC中的组件进⾏声明,指定组件的⾏为⽅式。
虽然两种不同的组件定义模式的外在表现看上去有所不同,但是SpringMVC在对其进⾏解析时最终都会将其转化为组件的定义⽽加载到WebApplicationContext之中进⾏管理。所以我们需要理解的是蕴藏在配置背后的⽬的⽽⾮配置本⾝的形式。
⾄于这两种不同的配置形式之间的关系,我们稍后会在Schema-based XML的讲解中详细展开。
Schema-based XML
【基本概念】
Schema-based XML本⾝并不是SpringMVC或者Spring Framework独创的⼀种配置模式。我们可以看看W3C对于其⽤途的⼀个⼤概解释:
W3C 写道
The purpose of an XSD schema is to define and describe a class of XML documents by using schema components to constrain and document the meaning, usage and relationships of their constituent parts: datatypes, elements and their content and attributes and their values. Schemas can also provide for the specification of additional document information, such as normalization and defaulting of attribute and element values. Schemas have facilities for self-documentation. Thus, XML Schema Definition Language: Structures can be used to define, describe and catalogue XML vocabularies for classes of XML documents.
这个解释稍微有点抽象。所以我们可以来看看Spring官⽅reference对于引⼊Schema-based XML的说法:
Spring Reference 写道
The central motivation for moving to XML Schema based configuration files was to make Spring XML configuration easier. The 'classic' <bean/>-based approach is good, but its generic-nature comes with a price in terms of configuration overhead.
也就是说,我们引⼊Schema-based XML是为了对Traditional的XML配置形式进⾏简化。通过Schema的定义,把⼀些原本需要通过⼏个bean的定义或者复杂的bean的组合定义的配置形式,⽤另外⼀种简单⽽可读的配置形式呈现出来。
所以,我们也可以由此得出⼀些有⽤的推论:
downpour 写道
Schema-based XML可以代替Traditional的XML配置形式,在Spring容器中进⾏组件的定义。
这⾥的代替⼀词⾮常重要,这就意味着传统的XML配置形式在这⾥会被颠覆,我们在对Schema-based XML进⾏解读时,需要使⽤⼀种全新的语义规范来理解。
Schema-based XML可以极⼤改善配置⽂件的可读性并且缩⼩配置⽂件的规模。
这是从引⼊Schema-based XML的⽬的反过来得出的推论。因为如果引⼊Schema-based XML之后,整个配置变得更加复杂,那么Schema-based XML的引⼊也就失去了意义。
同时,笔者在这⾥需要特别强调的是Schema-based XML的引⼊,实际上是把原本静态的配置动态化、过程化。有关这⼀点,我们稍后会有说明。
【引⼊⽬的】
在早期的Spring版本中,只有Traditional XML⼀种组件定义模式。当时,XML作为Java最好的朋友,⾃然⽽然在整个框架中起到了举⾜轻重的作⽤。根据Spring的设计原则,所有纳⼊WebApplicationContext中管理的对象,都被映射为XML中的⼀个<bean>节点,通过对于<bean>节点的⼀个完整描述,我们可以有效地将整个应⽤程序中所有的对象都纳⼊到⼀个统⼀的容器中进⾏管理。
这种统⼀化的描述,带来的是管理上的便利,不过同时也带来了逻辑上的困扰。因为统⼀的节点,降低了配置的难度,我们⼏乎只需要将<bean>节点与Java的对象模型对应起来即可。(有⼀定经验的Spring程序员可以回忆⼀下,我们在编写Spring配置⽂件时,是否也是⼀个将配置选项与Java对象中属性或者⽅法对应起来的过程)但是这样的配置形式本⾝并不具备逻辑语义,也就是说我们⽆法⾮常直观地看出某⼀个特定的<bean>定义,从逻辑上它到底想说明什么问题?
这也就是后来Schema-based XML开始被引⼊并流⾏开来的重要原因。从形式上看,Schema-based XML相⽐较Traditional XML⾄少有三个⽅⾯的优势:
namespace —— 拥有很明确的逻辑分类
element —— 拥有很明确的过程语义
attributes —— 拥有很简明的配置选项
这三⽅⾯的优势,我们可以⽤⼀幅图来进⾏说明:
在图中,我们分别⽤上下两层来说明某⼀个配置节点的结构名称以及它们的具体作⽤。由此可见,Schema-based XML中的配置节点拥有⽐较鲜明的功能特性,通过namespace、element和attributes这三⼤元素之间的配合,共同完成对⼀个动态过程的描述。
例如,<mvc:annotation-driven />这段配置想要表达的意思,就是在mvc的空间内实现Annotation驱动的配置⽅式。其中,mvc表⽰配置的有效范围,annotation-driven则表达了⼀个动态的过程,实际的逻辑含义是:整个SpringMVC的实现是基于Annotation模式,请为我注册相关的⾏为模式。
网络上xml是什么意思这种配置⽅式下,可读性⼤⼤提⾼:我们⽆需再去理解其中的实现细节。同时,配置的简易性也⼤⼤提⾼:我们甚⾄不⽤去关⼼哪些bean被定义了。
所以总体来说,Schema-based XML的引⼊,对于配置的简化是⼀个极⼤的进步。
【构成要素】
在Spring中,⼀个Schema-based XML有两⼤构成要素:过程实现和配置定义。
先谈谈过程实现。所谓过程实现,其实就是我们刚才所举的那个例⼦中,实现实际背后逻辑的过程。这个过程由两个Java接⼝来进⾏表述:
NamespaceHandler —— 对Schema定义中namespace的逻辑处理接⼝
BeanDefinitionParser —— 对Schema定义中element的逻辑处理接⼝
很显然,NamespaceHandler是⼊⼝程序,它包含了所有的属于该namespace定义下所有element的处理调⽤,所以BeanDefinitionParser的实现就成为了NamespaceHandler的调⽤对象了。这⼀点,我们可以通过NamesapceHandler的MVC实现类来加以证明:
public void init() {
2.    registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
3.    registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
4.    registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
5.    registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
6.    registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
7.}
我们可以看到,MvcNamespaceHandler的执⾏,只不过依次调⽤了不同的BeanDefinitionParser的实现类⽽已,⽽每⼀个BeanDefinitionParser的实现,则对应于Schema定义中的element逻辑处理。例如,AnnotationDrivenBeanDefinitionParser对应于:<mvc:annotation-driven />这个element实现;ResourcesBeanDefinitionParser则对应于<mvc:resources />的实现等等。
所以,要具体了解每个element的⾏为过程,只要研究每⼀个BeanDefinitionParser的实现类即可。我们以整个MVC空间中最重要的⼀个节点<mvc:annotation-driven />为例,对AnnotationDrivenBeanDefinitionParser进⾏说明,其源码如下:
public BeanDefinition parse(Element element, ParserContext parserContext) {
2.    Object source = actSource(element);
3.
4.    CompositeComponentDefinition compDefinition = new TagName(), source);
5.    parserContext.pushContainingComponent(compDefinition);
6.
7.    RootBeanDefinition methodMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
8.    methodMappingDef.setSource(source);
9.    methodMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
10.    PropertyValues().add("order", 0);
11.    String methodMappingName = ReaderContext().registerWithGeneratedName
(methodMappingDef);
12.
13.    RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
16.
17.    RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
18.    bindingDef.setSource(source);
19.    bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
20.    PropertyValues().add("conversionService", conversionService);
21.    PropertyValues().add("validator", validator);
22.    PropertyValues().add("messageCodesResolver", messageCodesResolver);
23.
24.    ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
25.    ManagedList<?> argumentResolvers = getArgumentResolvers(element, source, parserContext);
26.    ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, source, parserContext);
27.
28.    RootBeanDefinition methodAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
29.    methodAdapterDef.setSource(source);
30.    methodAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
31.    PropertyValues().add("webBindingInitializer", bindingDef);
32.    PropertyValues().add("messageConverters", messageConverters);
33.    if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
34.        Boolean ignoreDefaultModel = Boolean.Attribute("ignoreDefaultModelOnRedirect"));
35.
37.    }
38.    if (argumentResolvers != null) {
39.        PropertyValues().add("customArgumentResolvers", argumentResolvers);
40.    }
41.    if (returnValueHandlers != null) {
42.            PropertyValues().add("customReturnValueHandlers", returnValueHandlers);
43.    }
44.    String methodAdapterName = ReaderContext().registerWithGeneratedName(methodAdapterDef);
45.
46.    RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
47.    csInterceptorDef.setSource(source);
48.    ConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
49.    RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
50.    mappedCsInterceptorDef.setSource(source);
51.        mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
52.        ConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
53.        ConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
54.    String mappedInterceptorName = ReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
55.
56.    RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
57.    methodExceptionResolver.setSource(source);
58.        methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
59.        PropertyValues().add("messageConverters", messageConverters);
60.        PropertyValues().add("order", 0);
61.    String methodExceptionResolverName =
ReaderContext().registerWithGeneratedName(methodExceptionResolver);
63.
64.    RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
65.    responseStatusExceptionResolver.setSource(source);
66.        responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
67.        PropertyValues().add("order", 1);
68.    String responseStatusExceptionResolverName =
69.                ReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);
70.
71.    RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
72.    defaultExceptionResolver.setSource(source);
73.        defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
74.        PropertyValues().add("order", 2);
75.    String defaultExceptionResolverName =
76.                ReaderContext().registerWithGeneratedName(defaultExceptionResol
ver);
77.
78.    isterComponent(new BeanComponentDefinition(methodMappingDef, methodMappingName));
79.    isterComponent(new BeanComponentDefinition(methodAdapterDef, methodAdapterName));
80.    isterComponent(new BeanComponentDefinition(methodExceptionResolver, methodExceptionResolverName));
81.    isterComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
82.    isterComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
83.    isterComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
84.
85.    // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
86.        isterDefaultComponents(parserContext, source);
87.
88.    parserContext.popAndRegisterContainingComponent();
89.
90.    return null;
91.}
整个过程看上去稍显凌乱,不过我们发现其中围绕的⼀条主线就是:使⽤编程的⽅式来对bean进⾏注
册。也就是说,<mvc:annotation-driven />这样⼀句配置,顶上了我们如此多的bean 定义。难怪Schema-based XML被誉为是简化XML配置的绝佳帮⼿了。
有了过程实现,我们再来谈谈配置定义。配置定义的⽬的⾮常简单,就是通过⼀些配置⽂件,将上述的过程实现类串联起来,从⽽完成整个Schema-based XML的定义。
整个配置定义,也分为两个部分:
Schema定义 —— ⼀个xsd⽂件,描述整个Schema空间中element和attribute的定义
Where —— 组件的声明在哪⾥?
How —— 组件是如何被注册的?
What —— 究竟哪些组件被注册了?
对于这三个问题的研究,我们需要结合⽇志和Schema based XML的运⾏机理来共同进⾏分析。
引⽤
[main] INFO /sample - Initializing Spring FrameworkServlet 'dispatcher'
19:49:48,670  INFO XmlWebApplicationContext:495 - Refreshing WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Feb 16 19:49:48 CST 2012]; parent: Root WebApplicationContext
19:49:48,674  INFO XmlBeanDefinitionReader:315 - Loading XML bean definitions from class path resource [l]
## Schema定位和加载 (开始) ##
19:49:48,676 DEBUG DefaultDocumentLoader:72 - Using JAXP provider [s.internal.jaxp.DocumentBuilderFactoryImpl]
19:49:48,678 DEBUG PluggableSchemaResolver:140 - Loading schema mappings from [META-INF/spring.schemas]
19:49:48,690 DEBUG PluggableSchemaResolver:118 - Found XML schema [/schema/beans/spring-beans-3.1.xsd] in classpath:
org/springframework/beans/factory/xml/spring-beans-3.1.xsd
19:49:48,710 DEBUG PluggableSchemaResolver:118 - Found XML schema [/schema/mvc/spring-mvc-3.1.xsd] in classpath:
org/springframework/web/servlet/config/spring-mvc-3.1.xsd
19:49:48,715 DEBUG PluggableSchemaResolver:118 - Found XML schema [/schema/tool/spring-tool-3.1.xsd] in classpath:
org/springframework/beans/factory/xml/spring-tool-3.1.xsd
19:49:48,722 DEBUG PluggableSchemaResolver:118 - Found XML schema [/schema/context/spring-context-3.1.xsd] in classpath:
org/springframework/context/config/spring-context-3.1.xsd
## Schema定位和加载 (结束) ##
## NamespaceHandler执⾏阶段 (开始) ##
19:49:48,731 DEBUG DefaultBeanDefinitionDocumentReader:108 - Loading bean definitions
19:49:48,742 DEBUG DefaultNamespaceHandlerResolver:156 - Loaded NamespaceHandler mappings: {...}
19:49:48,886 DEBUG PathMatchingResourcePatternResolver:550 - Looking for matching resources in directory tree
[D:\Work\Demo2do\Sample\target\classes\com\demo2do\sample\web\controller]
19:49:48,896 DEBUG XmlBeanDefinitionReader:216 - Loaded 18 bean definitions from location pattern [classpath:l]  19:49:48,897 DEBUG XmlWebApplicationContext:525 - Bean factory for WebApplicationContext for namespace 'dispatcher-servlet':
org.springframework.beans.factory.support.DefaultListableBeanFactory@495c998a: defining beans [[
1. org.springframework.web.hod.annotation.RequestMappingHandlerMapping#0,
2. org.springframework.format.support.FormattingConversionServiceFactoryBean#0,
3. org.springframework.web.hod.annotation.RequestMappingHandlerAdapter#0,
4. org.springframework.web.servlet.handler.MappedInterceptor#0,
5. org.springframework.web.hod.annotation.ExceptionHandlerExceptionResolver#0,
6. org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0,
7. org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0,
8. org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
9. org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
10. org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
11. blogController,
12. userController,
13. t.annotation.internalConfigurationAnnotationProcessor,
14. t.annotation.internalAutowiredAnnotationProcessor,
15. t.annotation.internalRequiredAnnotationProcessor,
16. t.annotation.internalCommonAnnotationProcessor,
17. org.springframework.source.ResourceHttpRequestHandler#0,
18. org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0
]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@6602e323
19:49:48,949 DEBUG XmlWebApplicationContext:794 - Unable to locate MessageSource with name 'messageSource': using default
[t.support.DelegatingMessageSource@4b2922f6]
19:49:48,949 DEBUG XmlWebApplicationContext:818 - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default
[t.event.SimpleApplicationEventMulticaster@79b66b06]
19:49:48,949 DEBUG UiApplicationContextUtils:85 - Unable to locate ThemeSource with name 'the
meSource': using default
[org.t.support.DelegatingThemeSource@372c9557]
19:49:49,154 DEBUG RequestMappingHandlerMapping:98 - Looking for request mappings in application context: WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Feb 16 19:49:48 CST 2012]; parent: Root WebApplicationContext
19:49:49,175  INFO RequestMappingHandlerMapping:188 - Mapped "{[/blog],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto  public
org.springframework.web.servlet.ModelAndView com.demo2do.ller.BlogController.index()
19:49:49,177  INFO RequestMappingHandlerMapping:188 - Mapped "{[/register],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto  public
org.springframework.web.servlet.ModelAndView com.demo2do.ister(com.ity.User)
19:49:49,180  INFO RequestMappingHandlerMapping:188 - Mapped "{[/login],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto  public
org.springframework.web.servlet.ModelAndView com.demo2do.ller.UserController.login(java.lang.String,java.lang.String)
19:49:49,632 DEBUG BeanNameUrlHandlerMapping:71 - Looking for URL mappings in application context: WebApplicationContext for namespace 'dispatcher-servlet': startup date [Thu Feb 16
19:49:48 CST 2012]; parent: Root WebApplicationContext
19:49:49,924  INFO SimpleUrlHandlerMapping:314 - Mapped URL path [/static/**] onto handler 'org.springframework.source.ResourceHttpRequestHandler#0'
## NamespaceHandler执⾏阶段 (结束) ##
19:49:49,956 DEBUG DispatcherServlet:627 - Unable to locate RequestToViewNameTranslator with name 'viewNameTranslator': using default
[org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator@4d16318b]
19:49:49,980 DEBUG DispatcherServlet:667 - No ViewResolvers found in servlet 'dispatcher': using default
19:49:49,986 DEBUG DispatcherServlet:689 - Unable to locate FlashMapManager with name 'flashMapManager': using default
[org.springframework.web.servlet.support.DefaultFlashMapManager@1816daa9]
19:49:49,986 DEBUG DispatcherServlet:523 - Published WebApplicationContext of servlet 'dispatcher' as ServletContext attribute with name
[org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher]  19:49:49,986  INFO DispatcherServlet:463 - FrameworkServlet 'dispatcher': initialization completed in 1320 ms  19:49:49,987 DEBUG DispatcherServlet:136 - Servlet 'dispatcher' configured successfully
在上⾯的启动⽇志中,笔者还是把不同的⽇志功能使⽤不同的颜⾊进⾏了区分。这⾥进⾏逐⼀分析:
1. ⿊⾊加粗标记区域 —— 容器的启动和结束标志
这个部分的⽇志⽐较明显,位于容器的启动阶段和结束阶段,在之前的讨论中我们已经分析过,这⾥不再重复。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。