JavaWeb——Servlet生命周期

一、什么是 Servlet 生命周期?

Servlet 生命周期指的是一个 Servlet 对象从被创建、初始化、接收请求、处理请求,到最后被销毁的整个过程。这个过程由 Web 容器(如 Tomcat, Jetty) 全权管理。开发者不需要手动创建 new MyServlet(),容器会根据规则在合适的时机调用生命周期方法。

二、阶段一:初始化 (init)

目的:在 Servlet 开始处理客户端请求之前,进行一些一次性的、昂贵的资源加载工作(例如建立数据库连接、读取配置文件等)。

触发时机(两种)

  • 默认情况(延迟加载) :当容器启动后,Servlet 并不会立即被初始化。只有当 第一个请求 到达这个 Servlet 时,容器才会创建其实例并初始化。

  • 启动时加载(积极加载) :在 web.xml 中配置 <load-on-startup> 参数,可以让容器在 Web 应用启动时就创建和初始化 Servlet。数值越小,启动优先级越高。参数冲突时,Tomcat会自动处理。

XML 复制代码
<servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>com.example.MyServlet</servlet-class>
    <load-on-startup>1</load-on-startup> <!-- 数字1表示高优先级 -->
</servlet>

执行方法init(ServletConfig config)

  • 容器会调用这个方法。它只会被调用一次,在 Servlet 的整个生命周期中绝不会被调用第二次。

  • ServletConfig 对象包含了 Servlet 的初始化参数(在 web.xml 中配置)和 Servlet 上下文(ServletContext)的引用。

  • 通常,我们不会直接重写此方法,而是重写没有参数的 init() 方法。因为 GenericServlet 类已经提供了一个无参 init() 方法,它会在参数版的 init(ServletConfig) 方法中被调用。

代码示例

java 复制代码
public class MyServlet extends HttpServlet {

    private Connection dbConnection;

    @Override
    public void init() throws ServletException {
        // 这个方法在 init(ServletConfig) 中被调用,只执行一次
        try {
            // 执行一次性的初始化,比如建立数据库连接
            Class.forName("com.mysql.cj.jdbc.Driver");
            dbConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
            System.out.println("数据库连接在init()中建立");
        } catch (Exception e) {
            throw new ServletException("初始化数据库连接失败", e);
        }
    }
}

特点

  • init 方法执行完毕后,Servlet 就处于 "已就绪" 状态,随时可以处理客户端的请求。

三、阶段二:处理请求 (service)

目的:处理所有到达该 Servlet 的客户端请求并返回响应。

触发时机 :每一次客户端请求到达该 Servlet 时,容器都会调用 service 方法。

执行方法service(ServletRequest request, ServletResponse response)

  • 对于 HttpServlet,我们通常不需要重写这个方法。

  • HttpServlet 类已经为我们实现了标准的 service 方法。它会根据请求的 HTTP 方法(GET, POST, PUT, DELETE 等),自动调用相应的 doGet(), doPost(), doPut(), doDelete() 等方法。

  • 我们的主要工作就是重写那些 doXxx 方法来实现业务逻辑。

代码示例

java 复制代码
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 处理GET请求(如点击链接,直接访问URL)
        response.getWriter().println("处理了一个GET请求");
        // 可以使用在init中初始化的dbConnection
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 处理POST请求(如表单提交)
        String user = request.getParameter("user");
        response.getWriter().println("你好, " + user + "! 这是一个POST请求。");
    }
}

特点

  • service 方法(及其分支 doGet/doPost)在 Servlet 的生命周期中可以被调用无数次

  • 容器会为每个请求创建一个新的请求对象(HttpServletRequest)响应对象(HttpServletResponse) ,然后开启一个新的线程来执行 service 方法。因此,Servlet 实例是单例多线程的

四、阶段三:销毁 (destroy)

目的:在 Servlet 生命周期结束时,释放它所占用的资源(例如关闭数据库连接、清理内存等)。

触发时机

  • Web 应用被卸载(或重新加载)。

  • Web 服务器被关闭。

  • 容器检测到需要重新加载 Servlet(某些容器的开发模式)。

执行方法destroy()

  • 这个方法也只会被调用一次,在 Servlet 生命周期结束时。

  • destroy() 方法调用之后,容器会释放这个 Servlet 实例,随后它会被垃圾回收器回收。

  • 容器会在调用 destroy() 之前,确保所有正在 service 方法中执行的线程都已结束或超时。

代码示例

java 复制代码
public class MyServlet extends HttpServlet {

    private Connection dbConnection;

    // ... init() 和 doGet/doPost 方法 ...

    @Override
    public void destroy() {
        // 释放资源
        try {
            if (dbConnection != null && !dbConnection.isClosed()) {
                dbConnection.close();
                System.out.println("数据库连接在destroy()中关闭");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

五、要点

单例多线程

一个 Servlet 类在容器中通常只有一个实例 。对于并发请求,容器会使用多个线程,每个线程执行同一个 Servlet 实例的 service 方法。因此,要特别注意线程安全 问题。记住,不要使用实例变量来存储请求相关的数据 ,因为它们会被所有线程共享。但是可以使用局部变量,它们是线程安全的。

相关推荐
19226382 小时前
基于LabVIEW的转子故障诊断系统:振动信号里的秘密探寻
servlet
精神病不行计算机不上班5 小时前
[Java Web]在IDEA中完整实现Servlet的示例
java·servlet·tomcat·html·intellij-idea·web
精神病不行计算机不上班8 小时前
[Java Web]Java Servlet基础
java·前端·servlet·html·mvc·web·session
好学且牛逼的马9 小时前
HttpServlet 深度拆解:从设计模式看透其核心原理
java·servlet·设计模式
BD_Marathon2 天前
【JavaWeb】请求转发
servlet
cike_y2 天前
JavaWeb之过滤器Filter&监听器
java·servlet·javaweb
BD_Marathon3 天前
【JavaWeb】HttpServletRequest_获取请求行和请求头
servlet
BD_Marathon4 天前
【JavaWeb】Servlet_url-pattern的一些特殊写法问题
java·开发语言·servlet
BD_Marathon4 天前
【JavaWeb】Servlet_jar包导入和Content-Type问题
java·servlet·jar
梦想的旅途24 天前
媒体文件(图片/文件)的上传与管理:获取 Media ID 的技术细节
前端·http·servlet