Servlet的继承树,生命周期和线程不安全

 1、Servlet 继承树

Servlet的继承树,生命周期和线程不安全_第1张图片

 

3)Servlet的继承树
- Servlet接口
   public interface Servlet{
       public void init(config);
       public void service(request,response);
       public void destroy();
   }
- GenericServlet抽象类
   public abstract class GenericServlet implements Servlet{
       实现了init方法和destroy方法。service方法仍然保持抽象
   }
- HttpServlet抽象类 - 最初设计时,基于http协议,因此产生了HttpServlet,将来可能会基于其他协议出现其他协议下的Servlet
   public abstract class HttpServlet extends GenericServlet{
        实现了service方法。然后重载了service方法
        protected void service(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
            String method=request.getMethod();
            if("POST".equals(method)){
                doPost(request,response);
            }else if("PUT".equals(method)){
                doPut(...)
            }else{...
            }
        }
        细化了服务方法:
        public void doPost(){}
        public void doGet(){}
        public void doDelete(){}
        public void doPut(){}
   }

 2、Servlet 生命周期

    war
    
        
            jakarta.servlet
            jakarta.servlet-api
            6.0.0
        

        
            com.csdn
            pro03-fruit-optimize
            1.0-SNAPSHOT
        
    
package com.csdn.servlet;
import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
//4、演示Servlet生命周期
@WebServlet("/h04")
public class ServletLifecycle extends GenericServlet {
    // tomcat被执行的时候,他是不会被实例化的,这样是比较合理的
    // 因为假设项目里面有一万个Servlet,tomcat在启动的时候,
    // 就要实例化一万个实例对象,但是一万个也不知道用户什么时候来访问,
    // 放在tomcat里面,就会使tomcat启动的时间拉长,延迟实例化,只执行一次
    public ServletLifecycle() {
        System.out.println("ServletLifecycle正在实例化....");
    }
    //当有请求到来时,会被执行,多次请求可以执行多次
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("ServletLifecycle正在服务....");
    }
    //请求到来时,先实例化,然后执行init方法,只执行一次,然后执行service方法
    @Override
    public void init() throws ServletException {
        System.out.println("ServletLifecycle正在初始化....");

    }
    //tomcat停止时,执行destroy方法
    @Override
    public void destroy() {
        System.out.println("ServletLifecycle正在销毁....");
    }
}
4)Servlet的生命周期
- Servlet是tomcat去实例化的,不是程序员new的
- Servlet中的服务方法也不是程序员主动调用的,也是由tomcat去调用的。当有请求到来时,tomcat通过反射执行service方法
- Servlet的生命周期分为四个阶段:实例化、初始化、服务、销毁
- 默认情况下,Servlet不会随着容器的启动而被实例化,而是当第一次有人请求我的时候,我才会被实例化
  当容器停止时,容器中的Servlet实例会被销毁,destroy方法被调用

 3、Servlet 线程不安全问题

Servlet的继承树,生命周期和线程不安全_第2张图片

package com.csdn.servlet;
import jakarta.servlet.GenericServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
//5、演示线程不安全的问题
@WebServlet("/h05")
public class ThreadUnsafeServlet extends GenericServlet {
    public Integer i = 1;
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        if (i % 2 == 0) {
            System.out.print("A");
        } else {
            System.out.print("B");
        }
        i++;
    }
}
- Servlet在tomcat容器中是单实例的是线程不安全的
        ① 单实例的意思是:所有客户端发过来的请求都是同一个ServletLifecycle实例来处理
            第一个用户发请求过来时,容器会去实例化servlet,然后进入服务阶段,从此之后,所有的请求到来时,直接执行服务方法
        ② 线程不安全的意思时:既然所有的请求到来时是同一个servlet实例去处理的,那么这些请求之间不能共用数据(共用变量)
            什么情况下共用变量?servlet中有成员变量,而服务方法中需要根据成员变量的值决定程序流程
            如果第一个请求到来时,执行服务方法,然后在服务方法中更改成员的值,从而就会导致其他的请求到来时流程发生变化
            小结:线程不安全的本质是:Servlet由成员变量;成员变量的值可能发生变化;业务逻辑依赖于这个变量
        ③ 如何解决线程不安全的问题:尽量避免使用成员变量;如果非要使用成员变量,那么要注意业务逻辑不要受成员变量值影响

你可能感兴趣的:(#,Tomcat-Servlet,java,Servlet,生命周期,线程不安全)