《Java 100 天进阶之路》第68篇:JavaWeb核心技术之Servlet(2026版)
2026/8/2 3:28:04 网站建设 项目流程

第68篇:JavaWeb核心技术之Servlet(2026版)

📌系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第67篇:JVM面试压轴题 |
➡️ 下一篇:第69篇:JSP与EL表达式(待发布

🗺️ 本文阅读地图(3 分钟速览)

JVM调优专题已收官,本篇开启JavaWeb专题。Servlet是Java Web开发的“地基”——Spring MVC、Spring Boot底层都是Servlet。理解Servlet,才能真正理解Web框架:

模块核心问题一句话回答
Servlet是什么Java Web的“地基”是什么?运行在Web容器中的Java类,处理HTTP请求并返回响应
生命周期Servlet从生到死经历什么?加载→实例化→init()service()destroy()
核心对象请求和响应用什么对象?HttpServletRequest(请求)、HttpServletResponse(响应)
三大组件Servlet规范还有哪些组件?Servlet + Filter + Listener,三者分工协作
异步处理Servlet 3.0带来了什么?AsyncContext实现非阻塞处理,释放容器线程
Servlet vs Spring MVC现在还用Servlet吗?Spring MVC底层仍是Servlet,但封装了细节
Jakarta EE迁移javax包去哪了?javax.servlet迁移到jakarta.servlet(Jakarta EE 9+)
面试最爱问高频考点有哪些?见文末 🎤 小节

一、核心知识点

1. Servlet是什么?

Servlet(Server Applet)是Java EE(现Jakarta EE)规范中定义的服务器端组件,用于接收客户端请求并返回响应。它不依赖特定的平台或协议,最常用的是HTTP Servlet

💡本质:Servlet就是一个运行在Web容器(Tomcat、Jetty等)中的Java类,遵循特定的生命周期规范。

2. Servlet的核心地位

Servlet是Java Web一切框架的底层基石

无论是Spring MVC的DispatcherServlet,还是Spring Boot的内嵌Tomcat,底层都是Servlet。理解Servlet,是理解一切Java Web框架的前提。

3. 2026年重要背景:Jakarta EE迁移

从Jakarta EE 9开始,所有javax.servlet包名改为jakarta.servlet。Servlet API版本演进:

  • Servlet 4.0(Java EE 8):javax.servlet
  • Servlet 5.0+(Jakarta EE 9+):jakarta.servlet
  • Servlet 6.0(Jakarta EE 10+):去除SecurityManager相关API

💡面试注意:2026年,新建项目应使用jakarta.servlet,老项目迁移需注意包名变更。

4. Servlet三大核心组件

组件作用典型场景
Servlet处理具体业务请求用户登录、订单查询
Filter请求/响应预处理和后处理日志记录、编码过滤、权限校验
Listener监听Web应用生命周期事件应用启动初始化、Session管理

二、通俗讲解(1分钟开心学)

把Servlet想象成餐厅的“服务员”

  • 客户端(浏览器):顾客,坐在桌前要点菜(发请求)。

  • Servlet:服务员,负责接收顾客的点菜单(请求),去厨房(业务逻辑)拿菜,再把菜端给顾客(响应)。每个服务员只服务一位顾客(一个请求对应一个Servlet实例的service方法调用)。

  • Filter:餐厅门口的迎宾员。每个顾客进来,先经过迎宾员检查——带口罩了吗?有预约吗?(请求过滤),走的时候迎宾员再说声“欢迎下次光临”(响应后处理)。

  • Listener:餐厅的传感器。餐厅开门了(应用启动),传感器记录;有顾客进来了(Session创建),传感器记录;餐厅关门了(应用关闭),传感器记录。

  • Web容器(Tomcat):餐厅的管理系统,负责招聘服务员(创建Servlet实例)、安排工作(调用生命周期方法)、辞退服务员(销毁Servlet)。

一句话总结:Filter管“进出门”,Servlet管“核心服务”,Listener管“全程监控”。

三、Servlet生命周期

Servlet生命周期由Web容器(Tomcat等)全权管理,开发者不需要手动newServlet对象。

3.1 生命周期四阶段

各阶段详解

阶段方法调用次数触发时机说明
加载与实例化构造方法1次第一次请求到达(默认)或容器启动时默认懒加载,可通过<load-on-startup>改为容器启动时加载
初始化init()1次实例化后立即调用加载数据库连接池、配置文件等资源
服务service()每次请求每次HTTP请求到达根据请求方法分发到doGet()/doPost()
销毁destroy()1次容器关闭或应用卸载时释放资源,如关闭数据库连接

💡重要理解:Servlet是单例多线程——整个应用只有一个Servlet实例,但每个请求会创建一个新线程调用service()方法。因此Servlet实例变量不是线程安全的

3.2 代码示例
importjakarta.servlet.*;importjakarta.servlet.http.*;importjakarta.servlet.annotation.*;importjava.io.*;@WebServlet("/hello")publicclassHelloServletextendsHttpServlet{// ① 初始化(执行一次)@Overridepublicvoidinit()throwsServletException{System.out.println("Servlet初始化,加载资源");}// ② 服务(每次请求执行)@OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{resp.setContentType("text/html;charset=UTF-8");PrintWriterout=resp.getWriter();out.println("<h1>Hello, Servlet!</h1>");out.println("<p>当前时间:"+newjava.util.Date()+"</p>");}@OverrideprotectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// POST请求处理doGet(req,resp);}// ③ 销毁(执行一次)@Overridepublicvoiddestroy(){System.out.println("Servlet销毁,释放资源");}}

web.xml配置方式(传统,仍用于Servlet 6.0):

<web-app><servlet><servlet-name>hello</servlet-name><servlet-class>com.example.HelloServlet</servlet-class><load-on-startup>1</load-on-startup><!-- 容器启动时加载 --></servlet><servlet-mapping><servlet-name>hello</servlet-name><url-pattern>/hello</url-pattern></servlet-mapping></web-app>

四、核心对象:Request & Response

4.1 HttpServletRequest——请求对象
方法作用
getParameter(String name)获取单个请求参数
getParameterMap()获取所有请求参数Map
getHeader(String name)获取请求头
getSession()获取/创建Session
getRequestDispatcher()请求转发
setAttribute(String, Object)设置请求属性(转发传递数据)
startAsync()Servlet 3.0启动异步处理
4.2 HttpServletResponse——响应对象
方法作用
setContentType(String)设置响应内容类型(如text/html;charset=UTF-8
setStatus(int)设置HTTP状态码
getWriter()获取字符输出流(输出HTML)
getOutputStream()获取字节输出流(输出文件/图片)
sendRedirect(String)重定向(302)
addCookie(Cookie)添加Cookie
4.3 请求转发 vs 重定向
对比请求转发(forward)重定向(sendRedirect)
浏览器地址栏不变变化
请求次数1次(服务器内部)2次(客户端重新发起)
数据共享✅ 可共享request属性❌ 不可共享
性能更高(少一次请求)较低(多一次请求)
适用场景服务器内部跳转页面跳转、防止表单重复提交

五、Servlet 3.0+ 异步处理

5.1 为什么需要异步?

传统Servlet模型中,一个请求占用一个容器线程直到处理完成。如果业务有耗时操作(如调用外部API、大文件处理),容器线程会被长时间占用,导致并发能力下降

Servlet 3.0引入异步处理:将耗时任务交给新线程,释放容器线程处理其他请求,提升吞吐量。

5.2 异步Servlet实战
importjakarta.servlet.*;importjakarta.servlet.http.*;importjakarta.servlet.annotation.*;importjava.util.concurrent.*;@WebServlet(value="/async",asyncSupported=true)// 关键:启用异步publicclassAsyncServletextendsHttpServlet{privateExecutorServiceexecutor=Executors.newFixedThreadPool(10);@OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 1. 启动异步上下文AsyncContextctx=req.startAsync();//// 2. 提交耗时任务到线程池executor.submit(()->{try{// 模拟耗时操作(如调用外部API、查询数据库)Thread.sleep(3000);// 3. 获取响应并输出HttpServletResponseresponse=(HttpServletResponse)ctx.getResponse();response.setContentType("text/plain;charset=UTF-8");response.getWriter().println("异步处理完成!");}catch(Exceptione){e.printStackTrace();}finally{// 4. 完成异步处理ctx.complete();}});// 容器线程立即释放,不阻塞!}}

💡关键点asyncSupported = true启用异步,startAsync()获取AsyncContext,耗时任务在新线程执行,完成后调用complete()

六、三大组件:Filter & Listener

6.1 Filter——请求拦截器

Filter是Servlet规范的一部分,在请求到达Servlet之前和响应返回客户端之后执行。

典型场景:日志记录、统一编码处理、登录验证、跨域处理、敏感词过滤。

importjakarta.servlet.*;importjakarta.servlet.annotation.*;importjava.io.IOException;@WebFilter("/*")// 拦截所有请求publicclassLogFilterimplementsFilter{@Overridepublicvoidinit(FilterConfigconfig)throwsServletException{System.out.println("Filter初始化");}@OverridepublicvoiddoFilter(ServletRequestreq,ServletResponseresp,FilterChainchain)throwsIOException,ServletException{// 前置处理System.out.println("请求到达:"+System.currentTimeMillis());// 放行到下一个Filter或Servletchain.doFilter(req,resp);// 后置处理System.out.println("响应返回:"+System.currentTimeMillis());}@Overridepublicvoiddestroy(){System.out.println("Filter销毁");}}

Filter链执行顺序:多个Filter按@WebFilterfilterName字母顺序或web.xml配置顺序执行,形成责任链

6.2 Listener——事件监听器

Listener监听Web应用中关键对象的生命周期事件。

三种核心Listener

Listener监听对象典型场景
ServletContextListener应用上下文(启动/关闭)加载配置文件、初始化数据库连接池
HttpSessionListenerSession(创建/销毁)在线用户统计
ServletRequestListener请求(创建/销毁)请求日志记录
importjakarta.servlet.*;publicclassAppListenerimplementsServletContextListener{@OverridepublicvoidcontextInitialized(ServletContextEventsce){System.out.println("应用启动,加载配置...");// 加载数据库连接池、Spring容器等}@OverridepublicvoidcontextDestroyed(ServletContextEventsce){System.out.println("应用关闭,释放资源...");}}

七、Servlet vs Spring MVC

对比维度ServletSpring MVC
定位Java Web底层规范基于Servlet的高级Web框架
开发方式继承HttpServlet,手动配置映射注解驱动(@Controller@RequestMapping
参数绑定手动req.getParameter()自动绑定到方法参数
视图渲染手动拼接HTML或用JSP自动渲染,支持多种视图技术
启动速度较慢(需加载Spring上下文)
内存占用
适用场景理解底层、轻量级应用绝大部分企业级应用

💡核心结论:Spring MVC底层是DispatcherServlet,它本身就是一个Servlet。掌握了Servlet,就掌握了Spring MVC的“发动机”。

八、避坑要点

错误/误区后果正确做法
Servlet实例变量非线程安全多线程数据混乱尽量用局部变量,避免在Servlet中定义可变的实例变量
忘记asyncSupported = true异步功能不生效注解中加上asyncSupported = true
Filter中不调用chain.doFilter()请求被拦截,无法到达目标必须调用chain.doFilter()放行
请求转发和重定向混淆数据丢失或重复提交转发用forward,重定向用sendRedirect
忘记设置setContentType中文乱码统一设置text/html;charset=UTF-8
老项目使用javax.servlet不兼容Jakarta EE 9+新项目使用jakarta.servlet

九、面试高频考点

Q1:Servlet的生命周期有哪些阶段?

四个阶段:①加载与实例化(容器创建Servlet实例);②初始化(调用init(),执行一次);③服务(调用service(),每次请求执行);④销毁(调用destroy(),执行一次)。

Q2:Servlet是单例还是多例?线程安全吗?

Servlet是单例,整个应用只有一个实例。线程不安全——多个请求共享同一个Servlet实例,实例变量会被多线程共享。因此应避免在Servlet中使用可变的实例变量,尽量使用局部变量。

Q3:Filter和Interceptor的区别?

Filter是Servlet规范的一部分,运行在Web容器中,在请求到达Servlet之前执行。Interceptor是Spring MVC的组件,运行在Spring容器中,在Handler执行前后执行。Filter更底层,Interceptor功能更丰富(可注入Spring Bean)。

Q4:请求转发(forward)和重定向(redirect)的区别?

转发(forward)是服务器内部跳转,地址栏不变,1次请求,可共享request属性。重定向(redirect)是客户端重新发起请求,地址栏变化,2次请求,不可共享request属性。

Q5:javax.servletjakarta.servlet有什么区别?

Jakarta EE 9开始,所有javax包名改为jakarta。新项目使用jakarta.servlet。老项目迁移需修改import和依赖版本。

🎤 面试官追问陷阱(加分题)

追问1:“Servlet 3.0的异步处理中,startAsync()之后容器线程会怎样?”

👉 容器线程立即释放,回到线程池处理其他请求。耗时任务在AsyncContext关联的新线程中执行。完成后调用complete()通知容器。

追问2:“<load-on-startup>设置为正数和负数有什么区别?”

👉 正数:容器启动时加载Servlet,数值越小优先级越高。负数或未设置:懒加载——第一次请求到达时才创建Servlet实例。

十、练习题

  1. 代码题:编写一个Servlet,接收name参数,返回“Hello, [name]!”的HTML页面。

  2. 分析题:Filter和Servlet的执行顺序是什么?一个请求经过多个Filter时,顺序如何确定?

  3. 场景题:某Web应用需要统计在线用户数,应该使用什么组件?如何实现?

📊 你的学习进度

  • 当前:第68篇 / 共108篇 ·进阶篇:JavaWeb核心技术(第68~72篇)
  • ✅ 已完成:基础篇44篇 + 第45~68篇
  • 📖 正在学:第68篇
  • ⏳ 待学习:第69~108篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

👉 下一篇文章预告

🚀下一篇:《第69篇:JSP与EL表达式》

内容简介:JSP原理、九大内置对象、EL表达式语法、JSTL标签库、JSP与Servlet的关系。

👉JavaWeb专题持续深入,拿下JSP与EL!

📌《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询