1. 前言
2. 类图
了解DispatcherServlet之前,我们先来了解一下它的类关系图:
3. 方法跟踪时序图
4. 跟踪过程源码研究
4.1. defaultStrategies初始化
DispatcherServlet有一个静态类函数,负责从属性文件中加载默认的策略实现,静态函数和属性文件如下:
4.1.1. DispatcherServlet#static
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
4.1.2. 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.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
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
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
根据约定优于配置原则,Spring默认提供了一系列的策略实现类,并配置在了属性文件中,如处理请求映射的HandlerMapping等;
4.2. Servlet初始化init方法
DispatcherServlet本质上是继承的HttpServlet类,一个Servlet从创建到销毁主要有三个生命周期方法:init、doService、destroy。DispatcherServlet也不例外,其init方法负责初始化Servlet,doService负责处理http请求,这里,我们先看一下init方法如何初始化DispatcherServlet,至于doService方法如何处理http请求,后面再具体研究。
4.2.1. HttpServletBean#init
在DispatcherServlet创建之后,调用其init方法,此方法在其父类的HttpServletBean中实现,此方法也是DispatcherServlet的入口方法:
@Override
public final void init() throws ServletException {
// Set bean properties from init parameters.
// 省略
// Let subclasses do whatever initialization they like.
initServletBean();
}
此方法主要完成两件事:
- 初始化参数
- 调用子类的
initServletBean方法做初始化;
4.2.2. FrameworkServlet#initServletBean
@Override
protected final void initServletBean() throws ServletException {
// 省略日志代码。。。
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
// 省略catch、日志代码
}
我们知道,SpringMVC底层也是使用的Spring的核心功能,即ioc容器来做bean的管理。FrameworkServlet类中有一个很重要的变量:webApplicationContext,此变量即为Spring Web容器:
private WebApplicationContext webApplicationContext;
而方法initWebApplicationContext()用来进行容器的初始化。我们跟踪一下容器如何做得初始化。
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = getContextClass();
// 省略部分代码
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}
initWebApplicationContext最终调用了createWebApplicationContext方法来进行webAplicationContext的初始化,wac是通过contextClass变量进行的实例化:
public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
public Class<?> getContextClass() {
return this.contextClass;
}
此变量是写死的XmlWebApplicationContext.class,到这里,我们知道,spring mvc中的容器是使用的XmlWebApplicationContext进行的实例化。
4.2.3. configureAndRefreshWebApplicationContext
在创建了webApplicationContext对象之后,调用了configureAndRefreshWebApplicationContext()方法,此方法负责配置及刷新容器:
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
//省略部分代码
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
我们可以看到,最后一句wac.refresh();其实调用了AbstractApplicationContext容器的模板方法refresh,到这里,我们应该比较熟悉了,所有的容器类都是使用的此方法进行的初始化。而到此为止,DispatcherServlet的初始化看上去亦完成了。
通过查看debug日志,我们发现,在Servlet初始化完成之后,其实所有的url已经和Controller#method映射完成了,到目前为止我们没有看到映射的代码,这其实就涉及到spring的一个比较重要的概念,即上面代码中的wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));这行代码。
应用监听器是spring提供的一系列扩展接口的一种,下一章我们重要研究XmlWebApplicationContext的refresh执行过程,包括BeanPostProcessor后处理器、事件等;