手写tomcat(2):Servlet原理和自定义tomcat

作为 Java 后端开发,我们每天都在用 Tomcat,但你真的懂它和 Servlet 的底层逻辑吗?今天就从Servlet 的继承关系Tomcat 的请求流程 ,讲到如何手写一个简易 Tomcat,彻底搞懂 Web 容器的核心原理。

一、Servlet原理

Servlet 是 Java EE 定义的Web 组件接口,负责处理 HTTP 请求、生成响应。但直接用 Servlet 接口太麻烦,所以 Java EE 提供了 "接口 - 抽象类 - 实现类" 的简化体系:

1.1Servlet 的继承关系(核心分层)

Servlet 接口:定义了 Servlet 的生命周期方法(5 个核心方法):

java 复制代码
// Servlet接口的核心方法
init()          // 初始化:创建Servlet对象
getServletConfig() // 获取配置信息
service()       // 处理请求(核心)
getServletInfo() // 获取运行信息
destroy()       // 销毁对象

GenericServlet 抽象类 :帮我们实现了 Servlet 接口中除service()外的所有方法,减少重复代码。

HttpServlet 抽象类 :在 GenericServlet 基础上,把service()方法拆分成了 HTTP 请求对应的方法(doGet()doPost()等),适配 HTTP 协议。

自定义 Servlet 类 :我们实际开发时,只需要继承 HttpServlet,重写doGet()/doPost()即可。

二、Tomcat 是怎么工作的?请求从发起到响应的全流程

当你在浏览器输入http://ip:8080/xxx/my,Tomcat 到底做了哪些事?

2.1.Tomcat 请求处理流程(核心步骤)

1.网络通信层:Socket+ BIO/NIO

(1)Tomcat 通过网卡监听端口(比如 8080),用 Socket 建立客户端与服务器的连接;

(2)早期 Tomcat用BIO(阻塞 IO):一个请求占一个线程,效率低;后来升级为 NIO/AIO(非阻塞 IO)优化性能。

2.请求解析层:拆 HTTP 报文

(1)通过InputStream读取请求数据,解析出请求地址、请求类型(GET/POST)、Cookie等信息。

3.Servlet 容器:匹配对应的 Servlet

(1)Tomcat 内部维护了一个HashMap 容器 (Servlet 容器),key是 Servlet 的访问路径(比如/my),value是对应的 Servlet 对象;

(2)用解析出的请求地址作为key,找到对应的 Servlet 对象(比如MyServlet)。

4.调用 Servlet 处理请求

(1)根据请求类型(GET/POST),调用 Servlet 的doGet()/doPost()方法,处理业务逻辑并生成响应。

5.返回响应:通过 OutputStream 写回数据

(1)把响应结果通过OutputStream写回客户端,完成请求流程。

三、动手写一个简易 Tomcat:核心逻辑拆解

明白了 Tomcat 的原理,我们可以自己实现一个极简版 Web 容器,核心只需要 4 步:

步骤 1:启动时初始化 Servlet 容器

Tomcat 启动时,会扫描项目中的 Servlet 并初始化容器:

  1. 扫描 Servlet 类:遍历项目文件夹,获取所有 Servlet 类的全路径名;
  2. 解析 @WebServlet 注解 :读取注解中的访问路径(比如@WebServlet("/my"));
  3. 生成 Servlet 容器:用 HashMap 存储 "访问路径 → Servlet 对象" 的映射(通过反射创建 Servlet 对象)。

步骤 2:监听端口,接收请求

用 Socket 监听指定端口(比如 8080),等待客户端连接:

java 复制代码
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept(); // 阻塞等待请求

步骤 3:解析请求,封装 Request 对象

读取 Socket 的输入流,解析 HTTP 请求的路径、请求类型、参数 等信息,封装成自定义的HttpServletRequest对象。

步骤 4:匹配 Servlet / 静态资源,处理请求

  1. 匹配 Servlet :用请求路径从 HashMap 容器中找对应的 Servlet 对象,调用对应的doGet()/doPost()方法;
  2. 处理静态资源:如果请求的是 HTML/CSS/JS 等静态资源,直接读取文件并返回;
  3. 404 处理:既不是 Servlet 也不是静态资源时,返回 404 错误。

步骤 5:封装 Response,返回结果

把处理后的响应数据封装成HttpServletResponse对象,通过 Socket 的输出流写回客户端。

四、总结:Web 容器的核心本质

不管是 Tomcat 还是我们手写的简易容器,核心逻辑都是:

网络通信:用 Socket 实现客户端 - 服务器的连接;

请求解析:拆分 HTTP 报文,提取关键信息;

Servlet 管理:用容器(HashMap)管理 Servlet,实现 "路径→组件" 的映射;

请求分发:根据请求信息调用对应的组件(Servlet / 静态资源),生成响应。

相关推荐
孟陬2 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌2 小时前
一站式了解四种限流算法
java·后端·go
华仔啊2 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝3 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java
Nyarlathotep01134 小时前
SpringBoot Starter的用法以及原理
java·spring boot
wuwen54 小时前
WebFlux + Lettuce Reactive 中 SkyWalking 链路上下文丢失的修复实践
java
SimonKing4 小时前
GitHub 10万星的OpenCode,正在悄悄改变我们的工作流
java·后端·程序员
Seven975 小时前
虚拟线程深度解析:轻量并发编程的未来趋势
java
雨中飘荡的记忆15 小时前
ElasticJob分布式调度从入门到实战
java·后端