戴老师的博客 - Tomcat
type: channel
link: https://www.tushu.info/category/Tomcat/
description: Tomcat
items: 从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式
items: Tomcat 系统架构与设计模式
items: Java Web 高性能开发
items: Tomcat中Servlet的创建初始化体系结构及工作
items: Servlet工作原理解析
items: Tomcat处理HTTP请求源码分析
items: Tomcat 系统架构与设计模式，第 1 部分: 工作原理
items: 怎么使用Netty实现一个Tomcat
items: tomcat 的最大连接数设置
items: Jetty 的工作原理以及与 Tomcat 的比较

从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.…

Tomcat中Servlet的创建初始化体系结构及工作
type: item
date: 2026-07-09T04:33:49+00:00
description: Tomcat 中 Servlet 的创建初始化体系结构及工作一个 Web 应用对应一个 Context 容器。在 Tomcat 中，Context 容器是管理 Servlet 的核心，也是 Servlet 运行时的容器。当添加一个 Web 应用时，Tomcat 会创建一个 StandardContext 容器，并为其设置必要的参数。其中，url 和 path 分别代表该应用在 Tomcat 中的访问路径和实际的物理路径。Web 应用的初始化工作Tomcat 中 Web 应用的初始化工作主要在 ContextConfig 的 configureStart 方法中实现。初始化的核心任务是解析 web.xml 文件，该文件描述了 Web 应用的关键信息，是应用的入口。解析过程如下：查找全局配置：Tomcat 首先查找 globalWebXml，该文件位于 org/apache/catalina/startup/NO_DEFAULT_XML 或 conf/web.xml 中的任一个。查找宿主配置：接着查找 hostWebXml，即应用的配置文件（例如 examples/WEB-INF/web.xml）。解析与保存：web.xml 文件的各个配置项会被解析成相应的属性，保存在 WebXml 对象中。设置容器属性：随后将 WebXml 对象中的属性设置到 Context 容器中，包括创建 Servlet 对象、Filter、Listener 等。最后，Servlet 会被包装成 StandardWrapper 并作为子容器添加到 Context 中。因此，Context 容器才是真正运行 Servlet 的容器，其配置属性由应用的 web.xml 指定。创建 Servlet 对象如果 Servlet 的 load-on-startup 配置项大于 0，那么在 Context 容器启动时就会被实例化。前文提到，在解析配置文件时会读取默认的 globalWebXml。在 conf 下的 web.xml 文件中定义了一些默认配置项，其中定义了两个 Servlet：org.apache.catalina.servlets.DefaultServletorg.apache.jasper.servlet.JspServlet它们的 load-on-startup 分别是 1 和 3。这意味着当 Tomcat 启动时，这两个 Servlet 会被优先启动。JspServlet 主要用于将 JSP 页面转换成 Servlet，它会拦截所有以 .jsp 为后缀的文件。创建 Servlet 实例的方法是从 Wrapper.loadServlet 开始的。loadServlet 方法的主要任务是获取 servletClass，然后将其交给 InstanceManager 去创建一个基于 servletClass.class 的对象。初始化 Servlet由于 Servlet 在 Web 初始化时已经包装在 StandardWrapper 中，因此 Servlet 的初始化是在 StandardWrapper 的 initServlet 方法中进行的。该方法逻辑简单，主要是调用 Servlet 的 init 方法，同时将包装了 StandardWrapper 对象的 StandardWrapperFacade 作为 ServletConfig 传给 Servlet。如果该 Servlet 关联的是一个 JSP 文件，那么前面初始化的就是 JspServlet。接下来会模拟一次简单请求，调用这个 JSP 文件，以便将其编译为 class 文件，并初始化这个 class。Servlet 体系结构Java Web 应用是基于 Servlet 规范运转的。下面介绍一下 Servlet 的体系结构。顶层类关联从上图可以看出，Servlet 规范主要基于几个核心类运转。与 Servlet 主动关联的是三个类，分别是 ServletConfig、ServletRequest 和 ServletResponse。这三个类都是通过容器传递给 Servlet 的：ServletConfig：在 Servlet 初始化时传给 Servlet，主要用于获取 Servlet 的配置属性，这些属性可能在 Servlet 运行时被用到。ServletRequest 和 ServletResponse：在请求到达调用 Servlet 时传递过来。它们代表了请求和响应的具体对象，通常作为运输工具来传递交互结果。Servlet 的运行模式是一个典型的“握手型的交互式”运行模式。所谓“握手型的交互式”，是指两个模块为了交换数据通常都会准备一个交易场景，这个场景一直跟随交易过程直到交易完成。交易场景的…

Servlet工作原理解析
type: item
date: 2026-07-09T04:31:09+00:00
description: 从 Servlet 容器说起要介绍 Servlet 必须要先把 Servlet 容器说清楚，Servlet 与 Servlet 容器的关系有点像枪和子弹的关系，枪是为子弹而生，而子弹又让枪有了杀伤力。虽然它们是彼此依存的，但是又相互独立发展，这一切都是为了适应工业化生产的结果。从技术角度来说是为了解耦，通过标准化接口来相互协作。既然接口是连接 Servlet 与 Servlet 容器的关键，那我们就从它们的接口说起。前面说了 Servlet 容器作为一个独立发展的标准化产品，目前它的种类很多，但是它们都有自己的市场定位，很难说谁优谁劣，各有特点。例如现在比较流行的 Jetty，在定制化和移动领域有不错的发展，我们这里还是以大家最为熟悉 Tomcat 为例来介绍 Servlet 容器如何管理 Servlet。Tomcat 本身也很复杂，我们只从 Servlet 与 Servlet 容器的接口部分开始介绍，关于 Tomcat 的详细介绍可以参考我的另外一篇文章《 Tomcat 系统架构与模式设计分析》。Tomcat 的容器等级中，Context 容器是直接管理 Servlet 在容器中的包装类 Wrapper，所以 Context 容器如何运行将直接影响 Servlet 的工作方式。图 1 . Tomcat 容器模型从上图可以看出 Tomcat 的容器分为四个等级，真正管理 Servlet 的容器是 Context 容器，一个 Context 对应一个 Web 工程，在 Tomcat 的配置文件中可以很容易发现这一点，如下：清单 1 Context 配置参数<Context path="/projectOne " docBase="D:\projects\projectOne" reloadable="true" /> Show moreShow more icon下面详细介绍一下 Tomcat 解析 Context 容器的过程，包括如何构建 Servlet 的过程。Servlet 容器的启动过程Tomcat7 也开始支持嵌入式功能，增加了一个启动类 org.apache.catalina.startup.Tomcat。创建一个实例对象并调用 start 方法就可以很容易启动 Tomcat，我们还可以通过这个对象来增加和修改 Tomcat 的配置参数，如可以动态增加 Context、Servlet 等。下面我们就利用这个 Tomcat 类来管理新增的一个 Context 容器，我们就选择 Tomcat7 自带的 examples Web 工程，并看看它是如何加到这个 Context 容器中的。清单 2 . 给 Tomcat 增加一个 Web 工程Tomcat tomcat = getTomcatInstance(); File appDir = new File(getBuildDirectory(.html), "webapps/examples"); tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath(.html)); tomcat.start(); ByteChunk res = getUrl("http://localhost:" + getPort(.html) + "/examples/servlets/servlet/HelloWorldExample"); assertTrue(res.toString(.html).indexOf(" Hello World! ".html) > 0); Show moreShow more icon清单 1 的代码是创建一个 Tomcat 实例并新增一个 Web 应用，然后启动 Tomcat 并调用其中的一个 HelloWorldExample Servlet，看有没有正确返回预期的数据。Tomcat 的 addWebapp 方法的代码如下：清单 3 .Tomcat.addWebapppublic Context addWebapp(Host host, String url, String path.html) { silence(url.html); Context ctx = new StandardContext(); ctx.setPath( url .html); ctx.setDocBase(path.html); if (defaultRealm == null.html) { initSimpleAuth(); } ctx.setRealm(defaultRealm.html); ctx.addLifecycleListener(new DefaultWebXmlListener(.html))…

Tomcat处理HTTP请求源码分析
type: item
date: 2026-07-09T04:30:50+00:00
description: 许多开源应用服务器都集成 Tomcat 作为 Web 容器（Web Container），且对于 Tomcat 的 Servlet 容器部分代码很少改动。因此，这些应用服务器的性能基本上取决于 Tomcat 处理 HTTP 请求的 Connector 模块的性能。本文首先从应用层次分析了 Tomcat 所有的 Connector 种类及用法，接着从架构上分析了 Connector 模块在整个 Tomcat 中所处的位置，最后对 Connector 做了详细的源代码分析。并且我们以 Http11NioProtocol 为例，详细说明了 Tomcat 是如何通过实现 ProtocolHandler 接口而构建 Connector 的。通过本文的学习，读者应该可以轻松做到将 Tomcat 作为 Web 容器集成到第三方系统，并且自定义任何想要的高性能 HTTP 连接器。1 Connector 介绍1.1 Connector 的种类Tomcat 源码中与 Connector 相关的类位于 org.apache.coyote 包中，Connector 分为以下几类：Http Connector：基于 HTTP 协议，负责建立 HTTP 连接。它又分为 BIO Http Connector 与 NIO Http Connector 两种，后者提供非阻塞 IO 与长连接 Comet 支持。AJP Connector：基于 AJP 协议。AJP 是专门设计用来为 Tomcat 与 HTTP 服务器之间通信定制的协议，能提供较高的通信速度和效率。如与 Apache 服务器集成时，采用这个协议。APR HTTP Connector：用 C 实现，通过 JNI 调用。主要提升对静态资源（如 HTML、图片、CSS、JS 等）的访问性能。现在这个库已独立出来可用在任何项目中。Tomcat 在配置 APR 之后性能非常强劲。1.2 Connector 的配置对 Connector 的配置位于 conf/server.xml 文件中。1.2.1 BIO HTTP/1.1 Connector 配置一个典型的配置如下：<Connector port="8080" protocol="HTTP/1.1" maxThreads="150" connectionTimeout="20000" redirectPort="8443" />其它一些重要属性如下：acceptCount：接受连接 request 的最大连接数目，默认值是 10。address：绑定 IP 地址，如果不绑定，默认将绑定任何 IP 地址。allowTrace：如果是 true，将允许 TRACE HTTP 方法。compressibleMimeTypes：各个 mimeType，以逗号分隔，如 text/html,text/xml。compression：如果带宽有限的话，可以用 GZIP 压缩。connectionTimeout：超时时间，默认为 60000ms (60s.html)。maxKeepAliveRequest：默认值是 100。maxThreads：处理请求的 Connector 的线程数目，默认值为 200。如果是 SSL 配置，如下：<Connector port="8181" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" address="0.0.0.0" keystoreFile="E:/java/jonas-full-5.1.0-RC3/conf/keystore.jks" keystorePass="changeit" />其中，keystoreFile 为证书位置，keystorePass 为证书密码。1.2.2 NIO HTTP/1.1 Connector 配置<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" connectionTimeout="20000" redirectPort="8443" />1.2.3 Native APR Connector 配置APR 是用 C/C++ 写的，对静态资源（HTML，图片等）进行了优化。所以要下载本地库 tcnative-1.dll 与 openssl.exe，将其放在 %tomcat%\bin 目录下。下载地址是：http://tomcat.heanet.ie/native/1.1.…

Tomcat 系统架构与设计模式，第 1 部分: 工作原理
type: item
date: 2026-07-09T04:30:05+00:00
description: Tomcat 工作原理本文以 Tomcat 5 为基础，同时兼顾 Tomcat 6 和 Tomcat 4 的相关特性。Tomcat 的基本设计思路和架构具有较好的连续性。Tomcat 总体结构Tomcat 的结构虽然复杂，但其模块化设计非常清晰。找到了 Tomcat 最核心的模块，就抓住了 Tomcat 的“七寸”。下面是 Tomcat 的总体结构图：从上图中可以看出，Tomcat 的核心是两个组件：Connector 和 Container。这两个组件将在后面详细介绍。Connector 组件是可以被替换的，这样可以提供给服务器设计者更多的选择。因为这个组件不仅与服务器本身的设计相关，还与不同的应用场景十分相关，所以一个 Container 可以选择对应多个 Connector。多个 Connector 和一个 Container 形成了一个 Service。Service 的概念大家都很熟悉了，有了 Service 就可以对外提供服务了。但是 Service 还需要一个生存环境，必须要有人能够赋予其生命、掌握其生死大权，那就非 Server 莫属了。所以整个 Tomcat 的生命周期由 Server 控制。以 Service 作为“婚姻”我们将 Tomcat 中 Connector、Container 作为一个整体比作一对情侣的话：Connector 主要负责对外交流，可以比作为 Boy；Container 主要处理 Connector 接受的请求，主要是处理内部事务，可以比作为 Girl。那么这个 Service 就是连接这对男女的结婚证了。是 Service 将它们连接在一起，共同组成一个家庭。当然要组成一个家庭还要很多其它的元素。说白了，Service 只是在 Connector 和 Container 外面多包一层，把它们组装在一起，向外面提供服务。一个 Service 可以设置多个 Connector，但是只能有一个 Container 容器。这个 Service 接口的方法列表如下：从 Service 接口中定义的方法中可以看出，它主要是为了关联 Connector 和 Container，同时会初始化它下面的其它组件。注意接口中它并没有规定一定要控制它下面的组件的生命周期。所有组件的生命周期在一个 Lifecycle 的接口中控制，这里用到了一个重要的设计模式，关于这个接口将在后面介绍。Tomcat 中 Service 接口的标准实现类是 StandardService。它不仅实现了 Service 接口，同时还实现了 Lifecycle 接口，这样它就可以控制它下面的组件的生命周期了。StandardService 类结构图如下：从上图中可以看出，除了 Service 接口方法的实现以及控制组件生命周期的 Lifecycle 接口的实现，还有几个方法是用于事件监听的方法的实现。不仅是这个 Service 组件，Tomcat 中其它组件也同样有这几个方法，这也是一个典型的设计模式，将在后面介绍。下面看一下 StandardService 中主要的几个方法实现的代码，下面是 setContainer 和 addConnector 方法的源码：清单 1. StandardService.setContainerpublic void setContainer(Container container.html) { Container oldContainer = this.container; if ((oldContainer != null.html) && (oldContainer instanceof Engine.html)) ((Engine.html) oldContainer).setService(null.html); this.container = container; if ((this.container != null.html) && (this.container instanceof Engine.html)) ((Engine.html) this.container).setService(this.html); if (started && (this.container != null.html) && (this.container instanceof Lifecycle.html)) { try { ((Lifecycle.html) this.container).start(); } catch (LifecycleException e.html) { ; } } synchronized (connectors.html) { for (int i = …

怎么使用Netty实现一个Tomcat
type: item
date: 2026-07-09T04:29:44+00:00
description: 编者注：本文为历史博文归档；涉及 JDK、框架与工具链版本请以当前官方文档为准。引用外链图片可能失效，阅读时请注意时效性。项目概述Panda 是一个基于 Netty 构建的 Java Web 服务器项目（GitHub 仓库）。该项目展示了从简单 HTTP 服务器到集成 Spring Boot 的完整演进过程，旨在探索 Netty 在 Web 容器领域的实现细节。1. 项目名称与简介项目名称：panda简介：一个基于 Netty 的 Java Web 服务器。随着版本迭代，项目逐步增加了静态文件下载、Controller 支持、Servlet 支持，并最终实现了与 Spring Boot 的集成。2. 技术栈核心框架：Netty, Spring Boot, Spring WebNetty：高性能、异步事件驱动的 NIO 框架，用于构建可维护的高性能协议服务器和客户端。Spring Boot：简化基于 Spring 的应用开发，通过自动配置和启动类帮助开发者快速搭建 Spring 应用。Spring Web：Spring 框架的 Web 模块，提供全面的 Web 开发支持。3. 功能与特性支持静态文件下载。提供 Controller 和 Servlet 支持，便于开发传统 Web 应用。集成 Spring Boot，支持替换内嵌 Tomcat，使项目更易于部署和运行。支持异步处理逻辑与 HTTP 流事件分块传输（Chunked），提升应用性能与响应能力。4. 社区与文档项目托管于 GitHub，便于开发者协作与贡献。提供 README 文件，简要介绍项目使用方法与版本历史。可通过微信公众号"Java 码界探秘"获取更多项目相关技术信息。5. 许可证项目采用 Apache-2.0 许可证。允许用户自由地使用、修改、分发和再许可软件，但需遵守相关条件与限制。6. 未来展望随着技术发展与社区贡献，Panda 项目计划继续增加新功能并优化现有架构，以满足更多开发者的需求。架构设计项目整体架构遵循分层设计，从网络层到应用层的请求处理流程如下：外部客户端 --(HTTP 请求.html)--> Netty 网络层 | V Spring Boot 应用层 / \ Controller/ Session 管理 Servlet (包括异步处理.html) \ / 业务逻辑处理 | V 版本演进项目经历了多个版本的迭代，主要里程碑如下：v0.1：实现 HTTP 协议基础。v1.0：构建一个简单的 HTTP Server。v2.0：通信模型迁移至 Netty。支持静态文件下载。v3.0：添加 Controller 支持。v4.0：添加 Servlet 支持。对接 Spring Web。v5.0：集成 Spring Boot，替换内嵌 Tomcat。技术栈整合：Netty + Spring Boot + Spring Web。v6.0.0：新建模块 spring-boot-starter-netty。v6.0.1：新增 ChannelHandler 线程池。v6.0.2：新增 Session 处理逻辑。v6.0.3：新增异步处理逻辑。v6.0.4：支持 HTTP Stream Event Chunked 传输。社区与资源欢迎关注微信公众号获取更多技术资讯：博客地址：https://tushu.info/说明：本文涉及的技术版本（如 JDK、Spring Boot 等）可能随时间演进，具体兼容性请以官方文档及项目最新仓库为准。

tomcat 的最大连接数设置
type: item
date: 2026-07-09T04:28:54+00:00
description: 编者注：本文为历史博文归档；涉及 JDK、框架与工具链版本请以当前官方文档为准。引用外链图片可能失效，阅读时请注意时效性。背景与目的为了确保服务不会被过多的 HTTP 长连接压垮，我们需要对 Tomcat 设定最大连接数。超过该连接数的请求将被拒绝，从而将负载引导至其它机器。这既能达到自我保护的目的，也能起到连接数负载均衡的作用。核心参数探索与实验初步尝试：MaxKeepAliveRequests一开始根据故障 TodoList 提供的参数 MaxKeepAliveRequests 进行验证。我们将 Tomcat 配置 server.xml 修改为：同时，启动客户端模拟 30 个长连接。预期应该只有 10 个连接能保持住，但结果与预期不符：30 个连接都连上了，而且正常。这让我们怀疑该配置参数是否真正限制了最大连接数。KeepAlive 是在 HTTP/1.1 中定义的，用来保持客户机和服务器的长连接，通过减少建立 TCP Session 的次数来提高性能。常用的配置参数有 {KeepAlive, KeepAliveTimeout, MaxKeepAliveRequests}，具体含义如下：KeepAlive：决定开启 KeepAlive 支持。KeepAliveTimeout：决定一个 KeepAlive 的连接能保持多少时间。Timeout 后就尽快 shutdown 链接，若还有数据必须再建立新的连接。MaxKeepAliveRequests：与 KeepAliveTimeout 相似，意思是服务多少个请求就 shutdown 连接。显然，这些参数与我们想要求的“最大连接数限制”不符。再次尝试：maxConnections搜索其它配置参数后，发现 maxConnections。根据字面意思觉得就应该是这个了。去验证吧：最大连接数设置为 10，我们启动 30 个长连接。预期应该是只有 10 个长连接，实际结果却是远超过 10 个。这个现象有点不应该。最终验证：maxThreads 与 acceptCount原来还有个参数可以决定连接数的大小：maxThreads：Tomcat 启动的最大线程数，即同时处理的任务个数，默认值为 200。acceptCount：当 Tomcat 启动的线程数达到最大时，接受排队的请求个数，默认值为 100。这两个值如何起作用，请看下面三种情况：情况 1：接受一个请求，此时 Tomcat 启动的线程数没有到达 maxThreads，Tomcat 会启动一个线程来处理此请求。情况 2：接受一个请求，此时 Tomcat 启动的线程数已经到达 maxThreads，Tomcat 会把此请求放入等待队列，等待空闲线程。情况 3：接受一个请求，此时 Tomcat 启动的线程数已经到达 maxThreads，等待队列中的请求个数也达到了 acceptCount，此时 Tomcat 会直接拒绝此次请求，返回 connection refused。同时加上 maxConnections 配置：原来 Tomcat 最大连接数取决于 maxConnections 这个值加上 acceptCount 这个值。在连接数达到了 maxConnections 之后，Tomcat 仍会保持住连接，但是不处理，等待其它请求处理完毕之后才会处理这个请求。源码原理分析Tomcat 的最大连接数参数是 maxConnections，这个值表示最多可以有多少个 socket 连接到 Tomcat 上。BIO 模式：默认最大连接数是它的最大线程数（缺省是 200）。NIO 模式：默认是 10000。APR 模式：则是 8192（Windows 上则是低于或等于 maxConnections 的 1024 的倍数）。不限制：如果设置为 -1 则表示不限制。在 Tomcat 里通过一个计数器来控制最大连接，比如在 Endpoint 的 Acceptor 里大致逻辑如下：while (running.html) { ... //if we have reached max connections, wait countUpOrAwaitConnection(); //计数 +1，达到最大值则等待 ... // Accept the next incoming connection from the server socket socket = serverSock.accept(); ... processSocket(socket.html); ... countDownConnection(); //计数 -1 closeSocket(socket.html); }计数器是通过 LimitLatch 锁来实现的，它内部主要通过一个 jav…

Jetty 的工作原理以及与 Tomcat 的比较
type: item
date: 2026-07-09T04:27:49+00:00
description: Jetty 的工作原理以及与 Tomcat 的比较Jetty 的基本架构Jetty 目前是一个比较被看好的 Servlet 引擎，它的架构比较简单，也是一个可扩展性和非常灵活的应用服务器。它有一个基本数据模型，这个数据模型就是 Handler，所有可以被扩展的组件都可以作为一个 Handler 添加到 Server 中，Jetty 就是帮你管理这些 Handler。下图是 Jetty 的基本架构图，整个 Jetty 的核心组件由 Server 和 Connector 两个组件构成。整个 Server 组件是基于 Handler 容器工作的，它类似于 Tomcat 的 Container 容器（Jetty 与 Tomcat 的比较在后面详细介绍）。Jetty 中另外一个必不可少的组件是 Connector，它负责接受客户端的连接请求，并将请求分配给一个处理队列去执行。图 1. Jetty 的基本架构Jetty 中还有一些可有可无的组件，我们可以在它上做扩展。如 JMX，我们可以定义一些 MBean 把它加到 Server 中，当 Server 启动的时候，这些 Bean 就会一起工作。图 2. Jetty 的主要组件的类图从上图可以看出，整个 Jetty 的核心是围绕着 Server 类来构建。Server 类继承了 Handler，关联了 Connector 和 Container。Container 是管理 MBean 的容器。Jetty 的 Server 的扩展主要是实现一个个 Handler 并将 Handler 加到 Server 中，Server 中提供了调用这些 Handler 的访问规则。整个 Jetty 的所有组件的生命周期管理是基于观察者模式（Observer Pattern）设计，它和 Tomcat 的管理是类似的。下面是 LifeCycle 的类关系图：LifeCycle 的类关系图每个组件都会持有一个观察者（在这里是 Listener 类，这个类通常对应到观察者模式中常用的 Observer 角色。关于观察者模式可以参考 《Tomcat 系统架构与设计模式，第 2 部分：设计模式分析》 一文中关于观察者模式的讲解）集合。当 start、fail 或 stop 等事件触发时，这些 Listener 将会被调用。这是最简单的一种设计方式，相比 Tomcat 的 LifeCycle 要简单得多。Handler 的体系结构前面所述 Jetty 主要是基于 Handler 来设计的，Handler 的体系结构影响着整个 Jetty 的方方面面。下面总结了一下 Handler 的种类及作用：图 3. Handler 的体系结构（查看大图）Jetty 主要提供了两种 Handler 类型：HandlerWrapper：它可以将一个 Handler 委托给另外一个类去执行。如我们要将一个 Handler 加到 Jetty 中，那么就必须将这个 Handler 委托给 Server 去调用。配合 ScopeHandler 类我们可以拦截 Handler 的执行，在调用 Handler 之前或之后，可以做一些另外的事情，类似于 Tomcat 中的 Valve。HandlerCollection：这个 Handler 类可以将多个 Handler 组装在一起，构成一个 Handler 链，方便我们做扩展。Jetty 的启动过程Jetty 的入口是 Server 类，Server 类启动完成了，就代表 Jetty 能为你提供服务了。它到底能提供哪些服务，就要看 Server 类启动时都调用了其它组件的 start 方法。从 Jetty 的配置文件我们可以发现，配置 Jetty 的过程就是将那些类配置到 Server 的过程。下面是 Jetty 的启动时序图：图 4. Jetty 的启动流程因为 Jetty 中所有的组件都会继承 LifeCycle，所以 Server 的 start 方法调用就会调用所有已经注册到 Server 的组件。Server 启动其它组件的顺序是：首先启动设置到 Server 的 Handler，通常这个 Handler 会有很多子 Handler，这些 Handler 将组成一个 Handler 链。Server 会依次启动这个链上的所有 Handler。接着会启动注册在 Server 上 JMX 的 MBean，让 MBean 也一起工作起来。最后会启动 Connector，打开端口，接受客户端请求。启动逻辑非常简单。接受请求Jetty 作为一个独立的 Servlet 引擎可以独立提供 Web 服务，但是它也可以与其他 Web 应用服务器集成，所以它可以提供基于两种协议工作：一个是 HTTP，一个是…