SpringMVC之DispatcherServlet初始化顺序。

继承体系结构如下所示:

SpringMVC之DispatcherServlet初始化顺序。

HttpServletBean继承HttpServlet,因此在Web容器启动时将调用它的init方法,该初始化方法的主要作用。

  • 将Servlet初始化参数(init-param)设置到该组件上(如contextAttribute、contextClass、namespace、contextConfigLocation),通过BeanWrapper简化设值过程,方便后续使用;
  • 提供给子类初始化扩展点,initServletBean(),该方法由FrameworkServlet覆盖。

public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware {

@Override

public final void init() throws ServletException {

// 省略部分代码

// 1、如下代码的作用是将Servlet初始化参数设置到该组件上

// 如 contextAttribute、contextClass、namespace、contextConfigLocation

try {

PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig() , this.requiredProperties);

BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);

ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());

bw.registerCustomEditor(Resource.class , new ResourceEditor(resourceLoader , this.environment));

initBeanWrapper(bw);

bw.setPropertyValues(pvs , true);

} catch (BeansException ex) {

// ...... 省略其他代码

}

// 2、提供给子类初始化的扩展点,该方法由FrameworkServlet覆盖

initServletBean();

if(logger.isDebugEnabled()) {

logger.debug("servlet '" + getServletName() + "' configured successfully" );

}

}

// ... ... 省略其他代码

}

FrameworkServlet继承HttpServletBean,通过initServletBean()进行Web上下文初始化,该方法主要覆盖一下两件事情:

  • 初始化web上下文;
  • 提供给子类初始化扩展点;

public abstract class FrameworkServlet extends HttpServletBean {

@Override

protected final void initServletBean() throws ServletException {

// 省略部分代码

try {

// 1、初始化Web上下文

this.webApplicationContext = initWebApplicationContext();

// 2、提供给子类初始化的扩展点

initFrameworkServlet();

}

// 省略部分代码

}

}

protected WebApplicationContext initWebApplicationContext() {

// ROOT上下文(ContextLoaderListener加载的)

WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

WebApplicationContext wac = null;

if (this.webApplicationContext != null) {

// 1、在创建该Servlet注入的上下文

wac = this.webApplicationContext;

if (wac instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;

if(!cwac.isActive()) {

if (cwac.getParent() == null) {

cwac.setParent(rootContext);

}

configureAndRefreshWebApplicationContext(cwac);

}

}

}

if (wac == null) {

// 2、查找已经绑定的上下文

wac = findWebApplicationContext();

}

if (wac == null) {

// 3、如果没有找到相应的上下文,并指定父亲为ContextLoaderListener

wac = createWebApplicationContext(rootContext);

}

if (!this.refreshEventReceived) {

// 4、刷新上下文(执行一些初始化)

onRefresh(wac);

}

if (this.publishContext) {

// Publish the context as a servlet context attribute.

String attrName = getServletContextAttributeName()

getServletContext().setAttribute(attrName , wac);

// 省略部分代码

}

return wac;

}

从initWebApplicationContext()方法可以看出,基本上如果ContextLoaderListener加载了上下文将作为根上下文(DispatcherServlet的父容器)。

最后调用了onRefresh()方法执行容器的一些初始化,这个方法由子类实现,来进行扩展。

DispatcherServlet继承FrameworkServlet,并实现了onRefresh()方法提供一些前端控制器相关的配置:

public class DispatcherServlet extends FrameworkServlet {

// 实现子类的onRefresh()方法,该方法委托为initStrategies()方法。

@Override

protected void onRefresh(ApplicationContext context) {

initStrategies(context);

}

// 初始化默认的Spring Web MVC框架使用的策略(如HandlerMapping)

protected void initStrategies(ApplicationContext context) {

initMultipartResolver(context); 

initLocaleResolver(context);  

initThemeResolver(context);  

initHandlerMappings(context);  

initHandlerAdapters(context);  

initHandlerExceptionResolvers(context);  

initRequestToViewNameTranslator(context);  

initViewResolvers(context);  

initFlashMapManager(context);

}

}

从如上代码可以看出,DispatcherServlet启动时会进行我们需要的Web层Bean的配置,如HandlerMapping、HandlerAdapter等,而且如果我们没有配置,还会给我们提供默认的配置。

从如上代码我们可以看出,整个DispatcherServlet初始化的过程和做了些什么事情,具体主要做了如下两件事情:

  • 初始化Spring Web MVC 使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);
  • 初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。

服务器启动时的日志分析(此处加了ContextLoaderListener从而启动ROOT上下文容器):

SpringMVC之DispatcherServlet初始化顺序。

SpringMVC之DispatcherServlet初始化顺序。

SpringMVC之DispatcherServlet初始化顺序。

从如上日志我们也可以看出,DispatcherServlet会进行一些默认的配置。