1、Servlet 继承树
java3)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 生命周期
XML<packaging>war</packaging> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> </dependency> <dependency> <groupId>com.csdn</groupId> <artifactId>pro03-fruit-optimize</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
javapackage 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正在销毁...."); } }
java4)Servlet的生命周期 - Servlet是tomcat去实例化的,不是程序员new的 - Servlet中的服务方法也不是程序员主动调用的,也是由tomcat去调用的。当有请求到来时,tomcat通过反射执行service方法 - Servlet的生命周期分为四个阶段:实例化、初始化、服务、销毁 - 默认情况下,Servlet不会随着容器的启动而被实例化,而是当第一次有人请求我的时候,我才会被实例化 当容器停止时,容器中的Servlet实例会被销毁,destroy方法被调用
3、Servlet 线程不安全问题
javapackage 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++; } }
java- Servlet在tomcat容器中是单实例的是线程不安全的 ① 单实例的意思是:所有客户端发过来的请求都是同一个ServletLifecycle实例来处理 第一个用户发请求过来时,容器会去实例化servlet,然后进入服务阶段,从此之后,所有的请求到来时,直接执行服务方法 ② 线程不安全的意思时:既然所有的请求到来时是同一个servlet实例去处理的,那么这些请求之间不能共用数据(共用变量) 什么情况下共用变量?servlet中有成员变量,而服务方法中需要根据成员变量的值决定程序流程 如果第一个请求到来时,执行服务方法,然后在服务方法中更改成员的值,从而就会导致其他的请求到来时流程发生变化 小结:线程不安全的本质是:Servlet由成员变量;成员变量的值可能发生变化;业务逻辑依赖于这个变量 ③ 如何解决线程不安全的问题:尽量避免使用成员变量;如果非要使用成员变量,那么要注意业务逻辑不要受成员变量值影响