8:Servlet生命周期-Java Web

0 阅读4分钟

8.1 Servlet生命周期

Servlet的生命周期是指从Servlet被创建到最终销毁所经历的一系列阶段。主要包括以下四个阶段:

  1. 实例化:当Web容器首次接收到请求该Servlet的HTTP请求时,如果Servlet还没有实例化,容器会根据web.xml配置或注解信息加载并实例化Servlet类。

  2. 初始化:在Servlet实例化后,容器调用其init()方法进行初始化。通常情况下,开发者会重写这个方法来执行一次性设置操作,例如读取配置、初始化数据源等。可以通过实现ServletConfig接口的对象传入初始化参数。

  3. 服务请求:每当接收到一个与Servlet关联的HTTP请求时,Web容器都会为请求分配一个新的线程,并调用Servlet的service()方法。service()方法会根据请求类型(GET、POST等)调用相应的doGet()、doPost()等方法处理请求。

  4. 销毁:当Web应用程序关闭或者Servlet不再需要时(比如服务器关闭或重新部署应用),容器会调用Servlet的destroy()方法。在这个方法中,开发者可以释放资源,如数据库连接、清理临时文件等。

8.2 Servlet生命周期对应的方法

在这里插入图片描述

  • public void init(ServletConfig config) throws ServletException: 初始化方法,只在Servlet实例被创建后调用一次。
  • public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException: 核心方法,每次请求到达时都由容器调用。默认实现会根据请求类型调用doGet()或doPost()等方法。
  • protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException: 处理HTTP GET请求的方法,需要重写以提供具体功能。
  • protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException: 处理HTTP POST请求的方法,同样需要重写。
  • public void destroy(): 销毁方法,在Servlet生命周期结束时调用,用于释放资源。

在下面的代码和配置中,我们定义了一个名为LifeCycleServlet的Servlet类,并展示了其生命周期中的各个方法:init(), doGet()/doPost(), 和 destroy()。同时,在web.xml部署描述符文件中进行了相应的Servlet配置。

LifeCycleServlet.java

package com.org;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LifeCycleServlet extends HttpServlet {
    // 初始化阶段
    public void init() throws ServletException {
        System.out.println("** 1、Servlet初始化 --> init()");
        // 这里可以进行一些一次性设置操作,如读取配置、数据库连接等
    }

    // 处理HTTP GET请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, java.io.IOException {
        handleRequest(req, resp);
    }

    // 处理HTTP POST请求
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, java.io.IOException {
        handleRequest(req, resp);
    }

    // 公共处理逻辑,将GET和POST请求统一处理
    private void handleRequest(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("** 2、Servlet服务 --> doGet() 或 doPost()");
        // 在这里添加实际业务逻辑
    }

    // 销毁阶段
    public void destroy() {
        System.out.println("** 3、Servlet销毁 --> destroy()");
        // 这里可以释放资源,如关闭数据库连接、清理临时文件等
    }
}

web.xml配置

<!-- 配置Servlet -->
<servlet>
    <servlet-name>life</servlet-name>
    <!-- 定义Servlet类所在的包名和类名 -->
    <servlet-class>com.org.LifeCycleServlet</servlet-class>
    
    <!-- 自动加载并初始化Servlet,值越小优先级越高,值为负数则不会自动加载 -->
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- 映射Servlet -->
<servlet-mapping>
    <servlet-name>life</servlet-name>
    <!-- 设置访问Servlet的URL路径 -->
    <url-pattern>/LifeServlet</url-pattern>
</servlet-mapping>

在这个配置中,当Web应用启动时,由于设置了 <load-on-startup>1</load-on-startup>,Servlet容器会在应用程序启动时立即初始化并调用LifeCycleServletinit()方法。之后,每当客户端通过/LifeServlet URL发起HTTP请求(无论是GET还是POST),都会触发LifeCycleServlet的相应服务方法,并执行业务逻辑。最后,在Web应用停止或重新部署时,Servlet容器会调用LifeCycleServletdestroy()方法来清理资源。

8.3 Servlet的多线程机制

Servlet容器采用多线程机制处理并发请求。对于每一个新的HTTP请求,容器都会创建一个新的线程调用Servlet的service()方法。这意味着同一Servlet实例可能会被多个线程同时访问,因此Servlet设计必须考虑到线程安全问题。

由于Servlet是单实例多线程模型,即整个Web应用只有一个Servlet实例,所以在Servlet内部不应使用任何可变共享数据,除非确保了这些数据的线程安全性。为了处理这种情况,开发者应遵循以下原则:

  • 尽量避免在Servlet中使用静态变量存储状态信息。
  • 如果必须使用共享数据,请确保通过同步机制保护对这些数据的访问。
  • 使用ThreadLocal存储每个线程特有的数据。

总之,Servlet的生命周期管理及多线程机制使得它能够高效地处理并发请求,但在编写Servlet代码时,必须谨慎处理线程安全问题,以保证应用在高并发环境下的正确运行。