Web項目的啟動流程


在web項目的啟動過程中,我們希望知道它的一般流程是什么,這樣我們就可以在各個流程中加入相應的功能,或者對於我們排錯也有幫助。

  1. 啟動tomcat容器以后,容器首先初始化一些必要的組件;
  2. 加載項目所引用到的jar包(分別從jdk,tomcat,還有web-inf中的lib目錄下);
  3. 讀取web項目的web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/root-context.xml,classpath:spring/bwp-context.xml,classpath:spring/csp-context.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
 <!--  <listener>
    <listener-class>usi.btfb.filter.HttpSessionCollector</listener-class>
  </listener> -->
  
   <!-- session共享過濾器start,此過濾器要放在其他過濾器之前 -->
  <!-- <filter>
     <filter-name>springSessionRepositoryFilter</filter-name>
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
   </filter>
  <filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
     <url-pattern>/*</url-pattern>
   </filter-mapping> -->
   <!-- session共享過濾器end -->
  
  <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

 <!--  cxfservlet 
      <servlet>
        <servlet-name>cxf</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxf</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>-->

  <!-- 解決xss & sql漏洞 -->  
  <filter>
    <filter-name>jsFilter</filter-name>
    <filter-class>usi.btfb.filter.SpecialChrEscapeFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>jsFilter</filter-name>
    <url-pattern>*.do</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping> 
  
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>uiLoaderServlet</servlet-name>
    <servlet-class>usi.sys.servlet.UiLoaderServlet</servlet-class>
    <init-param>
      <param-name>uiConfigLocation</param-name>
      <param-value>classpath:ui/ui.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <filter>
    <filter-name>CheckSessionFilter</filter-name>
    <!-- <filter-class>usi.sys.filter.CheckSessionFilter</filter-class> -->
    <filter-class>usi.btfb.filter.CheckSessionFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CheckSessionFilter</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
    <filter-mapping>
    <filter-name>CheckSessionFilter</filter-name>
    <url-pattern>*.html</url-pattern>
  </filter-mapping>
  <context-param>
    <param-name>menuFilter</param-name>
    <param-value>true</param-value>
  </context-param>
  <filter>
    <filter-name>MenuAccessFilter</filter-name>
    <filter-class>usi.sys.filter.MenuAccessFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>MenuAccessFilter</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
  <filter>
    <filter-name>lazyLoadingFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>lazyLoadingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
    <filter-name>getSessionContentFilter</filter-name>
    <filter-class>usi.sys.filter.GetSessionContentFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>getSessionContentFilter</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
  <session-config>
    <session-timeout>600</session-timeout>
  </session-config>
  <error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/500.jsp</location>
  </error-page>
  <error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/views/404.jsp</location>
  </error-page>
  <error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/WEB-INF/views/500.jsp</location>
  </error-page>
  
  <!--druid監控頁面 -->
    <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
        <init-param>
            <!-- 不允許清空統計數據 -->
            <param-name>resetEnable</param-name>
            <param-value>false</param-value>
        </init-param>
        <!-- <init-param>
          //  用戶名
            <param-name>loginUsername</param-name>
            <param-value>admin</param-value>
        </init-param>
        <init-param>
          //  密碼
            <param-name>loginPassword</param-name>
            <param-value>GS_zhkf_2019@</param-value>
        </init-param> -->
    </servlet>
    <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
    </servlet-mapping>
    <!-- 如果需要監控uri,設置Web關聯監控配置 -->
    <filter>
        <filter-name>DruidWebStatFilter</filter-name>
        <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
        <init-param>
            <param-name>exclusions</param-name><!--排除統計干擾 -->
            <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>DruidWebStatFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--druid監控頁面 -->
</web-app>

 

可以看出web.xml的主要配置項有如下幾種。

  a.context-param:上下文參數,通過鍵值對的方式配置一些上下文信息,如contextConfigLocation,我們給他配置為classpath:ApplicationContext.xml,說明去classpath:ApplicationContext.xml這個地方去尋找spring的主配置文件。

  b.listener:listener就是監聽器,他會監聽一些變化(比如servlet的初始化),然后就可以觸發監聽器的代碼了。

<listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
  </listener>
<!--
1、此監聽器主要用於解決java.beans.Introspector導致的內存泄漏的問題
2、此監聽器應該配置在web.xml中與Spring相關監聽器中的第一個位置(也要在ContextLoaderListener的前面)
3、JDK中的java.beans.Introspector類的用途是發現Java類是否符合JavaBean規范如果有的框架或程序用到了Introspector類,那么就會啟用一個系統級別的緩存,
此緩存會存放一些曾加載並分析過的JavaBean的引用。當Web服務器關閉時,由於此緩存中存放着這些JavaBean的引用,所以垃圾回收器無法回收Web容器中的JavaBean對象,最后導致
內存變大。而org.springframework.web.util.IntrospectorCleanupListener就是專門用來處理Introspector內存泄漏問題的輔助類。IntrospectorCleanupListener會在
Web服務器停止時清理Introspector緩存,使那些Javabean能被垃圾回收器正確回收。Spring自身不會出現這種問題,因為Spring在加載並分析完一個類之后會馬上刷新JavaBeans Introspector緩存,
這就保證Spring中不會出現這種內存泄漏的問題。但有些程序和框架在使用了JavaBeans Introspector之后,沒有進行清理工作(如Quartz,Struts),最后導致內存泄漏
-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
<!--
作用:啟動Web容器時,自動裝配ApplicationContext的配置信息
-->

  c.filter:過濾器,顧名思義,就是對請求進行過濾,filter也會在項目啟動的時候被實例化。一般一個filter要對應filter-mapping,用於篩選所要執行過濾器中代碼的url路徑。如果一個filter沒有filter-mapping,那它存在的意義就不大,它在web.xml存在的目的純粹就是為了在項目啟動的時候被實例化,從而執行其內部的代碼。上述配置文件中的startFilter就是這個作用。

  d.servlet,servlet的配置與filter類似,就是對請求進行攔截,不同的請求分配到不同的servlet類進行處理。

啟動順序首先是context-param,接着是listener,在接下來是filter,最后才是servlet。

所以:簡單來說:web項目啟動經過如下步驟。

  1.項目啟動,加載依賴的jar包。

  2.web容器(tomcat)先提供一個全局上下文ServletContext.

  3.web容器去讀取web.xml文件,並且運行ContextLoaderListener監聽器,該監聽器因為實現了ServletContextListener接口,所以當發現容器生成了一個ServletContext實例的時候,便會執行ServletContextListener接口的初始化方法,在該初始化方法中根據contextConfigLocation指定的位置去讀取spring的主要配置文件,然后生成web應用上下文WebApplicationContext,並且將其作為一個屬性注入到ServletContext中。

  4.初始化WebApplicationContext以后,啟動了“業務層”的spring容器,並開始加載病初始化applicationContext配置文件中所掃描的類。

  5.然后就是初始化filter,最后初始化servlet。

  所以說作為web項目,WebApplicationContext的生成必須要在web容器存在的情況下才能實現,因為他需要ServletContext,而ServletContext是web容器生成的。

  

  DispatcherServlet是什么?有什么用。

  簡單來說,它就是一個servlet,但是它是一個特殊的servlet,是整個spring mvc框架的核心,他是一個前端servlet,spring mvc經過前端servlet來接受所有的請求,然后再講具體工作派發給其他的的servlet來具體實現。

同時,再servlet的配置文件中,我們看到名為SpringMvc的讀取了contextConfigLocation所定義的配置文件(classpath:ApplicationContext-mvc.xml),啟動了web層的spring容器,在這個容器里,我們初始化了所有的controller類。如控制台打印的日志所示。

  

  由於初始化DispatcherServlet伴隨着啟動spring mvc容器(即上面所說的web層容器),所以需要較長的時間,所以我們希望在項目啟動的時候就進行初始化的操作。這也是我們將load-on-startup項設為1的原因。因為這個屬性設為正數的表示在項目啟動的時候就初始化,數字越小表明越早初始化。如果我們將其設為負數的話。那么在項目啟動的時候,將不會啟動spring mvc的容器,而是當我們第一次訪問某個controller所對應的action的時候才來加載啟動容器,這將會造成較長時間的等待,所以我們一般將load-on-startup設為1.

 


免責聲明!

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



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