1. 前言

  上篇文章介绍了Spring容器的初始化

 

   如上图,DispatcherServlet本质上是一个Servlet。DispatcherServlet类的设计很巧妙,上层父类不同程度的实现了相关接口的部分方法,并留出了相关方法用于子类覆盖,将不变的部分统一实现,将变化的部分预留方法用于子类实现。对Servlet有一定了解的,Servlet初始化会首先调用init()方法。子类最后重写init()的是HttpServletBean,所以最开始对HttpServletBean的init()方法进行分析

 

   PropertyValues主要解析web.xml定义中<servlet>元素的子元素<init-param>中的参数值。见上图,有一个键值对就是SpringMvc的配置文件。bw.setPropertyValues(pvs, true) 将上一步解析的servlet初始化参数值绑定到DispatcherServlet对应的字段上;

  接着就是执行initServletBean方法,因为HttpServletBean中的initServletBean就是个空方法,通过观察上述类图,发现子类FrameworkServlet重写了其initServletBean。于是对FrameworkServle的initServletBean进行分析

复制代码
@Override protected final void initServletBean() throws ServletException {    getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");    if (this.logger.isInfoEnabled()) {       this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");    }    long startTime = System.currentTimeMillis();     try {       this.webApplicationContext = initWebApplicationContext();       initFrameworkServlet();    }    catch (ServletException ex) {       this.logger.error("Context initialization failed", ex);       throw ex;    }    catch (RuntimeException ex) {       this.logger.error("Context initialization failed", ex);       throw ex;    }     if (this.logger.isInfoEnabled()) {       long elapsedTime = System.currentTimeMillis() - startTime;       this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +             elapsedTime + " ms");    } }
复制代码

  该方法中比较重要的就是initWebApplicationContext()方法的调用,该方法仍由FrameworkServlet抽象类实现,继续查看其源码如下所示:

复制代码
protected WebApplicationContext initWebApplicationContext() {    /*         获取由ContextLoaderListener创建的根IoC容器         获取根IoC容器有两种方法,还可通过key直接获取         */  WebApplicationContext rootContext =          WebApplicationContextUtils.getWebApplicationContext(getServletContext());    WebApplicationContext wac = null;     if (this.webApplicationContext != null) {       // A context instance was injected at construction time -> use it      wac = this.webApplicationContext;       if (wac instanceof ConfigurableWebApplicationContext) {          ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;          if (!cwac.isActive()) {             // The context has not yet been refreshed -> provide services such as             // setting the parent context, setting the application context id, etc            if (cwac.getParent() == null) {                // The context instance was injected without an explicit parent -> set                // the root application context (if any; may be null) as the parent /*如果当前Servelt存在一个WebApplicationContext即子IoC容器并且上文获取的根IoC容器存在,则将根IoC容器作为子IoC容器的父容器                 */                cwac.setParent(rootContext);             } //