1. 前 Java 时代:CGI 与“一请求一进程”的噩梦

在 Servlet 诞生前,C/C++ 处理 Web 请求的主流方案是 CGI(通用网关接口)。

工作模式:90 年代初,Web 应用实质上是一系列独立的二进制可执行文件(如 .exe 或 .out)。当 Apache 等服务器接收到请求时,操作系统会为该请求 Fork(分叉)出一个全新的进程 来运行程序,通过标准输入输出(stdin/stdout)交换数据,任务结束后销毁进程。

致命缺陷:

资源开销巨大:进程的创建与销毁极其沉重。当并发量上千时,CPU 和内存会因频繁的上下文切换而崩溃。

跨平台性差:编译后的二进制文件与操作系统深度绑定,无法做到“一次编写,处处运行”。

2. Java 多线程:诞生于嵌入式的“并发基因”

Java 的多线程模型源于 James Gosling(Java 之父) 领导的“绿色小组(Green Team)”。

设计初衷:1991 年,Java(当时叫 Oak)的目标是机顶盒等嵌入式设备。这类设备性能孱弱,却需要同时处理遥控器输入、视频流解码和网络监听。

技术突破:Gosling 意识到,在机顶盒上像 CGI 那样频繁 Fork 进程无异于自杀。因此,他在 JVM 层面实现了 Thread 类和 synchronized 关键字,确保 Java 能在单个进程内安全、高效地切换任务。

3. Applet:客户端并发的先行者

在 90 年代中后期,Applet 是 Web 界的“黑科技”。它让原本死板的静态 HTML 网页能够直接运行 Java 程序。

本地运行逻辑:当浏览器加载 Applet 时,会启动本地的 JRE(Java 运行环境)。这意味着业务逻辑、复杂计算和图形渲染都直接消耗用户本地的 CPU 和内存。

多线程协作:Applet 可以在浏览器中开启子线程。例如:一个动画 Applet 可以让一个线程负责 UI 渲染,另一个处理背景音乐,第三个进行后台数据加载。这种能力让网页第一次具备了“类桌面软件”的交互体验。

4. Servlet 的诞生:将 Applet 搬回服务器

1997 年,Sun 公司的 詹姆斯·戴维森(James Davidson) 产生了一个灵感:既然 Applet 可以在客户端多线程运行,为什么不能在服务端也搞一个类似的“Server-side Applet”?

这便是 Servlet(Server + Applet)名字的由来。它继承了 Applet 的并发基因,但脱去了图形界面的外壳,专攻服务端逻辑。Servlet 容器(如 Tomcat)只需启动一个 JVM 进程,通过多线程来处理并发请求,彻底终结了 CGI 的低效时代。

5. 现代 Java Web 的基石:为什么 Servlet 依然不可替代?

尽管如今我们习惯于使用 Spring Boot 和 Spring MVC,但它们本质上是穿了“高级马甲”的 Servlet。

(1) 统一的标准接口
所有 Java Web 服务器(Tomcat, Jetty, Undertow)都是 Servlet 容器。Servlet 规范定义了 HTTP 请求与响应的标准化 API。如果没有它,Java Web 开发将陷入各大服务器厂商 API 互不兼容的割据局面。

(2) Spring MVC 的心脏:DispatcherServlet
Spring Boot 的核心其实就是一个特殊的 Servlet——DispatcherServlet。

前端控制器模式:Spring 并不取代 Servlet,而是构建了一个功能极强的 Servlet 来接收所有流量,再将其分发(Dispatch)给具体的 Controller。

血缘继承:查看源码你会发现,DispatcherServlet 的祖先正是 javax.servlet.http.HttpServlet。

(3) 状态管理的生命线
三大作用域(Request、Session、Application)构成了现代 Web 应用处理状态的基础。无论是登录状态维护还是权限拦截,其底层逻辑都建立在 Servlet 规范定义的监听器(Listener)与过滤器(Filter)之上。

(4) 进化:从阻塞到异步
Servlet 并没有固步自封。

Servlet 3.0+ 引入了异步处理机制。

Servlet 5.0/6.0 完美适配了 Jakarta EE 时代的云原生需求。
它让 Java 能够从容应对 WebSocket、长连接和极高并发场景,不再受限于“一个请求阻塞一个线程”的旧模式。

更多推荐