標籤:gpl hand 變數 自訂 mvc apt imp bean 基於
Spring架構提供了構建Web應用程式的全功能MVC模組,叫Spring MVC,通過Spring Core+Spring MVC即可搭建一套穩定的Java Web項目。本文通過Spring MVC源碼分析介紹它的核心實現原理。
Tomcat伺服器啟動入口檔案是web.xml,通過在其中配置相關的Listener和Servlet即可載入Spring MVC所需資料。基於Spring MVC最簡單的配置如下。
- <!-- 載入Spring設定檔 -->
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:spring-context*.xml
- </param-value>
- </context-param>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
-
- <!-- 載入spring mvc -->
- <servlet>
- <servlet-name>spring3mvc</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath:spring-mvc*.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>spring3mvc</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
ContextLoaderListener基於Web上下文層級的監聽器在啟動伺服器時就建立ApplicationContext並且將配置的Spring Bean載入到XML中。
DispatcherServlet是一個請求分發控制器,所有匹配的URL都會通過該Servlet分發執行,在建立Servlet對象時會初始化Spring MVC相關配置。
在web.xml中,我們看到基於ContextLoaderListener和DispatcherServlet都可以配置spring相關的XML,值得說明的是這兩種方式載入spring的ApplicationContext內容物件不是合并儲存的,具體可參考http://blog.csdn.net/madun/article/details/8988860。所以個人建議,基於mvc相關的spring配置由DispatcherServlet載入,而其餘的JavaBean都交給ContextLoaderListener載入。
一、ContextLoaderListener
ContextLoaderListener是一個實現了ServletContextListener介面的監聽器,在啟動項目時會觸發contextInitialized方法(該方法主要完成ApplicationContext對象的建立),在關閉項目時會觸發contextDestroyed方法(該方法會執行ApplicationContext清理操作)。
Java代碼
- public class ContextLoaderListener extends ContextLoader implements ServletContextListener
ConextLoaderListener載入Spring內容相關的過程可以用表示,黃色區塊是核心代碼。
簡單介紹一下的運行流程:
①啟動項目時觸發contextInitialized方法,該方法就做一件事:通過父類contextLoader的initWebApplicationContext方法建立Spring內容物件。
②initWebApplicationContext方法做了三件事:建立WebApplicationContext;載入對應的Spring檔案建立裡面的Bean執行個體;將WebApplicationContext放入ServletContext(就是Java Web的全域變數)中。
③createWebApplicationContext建立內容物件,支援使用者自訂的內容物件,但必須繼承自ConfigurableWebApplicationContext,而Spring MVC預設使用ConfigurableWebApplicationContext作為ApplicationContext(它僅僅是一個介面)的實現。
④configureAndRefreshWebApplicationContext方法用於封裝ApplicationContext資料並且初始化所有相關Bean對象。它會從web.xml中讀取名為contextConfigLocation的配置,這就是spring xml資料來源設定,然後放到ApplicationContext中,最後調用傳說中的refresh方法執行所有Java對象的建立。
⑤完成ApplicationContext建立之後就是將其放入ServletContext中,注意它儲存的key值常量。
Java代碼
- servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
- //常量
- public static final String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
註:要擷取 ContextLoader層級的IOC容器物件可以這樣寫:
- WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
二、DispatcherServlet
DispatcherServlet是前端控制器設計模式的實現,提供Spring Web MVC的集中訪問點,而且負責職責的指派,而且與Spring IoC容器無縫整合,從而可以獲得Spring的所有好處。
要瞭解DispatcherServlet是如何載入容器,需要先瞭解它的繼承關係,如所示:
如果在web.xml中設定了Servlet的<load-on-startup>1</load-on-startup>,則表示隨項目啟動,而我們知道Servelt建立時會首先調用init方法,所以繼承了HttpServlet的HttpServletBean就是關鍵入口了。那麼整個代碼運行流程如所示。
①HttpServletBean.init方法中執行initServletBean方法進行初始化操作,當然該方法在HttpServletBean是空方法,所以需要子類重寫。
②FrameworkServlet.initServletBean子類不負眾望,重寫了initServletBean方法,該方法最核心的操作就是調用initWebApplicationContext()執行內容Bean初始化。
③FrameworkServlet.initWebApplicationContext方法首先擷取自己的雙親上下文(也就是ContextLoaderListener初始化成功的WebApplicationContext);然後建立或者擷取當前Servelet的WebApplicationContext。
④無論是自己建立還是擷取現有的WebApplicationContext,最終都會讓Servelt層級的WebApplicationContext執行configureAndRefreshWebApplicationContext()方法進行上下文容器初始化。
通過以上幾步即可建立一個完整的IOC容器,而完成容器建立之後,DispatcherServlet還做了一件事:初始化Servelt控制器必備對象,這個是在initWebApplicationContext()方法中通過調用onRefresh(wac)方法實現的。而onRefresh也被重寫過,如果要瞭解怎麼初始化Servlet控制器必備對象可以查看DispatcherServlet的onRefresh方法瞭解。
Java代碼
- /**
- * This implementation calls {@link #initStrategies}.
- */
- @Override
- protected void onRefresh(ApplicationContext context) {
- initStrategies(context);
- }
-
- /**
- * 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);
- }
SpringMVC載入WebApplicationContext源碼分析