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

web项目启动流程探索的更多相关文章

  1. 05、NetCore2.0依赖注入(DI)之Web应用启动流程管理

    05.NetCore2.0依赖注入(DI)之Web应用启动流程管理 在一个Asp.net core 2.0 Web应用程序中,启动过程都做了些什么?NetCore2.0的依赖注入(DI)框架是如何管理 ...

  2. web理论知识--网页访问过程(附有Django的web项目访问流程)

    当我们闲暇之余想上网看看新闻,或者看个电影,通常的操作是:打开电脑.打开浏览器.输入网址.浏览页面信息.点击自己感兴趣的连接......那么有没有想过,这些网页从哪里来的?过程中计算机又做了什么事情了 ...

  3. 一个简单的Java Web项目搭建流程

    今天试图在服务器上搭建一个web服务器,顺便回顾了java web项目的入门,使用Servlet处理HTTP请求,并记录日志等操作.当很久没有做过web项目时,有些东西还是很容易忘记的. Maven配 ...

  4. 关于idea中,web项目启动tomcat,访问资源报错404

    背景: web项目启动tomcat,访问相应的资源,报错404,前提资源路径是没错的. 原因: 1.确定是不是web项目 不是的话: 配置web-inf的路径和webroot(web根目录)的路径 2 ...

  5. web项目开发流程

    对于一个web项目,在实际编码之前,有一些通用的步骤来planning a website: 0.Defining the project (predr0->dr0) 对于外部项目,客户一般会发 ...

  6. PC端Web项目开发流程

    从前一直再做前端,突然想到如果有一天领导让自己独立承担一个web 项目的话是否有足够的能力去接这个任务,要学会自己去搭建一些基础的工具信息.所有的这一切在心里都要有个大致的流程,不然真正做的时候难免会 ...

  7. 在web项目启动时,使用监听器来执行某个方法

    在web项目中有很多时候需要在项目启动时就执行一些方法,而且只需要执行一次,比如:加载解析自定义的配置文件.初始化数据库信息等等,在项目启动时就直接执行一些方法,可以减少很多繁琐的操作. 这里写了个简 ...

  8. maven的java web项目启动找不到Spring ContextLoaderListener的解决办法

    用maven搭建的java web项目,上传到git仓库后,当同事clone下来项目,部署到tomcat运行时,就报了如下错误,即启动web项目时,加载web.xml文件,找不到spring的监听器, ...

  9. 在web项目启动时,执行某个方法

    在web项目中有很多时候需要在项目启动时就执行一些方法,而且只需要执行一次,比如:加载解析自定义的配置文件.初始化数据库信息等等,在项目启动时就直接执行一些方法,可以减少很多繁琐的操作. 在工作中遇到 ...

随机推荐

  1. 【2】hadoop搭建准备软件

    准备一:VMware虚拟工具: 链接:http://pan.baidu.com/s/1o7F4A6I 密码:w5ti 准备二:CentOS6.8虚拟机(64位):如果64位不允许安装,可能是电脑设置问 ...

  2. C#算法面试题

    1.产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复. static void GetArray() { ]; ]; ; i < ; i++) { intArr[i] ...

  3. C#获得时间段

    DateTime today = dt.Date;//今天 00:00:00 DateTime tomorrow = dt.Date.AddDays(1);//明天 00:00:00 DateTime ...

  4. C#脏字过滤算法

    public class DirtyWordOper    {        private static Dictionary<string, object> hash = new Di ...

  5. SDN/NFV趋势思考点滴

    一.为什么控制器.网管OSS融合? 1.云化是趋势:传统网络架构管理规模达到瓶颈:微服务架构通过扩充多实例解决管理规模问题.2.NFV是趋势:设备运营商传统网元在云化,以软件形式提供VNF:3.运维体 ...

  6. FPGA时序约束——理论篇

    在FPGA 设计中,很少进行细致全面的时序约束和分析,Fmax是最常见也往往是一个设计唯一的约束.这一方面是由FPGA的特殊结构决定的,另一方面也是由于缺乏好用的工具造成的.好的时序约束可以指导布局布 ...

  7. Mysql相关知识点总结(一)

    information_schema库:information_schema库中的表大都是temporory表,都是只读的,不能进行更新.删除和插入等操作,也不能加触发器,因为它们实际只是一个视图,不 ...

  8. SQL1

    这是社团的题目,我现在就写出来吧,总共两种方法,一种手注,一种用工具(sqlmap). 一.手注(盲注) 1,我们打开题目,可以看到一个登陆页面,这是我们在输入框里面输入万能密码:  ' and '1 ...

  9. js中this的意义

    随着函数使用场合的不同,this的值会发生变化.但是有一个总的原则,那就是this指的是,调用函数的那个对象.

  10. 开始python成长之路

    因为某种特殊原因很不幸的得了脱髓鞘 正要去实习 大展身手 甚至公司都选好了 可就在这个节骨眼..得了传说中的脱髓鞘.经过一年的修养 我决定还是要站起来 毕竟一生的时间很长 这一段时间 我都在玩游戏赚钱 ...