Servlet 生命周期详解(完整流程解析)
Servlet 作为 Java Web 开发中的核心组件,其整个生命周期由 Servlet 容器(例如 Tomcat)统一管理。从加载创建到最终销毁,主要经历五个关键阶段:加载与实例化、初始化、请求处理、销毁,其中前四个为实际运行环节,最后一个为回收环节。整体执行顺序如下所示:
一、生命周期各阶段说明
| 阶段 | 触发时机 | 核心方法 | 执行次数 | 核心说明 |
|---|---|---|---|---|
| 1. 加载与实例化 | ① 容器启动时(通过配置决定); ② 首次请求到达该 Servlet 时 |
无显式方法调用(容器使用反射机制调用构造函数) | 仅一次 | 容器通过反射创建 Servlet 实例,默认采用单例模式;若需多实例需特殊配置 |
| 2. 初始化 | 实例化完成后立即执行 | init(ServletConfig config) |
仅一次 | 用于完成资源初始化工作,如数据库连接建立、配置文件读取等,可通过传入的 ServletConfig 获取初始化参数 |
| 3. 请求处理 | 每当客户端发起请求(GET、POST 等)时触发 | service(HttpServletRequest req, HttpServletResponse resp)(底层根据请求类型分发至 doGet / doPost 等) |
多次(每次请求均会执行) | 负责处理具体业务逻辑。容器为每个请求分配独立线程,因此在编写代码时必须考虑线程安全问题 |
| 4. 销毁 | ① 容器关闭; ② Web 应用被卸载; ③ 容器检测到 Servlet 长时间未使用(极少发生) |
destroy() |
仅一次 | 执行清理操作,如关闭数据库连接、释放缓存资源等。执行完毕后实例将被 JVM 垃圾回收 |
二、关键方法深入解析
1. 构造方法(实例化过程)
Servlet 的构造方法由容器通过反射机制自动调用。默认情况下使用无参构造函数。若开发者自定义了有参构造,也必须保留无参构造,否则容器无法完成实例化。
在默认的单例模式下,该构造方法仅执行一次,所有请求共享同一个实例对象。因此,在 Servlet 中应避免使用可变的成员变量,以防出现线程安全问题,推荐使用局部变量或 ThreadLocal 进行数据隔离。
2. init(ServletConfig config) 方法
此方法是初始化阶段的核心入口,容器会在实例化后立即调用,并自动传入一个 ServletConfig 对象,其中封装了 Servlet 名称、初始化参数以及对 ServletContext 的引用。
开发者可选择重写无参版本的 init() 方法,底层仍会调用带参方法,便于简化初始化逻辑。
ServletConfig
init()
init(ServletConfig)
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config); // 必须调用,否则ServletConfig无法被获取
// 初始化数据库连接
String dbUrl = config.getInitParameter("dbUrl");
System.out.println("Servlet初始化,数据库地址:" + dbUrl);
}
3. service(ServletRequest req, ServletResponse resp) 方法
当容器接收到客户端请求时,首先调用 service() 方法。该方法会根据请求方式(如 GET、POST、PUT 等)自动将请求转发给对应的处理方法(如 doGet()、doPost())。
如果子类未重写 service() 方法,则父类 HttpServlet 中的默认实现会进行判断和分发。若未提供对应请求方式的处理方法,则返回 HTTP 405 错误(Method Not Allowed)。
service
doXxx
doGet/doPost
HttpServletMethodNotSupportedException
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp); // 父类实现请求分发逻辑
System.out.println("处理请求:" + req.getMethod());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("处理GET请求");
}
4. destroy() 方法
在 Servlet 被销毁之前,容器会调用 destroy() 方法,用于执行必要的资源释放操作,如关闭数据库连接池、注销监听器、清除临时数据等。
该方法在整个生命周期中只执行一次,确保应用优雅退出。
@Override
public void destroy() {
// 关闭数据库连接、清理线程池等
System.out.println("Servlet销毁,释放资源");
}
三、重要特性与开发建议
单例特性
默认情况下,每个 Servlet 类在整个容器中只有一个实例,所有请求共用该实例。这意味着多个线程可能同时访问同一对象,因此:
- 禁止在 Servlet 中定义可变的成员变量;
- 推荐使用局部变量或
ThreadLocal来维护请求级别的状态信息; - 保证业务逻辑的线程安全性。
加载时机控制
Servlet 的加载可以是“懒加载”或“预加载”:
- 默认行为:首次请求时才加载并实例化(延迟加载);
- 预加载配置:可在
web.xml中通过 <load-on-startup> 标签设置,使容器在启动时即完成加载; - 数值越小,优先级越高,适用于需要提前初始化的核心服务组件。
<load-on-startup>1</load-on-startup>
@WebServlet(loadOnStartup = 1)
<!-- web.xml 配置示例 -->
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>dbUrl</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
ServletContext 作用域
ServletContext 是 Web 应用级别的上下文对象,其生命周期与整个应用一致——从应用启动到停止。它可用于存储全局共享数据(如系统配置、计数器、缓存等),并通过 getServletContext() 方法获取引用。
getServletContext()
四、生命周期流程图(简化版)
以下为 Servlet 从创建到销毁的整体流程示意:
容器启动/首次请求 → 加载Servlet类 → 实例化(构造方法) → init()初始化 →
↓(每次请求)
service() → doGet/doPost处理请求 →
↓(容器关闭/应用卸载)
destroy()销毁 → 实例被GC回收

雷达卡


京公网安备 11010802022788号







