手写Tomcat原理整理
一、启动阶段Tomcat 启动的时候主要做一件事把所有的 Servlet 找出来实例化然后存到容器里。具体分为六个步骤第1步扫描目录Tomcat 启动后首先会扫描 webapp 目录下的所有子目录和子文件把里面所有的 .class 文件都筛选出来。第2步获取全类名拿到每个 .class 文件后获取它的全路径名也就是包名加类名比如 com.example.MyServlet。第3步反射加载拿到全类名之后调用 Class.forName(全类名) 这个方法。这里用的是反射机制。为什么要用反射而不是直接 new 呢因为 Tomcat 的开发者在写框架的时候根本不知道使用者将来会写什么 Servlet类名叫什么在哪个包里。new 的前提是编译时必须知道类名所以这里只能通过反射在运行时动态加载类。第4步注解筛选拿到所有 Class 对象之后遍历每一个 Class 对象检查它上面有没有 WebServlet 注解。带这个注解的类才是我们要管理的 Servlet。注解里面还包含了 Servlet 的访问路径比如 WebServlet(/login)。第5步创建实例对筛选出来的 Servlet 类调用 newInstance() 方法创建实例。newInstance() 和 new 的区别在于new 是编译时确定类名而 newInstance() 是运行时通过 Class 对象动态创建它只能调用无参构造器。第6步构建容器实例创建好之后再通过反射获取这个 Servlet 类里的 doGet 和 doPost 方法对象Method。然后我们构建两个 HashMap第一个存 Servlet 实例key 是 WebServlet 注解里的路径value 是 Servlet 实例对象第二个存方法key 同样是路径value 是 doGet 或 doPost 的 Method 对象这样启动阶段就完成了。总结一下就是扫目录 → 筛类文件 → 反射加载 → 注解筛选 → 实例化 → 存 HashMap。二、请求处理阶段启动完成之后Tomcat 就进入运行状态开始接收和处理 HTTP 请求。整个处理流程也是八个步骤第1步Socket 监听端口Tomcat 通过 Socket 监听 8080 端口。这里要注意源码中的 Socket 不是 Java 标准库的普通 Socket而是用了 Netty 框架的 Socket因为 Netty 性能更高支持异步事件驱动。第2步请求放入线程池队列当一个 HTTP 请求到来时Tomcat 不会立即创建新线程来处理而是先把这个请求放到线程池的任务队列里。为什么要这么做呢有两个原因第一防止内存耗尽。 如果瞬间来上千个请求每个请求都开一个新线程每个 Java 线程默认栈空间是 1MB1000 个线程就是 1GB 内存很容易 OOM 导致服务器死机。线程池有最大线程数限制超出的请求在队列里等着队列满了还有饱和策略直接拒绝保护服务器不宕机。第二减少线程创建销毁的开销。 线程的创建和销毁调用的是操作系统的本地方法涉及栈空间的申请和回收这个开销是毫秒级的。高并发场景下频繁创建销毁线程的开销会非常大。线程池里的线程在 run() 方法里有一个死循环会不断从队列里取任务线程不会销毁实现了线程复用。第3步线程池分配线程处理线程池里的空闲线程会从任务队列中取出一个请求来处理。第4步封装 Request 和 Response 对象线程拿到请求后首先把通过端口传过来的 HTTP 字符流进行解析封装成 HttpRequest 对象和 HttpResponse 对象。同时从 URL 中提取出请求路径去掉 IP、端口号和项目名称剩下的就是真正的资源访问路径。第5步判断请求类型拿到路径之后判断这个请求是要访问静态资源还是访问 Servlet如果是静态资源CSS、JS、图片、HTML 等就按路径去对应的目录下找文件按相应的编码读取内容直接返回给前端。如果是Servlet 请求就用这个路径作为 key去启动阶段构建的两个 HashMap 里查找。第6步匹配 Servlet 实例和方法从第一个 HashMap 里取出 Servlet 实例从第二个 HashMap 里取出对应的 Method 对象doGet 或 doPost根据请求方式判断。第7步动态代理调用方法拿到实例和方法之后调用 method.invoke(servletInstance, request, response) 来执行 Servlet 的业务方法。这里用的是动态代理。为什么要用代理呢因为编译时我们不知道具体的 Servlet 类名没办法直接写 servlet.doGet(req, resp)。但 invoke() 的三要素和普通方法调用是完全对应的第一个参数是对象实例在哪个对象上调用后面的参数是方法参数。所以本质上和直接调用是一样的只是通过反射动态完成。doGet 和 doPost 都是 void 方法没有返回值它们的处理结果会写到 response 对象里。第8步返回响应最后通过 Socket 的输出流把 response 对象里封装的数据返回给客户端。一次请求处理就完成了。三、总结所以手写 Tomcat 的核心就是启动阶段扫描 → 反射 → 注解 → 实例化 → 存 HashMap请求阶段Socket 接收 → 线程池处理 → 封装 Request/Response → 判断静态资源还是 Servlet → HashMap 匹配 → invoke 调用 → 返回响应而支撑这一切的三大核心技术就是反射、线程池、动态代理。这也是几乎所有 Java 框架的通用模式。

相关新闻

华为MetaERP 一、SLA 设计哲学SLA(Subledger Accounting)是所有子模块到 GL 之间的会计转换引擎,不是记账工具。业财分离 OM/INV/AR 只抛“业务事件“,

华为MetaERP 一、SLA 设计哲学SLA(Subledger Accounting)是所有子模块到 GL 之间的会计转换引擎,不是记账工具。业财分离 OM/INV/AR 只抛“业务事件“,

一、SLA 设计哲学SLA(Subledger Accounting)是所有子模块到 GL 之间的会计转换引擎,不是记账工具。业财分离 OM/INV/AR 只抛"业务事件",不直写 GL;会计规则全收在 SLA,"一套业务、多套财务&…

2026/7/21 5:56:17 阅读更多 →
零基础读懂 Spring Boot AI 网关:从场景定义到调用大模型的完整流程

零基础读懂 Spring Boot AI 网关:从场景定义到调用大模型的完整流程

前言随着大语言模型技术的发展,AI 能力逐渐从单一对话工具转变为可嵌入业务系统的智能服务能力。本项目基于 Spring Boot 与 Spring AI 框架,设计并实现了一套轻量化 AI 网关服务,用于统一管理不同业务场景下的大模型调用流程。传统应用在接入…

2026/7/21 5:56:17 阅读更多 →
Effective C++ 学习笔记 条款39 明智而审慎地使用private继承

Effective C++ 学习笔记 条款39 明智而审慎地使用private继承

条款32 展示了 C 将 public 继承视为 is-a 关系。它通过这样一个例子来说明:当 Student 以 public 方式继承自 Person 时,如果函数调用需要,编译器会隐式地将 Student 转换为 Person。这里值得用 private 继承代替 public 继承,再…

2026/7/21 5:56:17 阅读更多 →

最新新闻

UE5碰撞系统核心:UpdateOverlaps源码解析与实战优化

UE5碰撞系统核心:UpdateOverlaps源码解析与实战优化

1. 项目概述:为什么我们需要深入理解UpdateOverlaps? 在虚幻引擎5(UE5)里做开发,无论是做角色拾取物品、子弹击中判定,还是简单的触发器门,都绕不开一个核心机制—— 重叠事件 。蓝图里拖个 …

2026/7/21 15:23:26 阅读更多 →
Mindustry终极指南:5步掌握自动化塔防策略游戏

Mindustry终极指南:5步掌握自动化塔防策略游戏

Mindustry终极指南:5步掌握自动化塔防策略游戏 【免费下载链接】Mindustry The automation tower defense RTS 项目地址: https://gitcode.com/GitHub_Trending/min/Mindustry 想不想体验一款融合了塔防、自动化和即时战略的科幻游戏?今天我就来给…

2026/7/21 15:23:26 阅读更多 →
揭秘scGPT:单细胞数据分析的AI革命,如何在1秒内处理千万级细胞数据?

揭秘scGPT:单细胞数据分析的AI革命,如何在1秒内处理千万级细胞数据?

揭秘scGPT:单细胞数据分析的AI革命,如何在1秒内处理千万级细胞数据? 【免费下载链接】scGPT 项目地址: https://gitcode.com/gh_mirrors/sc/scGPT 你是否曾为单细胞数据分析的复杂性而头疼?面对海量的基因表达数据&#x…

2026/7/21 15:23:26 阅读更多 →
Java代码审计:常见漏洞与安全开发实践

Java代码审计:常见漏洞与安全开发实践

1. Java代码审计概述:为什么需要关注不安全代码? 在Java开发领域,代码审计正逐渐成为保障应用安全的关键环节。去年某知名电商平台的数据泄露事件,根源就是一段未经验证的SQL拼接代码。这类安全问题往往隐藏在看似正常的业务逻辑中…

2026/7/21 15:23:26 阅读更多 →
深入解析TI C2000 eHRPWM模块:从架构原理到多模块同步实战

深入解析TI C2000 eHRPWM模块:从架构原理到多模块同步实战

1. 项目概述与核心价值 如果你正在开发电机驱动、数字电源或者任何需要精确控制功率开关的嵌入式系统,那么德州仪器(TI)C2000系列微控制器里的增强型高分辨率脉宽调制器(eHRPWM)模块,绝对是你绕不开的核心外…

2026/7/21 15:23:26 阅读更多 →
PyWxDump项目终结:从技术探索到合规反思的完整指南

PyWxDump项目终结:从技术探索到合规反思的完整指南

PyWxDump项目终结:从技术探索到合规反思的完整指南 【免费下载链接】PyWxDump 删库 项目地址: https://gitcode.com/GitHub_Trending/py/PyWxDump 还在寻找微信数据恢复工具却遭遇项目下架?想知道开源项目如何平衡技术创新与法律合规?…

2026/7/21 15:22:25 阅读更多 →

日新闻

Octane Render与C4D汉化版安装与优化指南

Octane Render与C4D汉化版安装与优化指南

1. Octane Render与C4D的黄金组合:为什么选择这个方案?在三维创作领域,渲染器的选择往往决定了作品的最终呈现质量和工作效率。作为Cinema 4D(C4D)用户,Octane Render的GPU加速特性与实时预览功能&#xff…

2026/7/21 0:00:19 阅读更多 →
GPMC接口设计:异步/同步模式与多路复用配置实战

GPMC接口设计:异步/同步模式与多路复用配置实战

1. GPMC接口设计:从硬件连接到软件配置的全局视角在嵌入式系统开发中,尤其是基于TI Sitara系列如AM263x这类高性能微控制器的项目里,外部存储器的扩展几乎是绕不开的一环。无论是存放大量非易失性代码的NOR Flash,还是作为高速数据…

2026/7/21 0:00:19 阅读更多 →
UE5 GAS框架下RPG被动技能系统:从核心原理到实战实现

UE5 GAS框架下RPG被动技能系统:从核心原理到实战实现

1. 项目概述:UE5 GAS RPG被动技能的核心价值在UE5里用GAS(Gameplay Ability System)做RPG游戏,主动技能像是你手里的武器,按一下打一下,逻辑直接,反馈也快。但被动技能,它更像是你身…

2026/7/21 0:00:19 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 8:48:31 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 5:34:47 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 8:25:39 阅读更多 →

月新闻