Jakarta EE课程扩展阅读(二)

Jakarta EE课程扩展阅读(二)

1. Servlet 与普通 Java 类的区别

从生命周期、运行环境、实例化方式三个角度来看,Servlet 和一个普通的 Java 类(POJO - Plain Old Java Object)有着本质的区别。

角度 普通 Java 类 (POJO) Servlet
生命周期 由开发者控制 。通过 new 关键字创建,当没有任何引用指向它时,由垃圾回收器(GC)在未来的某个时间点回收。生命周期短暂且不可预测。 由容器(Container)管理 。其生命周期与服务器或 Web 应用的生命周期绑定,经历加载与实例化 -> 初始化 (init) -> 服务 (service) -> 销毁 (destroy) 四个明确的阶段。
运行环境 运行在标准的 Java 虚拟机(JVM) 中。它不了解 Web 环境,无法直接处理 HTTP 请求。 运行在 Jakarta EE 容器(如 Tomcat, WildFly) 提供的特定环境中。容器为 Servlet 提供了处理 HTTP 请求所需的一切,包括 HttpServletRequestHttpServletResponse 对象。
实例化方式 由开发者显式创建 。例如:MyClass obj = new MyClass(); 由容器隐式创建 。开发者不使用 new 来创建 Servlet 实例。容器在需要时(通常是第一次被请求或服务器启动时)通过反射机制自动创建 Servlet 的实例,并且通常只创建一个单例

核心总结:普通 Java 类是独立的构建块,而 Servlet 是一个被动组件,它的整个生命和行为都由其运行的容器来驱动和管理,专门用于处理 Web 请求。


2. Servlet 生命周期四个阶段

Servlet 的生命周期完全由容器掌控,分为四个核心阶段:

加载与实例化 (Loading and Instantiation)

  • 何时发生
    • 延迟加载(默认):当第一个匹配该 Servlet 的 HTTP 请求到达时,容器才会创建它的实例。
    • 预加载 :如果在 web.xml@WebServlet 注解中配置了 <load-on-startup> (值为正整数),容器会在 Web 应用启动时就创建 Servlet 实例。
  • 如何发生 :容器通过 Java 的反射机制加载 Servlet 类(Class.forName(...))并创建其实例(.newInstance())。

初始化 (Initialization)

  • 何时发生 :在 Servlet 实例被创建后,容器会立即调用且仅调用一次 init(ServletConfig config) 方法。
  • 作用 :这是一个进行一次性初始化操作的绝佳时机,例如:
    • 建立数据库连接。
    • 加载配置文件或资源。
    • 初始化缓存。
  • 容器会传入一个 ServletConfig 对象,通过它可以获取部署描述符(web.xml)中配置的初始化参数。

请求处理 (Request Handling)

  • 何时发生 :每当有一个客户端请求到达时,容器都会调用 service(ServletRequest, ServletResponse) 方法。
  • 如何发生
    • 容器会为每个请求创建一个新的线程(或从线程池中取一个)。
    • 该线程负责执行 service() 方法。
    • 容器会创建该请求专属的 HttpServletRequestHttpServletResponse 对象,并作为参数传入。
  • 核心 :这是 Servlet 完成主要工作的地方。HttpServletservice() 方法会自动判断请求类型(GET, POST 等),并调用对应的 doGet(), doPost() 等方法。这个阶段会被反复、并发地执行

销毁 (Destruction)

  • 何时发生 :当 Web 应用被卸载或服务器关闭时,容器会调用且仅调用一次 destroy() 方法。
  • 作用 :用于释放 init() 方法中占用的资源,例如:
    • 关闭数据库连接。
    • 清理缓存。
    • 保存状态。
  • destroy() 方法执行完毕后,Servlet 实例会被标记为可回收,等待 GC 处理。

3. Servlet 的历史演进:替代 CGI

在 Servlet 出现之前,动态 Web 内容主要通过 CGI (Common Gateway Interface) 来生成。

CGI 的工作方式

  • 每当一个 Web 请求到达,Web 服务器会启动一个全新的操作系统进程来运行一个外部程序(如一个 Perl 脚本或 C 程序)。
  • 这个程序处理请求,生成 HTML,然后退出。
  • 服务器将程序的输出返回给浏览器。

CGI 的致命缺点

  • 性能极差:为每个请求都创建一个新进程的开销非常巨大,包括内存分配、进程调度等,导致服务器无法处理高并发。
  • 资源消耗高:成百上千的并发请求意味着成百上千个进程,会迅速耗尽服务器资源。
  • 非持久化:进程处理完请求就退出,无法方便地维持数据库连接池等共享资源。

Servlet 的革命性优势

  • 基于线程,而非进程 :Servlet 实例在内存中是持久化 的(单例)。对于每个请求,容器只需创建一个轻量的线程,而不是重量级的进程。这使得 Servlet 能够轻松处理数千个并发连接。
  • 资源共享:由于所有请求都由同一个 Servlet 实例的不同线程处理,因此可以轻松共享资源,如数据库连接池。
  • 平台无关性:作为 Java 技术,Servlet "一次编写,到处运行",可以部署在任何支持 Jakarta EE 的服务器上。

因此,Servlet 凭借其卓越的性能和资源管理模型,迅速取代了 CGI,成为构建高性能、可伸缩 Web 应用的核心技术。


4. Servlet 与 Jakarta EE:Web 技术体系的基础

在 Jakarta EE 的 Web 技术栈中,Servlet 扮演着基石的角色。它位于最底层,直接与 Web 容器交互,是所有上层 Web 技术的底层支撑。

  • JSP 的基础 :一个 JSP 文件在第一次被访问时,会被容器编译成一个 Servlet 类。后续所有对该 JSP 的访问,实际上都是在执行这个编译后的 Servlet。
  • JSF 的基础 :JSF 框架的核心是一个名为 FacesServlet 的前端控制器 Servlet。所有对 .jsf.xhtml 页面的请求都会被这个 Servlet 拦截,然后由它分发给 JSF 的生命周期处理器。
  • JAX-RS (REST) 的基础:大多数 JAX-RS 的实现(如 Jersey, RESTEasy)也是通过一个核心的 Servlet 来接收所有 REST API 请求,然后根据 URL 和注解将请求路由到正确的资源方法。
  • Spring MVC 的基础 :正如你将在下一个问题中看到的,Spring MVC 的核心 DispatcherServlet 本质上就是一个标准的 Servlet。

结论:无论你使用哪种上层 Java Web 框架,最终处理 HTTP 请求的入口点几乎总是 Servlet。理解 Servlet 是理解整个 Java Web 工作原理的关键。


5. Servlet 规范发展:从 2.x 到 6.0 的主要变化

Servlet 规范的演进反映了 Java Web 开发模式的变迁。

Servlet 2.x (XML 配置时代)

  • 配置方式 :所有 Servlet、Filter、Listener 的配置都必须在部署描述符文件 web.xml 中完成。
  • 缺点 :当项目变大时,web.xml 会变得异常臃肿和难以维护。

Servlet 3.0 (注解与异步时代 - 革命性变革)

  • 配置方式 :引入了 注解 (如 @WebServlet, @WebFilter, @WebListener),使得配置可以直接写在 Java 类中,web.xml 变为可选。
  • 主要功能
    • 异步处理:允许将耗时的请求(如 I/O 操作)移交给一个后台线程处理,从而释放容器的主线程去接收更多请求,极大地提升了应用的吞吐量。
    • 动态配置:允许通过代码动态地添加 Servlet 和 Filter。

Servlet 3.1 & 4.0 (现代化与 HTTP/2)

  • 主要功能 (3.1) :引入了非阻塞 I/O,允许在读写数据时也不阻塞线程,是异步处理的进一步增强。
  • 主要功能 (4.0) :最核心的更新是支持 HTTP/2,包括服务器推送(Server Push)等新特性。

Servlet 5.0 (Jakarta EE 时代)

  • 核心变化命名空间从 javax.servlet.* 变更为 jakarta.servlet.* 。这是由于 Java EE 迁移到 Eclipse 基金会后,Oracle 不允许其继续使用 javax 商标。这是一个重大的破坏性变更 ,所有代码都需要修改 import 语句。
  • 功能:在功能上与 4.0 基本保持一致,主要目标是完成迁移。

Servlet 6.0 (精简与未来)

  • 核心变化移除了许多已废弃的功能,例如 EJB 和安全相关的旧 API,使得整个规范更加精简和现代化。
  • 目标:更好地适应云原生和微服务环境,为未来的发展扫清障碍。

6. Servlet 与现代框架:Spring MVC 的基石

现代 Web 框架(如 Spring MVC)并没有抛弃 Servlet,而是巧妙地建立在 Servlet 之上,提供了一个更高层次的抽象,让开发者可以更专注于业务逻辑。

Spring MVC 为例,其工作流程完美地诠释了这种关系:

  1. 前端控制器模式 (Front Controller Pattern) :Spring MVC 的核心是一个名为 DispatcherServlet 的类。它本身就是一个实现了标准 jakarta.servlet.http.HttpServlet 接口的 Servlet。

  2. 配置 :在应用启动时,Web 容器(如 Tomcat)会加载并初始化这个 DispatcherServlet,并让它拦截所有(或指定的)Web 请求。

  3. 请求处理流程

    • 一个 HTTP 请求(如 GET /users/123)到达 Tomcat。
    • Tomcat 发现这个请求的 URL 模式被 DispatcherServlet 注册了,于是将 HttpServletRequestHttpServletResponse 对象传递给 DispatcherServletservice() 方法。
    • DispatcherServlet 接管请求后,不再需要开发者直接处理底层的 Request/Response 对象 。它会查询其内部的处理器映射(HandlerMapping),找到能够处理 /users/123 这个路径的、由开发者编写的 @Controller 类中的某个方法。
    • DispatcherServlet 调用该方法,并将请求参数自动绑定到方法的参数上。
    • 开发者的方法返回一个模型和视图名。
    • DispatcherServlet 根据视图名找到对应的视图(如一个 JSP 文件),渲染模型数据,并将最终的 HTML 写入 HttpServletResponse

总结:Spring MVC 等框架就像一个高级的"任务分配中心"。它自己作为一个标准的 Servlet 在底层与容器打交道,然后将请求优雅地分派给开发者编写的业务处理单元(Controller),从而将开发者从繁琐的底层 Servlet API 中解放出来。

相关推荐
滴滴滴嘟嘟嘟.4 小时前
Qt动画功能学习
开发语言·qt·学习
福大大架构师每日一题4 小时前
go 1.25.1发布:重点修复net/http跨域保护安全漏洞(CVE-2025-47910)
开发语言·http·golang
Ophelia(秃头版4 小时前
经典设计模式:单例模式、工厂模式
java·开发语言·单例模式
Dear.爬虫5 小时前
Golang中逃逸现象, 变量“何时栈?何时堆?”
开发语言·后端·golang
编码浪子5 小时前
趣味学RUST基础篇(构建一个命令行程序2重构)
开发语言·重构·rust
echoarts6 小时前
MATLAB R2025a安装配置及使用教程(超详细保姆级教程)
开发语言·其他·matlab
阿方.9186 小时前
《数据结构全解析:栈(数组实现)》
java·开发语言·数据结构
Dovis(誓平步青云)6 小时前
《探索C++11:现代语法的内存管理优化“性能指针”(下篇)》
开发语言·jvm·c++
charlie1145141917 小时前
前端三件套简单学习:HTML篇1
开发语言·前端·学习·html