Tomcat相关面试点

如果你在简历里写了"手写实现简易版 Tomcat",这绝对是一个能和面试官聊上很久的亮点!

这里为你整理了一套**"满分叙述话术"以及"延伸出的高频面试题库"**,建议按照这个逻辑去准备。


一、 🗣️ 面试话术:如何清晰地口述整个 Tomcat 流程?

面试官: "我看你手写了一个 Tomcat,能给我讲讲它的运行工作流程吗?"

🔥 满分叙述模板(建议背诵):

"面试官您好,我手写的 MyTomcat 核心流程主要分为两大阶段:启动初始化阶段请求处理阶段

  1. 首先是启动初始化阶段(类似 Spring 的 IoC 机制):
    Tomcat 启动前,会先执行 ServletConfigMapping 中的一段静态代码块。它利用反射文件遍历 技术,扫描我在指定包下的所有类。只要发现类头上带有 @WebServlet 注解,就会通过反射的 newInstance() 提取把这个 Servlet 实例化成一个单例对象 ,并以注解里的 URL 路径做 Key、对象做 Value,存进一个全局的 HashMap 中。这就建立起了一张**'路由映射表'**。
  2. 其次是服务器监听阶段:
    我在主线程中利用 ServerSocket 绑定了 7788 端口,并开启了一个 while(true) 的死循环,调用 accept() 方法阻塞等待客户端连接。
  3. 最后是请求处理与响应阶段:
    当浏览器发来 HTTP 请求时,连接建立。我取出网络连接的 InputStream,读取字节流转换成字符串(即 HTTP 请求报文)。接着我对字符串进行切割,解析出请求方式(GET/POST)请求路径(如 /first)
    拿到路径后,我去全局的 HashMap 里找对应的 Servlet 实例,如果找到了,就调用它的 service() 方法,最终分发到 doGet()doPost() 里处理业务代码。业务处理完后,再把拼接好的 HTML 字符串通过 OutputStream 按照 HTTP 协议格式写回给浏览器,最后关闭 Socket。这就是一整个完整闭环。"

二、 💼 连环炮:由这个项目引发的核心面试题(深度提问)

当你说完上述流程,面试官大概率会顺着你的项目,切入到底层原理。以下是高频考点分类整理

📝 考点 1:关于 Servlet 的基本功

Q1:Servlet 是单例的还是多例的?它是线程安全的吗?

  • :在 Tomcat 中默认是单例 的(路由表 HashMap 里只存了一个实例)。它不是线程安全的! 若多个用户同时访问,Tomcat 内部会开多线程去调用同一个对象的 service 方法。如果我们在这个 Servlet 类里定义了全局成员变量,就会导致数据混乱。
  • 如何解决:禁止使用全局变量,只在方法内部使用局部变量(局部变量在栈帧中,线程间隔离)。

Q2:说一下 Servlet 的生命周期?

  • :加载实例化 -> init() 初始化(只调用1次) -> service() 处理请求(调用无数次) -> destroy() 销毁(只调用1次)。
🌐 考点 2:关于并发模型与服务器架构 (重点拉开差距)

Q3:你写的这套 Tomcat 代码,它能扛住高并发吗?和真正的 Tomcat 有什么区别?

  • 答(承认不足+指出原理) :我写的版本由于使用的是 ServerSocket.accept() 以及在同一个线程里直接处理流,属于纯粹的 单线程 BIO (同步阻塞) 模型。同一时刻只能处理一个用户的请求,别人只能卡在外面等。
  • 真正的 Tomcat :使用的是 多路复用 NIO + 线程池(多线程) 模型。有一个专门的 Acceptor 线程负责快速接收连接,然后将 I/O 读写和业务处理的工作扔进一个全局线程池(Worker 线程)中异步处理,所以在高并发下完全不会阻塞。
🔍 考点 3:关于 HTTP 协议

Q4:当你通过 InputStream 读取到的那一大串字符串(请求报文),它到底包含哪些结构?

  • :标准的 HTTP 请求报文包含四个切片:
    1. 请求行 :如 GET /first HTTP/1.1
    2. 请求头 (Headers) :各种键值对,比如 HostUser-AgentCookie
    3. 空行:只有回车换行,用来分隔请求头和请求体。
    4. 请求体 (Body):如果是 POST 请求发送的表单数据或 JSON,就放在这里。

Q5:GET 和 POST 到底有什么区别?

  • 大白话总结 :GET 是向服务器**"索要/查询"数据,参数暴露在 URL 地址里,不安全,有长度限制;POST 是向服务器"提交/修改"**数据,参数藏在请求体 (Body) 里,相对安全,没有长度大小限制。
🧠 考点 4:关于设计模式与类加载器 (终极装逼点)

Q6:你知道 Tomcat 打破了双亲委派机制吗?为什么?

  • 通俗解答(杀手锏):在 Java 中原本类加载是双亲委派(儿子先让父亲去加载,保证基础类不被篡改)。但是 Tomcat 作为一个容器,里面可能部署了两个不同的项目,项目 A 用了 Spring 3,项目 B 用了 Spring 5。如果用传统的双亲委派,就会导致只能加载一个版本的 Spring,发生版本冲突。
  • 所以,Tomcat 自定义了 WebAppClassLoader(Web应用类加载器),它打破了委派机制,优先加载自己项目的 WEB-INF/lib 下的依赖。由于不同的项目有不同的类加载器,就实现了类之间的彻底隔离

Q7:你在解析 @WebServlet 时使用到了哪种设计思想?

  • :体现了 控制反转 (IoC) 的思想。以前我们要用什么类都是开发者主动 new,但在 Tomcat 里,是我们贴上注解,框架(Tomcat 容器)负责把对象实例化,并把控制权接管过去,在必要的时候再通过"回调"我们的 HashMap.get() + 反射回调"执行我们的代码。

第二题:手写 MyTomcat 和"MyTomcat 线程池版本"的区别在哪里?

我帮您对比了这两个文件夹的核心源码,本质的区别在于:服务器处理并发请求的模型从"单线程的纯 BIO" 升级到了"伪异步的 BIO (配合线程池)"

1. 版本一:普通版 MyTomcat(路边摊单人服务模式)
  • 运行机制 :在主线程里,serverSocket.accept() 接收到一个浏览器的请求后,直接在当前线程往下执行 读取流、解析请求、处理 Servlet 业务的方法。处理完并断开 Socket 之后,主循环才会进入下一次 accept()
  • 致命缺陷:如果你在代码里遇到一个很耗时的请求(比如下载文件花了10秒),在这 10 秒内,主线程被完全卡死。第二个、第三个人无论怎么发请求,Tomcat 都不会搭理,直接处于假死状态。
2. 版本二:MyTomcat 线程池版本(高级餐厅前后台分离模式)

这是企业级架构重构的第一步!在 myTomcat线程池版本 中,你新增了 HandleSocketServerPool.java 和 ServerThreadReader 类。

  • 运行机制
    • 你在启动时,创建了一个核心线程数2,最大线程数自定义,带阻塞队列的 ThreadPoolExecutor (线程池)
    • 主线程里的 while(true) 现在只干一件事 :专门负责 accept() 迎客。拿到客人的 Socket 对象后,立马把他打包成一个 Runnable 任务对象 (ServerThreadReader),扔给线程池去处理。
    • 然后主线程不管了,瞬间回头继续去门口等下一个客人。
  • 核心优势总结 (面试点)
    • 应对高并发:现在哪怕有某个请求卡了 10 秒,它也只是占用了线程池里的一名"服务员"。主线程依然能极快地接收其他上百个并发请求,把它分发给别的服务员处理,Tomcat 不会阻塞了!
    • 资源可控 :为什么不直接为每个请求 new Thread() 而是用线程池?因为如果瞬间来 10000 个请求,直接 new 一万个线程会把内存撑爆(OOM)。利用通过你代码里的 ArrayBlockingQueue 可以把多出来的请求先放在队列里排队,起到了削峰填谷的缓冲作用。

装逼建议 :如果面试官问"这套代码还有没有优化空间?"

你可以回答:"虽然线程池版本解决了主线程阻塞排队的问题,但它依然是 BIO 阻塞流(InputStream.read 会卡死线程)。如果有 1 万个用户保持连接却不说话(比如做聊天室),就会把线程池的 1 万个线程全占满一直干等着。下一步的究极进化就是改成 **NIO(非阻塞)+ 多路复用(Selector)**的架构,这也是真实 Tomcat 8 之后和 Netty 所采用的终极方案。"

相关推荐
低客的黑调2 小时前
MyBatis-Plus-从 CRUD 到高级特性
java·servlet·tomcat
天码-行空5 小时前
深入拆解 Tomcat 系统架构:连接器如何设计
java·系统架构·tomcat
我登哥MVP10 小时前
【SpringMVC笔记】 - 10 - 拦截器(Interceptor)
java·spring boot·spring·servlet·tomcat·maven
YaBingSec11 小时前
玄机靶场-第三届-长城杯-初赛-SnakeBackdoor WP
java·运维·笔记·tomcat·ssh
北辰屿风1 天前
宝塔部署tomcat项目,nginx负载均衡代理访问报错404问题
java·tomcat
ictI CABL1 天前
Linux环境下Tomcat的安装与配置详细指南
linux·运维·tomcat
fTiN CAPA2 天前
Tomcat 都有哪些核心组件
java·tomcat·firefox
untE EADO2 天前
Tomcat的server.xml配置详解
xml·java·tomcat
ictI CABL2 天前
Tomcat 乱码问题彻底解决
java·tomcat
yaodong5182 天前
Spring 中使用Mybatis,超详细
spring·tomcat·mybatis