Java Web应用的加载过程

       在介绍Spring IoC和MVC的加载前,用这篇小文章简单地记录下,最简单的web应用的加载过程。

一、从最简单的web应用出发

       使用Eclipse直接创建一个Dynamic Web Project即可,工程如下test-web,然后右键→Run as→Run on Server,然后访问:http://localhost:8080/test-web/

可以看到,返回的是404错误,表示找不到请求的资源。

       其实这个web应用是可运行而且没问题的。问题在于它没有Servlet可以接收并处理请求,在这里也没有定义首页和错误页的默认选项,因此应用直接返回了404找不到资源错误。如果把首页配置上去,默认的访问可以直接使用首页,我们增加web.xml和欢迎页index.jsp,如下

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xmlns="http://java.sun.com/xml/ns/javaee"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 5     id="WebApp_ID" version="3.0">
 6     <display-name>test-web</display-name>
 7     <welcome-file-list>
 8         <welcome-file>/WEB-INF/jsp/index.jsp</welcome-file>
 9     </welcome-file-list>
10 </web-app>

index.jsp

 1 <%@ page language="java" contentType="text/html; charset=utf-8"
 2     pageEncoding="utf-8"%>
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 4 <html>
 5 <head>
 6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 7 <title>Insert title here</title>
 8 </head>
 9 <body>Hello
10 </body>
11 </html>

       重新启动应用,然后访问http://localhost:8080/test-web/,结果如下。

       可见,确实得到了正确的响应。

二、Web应用的简单加载过程

那Web是怎样加载的呢?如下图:      

 

       简单地说,web应用加载后,会先初始化整个web应用的唯一的ServletContext,即Servlet应用上下文(说白了就只有这一步)。这个上下文是必须要有的,而且每个web应用只有一个。ServletContext定义了运行在Servlet的应用程序环境的一些行为和观点,可以使用ServletContext实现对象来取得所请求资源的URL、设置与存储属性、应用程序初始参数,甚至动态设置Servlet实例。web.xml中配置的首页、错误页等,都会被web应用解析并按照最后的请求适配处理。

       ServletContext属性的配置可以在web.xml的<context-param />中配置:

1     <context-param>
2         <param-name>contextConfigLocation</param-name>
3         <param-value>
4             classpath*:applicationContext*.xml
5         </param-value>
6     </context-param>

 

       总结一句话就是:web应用在部署时,web容器为web应用初始化了唯一的ServletContext,之后其他的可扩展选项按照配置进行初始化,然后就开始接收请求进行处理。

       以上便是一个最简web应用的加载。

三、Web应用的常规加载过程

       实际上,一个web.xml里面有很多的配置,而其中,接触最多的就是Listener、Filter、Servlet。在这里。我们并没有定义Listener、Filter、Servlet(实际处理请求的类),这是可行的,因为这些都是可扩展的选择。下面简单地介绍下这几个扩展选项:

1、Listener:

       Web容器管理Servlet/JSP相关的对象生命周期,若对HttpServletRequest对象、HttpSession对象、ServletContext对象在生成、销毁或相关属性设置发生变化的时机点有兴趣,需要进行一些处理,如进行资源的加载、数据库的初始化等,可以使用Listener。主要有2大类的监听器Listener:

  1. ServletContext事件监听器:ServletContextListener、ServletContextAttributeListener
  2. HttpSession事件监听器:HttpSessionListener、HttpSessionAttributeListener、HttpSessionBindingListener、HttpSessionActivationListener

下面主要讲解ServletContext相关的2个监听器,其作用如下:

       Spring IoC容器的配置就是ServletContextListener的实现类ContextLoaderListener,它在ServletContext加载之后就开始进行IoC容器的初始化和bean的加载解析。配置如下:

 1     <!-- 默认的spring配置文件是在WEB-INF下的applicationContext.xml -->
 2     <listener>
 3         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 4     </listener>
 5     <context-param>
 6         <param-name>contextConfigLocation</param-name>
 7         <param-value>
 8             classpath*:applicationContext*.xml
 9         </param-value>
10     </context-param>

 

2、Filter

       在容器调用Servlet的service()方法前,Servlet并不会知道有请求的到来,而在Servlet的service()方法运行后,容器真正对浏览器进行HTTP相应之前,浏览器也不会知道Servlet真正的响应是什么。过滤器Filter正如其名称所示,是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。Filter的解析是按照其在web.xml中的声明顺序来的。

       常见到的就是强制字符转码的CharacterEncodingFilter:

 1     <filter>
 2         <filter-name>CharacterEncodingFilter</filter-name>
 3         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
 4         <init-param>
 5             <param-name>encoding</param-name>
 6             <param-value>UTF-8</param-value>
 7         </init-param>
 8     </filter>
 9     <filter-mapping>
10         <filter-name>CharacterEncodingFilter</filter-name>
11         <url-pattern>/*</url-pattern>
12     </filter-mapping>

 

 

3、Servlet

       这是处理实际请求的类,整个web应用存在的意义,是因为存在可以处理实际请求的Servlet,因此,一般Web应用中都需要配置Servlet。而Spring Web MVC中配置的类就是DispatcherServlet,如下:

 1     <!-- springMVC的核心控制器 -->
 2     <servlet>
 3         <servlet-name>springMVC</servlet-name>
 4         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 5         <init-param>
 6             <param-name>contextConfigLocation</param-name>
 7             <param-value>classpath*:springMVC-servlet.xml</param-value>
 8         </init-param>
 9         <load-on-startup>1</load-on-startup>
10     </servlet>
11     <servlet-mapping>
12         <servlet-name>springMVC</servlet-name>
13         <url-pattern>/</url-pattern>
14     </servlet-mapping>

       从以上定义可以看出(实际上也可以进行调试debug):这些加载顺序  context-param  ==>  Listener  ==>  Filter  ==>  Servlet。

      大体的加载流程表示如下:

  1. 读取web.xml的配置参数,如context-param、listener配置等
  2. web容器为web应用初始化一个唯一的全局上下文ServletContext,并把上述的参数配置即context-param,维护到ServletContext中。
  3. ServletContext初始化完成后,初始化配置的Listener,这里是Spring的ContextLoaderListener(实现了ServletContextListener,ServletContext初始化完成后会调用其contextInitialized方法),初始化Spring的IoC容器,即ApplicationContext,同时把自己设置给ServletContext,并设置WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE。
  4. 按照顺序加载配置Filter
  5. 加载配置的Servlet。这里是DispatcherServlet,它会初始化自己的ApplicationContext(主要是controller),同时把IoC容器的ApplicationContext,即WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE设置为自己的父容器,并注册在ServletContext。

 

整体的web.xml配置

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xmlns="http://java.sun.com/xml/ns/javaee"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 5     id="WebApp_ID" version="3.0">
 6 
 7     <!-- 默认的spring配置文件是在WEB-INF下的applicationContext.xml -->
 8     <listener>
 9         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
10     </listener>
11     <context-param>
12         <param-name>contextConfigLocation</param-name>
13         <param-value>
14             classpath*:applicationContext*.xml
15         </param-value>
16     </context-param>
17 
18     <!-- 强制进行转码 -->
19     <filter>
20         <filter-name>CharacterEncodingFilter</filter-name>
21         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
22         <init-param>
23             <param-name>encoding</param-name>
24             <param-value>UTF-8</param-value>
25         </init-param>
26     </filter>
27     <filter-mapping>
28         <filter-name>CharacterEncodingFilter</filter-name>
29         <url-pattern>/*</url-pattern>
30     </filter-mapping>
31 
32     <!-- springMVC的核心控制器 -->
33     <servlet>
34         <servlet-name>springMVC</servlet-name>
35         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
36         <init-param>
37             <param-name>contextConfigLocation</param-name>
38             <param-value>classpath*:springMVC-servlet.xml</param-value>
39         </init-param>
40         <load-on-startup>1</load-on-startup>
41     </servlet>
42     <servlet-mapping>
43         <servlet-name>springMVC</servlet-name>
44         <url-pattern>/</url-pattern>
45     </servlet-mapping>
46 
47     <!-- session配置 -->
48     <session-config>
49         <session-timeout>30</session-timeout>
50     </session-config>
51 
52     <!-- 欢迎页面 -->
53     <welcome-file-list>
54         <welcome-file>index.html</welcome-file>
55         <welcome-file>index.jsp</welcome-file>
56     </welcome-file-list>
57 
58     <!-- 错误页面 -->
59     <error-page>
60         <error-code>403</error-code>
61         <location>/WEB-INF/jsp/403.jsp</location>
62     </error-page>
63     <error-page>
64         <error-code>404</error-code>
65         <location>/WEB-INF/jsp/404.jsp</location>
66     </error-page>
67     <error-page>
68         <error-code>500</error-code>
69         <location>/WEB-INF/jsp/500.jsp</location>
70     </error-page>
71     <error-page>
72         <exception-type>java.lang.Throwable</exception-type>
73         <location>/WEB-INF/jsp/error.jsp</location>
74     </error-page>
75 </web-app>

 

      备注:web.xml的其他配置、IoC的记载、DispatcherServlet的解析等后续将进行逐一介绍。

 

posted @ 2018-04-15 22:33  心明谭  阅读(365)  评论(0编辑  收藏  举报