本文目录
- 一、Servlet生命周期
- 1、生命周期四个阶段
- 1.1、实例化
- 1.2、初始化
- 1.3、服务
- 1.4、销毁
- 1.5、Servlet执行流程
- 二、Servlet特性
- 1、线程安全问题
- 2、如何保证线程安全
一、Servlet生命周期
1、生命周期四个阶段
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 初始化后调用 init () 方法。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 销毁前调用 destroy() 方法。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
现在让我们详细讨论生命周期的方法。
1.1、实例化
当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象。也可以在容器启动之后立刻创建实例。使用如下代码可以设置Servlet是否在服务器启动时就创建。
实例化只执行一次。
public LifeServlet() {
System.out.println("1、完成实例化");
}
1.2、初始化
在初始化阶段,init()方法会被调用。在后续每次用户请求时不再调用。因此,它是用于一次性初始化,就像 Applet 的 init 方法一样。
Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。
当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。
init()方法只被执行一次
public void init() throws ServletException {
super.init();
System.out.println("2、完成初始化");
}
1.3、服务
当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给service方法。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
service()方法会执行多次
public void service(ServletRequest request,
ServletResponse response)
throws ServletException, IOException{
}
doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。
doGet() 方法
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}
doPost() 方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Servlet 代码
}
1.4、销毁
当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。
destroy()方法执行一次
public void destroy() {
super.destroy();
System.out.println("4、销毁了");
}
1.5、Servlet执行流程
- 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
- Servlet 容器在调用 service() 方法之前加载 Servlet。
- 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
* 演示Servlet的生命周期
* 1、实例化
* 2、init:初始化
* 3、service:服务
* 4、destory:销毁
*/
@WebServlet("/LifeServlet")
public class LifeServlet extends HttpServlet {
public LifeServlet() {
System.out.println("1、完成实例化");
}
@Override
public void init() throws ServletException {
super.init();
System.out.println("2、完成初始化");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("3、就绪中");
response.getWriter().append("Served at:").append(request.getContextPath());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
public void destroy() {
super.destroy();
System.out.println("4、销毁了");
}
}
二、Servlet特性
1、线程安全问题
Servlet在访问之后,会执行实例化操作,创建一个Servlet对象。而我们Tomcat容器可以同时多个线程并发访问同一个Servlet,如果在方法中对成员变量做修改操作,就会有线程安全问题。
2、如何保证线程安全
- synchronize
- 将存在线程安全问题的代码放到同步代码块中
- 实现SingleThreadModel接口
- servlet实现SingleThreadMode接口后。每个线程都会创建servlet实例,这样每个客户端请求就不存在共享资源的问题,但是servlet响应客户端的效率太低,所以已经淘汰。
- 尽可能使用局部变量
将全局变量public boolean status;改为局部变量boolean status = true;
public class TestServlet extends HttpServlet{
// public boolean status;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
boolean status = true;
String cmd = req.getParameter("cmd");
if (cmd.contains("Calculator")) {
status = false;
try {
Thread.sleep(1000);
}catch (Exception e){
}
}
if (!status) {
return;
}
if (cmd.contains("Calculator")){
resp.getWriter().write(cmd);
}
}
}
标签:生命周期,方法,init,调用,线程,Servlet,public From: https://blog.51cto.com/u_15740516/5967176