基础
简介
- 一个 Servlet 程序就是一个实现了特殊接口的java类,它由支持 Servlet (具有 Servlet 引擎)的web服务器调用和启动运行
- 一个 Servlet 程序负责处理它所对应的一个或一组url地址的访问请求,并接收客户端发出的访问请求信息和产生响应内容。它的请求-响应的典型过程如下图:
编码实现
- 所有的自定义的 Servlet 实现都必须实现
javax.servlet.Servlet
接口 。该接口中有很多方法不需要实现,所以可以去继承已经实现了该接口的类
- GenericServlet类。GenericServlet 实现了 Servlet 接口的基本特征和功能
- HttpServlet类。HttpServlet 继承了 GenericServlet 类,并在其基础上进行了一些对 Http 协议的扩充。
- 所以一般,我们编写 Servlet 直接继承
HttpServlet
类,并覆盖需要的方法即可
- 客户端每次访问一个支持HTTP的Servlet程序时,Servlet引擎都将调用Servlet的service()方法来进行处理。
-
HTTPServletRequest
用于封装 Http 请求,HTTPServletResponse
用于封装 Http 响应。
生命周期
源码分析
Servlet 的生命周期是由Web服务器来维护的,其相关的方法,在javax.servlet.Servlet
接口中都有定义。接口源码如下(版本不同略有出入)
public interface Servlet {
// 初始化方法
public void init(ServletConfig config) throws ServletException;
// 获取参数配置
public ServletConfig getServletConfig();
// 运行方法
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
// 获取Servlet 信息
public String getServletInfo();
// 销毁方法
public void destroy();
}
生命周期概述
- Servlet 启动的时候,初始化并开始生命周期,在服务器关闭的时候,销毁这个对象,结束生命周期
- 整个生命周期只有一个 Servlet 对象。多客户端并发请求该 Servlet 时,服务器启动多个线程分别执行该 Servlet 的 service() 方法
- Servlet 启动的时机(web.xml中配置)
- 服务器启动就会启动(如Tomcat启动的时候):load-on-startup = 1
- 第一次请求这个 Servlet 才启动:load-on-startup = 0
[图片上传失败...(image-85e858-1530584334578)]
- Servlet的生命周期是由 Servlet 的容器来控制的,它可以分为3个阶段: 初始化、运行、销毁
初始化阶段
- Servlet 容器加载 Servlet 类,把 Servlet 类的 class 文件数据读到内存中
- 创建一个 ServletConfig 对象,包含了 Servlet 的初始化配置信息
- 创建一个 Servlet 对象
- 调用 Servlet 对象的 init() 方法进行初始化
运行阶段
- 当servlet容器接收到一个请求时,servlet容器会针对这个请求创建 servletRequest 和 servletResponse 对象
- 然后调用 service() 方法。并把这两个参数传递给 service() 方法。service() 方法通过 servletRequest 对象获得请求的信息, 并处理该请求
- 通过 servletResponse 对象生成这个请求的响应结果。然后销毁servletRequest和servletResponse对象。我们不管这个请求是post提交的还是get提交的,最终这个请求都会由service() 方法来处理
销毁阶段
- 当Web应用被终止时,servlet容器会先调用servlet对象的destrory()方法,然后再销毁servlet对象,同时也会销毁与servlet对象相关联的servletConfig对象
- 我们可以在destroy()方法的实现中,释放servlet所占用的资源,如关闭数据库连接,关闭文件输入输出流等
生命周期分析
注意
- 构造方法、init()方法、destroy()方法只会被调用一次
- 每次访问会重新发一次请求调用 service() 方法
- getLastModified() 只有当访问方式是 Get 的时候才会调用,返回 -1 表示永远是新的,不使用缓存
关联注解
@PostConstruct
、@PreDestroy
两个注解和 Servlet 的生命周期有关,这两个注解被用来修饰非静态方法,且不能抛出异常
-
@PostConstruct
: 在构造方法之后,init()之前被调用,只调用一次 -
@PreDestroy
: 在destroy()之后,Servlet被彻底卸载之前调用,只调用一次
完整生命周期
[图片上传失败...(image-146269-1530584334578)]
测试代码,源码地址
- 环境设置:
Idea + Maven + Servlet2.5 + tomcat8
。Pom 依赖如下, Idea 的使用,见本博客Idea
分类文章
<!--2.X 版本-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
- 代码
public class LifeCycleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LifeCycleServlet() {
System.out.println("调用 构造方法, 多次访问只被调用一次");
}
/**
* 在构造方法之后,init()之前被调用, 只调用一次
*/
@PostConstruct
public void postConstruct() {
System.out.println("调用 postConstruct()方法, 多次访问只被调用一次");
}
@Override
public void init() {
System.out.println("调用 init()方法 , 多次访问只被调用一次");
}
/**
* 继承自 javax.servlet.Servlet
* 这个方法中会去调用 javax.servlet.http.HttpServlet.service() 方法
*
* @param req
* @param res
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("调用 Servlet接口的 service()方法 ");
super.service(req, res);
}
/**
* 继承自 javax.servlet.http.HttpServlet
* 这个方法中会判断请求方式 然后分别调用 doGet()、doPost()等
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("调用 HttpServlet的 service()方法 ");
super.service(req, resp);
}
/**
* 只有以get方式调用该servlet的时候才会调用getLastModified
* 返回-1 表示永远是最近的,不使用缓存
* 在 doGet() 之前被调用
*
* @param req
* @return
*/
@Override
protected long getLastModified(HttpServletRequest req) {
System.out.println("调用 getLastModified()方法 ");
return super.getLastModified(req);
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
System.out.println("调用 doGet()方法 ");
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) {
System.out.println("调用 doPost()方法 ");
}
@Override
public void destroy() {
System.out.println("调用 destroy()方法 ");
super.destroy();
}
/**
* 在destroy()之后,Servlet被彻底卸载之前调用,只调用一次
*/
@PreDestroy
public void preDestroy() {
System.out.println("调用 preDestroy()方法, 多次访问只被调用一次");
}
}
- web.xml 配置
<servlet>
<servlet-name>LifeCycleServlet</servlet-name>
<servlet-class>com.learning.select2.base.LifeCycleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeCycleServlet</servlet-name>
<url-pattern>/lifeCycleServlet</url-pattern>
</servlet-mapping>
- 输出结果
【Get 调用输出】
调用 构造方法, 多次访问只被调用一次
调用 postConstruct()方法, 多次访问只被调用一次
调用 init()方法 , 多次访问只被调用一次
调用 Servlet接口的 service()方法
调用 HttpServlet的 service()方法
调用 getLastModified()方法
调用 doGet()方法
调用 Servlet接口的 service()方法
调用 HttpServlet的 service()方法
调用 getLastModified()方法
调用 doGet()方法
【Post 调用输出】
调用 Servlet接口的 service()方法
调用 HttpServlet的 service()方法
调用 doPost()方法
【UnDeploy 应用下线】
调用 destroy()方法
调用 preDestroy()方法, 多次访问只被调用一次