戴老师的博客 - Tomcat
type: channel
link: https://tushu.info/tag/Tomcat/
items: 第六章：支持 Session 和 Cookie-Minitomcat
items: 第八章：实现异步请求支持（基于 Servlet 协议）-Minitomcat
items: 第七章：实现多线程支持-Minitomcat
items: MiniTomcat 项目大纲
items: 从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式
items: Tomcat 系统架构与设计模式
items: Java Web 高性能开发
items: 第九章：实现过滤器（Filter）和监听器（Listener）-Minitomcat
items: 第二章：解析 HTTP 请求，支持静态文件-MiniTomcat
items: 第十二章：实现 Facade（外观模式）-MiniTomcat

第六章：支持 Session 和 Cookie-Minitomcat
type: item
date: 2026-07-09T04:39:31+00:00
description: 本章将实现对 HTTP Session 和 Cookie 的支持，以便维护客户端的会话状态，使服务器能够识别每次请求是否来自同一客户端并跟踪其状态。我们将通过实现一个计数器 Servlet，来记录每个客户端的访问次数，从而验证会话管理功能的有效性。6.1 功能目标实现会话管理：通过 HttpSession 接口支持，为每个客户端分配唯一的 Session ID，并在服务器端保持会话状态。支持 Cookie：实现对请求中 Cookie 的解析，提取相关信息，并能够在响应中设置新的 Cookie 信息（如 JSESSIONID）。6.2 代码结构更新后的 MiniTomcat 项目结构如下。新增了 CustomHttpSession、SessionManager、HttpRequestParser 等相关类，以及用于测试的 CounterServlet 示例。MiniTomcat ├─ src │ ├─ main │ │ ├─ java │ │ │ ├─ com.daicy.minitomcat │ │ │ │ ├─ servlet │ │ │ │ │ ├─ CustomServletOutputStream.java // 自定义的 Servlet 输出流类 │ │ │ │ │ ├─ CustomHttpSession.java // 自定义的 HttpSession 实现 │ │ │ │ │ ├─ HttpServletRequestImpl.java // HTTP 请求的实现类 │ │ │ │ │ ├─ HttpServletResponseImpl.java // HTTP 响应的实现类 │ │ │ │ │ ├─ ServletConfigImpl.java // Servlet 配置的实现类 │ │ │ │ │ ├─ ServletContextImpl.java // Servlet 上下文的实现类 │ │ │ │ ├─ CounterServlet.java // Session 功能 Servlet 示例类 │ │ │ │ ├─ HelloServlet.java // Servlet 示例类 │ │ │ │ ├─ HttpConnector.java // 连接器类 │ │ │ │ ├─ HttpProcessor.java // 请求处理器 │ │ │ │ ├─ HttpServer.java // 主服务器类 │ │ │ │ ├─ HttpRequestParser.java // HttpRequest 信息解析类 │ │ │ │ ├─ ServletLoader.java // Servlet 加载器 │ │ │ │ ├─ ServletProcessor.java // Servlet 处理器 │ │ │ │ ├─ StaticResourceProcessor.java // 静态资源处理器 │ │ │ │ ├─ SessionManager.java // Session 管理器 │ │ │ │ ├─ WebXmlServletContainer.java // Servlet 容器相关类 │ │ ├─ resources │ │ │ ├─ webroot │ │ │ │ ├─ index.html │ │ │ ├─ web.xml │ ├─ test ├─ pom.xml6.3 代码实现6.3.1 创建 CustomHttpSession 类CustomHttpSession 类负责管理每个客户端的会话数据，并为每个会话分配唯一的 Session ID。该类实现了 javax.servlet.http.HttpSession 接口的核心功能。package com.daicy.minitomcat.servlet; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import java.util.*; // 自定义类模拟实现 HttpSession 接口的部分功能 public class CustomHttpSession implements HttpSession { private String id; private Date creationTime; private Date lastAccessedTime; private int maxInactiveInterval; private Map<String, Object> attributes = new HashMap<>(); public CustomHttpSession(String sessionId.htm…

第八章：实现异步请求支持（基于 Servlet 协议）-Minitomcat
type: item
date: 2026-07-09T04:39:24+00:00
description: 第八章：实现异步请求支持（基于 Servlet 协议）在本章中，我们将进一步扩展 MiniTomcat，加入对 Servlet 规范 的支持，特别是 异步请求处理 功能。Servlet 3.0 引入了异步处理机制，允许请求在后台线程中异步执行，从而避免阻塞主线程。这一机制能显著提高服务器处理效率，尤其适用于处理耗时较长的任务（如文件上传、大数据处理或外部 API 调用等）。8.1 功能目标本章主要实现以下目标：实现 Servlet 3.0 异步请求处理：基于 Servlet 3.0 标准构建异步支持能力。提供 AsyncContext 机制：通过 AsyncContext 管理异步请求和响应的生命周期，允许后台线程处理长时间任务而不阻塞主线程。支持异步响应：确保异步任务完成后，能够正确地向客户端发送响应数据。8.2 异步处理流程异步请求的处理流程主要包含以下三个阶段：启动异步请求：客户端发起请求后，Servlet 容器检查请求是否需要异步处理。若需要，调用 request.startAsync() 启动异步上下文。异步任务执行：Servlet 容器将请求处理逻辑分配到后台线程执行，主线程立即返回并释放资源，继续处理其他请求。完成异步处理：后台线程执行完任务后，调用 AsyncContext.complete() 结束异步处理，并向客户端发送响应。8.3 代码实现8.3.1 修改 HttpServletRequestImpl 类，支持异步请求为了支持异步请求，我们需要在 HttpServletRequestImpl 中引入 AsyncContext 相关状态，并实现启动异步任务的方法。public class HttpServletRequestImpl implements HttpServletRequest { // ... 其他成员变量 private boolean asyncStarted = false; private AsyncContext asyncContext; public HttpServletRequestImpl(String method, String requestURI, String queryString, Map<String, String> headers.html) { // ... 初始化逻辑 } @Override public boolean isAsyncStarted() { return asyncStarted; } @Override public AsyncContext getAsyncContext() { if (!asyncStarted.html) { throw new IllegalStateException("Async not started".html); } return asyncContext; } @Override public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse.html) throws IllegalStateException { if (asyncStarted.html) { throw new IllegalStateException("Async already started".html); } asyncStarted = true; asyncContext = new AsyncContextImpl(this, servletResponse.html); return asyncContext; } @Override public boolean isAsyncSupported() { return asyncStarted; } // ... 其他方法 }8.3.2 修改 HttpProcessor 类，支持异步请求在 HttpProcessor 中，我们需要判断当前请求是否进入了异步模式。如果是异步请求，连接关闭的逻辑需要相应调整，以避免在后台任务完成前过早关闭连接。package com.daicy.minitomcat; import com.daicy.minitomcat.servlet.HttpServletRequestImpl; import com.daicy.minitomcat.servlet.HttpServletResponseImpl; import javax.servlet.AsyncContext; import javax.servlet.http.HttpServletRequest; import java.io.*;…

第七章：实现多线程支持-Minitomcat
type: item
date: 2026-07-09T04:38:05+00:00
description: 第七章：实现多线程支持在本章中，我们将为 MiniTomcat 引入多线程支持，旨在显著提升服务器的并发处理能力。通过引入线程池（Thread Pool）机制，服务器能够同时处理多个客户端请求，避免单线程模型下的请求阻塞问题。这将使服务器在面对高并发场景时更加高效，更好地支持多用户同时访问。7.1 功能目标本章的核心改造目标如下：多线程支持：利用线程池管理线程资源，为每个客户端请求分配独立的线程进行处理。线程池机制：避免为每个请求频繁创建和销毁线程，通过复用线程降低系统开销，提高执行效率。并发处理：支持多个客户端同时访问不同的 Servlet，确保请求之间互不干扰，实现真正的并发处理。7.2 代码结构本次修改将引入线程池机制，主要通过 ExecutorService 来管理工作线程。项目代码结构更新如下：MiniTomcat ├─ src │ ├─ main │ │ ├─ java │ │ │ ├─ com.daicy.minitomcat │ │ │ │ ├─ servlet │ │ │ │ │ ├─ CustomServletOutputStream.java // 自定义的 Servlet 输出流类 │ │ │ │ │ ├─ CustomHttpSession.java // 自定义的 HttpSession │ │ │ │ │ ├─ HttpServletRequestImpl.java // HTTP 请求的实现类 │ │ │ │ │ ├─ HttpServletResponseImpl.java // HTTP 响应的实现类 │ │ │ │ │ ├─ ServletConfigImpl.java // Servlet 配置的实现类 │ │ │ │ │ ├─ ServletContextImpl.java // Servlet 上下文的实现类 │ │ │ │ ├─ CounterServlet.java // Session 功能 Servlet 示例类 │ │ │ │ ├─ HelloServlet.java // Servlet 示例类 │ │ │ │ ├─ HttpConnector.java // 连接器类 │ │ │ │ ├─ HttpProcessor.java // 请求处理器 │ │ │ │ ├─ HttpServer.java // 主服务器类 │ │ │ │ ├─ HttpRequestParser.java // HttpRequest 信息解析类 │ │ │ │ ├─ ServletLoader.java // Servlet 加载器 │ │ │ │ ├─ ServletProcessor.java // Servlet 处理器 │ │ │ │ ├─ StaticResourceProcessor.java // 静态资源处理器 │ │ │ │ ├─ SessionManager.java // Session 管理器 │ │ │ │ ├─ ThreadPool.java // 线程池管理 │ │ │ │ ├─ WebXmlServletContainer.java // Servlet 容器相关类 │ │ ├─ resources │ │ │ ├─ webroot │ │ │ │ ├─ index.html │ │ │ ├─ web.xml │ ├─ test ├─ pom.xml7.3 代码实现7.3.1 创建 ThreadPool 类我们将基于 Java 并发包中的 ThreadPoolExecutor 来实现线程池管理。ThreadPool 类负责封装线程池的生命周期，并提供提交任务的接口。package com.daicy.minitomcat; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class ThreadPool { private ExecutorService executor; public ThreadPool(int poolSize.html) { // 创建固定大小的线程池 executor = Executors.newFixedThreadPool(poolSize.html); } public void submitTask(Runnable task.html) { executor.submit(task.html); } public void shutdown() { if (executor != null.ht…

MiniTomcat 项目大纲
type: item
date: 2026-07-09T04:37:43+00:00
description: 上一章内容：打造属于你的 MiniTomcat：深入理解 Web 容器核心架构与实现之路从零开始实现一个类似 Tomcat 的轻量级 Java Web 容器，可以分为多个步骤逐步构建核心功能。以下是一个详细的实现路径大纲，涵盖了每一步的目标功能，旨在帮助你从简单的 HTTP 服务器起步，逐步深入实现基本的 Servlet 容器。第 1 章：实现基础 HTTP 服务器功能目标创建一个简单的 HTTP 服务器，能够监听指定端口、接收 HTTP 请求，并返回 HTTP 响应。实现内容使用 Java 的 ServerSocket 监听指定端口。读取客户端请求，解析 HTTP 请求行和头部信息。返回简单的 HTTP 响应，例如 200 OK 或 404 Not Found。示例功能访问 http://localhost:8080/ 时，返回一段静态文本。学习收获理解 HTTP 协议的基本结构，包括请求和响应的格式。第 2 章：解析 HTTP 请求，支持静态文件功能目标解析 HTTP 请求中的路径、方法（GET、POST 等）和头部信息。基于请求路径提供静态文件支持，类似于静态资源服务器。实现内容根据 URL 路径，查找服务器本地的文件并返回其内容（如 HTML、CSS、JS 文件）。支持 MIME 类型识别，如 text/html、application/javascript，返回正确的 Content-Type。示例功能访问 http://localhost:8080/index.html 时，返回服务器上的 index.html 文件内容。学习收获加深对 HTTP 请求和响应头的理解，熟悉静态文件的处理方式。第 3 章：实现连接器（Connector）组件功能目标实现一个连接器组件，用于处理 HTTP 连接和数据包解析。该组件用于管理网络传输和请求解析，将网络传输与请求处理解耦，提升代码清晰度和容错性。实现内容创建 Connector 组件，用于与客户端建立连接，读取 HTTP 数据包，并交由请求解析器处理。第 4 章：实现 Servlet 容器的基本功能功能目标实现一个简单的 Servlet 容器，支持加载、初始化、调用和销毁 Servlet。实现内容实现 HttpServletRequest 和 HttpServletResponse 类，用于封装请求和响应数据。根据请求路径映射到对应的 Servlet 类，并调用 Servlet 的 service() 方法处理请求。提供 ServletContext 和 ServletConfig 支持，维护 Servlet 的生命周期。示例功能定义一个简单的 Servlet，如 HelloServlet，访问时返回自定义的响应内容。学习收获熟悉 Servlet 的生命周期（init、service、destroy），理解 Servlet 和 Web 容器之间的交互关系。第 5 章：支持 Servlet 配置和 URL 映射功能目标通过配置文件（例如 web.xml）管理 Servlet 路由映射和初始化参数。实现内容解析 web.xml 文件，读取 Servlet 映射信息，将 URL 路径映射到对应的 Servlet 类。支持 Servlet 的初始化参数，并在 ServletConfig 中提供获取方式。示例功能根据 web.xml 的配置，访问 /hello 路径时自动调用 HelloServlet。学习收获学习解析 XML 文件，掌握基于配置的 URL 路由映射。第 6 章：支持 Session 和 Cookie功能目标增加对 Session 和 Cookie 的支持，实现简单的会话管理。实现内容实现 HttpSession，为每个客户端会话分配唯一的 Session ID，并保持会话状态。实现对 Cookie 的支持，解析请求中的 Cookie，并将响应的 Cookie 发送到客户端。示例功能实现一个简单的计数器 Servlet，记录每个客户端的访问次数。学习收获掌握会话管理的基本原理，理解如何使用 Session 和 Cookie 维护客户端状态。第 7 章：实现多线程支持功能目标支持多线程处理，提高服务器并发能力，允许多个请求同时处理。实现内容使用线程池处理每个客户端的连接，避免阻塞其他请求。可以使用 ExecutorService 或 ThreadPoolExecutor 创建线程池。示例功能多个客户端可以同时访问不同的 Servlet，不会互相影响。学习收获了解多线程编程和线程池的概念，掌握如何设计并发安全的 Web 服务器。第 8 章：实现异步请求支持功能目标在多线程支持的基础上，引入异步请求处理。异步请求能够在高并发和长时间请求（如大文件上传、长连接）场景下提升处理效…

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式
type: item
date: 2026-07-09T04:37:08+00:00
description: 编者注：本文为历史博文归档；涉及 JDK、框架与工具链版本请以当前官方文档为准。引用外链图片可能失效，阅读时请注意时效性。如何正确使用 NIO 构建网络服务器一直是值得深入探讨的问题。为此，我们分析了 Jetty、Tomcat 和 Mina 有关 NIO 的源码，发现三者基于类似的方式实现。这应该算是 NIO 构架网络服务器的经典模式。基于这种模式，我们编写了一个小型网络服务器，经过压力测试，效果良好。下文将具体分析这三者是如何使用 NIO 的。Jetty Connector 的实现先看看有关类图：其中各组件职责如下：SelectChannelConnector：负责组装各组件SelectSet：负责侦听客户端请求SelectChannelEndPoint：负责 IO 的读和写HttpConnection：负责逻辑处理在整个服务端处理请求的过程可以分为三个阶段，时序图如下所示：阶段一：监听并建立连接这一过程主要是启动一个线程负责 accept 新连接，监听到后分配给相应的 SelectSet，分配的策略就是轮询。阶段二：监听客户端的请求这一过程主要是启动多个线程（线程数一般为服务器 CPU 的个数），让 SelectSet 监听所管辖的 channel 队列。每个 SelectSet 维护一个 Selector，这个 Selector 监听队列里所有的 channel，一旦有读事件，从线程池里拿线程去做处理请求。阶段三：处理请求这一过程就是每次客户端请求的数据处理过程。值得注意的是，为了不让后端的业务处理阻碍 Selector 监听新的请求，采用多线程来分隔开监听请求和处理请求两个阶段。由此可以大致总结出 Jetty 有关 NIO 使用的模式，如下图所示：最核心的设计就是把三件不同的事情隔离开，并用不同规模的线程去处理，最大限度地利用 NIO 的异步和通知特性。Tomcat Connector 的实现下面再来看看 Tomcat 是如何使用 NIO 来构架 Connector 这块的。先看看 Tomcat Connector 这块的类图：其中各组件职责如下：NioEndpoint：负责组装各部件Acceptor：负责监听新连接，并把连接交给 PollerPoller：负责监听所管辖的 channel 队列，并把请求交给 SocketProcessor 处理SocketProcessor：负责数据处理，并把请求传递给后端业务处理模块在整个服务端处理请求的过程可以分为三个阶段，时序图如下所示：阶段一：监听并建立连接这一阶段主要是 Acceptor 监听新连接，并轮询取一个 Poller，把连接交付给 Poller。阶段二：监听客户端的请求这一过程主要是让每个 Poller 监听所管辖的 channel 队列，select 到新请求后交付给 SocketProcessor 处理。阶段三：处理请求这一过程就是从多线程执行 SocketProcessor，做数据和业务处理。于是我们发现，抛开具体代码细节，Tomcat 和 Jetty 在 NIO 的使用方面是非常一致的，采用的模式依然是下图：Mina 的实现最后我们再看看 NIO 方面最著名的框架 Mina。抛开 Mina 有关 session 和处理链条等方面的设计，单单挑出前端网络层处理来看，也采用的是与 Jetty 和 Tomcat 类似的模式。只不过它做了些简化，没有隔开请求侦听和请求处理两个阶段，因此宏观上看它只分为两个阶段。先看看它的类图：其中各组件职责如下：SocketAcceptor：起线程调用 SocketAcceptor.Work 负责新连接侦听，并交给 SocketIoProcessor 处理SocketIoProcessor：起线程调用 SocketIoProcessor.Work 负责侦听所管辖的 channel 队列，select 到新请求后交给 IoFilterChain 处理IoFilterChain：组装了 Mina 的处理链条在整个服务端处理请求的过程可以分为两个阶段，时序图如下所示：阶段一：监听并建立连接阶段二：监听并处理客户端的请求总结与实践总结来看 Jetty、Tomcat 和 Mina，我们大概清楚了该如何基于 NIO 来构架网络服务器。通过这个提炼出来的模式，我们写了个很简单的 NIO Server。在保持连接的情况下，可以很轻松地保持 6 万连接（由于有 65535 连接限制），并能在负载只有 3 左右的情况下（4 核），承担 3 到 4 万的 TPS 请求（当然做的事情很简单，仅仅是把 buffer 转化为自定义协议的包，然后再把包转为 buffer 写到客户端）。简单地实践一下可以证明这个模式的有效性。不妨再看看这个图，希望对大伙以后写 …

Tomcat 系统架构与设计模式
type: item
date: 2026-07-09T04:37:01+00:00
description: 门面设计模式门面设计模式（Facade Pattern）在 Tomcat 中有多处应用，例如 Request 和 Response 对象的封装、Standard Wrapper 到 ServletConfig 的封装、以及 ApplicationContext 到 ServletContext 的封装等。门面设计模式的原理门面设计模式的核心作用在于封装。顾名思义，就是将复杂的内部结构封装成一个统一的“门面”，以便与其他模块更便捷地进行交互，类似于国家外交部统一对外接口的角色。该模式主要应用于由多个子系统组成的大型系统中。子系统之间必然涉及相互通信，但每个子系统不应将内部数据过多地暴露给其他系统，否则划分子系统的意义将大打折扣。因此，每个子系统都会设计一个门面，将外部感兴趣的数据封装起来，并通过这个门面提供访问接口。这就是门面设计模式存在的意义。门面设计模式示意图如下：客户端（Client）仅能访问 Facade 提供的数据，这是门面设计模式的关键所在。至于 Client 如何访问 Facade，以及 Subsystem 如何提供 Facade，该模式并没有严格规定。Tomcat 的门面设计模式示例Tomcat 中包含众多不同组件，组件间需要相互交互数据，使用门面模式隔离数据是一种有效的方法。以下是 Request 对象上使用的门面设计模式示例：从类图可以看出，HttpRequestFacade 类封装了 HttpRequest 接口能够提供的数据。通过 HttpRequestFacade 访问到的数据都被代理到 HttpRequest 中。通常被封装的对象会被设为 Private 或者 Protected 访问修饰符，以防止在 Facade 之外被直接访问。观察者设计模式观察者设计模式（Observer Pattern）是一种常用的设计方法，通常也称为发布 - 订阅模式（Publish-Subscribe Pattern）或事件监听机制。它通常在某个事件发生的前后触发一些特定操作。观察者模式的原理观察者模式的原理相对简单：当主体（Subject）状态发生变化时，依赖该主体的观察者（Observer）会收到通知并执行相应操作。观察者必须向主体注册（登记），否则主体无法通知它。观察者模式通常包含以下几个角色：Subject（抽象主题）：负责管理所有观察者的引用，同时定义主要的事件操作。ConcreteSubject（具体主题）：实现抽象主题定义的所有接口，当自身状态发生变化时，通知所有观察者。Observer（观察者）：定义监听主题发生变化时的相应操作接口。Tomcat 的观察者模式示例Tomcat 中多处使用了观察者模式。前面提到的控制组件生命周期的 Lifecycle 接口就是这种模式的体现，此外 Servlet 实例的创建、Session 的管理、Container 的管理等都采用了同样的原理。下面主要看一下 Lifecycle 的具体实现。Lifecycle 的观察者模式结构图如下：在上述结构图中：LifecycleListener 代表抽象观察者，它定义了一个 lifecycleEvent 方法，这是当主题变化时要执行的方法。ServerLifecycleListener 代表具体观察者，它实现了 LifecycleListener 接口的方法。Lifecycle 接口代表抽象主题，它定义了管理观察者的方法以及其他相关方法。StandardServer 代表具体主题，它实现了抽象主题的所有方法。Tomcat 对观察者模式做了扩展，增加了两个辅助类：LifecycleSupport 和 LifecycleEvent。LifecycleEvent 使得可以定义事件类别，不同的事件可区别处理，更加灵活。LifecycleSupport 类代理了主题对多观察者的管理，将这个管理逻辑抽出来统一实现。以后如果需要修改，只需修改 LifecycleSupport 类，而不需要修改所有具体主题，因为所有具体主题对观察者的操作都被代理给了 LifecycleSupport 类。这可以认为是观察者模式的一种改进版。LifecycleSupport 调用观察者的方法代码如下：public void fireLifecycleEvent(String type, Object data.html) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data.html); LifecycleListener interested[] = null; synchronized (listeners.html) { interested = (LifecycleListener[…

Java Web 高性能开发
type: item
date: 2026-07-09T04:36:56+00:00
description: 引言在前端优化的第一部分中，主要讲解了对静态资源的优化措施，包括图片压缩、CSS Sprites 技术、GZIP 压缩等。本文作为系列的第二部分，将深入讲解前端优化中关键的 Flush 机制、动静分离、HTTP 持久连接、HTTP 协议的灵活应用以及 CDN 等技术。结合这些技术策略，旨在进一步提升 Java Web 应用程序的整体性能。Flush 机制的使用在 Web 技术中，Flush 机制并非新概念。其核心思想是无需等待网页内容全部加载完毕再一次性写回客户端，而是可以分部分逐次返回。对于内容较大的网页，一次性写回全部内容会导致用户长时间面对空白页面，体验较差。Flush 机制允许开发人员将网页内容按文档流顺序逐步返回给客户端，使用户感知到系统正在工作，从而提升等待过程中的用户体验。这是一个经典的优化手段，至今仍在广泛使用。在 Java Web 技术中，实现 Flush 非常简单。只需调用 HttpServletResponse.getWriter() 输出流的 flush() 方法，即可将已经加载完成的内容写回给客户端。然而，是否每个网页都需要使用该技术？并不建议。将网页内容加载完毕后一次性返回客户端也有其优势。网络传输存在最大传输单元（MTU），内容加载完毕后一次性输出可以最大程度地利用传输带宽，减少分块和传输次数。换言之，Flush 机制可能会略微增加用户等待时间和浏览器渲染时间。但对于大型网页而言，牺牲这点效率来换取用户体验的提升，通常是值得的。动静分离所谓的动静分离，就是将 Web 应用程序中的静态内容和动态内容分别部署在不同的 Web 服务器上，针对性地处理不同类型的请求，从而达到性能提升的目的。本文基于 Java Web 环境讲解优化，主流服务器软件为 Tomcat。需要注意的是，Tomcat 在高并发和静态资源处理能力上相对较弱。既然选择了 Java Web，我们就应通过架构优化来弥补不足。动静分离便是其中一种有效方法：将静态资源的处理任务交给更擅长的软件，而让 Tomcat 专注于处理 JSP/Servlet 动态请求。服务器软件选择对于静态资源处理，可以选择 Nginx。这是一款高性能的 HTTP 和反向代理服务器，支持高并发，对静态资源的处理能力较强。事实上，动静分离的方案多种多样：有人采用 Apache+Tomcat 组合，也有人使用 Tomcat+Tomcat 组合（部署于不同主机或域名）。其中 Apache+Tomcat 方案与 Nginx 方案原理相似，均基于反向代理。相比之下，Nginx 配置动静分离更为简洁，而 Apache 则需要配置 mod_proxy 模块。Apache 配置示例在 Apache 中，mod_proxy 模块负责反向代理的实现。核心配置内容如清单 1所示（该配置源自实际项目经验）。清单 1. 动静分离的 Apache 核心配置<Proxy balancer://proxy> BalancerMember http://192.168.1.178:8080 loadfactor=1 BalancerMember http://192.168.1.145:8080 loadfactor=1 </Proxy> NameVirtualHost *:80 <VirtualHost *:80> ServerAdmin service@xuanli365.com ServerName www.xuanli365.com DocumentRoot /www DirectoryIndex index.shtml <Directory /www> AllowOverride All AddType text/html .shtml AddType application/x-rar .rar AddHandler server-parsed .shtml Options +IncludesNOEXEC </Directory> RewriteEngine on ProxyRequests Off ProxyPass /static/! ProxyPass / balancer://proxy/ ProxyPassReverse / balancer://proxy/ ProxyPreserveHost on </VirtualHost>根据 Apache 官方对 mod_proxy 模块的介绍，ProxyPass 属性可以将远端服务器映射到本地服务器的 URL 空间中，实现地址映射。在清单 1的配置中：当访问路径不在 /static/ 下时（! 表示非），请求转发给后端服务器（即 Tomcat）。当访问路径在 /static/ 下时，直接访问本机。例如，访问 www.xuanli365.…

第九章：实现过滤器（Filter）和监听器（Listener）-Minitomcat
type: item
date: 2026-07-09T04:35:44+00:00
description: 第九章：实现过滤器（Filter）和监听器（Listener）本章目标本章旨在为 Minitomcat 容器增加 Filter（过滤器） 和 Listener（监听器） 的支持，以便在请求处理过程中插入额外的操作或监听特定事件。具体实现目标如下：实现 Filter 接口：支持在请求到达 Servlet 之前和响应返回客户端之前插入自定义逻辑，例如日志记录、认证拦截等。实现 Listener 接口：支持监听 Servlet 上下文（Context）、会话（Session）或请求的生命周期事件。示例功能：实现一个日志过滤器，记录每个请求的访问时间和路径。在 Servlet 上下文初始化时创建监听器，监听上下文和会话的创建与销毁事件。9.1 过滤器（Filter）Filter 是 Servlet 容器提供的一个接口，它允许开发者在请求到达 Servlet 之前和响应返回客户端之前插入自定义的处理逻辑。过滤器常用于执行日志记录、权限验证、请求重定向、输入输出数据处理等通用任务。1. Filter 接口的实现标准的 Filter 接口主要包含三个方法：init(FilterConfig config.html)：初始化过滤器。doFilter(ServletRequest request, ServletResponse response, FilterChain chain.html)：执行过滤器的核心逻辑，并将请求传递给下一个过滤器或目标 Servlet。destroy()：销毁过滤器，释放资源。2. 日志过滤器的实现下面实现一个简单的日志过滤器，用于记录每个请求的访问时间和请求路径。package com.daicy.minitomcat; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Date; public class LoggingFilter implements Filter { @Override public void init(FilterConfig filterConfig.html) throws ServletException { // 初始化操作，如果有需要可以在这里读取配置参数等 } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain.html) throws IOException, ServletException { long startTime = System.currentTimeMillis(); HttpServletRequest request = (HttpServletRequest.html) servletRequest; System.out.println("Request started at: " + startTime + " for path: " + request.getRequestURI(.html)); // 将请求传递给下一个过滤器或目标 Servlet filterChain.doFilter(servletRequest, servletResponse.html); long endTime = System.currentTimeMillis(); System.out.println("Request completed at: " + endTime + " for path: " + request.getRequestURI(.html) + " Took: " + (endTime - startTime.html) + "ms"); } @Override public void destroy() { // 清理资源操作 } }在 LoggingFilter 中，doFilter() 方法记录了请求的开始时间、路径，并通过 chain.doFilter() 将请求传递给链中的下一个节点。过滤器执行完毕后，记录结束时间及总耗时。3. FilterChain 接口的实现为了实现过滤器的链式调用，我们需要设计一个 FilterChain 结构。它能够依次调用过滤器列表中的每个 Filter，直到最后一个过滤器或者目标 Servlet 被调用。FilterChain 设计概念FilterChain 是责任链模式的实现，每个过滤器执行完后，调用链中的下一个过滤器。doFilt…

第二章：解析 HTTP 请求，支持静态文件-MiniTomcat
type: item
date: 2026-07-09T04:35:18+00:00
description: 第二章：解析 HTTP 请求，支持静态文件-MiniTomcat上一章内容：第一章：实现基础 HTTP 服务器-MiniTomcat在本章节中，我们将为 HTTP 服务器增加对请求路径、方法和头部信息的解析能力，并基于请求路径返回服务器上的静态文件内容。通过实现这一功能，服务器将能够类似于静态资源服务器，为客户端提供 HTML、CSS、JavaScript 等文件的访问服务。2.1 功能目标解析 HTTP 请求：识别请求路径、请求方法（如 GET、POST）。静态文件支持：根据请求路径查找服务器上的文件（如 index.html），并返回文件内容。MIME 类型支持：根据文件类型设置正确的 Content-Type 响应头，确保浏览器可以正确解析文件。2.2 代码实现我们将扩展之前的 SimpleHttpServer 类，增加对 HTTP 请求解析的逻辑，并在服务器文件系统中查找并返回请求的静态文件。import java.io.*; import java.net.*; public class SimpleHttpServer { private static final int PORT = 8080; private static final String WEB_ROOT = "webroot"; // 静态文件根目录 public static void main(String[] args.html) { try (ServerSocket serverSocket = new ServerSocket(PORT.html)) { System.out.println("HTTP Server is running on port " + PORT.html); while (true.html) { // 接受客户端连接 Socket clientSocket = serverSocket.accept(); System.out.println("New connection from " + clientSocket.getInetAddress(.html)); // 处理请求并发送响应 handleRequest(clientSocket.html); } } catch (IOException e.html) { e.printStackTrace(); } } private static void handleRequest(Socket clientSocket.html) { try (InputStream inputStream = clientSocket.getInputStream(.html); OutputStream outputStream = clientSocket.getOutputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream.html))) { // 读取并解析请求行 String requestLine = reader.readLine(); if (requestLine == null || requestLine.isEmpty(.html)) return; System.out.println("Request: " + requestLine.html); // 解析请求方法和路径 String[] parts = requestLine.split(" ".html); String method = parts[0]; String path = parts[1]; // 检查是否为 GET 请求 if (!method.equals("GET".html)) { sendResponse(outputStream, 405, "Method Not Allowed", "Only GET method is supported.".html); return; } // 查找请求的静态文件 URL url = SimpleHttpServer.class.getClassLoader().getResource(WEB_ROOT + path.html); if (null == url.html) { sendResponse(outputStream, 404, "Not Found", "The requested resource was not found.".html); return; } File file = new File(url.getPath(.html)); if (file.exists(…

第十二章：实现 Facade（外观模式）-MiniTomcat
type: item
date: 2026-07-09T04:34:58+00:00
description: 第十二章：实现 Facade（外观模式）功能目标本章的核心目标是使用 Facade（外观）模式 简化外部对 Servlet API 的访问。通过该模式，我们可以隐藏内部复杂的实现细节，提供更简洁、统一的接口供外部调用，从而降低系统的耦合度。实现内容Facade 模式概述：Facade 是一种结构型设计模式，用于封装复杂的子系统。它提供一个统一的接口，使得外部系统无需了解内部实现细节即可轻松访问子系统功能。在 Servlet 容器中的应用：在 Web 容器内部，我们可以通过 Facade 包装 HttpServletRequest 和 HttpServletResponse 等核心对象。这样做不仅限制了对内部结构的直接访问，还简化了对外接口的复杂度。具体实现类：本章将实现 RequestFacade 和 ResponseFacade 类。它们分别封装了请求和响应对象，隐藏了底层复杂细节，对外提供标准的 Servlet 接口。示例功能我们将创建一个 RequestFacade 类，封装实际的请求对象，屏蔽不必要的内部细节，从而简化外部对请求信息的访问流程。12.1 Facade 模式设计Facade 模式 的关键在于将复杂的子系统操作封装在一个简单的接口背后。对于 Web 容器而言，我们需要简化客户端访问 HttpServletRequest 和 HttpServletResponse 的过程，同时隐藏底层实现的具体细节。在本项目中，我们将向用户提供 RequestFacade 和 ResponseFacade 对象，代替直接暴露原始的 HttpServletRequest 和 HttpServletResponse 实现类。12.2 实现 RequestFacade 类RequestFacade 类封装了对 HttpServletRequest 的操作，隐藏了请求底层的复杂实现细节。客户端仅通过 RequestFacade 来访问请求的相关信息，无法直接操作底层对象。package com.daicy.minitomcat; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class RequestFacade extends HttpServletRequestWrapper { /** * Constructs a request object wrapping the given request. * * @param request * @throws IllegalArgumentException if the request is null */ public RequestFacade(HttpServletRequest request.html) { super(request.html); } }通过继承 HttpServletRequestWrapper，RequestFacade 可以方便地代理以下常用方法：getRequestURI()：获取请求的 URI。getHeaderNames()：获取请求头的名称枚举。getHeader(String name.html)：根据头名称获取请求头的值。getParameter(String name.html)：获取请求参数。getMethod()：获取请求方法（如 GET、POST 等）。通过封装 HttpServletRequest，外部系统不需要直接与复杂的请求对象交互，只需使用 RequestFacade 提供的简洁接口即可。12.3 实现 ResponseFacade 类ResponseFacade 类封装了对 HttpServletResponse 的操作，隐藏了响应的复杂实现细节。客户端通过 ResponseFacade 来操作响应数据，确保响应行为符合容器规范。package com.daicy.minitomcat; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class ResponseFacade extends HttpServletResponseWrapper { /** * Constructs a response adaptor wrapping the given response. * * @param response * @throws IllegalArgumentException i…