1. 程式人生 > >spring啟動流程

spring啟動流程

配置 map filter 流程 例如 apps 調用 正是 解析

ServletContext

Web容器在啟動的過程中,會為每個Web應用程序創建一個對應的ServletContext對象,它代表了當前的Web應用,為Spring IoC容器提供宿主環境。

在部署Web工程的時候,Web容器會讀取web.xml,創建ServletContext,當前Web工程所有部分都共享這個Context。context-param為ServletContext提供鍵值對,即Servlet上下文的信息,這些信息Listener、Filter和Servlet都有可能使用到,因此先加載context-param,創建ServletContext,然後加載Listener,再加載Filter,最後加載Servlet。

接下來我將按照這個加載順序來分析Spring容器的啟動過程。

ContextLoaderListener

web.xml中配置有ContextLoaderListener,也可以自定義一個實現了ServletContextListener接口的Listener類,web.xml中的配置實例如下。

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

Web容器在啟動的過程中會觸發ServletContextEvent事件,會被ContextLoaderListener監聽到,並調用ContextLoaderListener中的contextInitialized方法,contextInitialized方法如下所示。

public void contextInitialized(ServletContextEvent event) { 
    this.initWebApplicationContext(event.getServletContext());
}

ContextLoaderListener類繼承了ContextLoader,在初始化Context的過程中,調用ContextLoader的initWebApplicationContext方法初始化WebApplicationContext。WebApplicationContext是一個接口,Spring默認的實現類為XmlWebApplicationContext,XmlWebApplicationContext就是Spring的IoC容器。

在初始化XmlWebApplicationContext之前,Web容器已經加載了context-param,web.xml中的context-param實例如下所示。作為Spring的IoC容器,其對應的Bean定義的配置正是context-param指定的。

<context-param>
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

接著進入到initWebApplicationContext方法內,initWebApplicationContext方法定義如下(已省略部分代碼)。

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {      
    if(servletContext.getAttribute(
        WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
            throw new IllegalStateException("...");
    }else{
        if(this.context == null) {
            this.context = this.createWebApplicationContext(servletContext);
        }
    }
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
}

在Spring IoC容器初始化前,initWebApplicationContext先檢測以ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE為key的值是否為空,若不為空,則初始化IoC Context,並在初始化完畢後,以ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE為key將IoC Context存儲到ServletContext中。

初始化Servlet

Servlet可以在web.xml中配置多個,在Spring中,最基本的Servlet為DispatcherServlet,對應的配置實例如下所示。

<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>  

DispatcherServlet會建立自己的IoC Context,用以持有相關的Bean,在初始化自己的IoC Context的過程中,先通過WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,從ServletContext中獲取WebApplicationContext,將WebApplicationContext作為DispatcherServlet的IoC Context的 parent Context。DispatcherServlet自己的IoC Context的初始化工作在DispatcherServlet的initStrategies方法中完成,包括控制器映射,視圖解析等,initStrategies方法如下所示。

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

DispatcherServlet自己的IoC Context的類型也是XmlWebApplicationContext,初始化完畢後,Spring將以與DispatcherServlet的servlet-name屬性相關的符號作為key,將IoC Context保存到 ServletContext中。這樣每個Servlet就都可以持有自己的Context,也就是都擁有自己的Bean空間,同時,各個Servlet之間還共享著key為WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的WebApplicationContext,其中定義的Bean為各個Servlet共享的Bean。

//----------------------

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

  2. 其次,在web.xml中會提供有contextLoaderListener。在web容器啟動時,會觸發容器初始化事件,此時contextLoaderListener會監聽到這個事件,其contextInitialized方法會被調用,在這個方法中,spring會初始化一個啟動上下文,這個上下文被稱為根上下文,即WebApplicationContext,這是一個接口類,確切的說,其實際的實現類是XmlWebApplicationContext。這個就是spring的IoC容器,其對應的Bean定義的配置由web.xml中的context-param標簽指定。在這個IoC容器初始化完畢後,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE為屬性Key,將其存儲到ServletContext中,便於獲取;

  3. 再次,contextLoaderListener監聽器初始化完畢後,開始初始化web.xml中配置的Servlet,這個servlet可以配置多個,以最常見的DispatcherServlet為例,這個servlet實際上是一個標準的前端控制器,用以轉發、匹配、處理每個servlet請求。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文,用以持有spring mvc相關的bean。在建立DispatcherServlet自己的IoC上下文時,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文。有了這個parent上下文之後,再初始化自己持有的上下文。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化處理器映射、視圖解析等。這個servlet自己持有的上下文默認實現類也是mlWebApplicationContext。初始化完畢後,spring以與servlet的名字相關(此處不是簡單的以servlet名為Key,而是通過一些轉換,具體可自行查看源碼)的屬性為屬性Key,也將其存到ServletContext中,以便後續使用。這樣每個servlet就持有自己的上下文,即擁有自己獨立的bean空間,同時各個servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定義的那些bean。

//------------------------------------



作者:yang2yang
鏈接:https://www.jianshu.com/p/5226c7fec43a
來源:簡書

spring啟動流程