SpringMVC啟動過程


1、  對於一個web應用,其部署在web容器中,web容器提供一個其一個全局的上下文環境,這個上下文環境就是ServletContext,它為后面的spring IoC容器提供宿主環境;

2、  web.xml中有配置ContextLoaderListener,也可以自定義一個實現ServletContextListener接口的Listener方法,web.xml中的配置實例如下:

<listener>

      <listener-class>com.manager.init.SystemInitListener</listener-class>

</listener>

<listener> 
  
  <
listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>

 

Web容器啟動時觸發ServletContextEvent事件,被contextLoaderListener監聽到,並調用contextInitialized方法:

   /**

     * Initialize the root web application context.

   */

   public void contextInitialized(ServletContextEvent event) {

           this.contextLoader = createContextLoader();

           if (this.contextLoader == null) {

                 this.contextLoader = this;

           }

           this.contextLoader.initWebApplicationContext(event.getServletContext());

  }

 

這里調用ContextLoader中的initWebApplicationContext方法初始化WebApplicationContext,WebApplicationContext只是一個接口,默認的實現類是XmlWebApplicationContext。為什么是這個XmlWebApplicationContext?我們到ContextLoader中,看到有這么一段static代碼塊:

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, ContextLoader.class);

                 defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

           }

           catch (IOException ex) {

                 throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());

           }

      }

 

ContextLoader.properties文件內容如下:

# Default WebApplicationContext implementation class for ContextLoader.

# Used as fallback when no explicit context implementation has been specified as context-param.

# Not meant to be customized by application developers.

 

 

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

這樣就能根據屬性文件中的定義反射出一個XmlWebApplicationContext上下文,也就是默認實現的WebApplicationContext.

再繼續看怎么初始化XmlWebApplicationContext之前,我們需要意識到web.xml文件中有配置spring的Ioc容器,也就是:

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

     <param-name>contextConfigLocation</param-name>

     <param-value>/WEB-INF/spring/root-context.xml</param-value>

</context-param>

 

接着就是進入到ContextLoader類中的initWebApplicationContext方法中,看它是怎么初始化的?

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

              //省略了很多前面的代碼

              // Store context in local instance variable, to guarantee that

              // it is available on ServletContext shutdown.

              if (this.context == null) {

                     //初始化root WebApplicationContext, 采用默認的或者是用戶指定的

                     this.context = createWebApplicationContext(servletContext);

              }

              if (this.context instanceof ConfigurableWebApplicationContext) {

                     ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;

                     if (!cwac.isActive()) {

                            //省略部分代碼

                            //獲取contextConfigLocation指定的xml文件,customize the context

                            configureAndRefreshWebApplicationContext(cwac, servletContext);

                     }

              }

              //建立servletContext和WebApplicationContext之間的宿主關系

              servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

       }

//省略部分代碼

}

 

3、 初始化web.xml中配置的Servlet,這個servlet可以配置多個,最常見的是DispatcherServlet。web.xml中的配置如下圖:

   <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/appServlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

這個servlet實際上是一個標准的前端控制器,用以轉發、匹配、處理每個servlet請求。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文,用以持有spring mvc相關的bean。在建立DispatcherServlet自己的IoC上下文時,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文。有了這個parent上下文之后,再初始化自己持有的上下文。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化處理器映射、視圖解析等。

/**

 * Initialize the strategy objects that this servlet uses.

 * <p>May be overridden in subclasses in order to initialize further strategy objects.

       */

protected void initStrategies(ApplicationContext context) {

           initMultipartResolver(context);

           initLocaleResolver(context);

           initThemeResolver(context);

           initHandlerMappings(context);

           initHandlerAdapters(context);

           initHandlerExceptionResolvers(context);

           initRequestToViewNameTranslator(context);

           initViewResolvers(context);

           initFlashMapManager(context);

      }

 

這個servlet自己持有的上下文默認實現類也是XmlWebApplicationContext。初始化完畢后,spring以與servlet的名字相關(此處不是簡單的以servlet名為Key,而是通過一些轉換,具體可自行查看源碼)的屬性為屬性Key,也將其存到ServletContext中,以便后續使用。這樣每個servlet就持有自己的上下文,即擁有自己獨立的bean空間,同時各個servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定義的那些bean。

 

 

參考資料:

[1] http://hi.baidu.com/df_world/item/e028d891f5383f1e924f414d

[2] spring的啟動過程http://segmentfault.com/q/1010000000210417

[3] IOC是什么 http://www.cnblogs.com/DebugLZQ/archive/2013/06/05/3107957.html

[4] spring啟動過程 http://gcq04552015.iteye.com/blog/1673530


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM