zoukankan      html  css  js  c++  java
  • web项目启动流程探索

      在web项目的启动过程中,我们希望知道它的一般流程是什么,这样我们就可以在各个流程中加入相应的功能,或者对于我们排错也有帮助。

      我们知道,当我们启动tomcat容器以后,容器首先初始化一些必要的组件,加载项目所引用到的jar包(分别从jdk,tomcat,还有web-inf中的lib目录下),然后接下来的一步就是去读取web项目的web.xml配置文件。所以web项目里面必须要有web.xml配置文件。

     

      我们来看一份标准的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"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
        version="3.1">
        <!-- spring上下文 -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:ApplicationContext.xml,
            </param-value>
        </context-param>
        <!-- 加载log4j配置文件 -->
        <context-param>
            <param-name>log4jConfigLocation</param-name>
            <param-value>classpath:log4j.properties</param-value>
        </context-param>
        <context-param>
            <param-name>webAppRootKey</param-name>
            <param-value>www.warrior.com</param-value>
        </context-param>
        <!-- 监听器 -->
        <listener>
            <listener-class>org.springframework.web.util.Log4jConfigListener
            </listener-class>
        </listener>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
        <!-- 字符编码过滤器 -->
        <filter>
            <filter-name>encodingFilter</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>
        </filter>
        <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- 初始化filter -->
        <filter>
            <filter-name>startFilter</filter-name>
            <filter-class>com.xdx.filter.StartFilter</filter-class>
        </filter>
        <!-- session过滤器 -->
        <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>
        <!-- 以下配置是spring mvc -->
        <servlet>
            <servlet-name>springMvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:ApplicationContext-mvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springMvc</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        <error-page>
            <error-code>404</error-code>
            <location>/404.jsp</location>
        </error-page>
        <session-config>
            <session-timeout>600</session-timeout>
        </session-config>
    </web-app>

       

      可以看出web.xml的主要配置项有如下几种。

      a.context-param:上下文参数,通过键值对的方式配置一些上下文信息,如contextConfigLocation,我们给他配置为classpath:ApplicationContext.xml,说明去classpath:ApplicationContext.xml这个地方去寻找spring的主配置文件。

      b.listener:listener就是监听器,他会监听一些变化(比如servlet的初始化),然后就可以触发监听器的代码了。

      c.filter:过滤器,顾名思义,就是对请求进行过滤,filter也会在项目启动的时候被实例化。一般一个filter要对应filter-mapping,用于筛选所要执行过滤器中代码的url路径。如果一个filter没有filter-mapping,那它存在的意义就不大,它在web.xml存在的目的纯粹就是为了在项目启动的时候被实例化,从而执行其内部的代码。上述配置文件中的startFilter就是这个作用。

      d.servlet,servlet的配置与filter类似,就是对请求进行拦截,不同的请求分配到不同的servlet类进行处理。

      为了观察项目中各组件的启动顺序,我在相关的dao,entity类,service类,controllers类均加上了static代码块和无参的构造函数。static代码块是在类加载的时候运行,构造函数在类实例化时候运行,如下所示。

     

      

       运行项目。看看控制台打印出来的日志。

      

      我们可以看到,项目的启动顺序首先是context-param,接着是listener,在接下来是filter,最后才是servlet。

      

      问题1:改换context-param,listener,filter,servlet配置语句在web.xml中的顺序,其启动顺序是否会变呢?

      答案是否定的,即便是吧关于servlet的配置放在最前面,其加载顺序还是会在最后。但是需要注意的是,在同一类型的配置项中,其在web.xml的顺序会影响其启动的顺序,比如有两个filter,filter1在配置文件中先于filter2,则filter1先于filter2被加载实例化。

      

      问题2:org.springframework.web.context.ContextLoaderListener的作用。

      ContextLoaderListener这个监听器继承自ContextLoader并且实现了ServletContextListener,他的主要作用是去寻找并读取spring主配置文件ApplicationContext.xml(也就是context-param中所定义的contextConfigLocation),然后启动WebApplicationContext,也可叫做web应用上下文,并且最重要的是,它将WebApplicationContext注入到servletContext容器中(作为servletContext的一个attribute,属性),并且在WebApplicationContext中保留了一个servletContext的引用。所以我们可以通过

       WebApplicationContext得到servletContext,也可以通过servletContext获取到WebApplicationContext

      通过WebApplicationContext得到servletContext:

      WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();

        ServletContext servletContext = webApplicationContext.getServletContext();

      通过servletContext获取WebApplicationContext:

      ServletContext servletContext = event.getServletContext();

      ApplicationContext application = WebApplicationContextUtils .getWebApplicationContext(servletContext);

     

      问题3:webApplicationContext和servletContext是谁先存在呢?

      当然是servletcontext,ServletContext是web容器(tomcat等)为web项目提供的一个全局上下文,一个web项目中只有一个。它其实是后面生成的WebApplicationContext容器的一个宿主。

      

      所以:简单来说: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容器生成的。

      

      问题4:DispatcherServlet是什么?有什么用。

      简单来说,它就是一个servlet,但是它是一个特殊的servlet,是整个spring mvc框架的核心,他是一个前端servlet,spring mvc经过前端servlet来接受所有的请求,然后再讲具体工作派发给其他的的servlet来具体实现。

    同时,再servlet的配置文件中,我们看到名为SpringMvc的读取了contextConfigLocation所定义的配置文件(classpath:ApplicationContext-mvc.xml),启动了web层的spring容器,在这个容器里,我们初始化了所有的controller类。如控制台打印的日志所示。

      

      问题5:由于初始化DispatcherServlet伴随着启动spring mvc容器(即上面所说的web层容器),所以需要较长的时间,所以我们希望在项目启动的时候就进行初始化的操作。这也是我们将load-on-startup项设为1的原因。因为这个属性设为正数的表示在项目启动的时候就初始化,数字越小表明越早初始化。如果我们将其设为负数的话。那么在项目启动的时候,将不会启动spring mvc的容器,而是当我们第一次访问某个controller所对应的action的时候才来加载启动容器,这将会造成较长时间的等待,所以我们一般将load-on-startup设为1.

     

  • 相关阅读:
    进度条
    html5 表单新增事件
    html5 表单的新增type属性
    html5 表单的新增元素
    html5 语义化标签
    jq 手风琴案例
    codeforces 702D D. Road to Post Office(数学)
    codeforces 702C C. Cellular Network(水题)
    codeforces 702B B. Powers of Two(水题)
    codeforces 702A A. Maximum Increase(水题)
  • 原文地址:https://www.cnblogs.com/roy-blog/p/7656834.html
Copyright © 2011-2022 走看看