Servlet 生命周期
文章目录
- 生命周期方法
- 生命周期
- 被创建(`init` 方法,只执行一次)
- 提供服务(`service` 方法,执行多次)
- 被销毁(`destroy` 方法,只执行一次)
- 参考
生命周期方法
@WebServlet("/demo")
public class ServletDemo implements Servlet {/*** 初始化 Servlet 的方法,可以在部署应用时执行一些初始化操作* 被创建时执行,只会执行一次* @param servletConfig* @throws ServletException*/@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("Servlet 初始化");}/*** 返回 Servlet 的配置信息* @return*/@Overridepublic ServletConfig getServletConfig() {return null; // 尚未实现,应返回Servlet的配置信息}/*** 提供服务的方法* 每一次 Servlet 被访问时执行,可以执行多次* @param servletRequest* @param servletResponse* @throws ServletException* @throws IOException*/@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("Hello Servlet!"); // 输出欢迎信息到控制台}/*** 返回 Servlet 的相关信息,如作者、版本等* @return*/@Overridepublic String getServletInfo() {return ""; // 尚未实现,应返回Servlet的相关信息}/*** 在 Servlet 被移除前调用,用于释放资源* 在服务器正常关闭时执行,只会执行一次*/@Overridepublic void destroy() {System.out.println("Servlet 销毁");}
}
根据抽象实现 Servlet
接口 Servlet
类,简单了解 Servlet
的生命周期
- 被创建:执行
init
方法,只执行一次 - 提供服务:执行
service
方法,可以执行多次 - 被销毁:执行
destroy
方法,只执行一次
根据启动 SpringBoot
服务,调用 /demo
接口,最后终止服务,可以看出打印信息
Servlet 初始化
Hello Servlet!
2025-06-03T15:57:54.774+08:00 INFO 78287 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2025-06-03T15:57:56.784+08:00 INFO 78287 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
Servlet 销毁
生命周期
被创建(init
方法,只执行一次)
触发时机 | 具体配置 | load-on-startup 取值 |
---|---|---|
第一次被访问 时创建 | <servlet> 标签下省略或显式配置 | 负数 |
服务器启动 时创建 | <servlet> 标签下配置 | 0 或 正整数 |
init()
仅在 Servlet 实例化后调用一次,这意味着 同一个 Servlet 在内存中只有一个对象(单例)。- 多用户并发访问时可能出现 线程安全问题。尽量不要在 Servlet 中定义可变的成员变量;若必须定义,也避免对其修改。
而在 SpringBoot 中,也是只会被调用一次,Servlet 规范在容器层面确保“单实例、线程复用”,只是把把实例创建这件事自动化配置
Spring Boot 组件 | 创建时机 | 对应的 Servlet 生命周期 |
---|---|---|
DispatcherServlet (Spring MVC 默认入口) | Spring 容器启动完毕后,由 DispatcherServletAutoConfiguration 注册到嵌入式 Tomcat,并默认 loadOnStartup=1 → 随 应用启动即实例化 | 调用一次 init() 做框架级别初始化(HandlerMapping、ViewResolver 等) |
你自定义的 @WebServlet 或 ServletRegistrationBean 注册的原生 Servlet | - 若显式设置 loadOnStartup≥0 → 跟随应用启动立刻实例化- 否则懒加载:第一次请求命中 URL 才建实例 | 同上,实例化后立即执行一次 init() |
@WebServlet(value = "/demo", loadOnStartup = 20)
public class ServletDemo implements Servlet {}
当 loadOnStartup≥0
时,根据启动信息输出,自定义 Servlet 类根据 SpringBoot 启动类初始化,无需调用对应接口调用时初始化
2025-06-03T16:27:16.598+08:00 INFO 78895 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 250 ms
Servlet 初始化
2025-06-03T16:27:16.703+08:00 INFO 78895 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2025-06-03T16:27:16.706+08:00 INFO 78895 --- [ main] web.servlet.DemoApplication : Started DemoApplication in 0.505 seconds (process running for 0.668)
提供服务(service
方法,执行多次)
每次客户端请求该 Servlet,容器都会调用一次 service()
(或其内部的 doGet()
/ doPost()
等方法)。
而在 SpringBoot 中主要探究就是 service
方法在 Spring MVC 链路中的位置,根据请求流程,在 SpringBoot 中几乎只会写 Controller 层,但是这些 Servlet 都能被调用起来,根源仍是 Servlet 的 service()
被 Tomcat 触发
- Tomcat 接受到 HTTP 报文并解析为
HttpServletRequest/Response
对象 - 请求被派发到
DispatcherServlet.service()
,这就是经典 Servletservice()
回调 DispatcherServlet
再把请求继续分发- 走一系列
HandlerInterceptor
/Filter
- 通过
HandlerMapping
匹配到@Controller
/@RestController
方法 - 适配器 (
HandlerAdapter
) 解析参数、执行方法、序列化返回值(HttpMessageConverter
)
- 走一系列
- 最终写回
HttpServletResponse
,返回给浏览器
被销毁(destroy
方法,只执行一次)
- 当服务器正常关闭或应用下线时,Servlet 被销毁,容器调用
destroy()
。 destroy()
在实例被回收前执行,通常用于 释放资源(关闭连接、清理缓存等)。
当 SpringBoot 正常关闭(终止服务),根据之前的实例输出可得
- SpringBoot 发送
ContextClosedEvent
-> Spring Bean 的PreDestory
先执行 - Tomcat 停机流程开始,依次调用注册的 Servlet
destory
方法
当 SpringBoot 容器崩溃/强杀时,操作系统直接回收进程,destroy()
也不会被调用
根据以上两种情况得知,关键资源(连接池、临时文件)依旧建议交给 Spring-managed Bean 来托管并在 @PreDestroy
或 DisposableBean
里关闭
参考
- 3_Servlet_执行原理_哔哩哔哩_bilibili