当前位置: 首页 > news >正文

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 等)
你自定义的 @WebServletServletRegistrationBean 注册的原生 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() ,这就是经典 Servlet service() 回调
  • 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 来托管并在 @PreDestroyDisposableBean 里关闭

参考

  • 3_Servlet_执行原理_哔哩哔哩_bilibili

相关文章:

  • 无人机自主降落论文解析
  • recipes中声明 DEPENDS += “virtual/kernel“ 的效果
  • 25年宁德时代新能源科技SHL 测评语言理解数字推理Verify题库
  • 兼容老设备!EtherNet/IP转DeviceNet网关解决储能产线通讯难题
  • Modbus转ETHERNET IP网关:快速冷却系统的智能化升级密钥
  • impala中更改公网ip为内网ip
  • Vue混入
  • 第二章支线六 ·CSS幻纹术:背景、遮罩与视觉层级
  • 吃透 Golang 基础:数据结构之 Map
  • MyBatis相关面试题
  • Snakemake 中 glob_wildcards() 使用注意事项总结
  • 立志成为一名优秀测试开发工程师(第十一天)—Postman动态参数/变量、文件上传、断言策略、批量执行及CSV/JSON数据驱动测试
  • Nginx 配置视频文件播放指南
  • TitanIDE智算版:一键开启云端算法开发环境
  • Qt企业级串口通信实战:高效稳定的工业级应用开发指南
  • QUIC——UDP实现可靠性传输
  • DeepSeek眼中的文明印记:山海经
  • 软件评测师 案例真题笔记
  • 黑马程序员TypeScript课程笔记3
  • 电脑安装系统蓝屏的原因
  • 孝感网站建设/网站建设 全网营销
  • 手机网站支持微信支付吗/寄生虫seo教程
  • 网站制作如皋/十大搜索引擎
  • 名字logo设计生成器免费/网站seo诊断技巧
  • 宠物网站设计说明书/网站软件下载app
  • win7 iis配置网站 视频教程/爱站网能不能挖掘关键词