Servlet 生命周期(完整解析)
Servlet 是 Java Web 核心组件,其生命周期完全由 Servlet 容器(如 Tomcat) 管理,从创建到销毁分为 初始化、请求处理、销毁 三个核心阶段,还包含加载与实例化的前置环节,整体流程如下:
一、生命周期完整阶段(按执行顺序)
| 阶段 | 触发时机 | 核心方法 | 执行次数 | 核心说明 |
|---|---|---|---|---|
| 1. 加载与实例化 | ① 容器启动时(<load-on-startup> 配置);② 首次请求该 Servlet 时 |
无(容器调用构造方法) | 仅 1 次 | 容器通过反射创建 Servlet 实例(默认单例,多实例需配置 SingleThreadModel) |
| 2. 初始化 | 实例化后立即执行 | init(ServletConfig) |
仅 1 次 | 初始化资源(如数据库连接、配置加载),可通过 ServletConfig 获取初始化参数 |
| 3. 请求处理 | 客户端发送请求(GET/POST 等)时 | service(ServletRequest, ServletResponse)(底层调用 doGet/doPost) |
多次(每次请求) | 核心业务逻辑处理,容器为每个请求分配独立线程,需注意线程安全 |
| 4. 销毁 | ① 容器关闭;② 应用卸载;③ 容器检测到 Servlet 长时间未使用(极少触发) | destroy() |
仅 1 次 | 释放资源(如关闭连接、清理缓存),销毁后实例被垃圾回收 |
二、核心方法详解
1. 构造方法(实例化阶段)
- 由容器调用,默认无参构造,若自定义有参构造需保证无参构造存在(否则容器无法实例化);
- 单例模式下仅执行一次,所有请求共享同一个 Servlet 实例(需注意成员变量线程安全)。
2. init (ServletConfig config) 方法
-
初始化入口,容器自动传入
ServletConfig对象(包含 Servlet 名称、初始化参数、ServletContext); -
可重写
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 等)自动分发到对应doXxx方法; -
若未重写
doGet/doPost,默认抛出HttpServletMethodNotSupportedException; -
示例(HttpServlet 子类):
@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 前调用,用于释放资源,示例:
@Override public void destroy() { // 关闭数据库连接、清理线程池等 System.out.println("Servlet销毁,释放资源"); }
三、关键特性与注意事项
-
单例特性:默认情况下,一个 Servlet 类在容器中仅存在一个实例,所有请求共用该实例 → 避免在 Servlet 中定义可变成员变量(易引发线程安全问题),建议使用局部变量或 ThreadLocal。
-
加载时机控制 :
-
默认:首次请求时加载实例化(懒加载);
-
配置
<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><load-on-startup>1</load-on-startup>(web.xml)或@WebServlet(loadOnStartup = 1):容器启动时立即加载,数字越小优先级越高(用于初始化核心服务)
-
-
ServletContext 作用域 :生命周期贯穿整个 Web 应用,可通过
getServletContext()获取,用于共享应用级数据(如全局配置)。
四、生命周期流程图(简化)
容器启动/首次请求 → 加载Servlet类 → 实例化(构造方法) → init()初始化 →
↓(每次请求)
service() → doGet/doPost处理请求 →
↓(容器关闭/应用卸载)
destroy()销毁 → 实例被GC回收