1. 目录

[TOC]

2. 说明

本文分析springmvc的启动过程,spring的启动前面已经分析了,此处就默认spring启动流程已经OK

3. 流程分析

  • 首先spring通过 ContextLoaderListener实现tomcat调用的javax.util.EventListener.ServletContextListener来启动spring容器ApplicationContext
  • 启动完成后继续执行tomcat的方法
  • 然后 springmvc 通过 DispatcherServlet实现tomcat 的HttpServlet来启动spring-mvc的容器
    ApplicationContext,初始化完成之前会创建初始化完成事件监听器,
  • springmvc监听事件,容器初始化后执行监听方法,初始化springmvc的九大组件

流程

4. 源码分析

4.1. spring 启动

tomcat初始化时会调用StandardContext#listenerStart()下的ServletContextListener#contextInitialized()方法,而web.xml配置了启动spring的监听方法

1
2
3
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

详细流程见 spring源码分析的xml启动

4.2. spring-mvc 启动

springmvc 启动在spring初始化完成之后,及tomcat的监听方法调用完了之后开始执行的,执行到

4.2.1. tomcat 钩子函数调用到spring-mvc

tomcat 执行servlet时候调用GenericServlet#init()方法,而web.xml配置了启动servlet的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
<!--<param-value>com.kewen.interceptor.GlobalInterceptor</param-value>-->
<!--<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>-->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

通过此配置则可以调用起来DispatcherServlet,因此通过此处调用实现类DispatcherServlet#contextInitialized()开始springmvc的初始化

4.2.2. 创建 WebApplicationContext上下文

init()方法继续执行,会调用到DispatcherServlet的父类FrameworkServlet#initWebApplicationContext()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// FrameworkServlet.class
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;

if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}

//刷新,子类DespatchServlet实现
//其实不是从这里刷新的,ContextRefreshListener监听器监听spring容器的刷新事件调起,此处是没有刷新的话再刷新一次,刷新过就不刷新了
if (!refreshEventReceived){
//主要用于上下文不支持刷新(无刷新监听)或者已经刷新过了
onRefresh(wac);
}

return wac;
}

此方法拿到之前spring创建的上下文,然后自行通过createWebApplicationContext()创建springmvc的上下文
创建完成之后有一个判断是否已经刷新了,没有刷新则会调用刷新,实际上在webApplicationContext中通过监听器的方式已经刷新了,此处是不会再刷新的,这里是给不支持刷新的上下文准备的

4.2.2.1. createWebApplicationContext() 创建上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = getContextClass();

//创建并设置基本信息
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}


//主要逻辑
configureAndRefreshWebApplicationContext(wac);

return wac;

}

这里主要是创建,没有过多的逻辑,逻辑实在configureAndRefreshWebApplicationContext()方法中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

private void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

//设置id,不判定了,直接走应该有的分支
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX+getServletContext().getContextPath());
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
//原MVC框架是组装成PropertyValue并从获取的。此处简化与spring获取的方式保持一致,简单
wac.setConfigLocation(getServletConfig().getInitParameter("contextConfigLocation"));

//ContextRefreshListener上下文初始化完成刷新器,预埋此监听器在上下文刷新完成后初始化9大组件
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

//钩子函数,可扩展
postProcessWebApplicationContext(wac);

//应用初始化器
applyInitializers(wac);

//刷新,spring中的通用刷新方法,可不管
wac.refresh();

}

此处逻辑和spring中的逻辑及其相似,就不再分析了,wac.refresh()完全一样,通用的刷新流程

4.2.2.2. 初始化mvc部分

刷新完成后通过监听器初始化Mvc部分,DispathcerServlet的父类FrameworkServlet实现了ApplicationListener<E extends ApplicationEvent>

1
2
3
4
5
6
//  FrameworkServlet
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived=true;
onRefresh(event.getApplicationContext());
}
1
2
3
4
5
//  DispathcerServlet
@Override
protected void onRefresh(ApplicationContext wac) {
initStrategies(wac);
}

initStrategies() 则是初始化 mvc 9大组件的核心逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void initStrategies(ApplicationContext context) {
//文件上传组件,先不管
initMultipartResolver(context);
//本地语言组件,先不管
initLocaleResolver(context);
//主题解析器,先不管
initThemeResolver(context);
//映射处理器
initHandlerMappings(context);
//适配器处理器
initHandlerAdapters(context);
//异常处理器
initHandlerExceptionResolvers(context);
//请求转换,先不管
initRequestToViewNameTranslator(context);
//视图解析器,先不管,目标可以解析出json就可以
initViewResolvers(context);
//flash管理器,先不管
initFlashMapManager(context);
}

九大组件的分析后续单独解析,只取initHandlerMappings()initHandlerAdapters()initHandlerExceptionResolvers()三个主要的分析

4.3. springmvc启动中特殊用途的初始化

在初始化mvc上下问的时候解析加载beanDefinition的时候,spring在DefaultBeanDefinitionDocumentReader解析自定义节点的时候,会通过BeanDefinitionParserDelegate加载MvcNamespaceHandler作为NamespaceHandlerSupport解析xml节点。
NamespaceHandlerSupport配置的替换规则是在spring-mvc包下的META-INF/spring.handlers中(具体spring的beanDifinition加载中有解析),
我们来看MvcNamespaceHandler代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public void init() {

// 解析<mvc:annotation-driven>,HaderlerMapping和HandlerAdaptor等一些额外的也在这里初始化进去(一点坑)
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());

//拦截器解析器,解析mvc:interceptors
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());

registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}

4.3.1. AnnotationDrivenBeanDefinitionParser注解驱动解析器

在spring-mvc.xml中配置了mvc:annotation-driven的,会执行AnnotationDrivenBeanDefinitionParser.parse()解析,
这里解析的时候会加入很多默认的映射器处理器等(坑啊,没有加注解的解析就放在DispatcherServlet初始化或者在各自的业务里,真坑啊!)

1
2
3
4
5
6
7
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="*/*"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

有了这个配置,则会加载很多默认的处理器、映射器等spring-mvc需要的类,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// AnnotationDrivenBeanDefinitionParser.java
public BeanDefinition parse(Element element, ParserContext context) {
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();

CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
context.pushContainingComponent(compDefinition);

RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, context);

//加载RequestMappingHandlerMapping,并配置优先级,
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

if (element.hasAttribute("enable-matrix-variables")) {
Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}

configurePathMatchingProperties(handlerMappingDef, element, context);
//注册HandlerMappings
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);


//注册的Cors配置
RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);

RuntimeBeanReference conversionService = getConversionService(element, source, context);
RuntimeBeanReference validator = getValidator(element, source, context);
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);

ManagedList<?> messageConverters = getMessageConverters(element, source, context);
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
String asyncTimeout = getAsyncTimeout(element);
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");


//加载 RequestMappingHandlerAdapter
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
addRequestBodyAdvice(handlerAdapterDef);
addResponseBodyAdvice(handlerAdapterDef);

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
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);



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);

RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedInterceptorDef.setSource(source);
mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);



//加载异常解析器增强器 @AdvanceHandler对应的逻辑处理
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
methodExceptionResolver.getPropertyValues().add("order", 0);
addResponseBodyAdvice(methodExceptionResolver);
if (argumentResolvers != null) {
methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);

RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
statusExceptionResolver.setSource(source);
statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
statusExceptionResolver.getPropertyValues().add("order", 1);
//注册异常解析器增强器
String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);


//加载异常解析器
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add("order", 2);
//注册异常解析器
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"
MvcNamespaceUtils.registerDefaultComponents(context, source);

context.popAndRegisterContainingComponent();

return null;
}

4.3.2. InterceptorsBeanDefinitionParser 拦截器解析器

拦截器解析专门用一小节说明,记住从MvcNamespaceHandler这里加载InterceptorsBeanDefinitionParser用来解析<mvc:interceptor>

5. 总结

6. 注意事项