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,如下
<?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_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>test-web</display-name>
<welcome-file-list>
<welcome-file>/WEB-INF/jsp/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>Hello
</body>
</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 />中配置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:applicationContext*.xml
</param-value>
</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:
- ServletContext事件监听器:ServletContextListener、ServletContextAttributeListener
- HttpSession事件监听器:HttpSessionListener、HttpSessionAttributeListener、HttpSessionBindingListener、HttpSessionActivationListener
下面主要讲解ServletContext相关的2个监听器,其作用如下:
Spring IoC容器的配置就是ServletContextListener的实现类ContextLoaderListener,它在ServletContext加载之后就开始进行IoC容器的初始化和bean的加载解析。配置如下:
<!-- 默认的spring配置文件是在WEB-INF下的applicationContext.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:applicationContext*.xml
</param-value>
</context-param>
2、Filter
在容器调用Servlet的service()方法前,Servlet并不会知道有请求的到来,而在Servlet的service()方法运行后,容器真正对浏览器进行HTTP相应之前,浏览器也不会知道Servlet真正的响应是什么。过滤器Filter正如其名称所示,是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。Filter的解析是按照其在web.xml中的声明顺序来的。
常见到的就是强制字符转码的CharacterEncodingFilter:
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、Servlet
这是处理实际请求的类,整个web应用存在的意义,是因为存在可以处理实际请求的Servlet,因此,一般Web应用中都需要配置Servlet。而Spring Web MVC中配置的类就是DispatcherServlet,如下:
<!-- springMVC的核心控制器 -->
<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*:springMVC-servlet.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>
从以上定义可以看出(实际上也可以进行调试debug):这些加载顺序 context-param ==> Listener ==> Filter ==> Servlet。
大体的加载流程表示如下:
- 读取web.xml的配置参数,如context-param、listener配置等
- web容器为web应用初始化一个唯一的全局上下文ServletContext,并把上述的参数配置即context-param,维护到ServletContext中。
- ServletContext初始化完成后,初始化配置的Listener,这里是Spring的ContextLoaderListener(实现了ServletContextListener,ServletContext初始化完成后会调用其contextInitialized方法),初始化Spring的IoC容器,即ApplicationContext,同时把自己设置给ServletContext,并设置WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE。
- 按照顺序加载配置Filter
- 加载配置的Servlet。这里是DispatcherServlet,它会初始化自己的ApplicationContext(主要是controller),同时把IoC容器的ApplicationContext,即WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE设置为自己的父容器,并注册在ServletContext。
整体的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_0.xsd"
id="WebApp_ID" version="3.0"> <!-- 默认的spring配置文件是在WEB-INF下的applicationContext.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:applicationContext*.xml
</param-value>
</context-param> <!-- 强制进行转码 -->
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <!-- springMVC的核心控制器 -->
<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*:springMVC-servlet.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> <!-- session配置 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config> <!-- 欢迎页面 -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <!-- 错误页面 -->
<error-page>
<error-code>403</error-code>
<location>/WEB-INF/jsp/403.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/jsp/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/WEB-INF/jsp/error.jsp</location>
</error-page>
</web-app>
备注:web.xml的其他配置、IoC的记载、DispatcherServlet的解析等后续将进行逐一介绍。
最新文章
- 利用nodeJS实现的网络小爬虫
- Kafka笔记
- JUC全景图
- ZigZag-LeetCode
- javaweb学习总结(七)——HttpServletResponse对象(一)(转)
- 一个滑动选中RecyclerView中Item的布局SlidingCheckLayout,手指滑过Item时多项选中。
- Android输入控件详解
- poj 3468 A Simple Problem with Integers(线段树区间更新)
- JsonBuilder初出茅庐
- 【CodeForces 730H】Delete Them
- Springboot项目打包成jar运行2种方式
- maven项目提示web.xml is missing或红色感叹号
- 开源的.NET系统推荐
- HTML5中的audio在手机端和 微信端的自动播放
- vs2013安装及opencv3.0的配置
- Netty 源码剖析之 unSafe.write 方法
- LeetCode题解之Longest Increasing Subsequence
- 如何配置pl/sql 连接远程oracle服务器
- Kubernetes 详解
- C3P0连接参数解释