Servlet的生命周期从创建到销毁可分为如下四个过程:
- Servlet实例化;
- 调用init()方法初始化;
- 调用service()方法来处理客户端的请求;
- 调用destory()方法销毁;
接下来我们详细了解下Servlet生命周期的四个过程。
一、实例化
根据Servlet请求的路径,查找Servlet的实例,如果实例不存在,则通过调用构造方法完成Servlet实例的创建。Servlet的请求路径可通过配置web.xml文件或者注解的方式,一般都使用注解,比较方便例如(@WebServlet("/demo.do"));
二、初始化
通过Servlet实例调用init()方法初始化,init()方法只能调用一次,在第一次创建Servlet时被调用,在之后每次请求时则不再调用。在init()方法里面创建的数据,可以被用于Servlet的整个生命周期。
代码举例:
package com.my.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/demo.do")
public class DemoServlet extends HttpServlet {
//1.实例化
//构造方法
public DemoServlet() {
System.out.println("DemoServlet被实例化!");
}
//2.初始化
//重写HttpServlet(父类)的init()方法初始化
//通过创建的实例自动调用init()方法
@Override
public void init() throws ServletException {
System.out.println("DemoServlet被初始化!");
}
//3.服务
//通过实例调用父类的Service()方法
//Service()方法会根据请求方式的不同(GET或POST)
//调用子类重写的doGet或doPost方法
//如果子类没有重写,则调用父类的方法(响应405)
// 根据响应方式的不同,需要调用不同的请求方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("service方法被调用!");
}
当浏览器请求该Servlet路径时,先通过构造方法创建实例,在通过实例调用init()方法进行初始化,这里浏览器发起了6次请求,可以发现init()方法只被调用了一次。
三、服务
service()方法是执行实际任务的主要方法。Servlet容器调用service()方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
每次服务器接收到一个Servlet请求时,实例化Servlet后,通过实例调用父类的Service()方法,Service()方法会根据请求方式的不同(GET或POST),调用子类重写的doGet()或doPost()方法,如果子类没有重写,则调用父类的方法doGet()或doPost()方法,而父类的doGet()和doPost()方法响应一个405错误页面,所以一般都会重写doGet()和doPost()方法。当然,你也可以重写父类的Service方法,但没有实际意义。
父类HttpServlet中源码如下:
根据响应方式的不同,需要调用不同的请求方法
代码演示:
package com.my.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/demo.do")
public class DemoServlet extends HttpServlet {
//1.实例化
//构造方法
public DemoServlet() {
System.out.println("DemoServlet被实例化!");
}
//2.初始化
//重写HttpServlet(父类)的init()方法初始化
//通过创建的实例自动调用init()方法
@Override
public void init() throws ServletException {
System.out.println("DemoServlet被初始化!");
}
//3.服务
//通过实例调用父类的Service()方法
//Service()方法会根据请求方式的不同(GET或POST)
//调用子类重写的doGet或doPost方法
//如果子类没有重写,则调用父类的方法(响应405)
// 根据响应方式的不同,需要调用不同的请求方法
// @Override
// protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("doGet方法被调用!");
// }
// @Override
// protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("doPost方法被调用!");
// }
子类中没有重写父类的doGet()和doPost()方法时,收到来自浏览器的GET请求,则会出现405错误页面。405状态码:代表请求的方式服务器不提供支持。
子类重写doGet()方法,收到来自浏览器的GET请求,则会通过父类service()方法进行逻辑判断后调用子类重写的doGet()方法。这里我将结果输出至控制台。
四、销毁
服务器关闭或重启的时候,会调用Servlet实例的destroy()销毁所有的Servlet实例。destroy()方法也只会被调用一次,在Servlet生命周期结束时调用。destroy()方法会将Servlet关闭数据库连接、停止后台线程、把Cookie列表或点击计数器写入到磁盘,并执行其他类似的清理活动。在调用destroy()方法之后,Servlet对象会被标记为垃圾回收。
代码示例:
package com.my.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/demo.do")
public class DemoServlet extends HttpServlet {
//1.实例化
//构造方法
public DemoServlet() {
System.out.println("DemoServlet被实例化!");
}
//2.初始化
//重写HttpServlet(父类)的init()方法初始化
//通过创建的实例自动调用init()方法
@Override
public void init() throws ServletException {
System.out.println("DemoServlet被初始化!");
}
//3.服务
//通过实例调用父类的Service()方法
//Service()方法会根据请求方式的不同(GET或POST)
//调用子类重写的doGet或doPost方法
//如果子类没有重写,则调用父类的方法(响应405)
// 根据响应方式的不同,需要调用不同的请求方法
// @Override
// protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("service方法被调用!");
// }
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet方法被调用!");
}
// @Override
// protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("doPost方法被调用!");
// }
//销毁
//重写父类的destroy()方法
@Override
public void destroy() {
System.out.println("实例对象已被销毁!");
}
}
通过浏览器请求Servlet路径发起请求,这里我发送了三次,最后关闭tomcat服务器。
运行结果:
总结:
当用调用一个Servlet时,就会创建一个Servlet实例,通过实例调用init()方法初始化,可以将Servlet中一直用到的资源放在init()方法中。当客户端(浏览器)请求Servlet路径发起请求,通过请求方式的不同,执行doGet()或doPost()方法,子类中重写doGet()或doPost()方法请求和响应给客户端浏览器。当服务器关闭或重启时,通过实例调用distroy()方法销毁所有Servlet实例,Servlet的生命周期到此就结束了。