当我们访问购物网站时,常常会看到形如 http://xx.com/brandNo=1 的 URL 请求,服务器接收这类请求后,向浏览器返回的大多是 JSON 格式的数据。这个过程看似简单,背后却隐藏着一套成熟的 Web 处理机制

早期 Web 开发中,每个请求的处理通常包含三个基本步骤:接收请求、处理请求和响应请求。其中,接收和响应这两个环节的逻辑高度一致,属于通用功能,不具备业务差异性。于是,工程师们将这部分公共流程抽象出来,封装成独立的“Web 服务器”,负责统一完成请求的解析与响应的返回

而处理请求的部分则因业务逻辑不同而变化多样,因此被抽取为 Servlet,交由开发人员自行编写具体实现

随着架构的演进,三层架构(表现层、业务逻辑层、数据访问层)逐渐普及,原先集中在 Servlet 中的业务逻辑被进一步拆分,转由 Service 层和 Dao 层分别承担,Servlet 逐渐退化为纯粹的控制层组件

由于 Servlet 本身不擅长动态生成 HTML 页面,JavaServer Pages(JSP)技术应运而生,用于更方便地实现页面渲染。而随着 Spring 生态的成熟,SpringMVC 逐渐取代了传统 Servlet 在 Web 层的主导地位,提供了更强大、更便捷的请求映射、参数解析和视图解析机制

在学习 Java Web 技术的过程中,很多开发者会经历这样的心理变化:从 Servlet,到 Filter、Listener,我们逐渐发现自己写的类没有 main 方法,也没有显式 new 实例,只是简单地在 web.xml 中配置标签,它们就“自动”运行了起来。这种开发模式背后,其实是“注入”和“回调”机制在发挥作用

越深入编程,我们越会意识到:我们能做的事情其实非常有限。主流框架已经完成了大部分底层和架构性工作。我们只需实现某个接口、添加某个注解,框架便会自动创建实例,并通过依赖注入将组件装配到合适的位置。最终,在它预设的执行流程中,我们的代码被自动调用

这种开发模式可以用一个古老的成语来形象地概括:“闭门造车,出门合辙”。我们只需关注业务实现,而框架确保这些实现能够嵌入到更大的运行流程中

很多时候,框架如同一位傀儡师,而我们编写的代码则像是傀儡——我们负责为傀儡设计外观与装饰,真正的调度和运作,则完全由背后的框架(傀儡师)掌控

尽管如今直接编写 Servlet 的机会变少,但理解其设计思想与演进历程,仍然对我们把握 Web 开发本质具有深刻意义

Servlet 版本进化

Servlet 技术的演进几乎是 Java Web 技术发展的缩影

梳理各个主要版本的进化历程、核心特性和其背后的意义

1. Servlet 初期:开创时代

  • 版本: Servlet 1.0 (1997)

  • 核心特性

    • 定义了最基本的 Servlet 接口 (init, service, destroy) 和 ServletRequest/ServletResponse 对象
    • 提供了处理 Web 请求的基本框架
  • 意义与局限

    • 意义: 首次将 Java 应用于服务器端动态网页技术,统一了 HTTP 请求/响应的处理模型,奠定了 Java Web 技术的基石
    • 局限: 功能非常原始,所有逻辑都在 service 方法中完成,需要手动解析请求参数、组装响应,开发效率极低。配置复杂

    Servlet 组件运行在 Servlet 容器(Container)中,通过与容器交互,就可以响应一个 HTTP 请求

2. Servlet 2.x:走向成熟与 JSP 的黄金组合

  • 代表性版本: Servlet 2.3 (2001) & Servlet 2.4 (2003)
  • 核心进化:
    • Filter(过滤器) (2.3引入): 这是一个革命性的特性。允许对请求和响应进行预处理和后处理,实现了横切关注点(如:日志记录、安全验证、编码设置、性能审计)的模块化,与业务逻辑(Servlet)解耦
    • 监听器(Listener) (2.3引入): 可以监听 Web 应用生命周期中的事件(如:应用启动、关闭、Session 的创建和销毁),为应用初始化、资源加载等提供了hook(钩子)
    • War包标准: 明确了 Web 应用打包和部署的标准格式
    • XML配置支持: 使用 web.xml 作为标准的部署描述符,配置更加规范
  • 意义:
    • MVC 雏形: Servlet + JSP + JavaBean 的组合成为了早期 Java Web 开发的事实标准,即 Model 1 和 Model 2(MVC)架构
    • 职责分离: Filter 的引入使得公共逻辑得以抽取,Servlet 可以更专注于核心业务处理
    • 生态系统形成: 基于这套稳定的标准,大量的第三方框架(如 Struts、Spring)开始涌现

3. Servlet 2.5:注解的曙光

  • 版本: Servlet 2.5 (2005)
  • 核心进化
    • 要求运行在 Java 5 及以上平台
    • 支持注解(Annotation),最主要的是 @WebServlet, @WebFilter, @WebListener
  • 意义
    • 简化配置: 开始减少对 web.xml 的依赖,开发者可以直接在 Servlet 类上使用 @WebServlet("/url") 进行配置,开发体验大幅提升。这是向“约定优于配置”理念迈出的重要一步

4. Servlet 3.0:异步革命与全面可编程配置

  • 版本: Servlet 3.0 (2009)
  • 核心进化
    • 异步处理: 提供了 AsyncContext 接口,允许 Servlet 线程在处理耗时操作(如数据库查询、调用外部API)时,将请求挂起并释放容器线程,待耗时操作完成后再恢复响应。这极大地提升了容器对高并发请求的处理能力,是应对现代 Web 应用复杂性的关键特性
    • 可编程式配置: 允许通过代码(实现 ServletContainerInitializer 接口)在应用启动时动态添加 Servlet、Filter 和 Listener,彻底告别 web.xml这是 Spring MVC 等现代框架无缝集成的基础
    • 模块化部署: 支持 Web 片段(web-fragment.xml),允许库(JAR 包)自带 Web 配置,实现了插拔式的组件化。
    • 安全增强: 提供了更强大的身份验证和授权机制
  • 意义
    • 为现代框架铺平道路: Spring 等框架利用可编程配置,实现了“零配置”启动和强大的自动化配置
    • 支持高性能应用: 异步处理为开发实时应用、Comet 风格应用以及后来的 WebSocket 打下了基础

5. Servlet 3.1:非阻塞 I/O 的补充

  • 版本: Servlet 3.1 (2013)
  • 核心进化
    • 非阻塞 I/O: 引入了 ReadListenerWriteListener 接口。与 3.0 的异步处理结合,允许在数据读写这种 I/O 操作本身也不阻塞线程,进一步榨干性能,适用于文件上传/下载、大数据流处理等场景
    • 协议升级处理: 支持处理 HTTP 协议升级请求(例如升级到 WebSocket)
  • 意义
    • 将异步支持从请求处理层面扩展到了数据读写层面,形成了完整的异步非阻塞解决方案

6. Servlet 4.0:拥抱 HTTP/2

  • 版本: Servlet 4.0 (2017)
  • 核心进化
    • 基于 HTTP/2: 强制要求容器支持 HTTP/2 协议,带来了服务器推送(Server Push)、多路复用(Multiplexing)、头部压缩等现代化特性
    • 服务器推送API: 提供了 PushBuilder API,让 Servlet 可以方便地向客户端推送资源
  • 意义
    • 让 Java Web 应用能够充分利用 HTTP/2 的性能优势,提升页面加载速度和用户体验。这是对底层网络协议演进的一次重要跟进

7. Servlet 5.0

  • Servlet 5.0 (2020): 主要是为了将 Java EE 改名为 Jakarta EE 而更新的版本。所有 javax.servlet 包名全部更名为 jakarta.servlet。这是一个重要的品牌和法律变更,技术功能上没有变化

8. Servlet 6.0

Servlet 6.0(随 Jakarta EE 10 发布)主要包括以下改进

https://jakarta.ee/zh/specifications/servlet/6.0/

  1. URI 路径的解码与规范化澄清 改进路径安全处理,明确何时如何归一化 URI,使路径解析更加一致、安全
  2. Cookie API 全面更新
    • 更新 Cookie 类及相关文档,从使用指定早期标准(FC 2109)迁移到 RFC 6265
    • 增加对 SameSite 属性等新属性的支持,改进 Session Cookie 和普通 Cookie 的属性支持
  3. 新增唯一标识 API 添加入方法,用于获取当前请求或关联连接的唯一标识符,便于更精细的追踪与诊断
  4. 模块化支持增强 提供 module-info.java,支持在 Java Platform Module System(JPMS)模块化环境中使用 Servlet API,更符合 Jakarta EE 10 的方向
  5. 废除 X-Powered-By 建议 删除容器默认添加 X-Powered-By HTTP 头的推荐,提升安全性
  6. 异步与请求/响应行为澄清
    • 明确 getRemoteAddress()setCharacterEncoding(null) 等方法在不同场景下的行为
    • 优化 ServletInputStream.isReady()ServletOutputStream.isReady() 的文档说明,解释调度或阻塞行为
  7. 容器包装行为调整 放宽对请求与响应包装(wrapping)的严格要求,允许容器以更灵活的方式实现 RequestDispatcher 功能
  8. 对动态添加的监听器限制放宽 去除程序化添加 ServletContextListener 等监听器时对某些 ServletContext 方法的使用限制,提高动态配置弹性
  9. 与 JSP Pages 协同更新JspPropertyGroupDescriptor 中新增 getErrorOnELNotFound() 方法,以配合 Jakarta Pages 3.1 的变更
  10. 废弃与移除旧 API
    • 弃用 doHead 中响应包装(wrapped response),鼓励容器本身处理 HEAD 请求行为
    • 移除长期弃用的 API,如 SingleThreadModelHttpSessionContextHttpUtils 以及若干已弃用的方法
  11. Java SE 最低版本要求提高 Servlet 6.0 需要至少 Java SE 11 或更高版本

总结与进化脉络

版本 发布年份 核心特性 意义
1.0 1997 基本接口 奠定基础,开创Java Web时代
2.3 2001 Filter, Listener 实现模块化,形成MVC雏形,生态繁荣
2.5 2005 注解支持 (@WebServlet) 开始简化配置,提升开发效率
3.0 2009 异步处理,可编程配置 为现代框架(Spring Boot)奠基,支持高并发
3.1 2013 非阻塞I/O 完善异步性能,支持流式处理
4.0 2017 HTTP/2支持 拥抱现代网络协议,提升应用性能
5.0 2020 javax -> jakarta 品牌和法律变更,迈向新时代

进化主脉络

  1. 功能增强:从处理基本请求,到增加过滤器、监听器等模块化功能
  2. 配置简化:从繁冗的 web.xml 到方便的注解,再到完全可编程的配置
  3. 性能提升:从同步阻塞模型,到异步处理,再到非阻塞 I/O,不断适应高并发、实时性的需求
  4. 协议跟进:持续支持最新的网络协议标准,如 HTTP/2
  5. 角色转变:从台前的主力(MVC中的Controller),逐渐退居幕后,成为底层基石,被 SpringMVC 等更上层的框架所封装和增强,但其核心思想始终是Java Web技术的绝对核心