DispatcherServlet的初始化,是在org.springframework.web.context.ContextLoaderListener完成加载后,才开始的。这时候WebApplicationContext(包含DAO,Service等)已经初始完毕。

DispatcherServlet的初始过程主要完成

1.WebApplicationContext父子容器维护

2.初始化Servlet策略

本文主要内容

  1. DispatcherServlet的集成体系

  2. DispatcherServlet初始化过程


1.DispatcherServlet的继承体系


3.jpg

DispatcherServlet是个普通servlet,是访问入口。明白了继承体系,方便梳理初始化模板。

2.DispatcherServlet初始化过程

4.jpg

2.1 init

public final void init() throws ServletException {

   // Set bean properties from init parameters.
   //将Servlet配置的参数封装到pvs变量中
   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));
      initBeanWrapper(bw);//bw就是DispatcherServlet
      bw.setPropertyValues(pvs, true);
   }

   // 让子类实现
   initServletBean();

   if (logger.isDebugEnabled()) {
      logger.debug("Servlet '" + getServletName() + "' configured successfully");
   }
}

2.2 initServletBean方法

protected final void initServletBean() throws ServletException {
      this.webApplicationContext = initWebApplicationContext();
      initFrameworkServlet();//子类可以实现

}

初始化webApplicationContext ;初始化FrameworkServlet

2.3 initWebApplicationContext方法

protected WebApplicationContext initWebApplicationContext() {
   WebApplicationContext wac = findWebApplicationContext();
   if (wac == null) {
      // No fixed context defined for this servlet - create a local one.
      WebApplicationContext parent =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
      wac = createWebApplicationContext(parent);
   }

   if (!this.refreshEventReceived) {
      // Apparently not a ConfigurableApplicationContext with refresh support:
      // triggering initial onRefresh manually here.
      onRefresh(wac);////调用DispatcherServlet.initStrategies入口
   }

   if (this.publishContext) {
      // Publish the context as a servlet context attribute.
      String attrName = getServletContextAttributeName();
      getServletContext().setAttribute(attrName, wac);
      ...
      }
   }

   return wac;
}

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
   Class<?> contextClass = getContextClass();
   ConfigurableWebApplicationContext wac =
         (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
   wac.setParent(parent);//维护双亲委派
   wac.setServletContext(getServletContext());
   wac.setServletConfig(getServletConfig());
   wac.setNamespace(getNamespace());
   wac.setConfigLocation(getContextConfigLocation());
   //调用DispatcherServlet.initStrategies入口
   wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
   postProcessWebApplicationContext(wac);
   wac.refresh();
   return wac;
}

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

   public void onApplicationEvent(ContextRefreshedEvent event) {
      FrameworkServlet.this.onApplicationEvent(event);
   }
}

2.5.initStrategies方法

protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
   initHandlerMappings(context);
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
}

初始化9个组件。

初始化组件过程,大体都是先从容器中获取,获取不到,则调用getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface)方法。

默认配置来自DispatcherServlet.properties

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

2.6.initHandlerMappings方法

private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;
   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<HandlerMapping>(matchingBeans.values());
         // We keep HandlerMappings in sorted order.
         OrderComparator.sort(this.handlerMappings);
      }
   }
   else {
...
   }

   }
}

将spring mvc容器中HandlerMapping对象赋给handlerMappings 列表。这些对象都是在标签解析时,自动加载入容器中的。具体<SpringMVC源码分析(1)标签解析>

2.7 initHandlerAdapters方法

与initHandlerMappings思路完全一致。