springmvc web.xml配置之 -- DispatcherServlet


springMVC servlet配置與啟動

看一下springmvc的web.xml常見配置:

 <servlet> <!-- 配置DispatcherServlet -->   <servlet-name>springMvc</servlet-name>   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   <!-- 指定spring mvc配置文件位置 不指定使用默認情況 -->   <init-param>   <param-name>contextConfigLocation</param-name>   <param-value>classpath:spring/spring-mvc.xml</param-value>    </init-param>   <!-- 設置啟動順序 -->   <load-on-startup>1</load-on-startup>   </servlet>   <!-- ServLet 匹配映射 -->   <servlet-mapping>   <servlet-name>springMvc</servlet-name>    <url-pattern>/</url-pattern>   </servlet-mapping>

DispatcherServlet是一個特殊的Servlet,因此本文首先看看常規servlet的特性。

1. servlet特性

1.1 Servlet 啟動過程

Servlet的啟動過程如何? 難道和springmvc Ioc容器一樣隨web容器啟動的時候就啟動嗎?

其實仔細想一想,可以猜出來Servlet並不一定是隨web容器啟動而創建,我們知道一個web容器中可能有非常多的Servlet,如果有百千個servlet,那服務器啟動的時候就要實例化那么多個類,顯然對於內存而言負載量相當的大。其實在web.xml的<servlet>標簽中可以通過<load-on-startup>來控制Servlet的是否隨web容器啟動而初始化以及多個Servlet同時創建時的初始化順序。

loadOnStartup設置分為三種情況:

  • loadOnStartup < 0 web容器啟動的時候不實例化處理,servlet首次被調用時才被實例化 ,loadOnStartupm默認是這種(即沒有配置時)。

  • loadOnStartup > 0 web容器啟動的時候做實例化處理,順序是由小到大,正整數小的先被實例化。

  • loadOnStartup = 0 web容器啟動的時候做實例化處理,相當於是最大整數,因此web容器啟動時,最后被實例化。

另外,<servlet-mapping>會攔截請求,然后對應的servlet處理這個請求。上述配置<url-pattern>/</url-pattern>表示攔截除了jsp以外的所有url,DispatchServlet將會處理這些請求。

1.2 Servlet 生命周期
  • Servlet 通過調用 init () 方法進行初始化。
  • Servlet 調用 service() 方法來處理客戶端的請求。
  • Servlet 通過調用 destroy() 方法終止(結束)。
  • 最后,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。

下圖展示了一個典型的Servlet生命周期方案:

Servlet生命周期

servlet初始化時由容器調用servlet的init()方法,調用servlet的ini()方法時會將ServletConfig對象傳遞給servlet,當用戶發出HTTP請求后,會被委派到web容器(Servlet容器),多個請求同時發起時交由Servlet 容器線程池處理,線程池中分配多個線程處理任務,每個線程執行一個單一的 Servlet 實例的 service() 方法。

2. DispatcherServlet

DispatcherServlet本質上也是一個Servlet,從繼承關系上看,它繼承了HttpServletBean,HttpServletBean中實現了init()方法,因為在Web容器啟動時將調用它的init方法,該方法的作用:

  1. 將Servlet初始化參數(init-param)設置到該組件上,主要ServletConfig對象傳遞給servlet。
  2. 提供給子類初始化擴展點,initServletBean() 
DispatcherServlet結構圖
2.1 Servlet 加載配置文件

(略)

2.1 初始化ServletBean

FrameworkServlet繼承了HttpServletBean,它通過initServletBean()進行Web上下文初始化。

@Override
protected final void initServletBean() throws ServletException {
    try {
        // 1.初始化web上下文
        this.webApplicationContext = initWebApplicationContext();
        // 2. 提供給子類初始化的擴展點
        initFrameworkServlet();
    }catch 
    ...
   }
}

initWebApplicationContext初始化WebApplicationContext:

protected WebApplicationContext initWebApplicationContext() {
        // 查找父容器,也就是web容器加載時ContextLoaderListener觸發執行得到的IOC容器
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if(this.webApplicationContext != null) {
          // 1.創建DispatherServlet自己的容器
            wac = this.webApplicationContext;
            if(wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext attrName = (ConfigurableWebApplicationContext)wac;
                if(!attrName.isActive()) {
                    if(attrName.getParent() == null) {
                        // 1.1 指定父容器,即ContextLoaderListener過程加載的IOC容器
                        attrName.setParent(rootContext);
                    }
                    // 1.2 執行wac.refresh(),也就是容器初始化
                    this.configureAndRefreshWebApplicationContext(attrName);
                }
            }
        }

        if(wac == null) {
          // 2.查找已經綁定的上下文
           wac = this.findWebApplicationContext();
        }

        if(wac == null) {
            // 3.如果沒有找到相應的上下文,並指定父親為ContextLoaderListener
            wac = this.createWebApplicationContext(rootContext);
        }

        if(!this.refreshEventReceived) {
           // 4.刷新上下文(執行一些初始化)
            this.onRefresh(wac);
        }

        if(this.publishContext) {
            String attrName1 = this.getServletContextAttributeName();
            this.getServletContext().setAttribute(attrName1, wac);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Published WebApplicationContext of servlet \'" + this.getServletName() + "\' as ServletContext attribute with name [" + attrName1 + "]");
            }
        }

        return wac;
    }

從上看出DispatcherServlet會維持一個自己的WebApplicationContext,ContextLoaderListener中創建ApplicationContext作為rootContext,傳入DispatcherServlet的容器中,然后初始化自己的Ioc容器。

這兩個容器的區別:

  1. ContextLoaderListener創建的WebApplicationContext是共享於整個Web應用程序的。
  2. DispatcherServlet創建的ApplicationContext主要用於和該Servlet相關的一些組件,比如Controller、ViewResovler等。

另外一點,上述代碼中的this.onRefresh(wac)過程會觸發DispatchServlet初始話方法onRefresh(wac):

protected void onRefresh(ApplicationContext context) {
    this.initStrategies(context);
}

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);
}

這個過程就是Spring Web MVC框架初始化默認的使用的九大策略,這九大策略參考下篇文章。

 

 


免責聲明!

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



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