从SpringMVC 源码分析(一)中我们知道当请求第一次过来的时候,Servlet容器(如:Tomcat,本文使用Tomcat来作为Servlet容器)会依次调用Servlet的无参构造器、init、service方法,无参构造器是tomcat将项目中的Servlet加载到Tomcat容器中所调用的。也可以在web.xml中设置Servlet的参数load-on-startup大于0,Tomcat就会在启动的时候便调用无参构造器。使用无参主要为了能顺利启动,因为调用有参构造器可能会因为业务原因而报错导致无法启动,所以也是一种规范,不用多说。
当我们的Spring boot项目启动之后,从SpringMVC 源码分析(二)中可以知道我们的Controller的url映射关系也都已初始化好了,这个时候用户就可以向服务发送请求了,
当我们项目引入Spring MVC后,就不需要那么多Servlet了,所有请求全部由DispatcherServlet来代理并分发给Controller中的方法。
那么本片文章我们先一起看下DispatcherServlet的初始化方法init。
当我们的第一次请求过来的时候,首先由Tomcat中的StandardWrapper#allocate来选择最终干活的Servlet类,并且判断这个Servlet类有没有调用init方法初始化过,没有的话就会去调用该方法,可以看到此时我们的Servlet类(instance)就是DispatcherServlet。

继续进入StandardWrapper#initServlet方法中,可以看到最终调用了Servlet的init方法,那么我们的DispatcherServlet初始化就从这里开始了

因为有参init方法DispatcherServlet没有实现,最终调用的是父类GenericServlet的init方法,GenericServlet#init(javax.servlet.ServletConfig),此时的this为DispatcherServlet,接下来调用无参的init方法。

调用DispatcherServlet的init方法,该方法由父类(FrameworkServlet)的父类HttpServletBean实现,init方法使用了模版方法设计模式,可以看到该方法最后调用了initServletBean方法,initServletBean方法由子类去实现。

进入initServletBean方法继续深入探索,该方法是由DispatcherServlet的父类FrameworkServlet实现的,我们去掉其他打印日志的逻辑代码,最终initServletBean只有这几行代码,也是使用了模版方法设计模式,其中initFrameworkServlet方法是一个空方法,留给子类扩展,目前我们的DispatcherServlet类并没有去实现它,所以不用看。我们主要看的核心逻辑就在initWebApplicationContext方法中。

我们继续进入initWebApplicationContext方法中
protected WebApplicationContext initWebApplicationContext() {
// 先获取父类容器,用来设置当前容器的父容器。
// 因为我的是SpringBoot项目,所以容器是AnnotationConfigServletWebServerApplicationContext
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// 如果当前容器已经存在,就使用该容器
// 我debug过来,容器仍是AnnotationConfigServletWebServerApplicationContext,同rootContext,是同一个对象
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
// 判断该容器是否刷新过,是AbstractApplicationContext的一个变量,调用refresh时设置为true
// 即是否调用过refresh方法,这里直接跳出if判断,走下一个逻辑,因为springboot在启动的时候会调用
if (!cwac.isActive()) {
// 如果父容器为空,设置父容器,该逻辑在这里不会走
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
// 配置并刷新容器,该逻辑在这里不会走
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//容器不存在,就通过FrameworkServlet的属性contextAttribute找容器
wac = findWebApplicationContext();
}
if (wac == null) {
// 容器仍不存在的话,创建一个容器
wac = createWebApplicationContext(rootContext);
}
// refreshEventReceived默认为false
// refreshEventReceived在FrameworkServlet的内部类ContextRefreshListener监听ContextRefreshedEvent事件设置为true的
// 但在Springboot项目启动的时候并没有将该监听器添加进去,所以ContextRefreshListener的onApplicationEvent方法最终没有被调用
// 该监听器可能是在哪里配置的,所以没有被加载进ContextRefreshedEvent监听器集合中,这里我们不深究,
if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
// 模版方法,空实现,留给子类去覆写扩展
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
我们重点关注最后的onRefresh方法,该方法被子类DispatcherServlet覆写,用于初始化DispatcherServlet的功能组件,在DispatcherServlet的onRefresh方法中又调用了initStrategies方法,也是Spring代码的功能模块化体现,onRefresh是顶层逻辑,而同一个功能直接封装到单个方法中处理,增加可读性,后面onRefresh有其他功能逻辑处理就可以再写一个封装的方法,接下来我们在initStrategies方法就可以直观明了的看出也是这种写法。

在initStrategies方法中看到,每一个功能组件的初始化都封装了一个方法,代码结构一目了然,可读性大大增加,其实这个方法就是对DispatcherServlet中的成员变量组件进行初始化,在DispatcherServlet处理请求的过程中扮演着不同的角色,下面把初始化的代码贴上,都是一个套路,从容器中获取注册的bean,如果没有就设置一个默认的组件类

private void initMultipartResolver(ApplicationContext context) {
try {
// 从容器中直接获取该类,MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver"
// multipartResolver 为 org.springframework.web.multipart.support.StandardServletMultipartResolver
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.multipartResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isTraceEnabled()) {
logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
}
}
private void initLocaleResolver(ApplicationContext context) {
try {
// 从容器中直接获取该类,LOCALE_RESOLVER_BEAN_NAME = "localeResolver"
// 在容器中没有获取到,进入catch中获取默认的组件
// localeResolver 为 org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.localeResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
}
}
}
private void initThemeResolver(ApplicationContext context) {
try {
// 从容器中直接获取该类,THEME_RESOLVER_BEAN_NAME = "themeResolver"
// 在容器中没有获取到,进入catch中获取默认的组件
// themeResolver 为 org.springframework.web.servlet.theme.FixedThemeResolver
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.themeResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +
"': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
}
}
}
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//从容器中获取所有实现HandlerMapping接口的实现类
//容器中没有的话就设置为默认处理器
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
private void initHandlerExceptionResolvers(ApplicationContext context) {
//从容器中获取所有实现HandlerExceptionResolver接口的实现类
//容器中没有的话就设置为默认的异常处理器
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
// We keep HandlerExceptionResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, no HandlerExceptionResolver is fine too.
}
}
// Ensure we have at least some HandlerExceptionResolvers, by registering
// default HandlerExceptionResolvers if no other resolvers are found.
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.viewNameTranslator);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
}
}
}
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<>(matchingBeans.values());
// We keep ViewResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
try {
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default ViewResolver later.
}
}
// Ensure we have at least one ViewResolver, by registering
// a default ViewResolver if no other resolvers are found.
if (this.viewResolvers == null) {
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
private void initFlashMapManager(ApplicationContext context) {
try {
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.flashMapManager);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
if (logger.isTraceEnabled()) {
logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +
"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
}
}
}