在web项目的启动过程当中,咱们但愿知道它的通常流程是什么,这样咱们就能够在各个流程中加入相应的功能,或者对于咱们排错也有帮助。前端
咱们知道,当咱们启动tomcat容器之后,容器首先初始化一些必要的组件,加载项目所引用到的jar包(分别从jdk,tomcat,还有web-inf中的lib目录下),而后接下来的一步就是去读取web项目的web.xml配置文件。因此web项目里面必需要有web.xml配置文件。java
咱们来看一份标准的web.xml配置文件,这是我从个人项目中抽取出来的。web
能够看出web.xml的主要配置项有以下几种。spring
a.context-param:上下文参数,经过键值对的方式配置一些上下文信息,如contextConfigLocation,咱们给他配置为classpath:ApplicationContext.xml,说明去classpath:ApplicationContext.xml这个地方去寻找spring的主配置文件。tomcat
b.listener:listener就是监听器,他会监听一些变化(好比servlet的初始化),而后就能够触发监听器的代码了。session
c.filter:过滤器,顾名思义,就是对请求进行过滤,filter也会在项目启动的时候被实例化。通常一个filter要对应filter-mapping,用于筛选所要执行过滤器中代码的url路径。若是一个filter没有filter-mapping,那它存在的意义就不大,它在web.xml存在的目的纯粹就是为了在项目启动的时候被实例化,从而执行其内部的代码。上述配置文件中的startFilter就是这个做用。mvc
d.servlet,servlet的配置与filter相似,就是对请求进行拦截,不一样的请求分配到不一样的servlet类进行处理。app
为了观察项目中各组件的启动顺序,我在相关的dao,entity类,service类,controllers类均加上了static代码块和无参的构造函数。static代码块是在类加载的时候运行,构造函数在类实例化时候运行,以下所示。框架
运行项目。看看控制台打印出来的日志。jsp
咱们能够看到,项目的启动顺序首先是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.