这份文档是对"手写 Tomcat"项目中涉及到底层核心技术的概念普及。我们将那些抽象的英文名词(Socket、BIO、HashMap等)用最通俗的大白话解释清楚,让你在面试中不仅知其然,更知其所以然。
🔌 1. 网络通信三大剑客:Socket、ServerSocket、WebSocket
在读 Tomcat 源码时,这三个词出场率极高,它们到底是什么关系?
> Socket(套接字)------ "连接你我的专属电话管"
- 到底是什么: 它不是一个协议,它是操作系统提供给程序员在网络中发送和接收数据的一套接口(API)。
- 大白话比喻: 想象一根水管(或者电话线)。浏览器和服务器之间要传数据,必须先连上一根管子。这个
Socket对象,就是这根管子在你 Java 代码里的代表。 - 怎么用: 拿到
Socket后,你可以通过它获取InputStream(听筒,接收浏览器数据)和OutputStream(话筒,发数据给浏览器)。
> ServerSocket(服务端套接字)------ "总机迎宾大门"
- 到底是什么: 这是服务端专用的一种特殊 Socket。它的任务只有一个:绑定一个端口(如 7788),然后死死盯着这个端口,等别人来连接。
- 大白话比喻: 如果说 Socket 是一对一的私密电话线,那么 ServerSocket 就是公司的**"总机前台"**。前台(
serverSocket.accept())接到一个外部打进来的电话,就会马上把这通电话转接分配给一条内部专线(生成一个普通的Socket),然后前台继续挂机等下一个人。
> WebSocket(网络协议)------ "能互相喊话的高铁"
- 到底是什么: 它是一个真正的网络通信协议(属于应用层,和 HTTP 是兄弟),底层也是基于 Socket 实现的。
- 它解决什么痛点: HTTP 是"半双工"的(客户端不发请求,服务器绝不主动给数据,且发完就断开)。而 WebSocket 一旦连接成功,就变成全双工长连接,服务器随时可以主动给浏览器推送消息。
- 和 Socket 的区别: Socket 是底层的"铺路工程",没有数据格式规矩;WebSocket 是跑在这条路上的"专属高铁",有非常严格的数据帧格式规定。
🚦 2. I/O 运行模型:阻塞与非阻塞的区别
这其实是面试最爱考的系统底层原理。
> BIO(Blocking I/O - 同步阻塞)
- 概念: 传统
java.io包下的模型。你的初代手写 Tomcat 用的就是这个。 - 什么是"阻塞": 就像你去食堂排队打菜,没有叫号系统!如果
serverSocket.accept()没等到客人,或者inputStream.read()这里客人网卡了数据没发完,整个程序线程就会彻底卡死在这行代码,一步也不能往下走,后续的人全得排在整个服务器外面。
> NIO(Non-Blocking I/O - 同步非阻塞)
- 概念: 这是现代 Netty 和真实 Tomcat 8.x 版本处理高并发的神兵利器(基于
Selector多路复用器)。 - 什么是"非阻塞": 就像去高级餐厅拿了叫号器。服务器只用极少数的线程,不断轮询所有的连接。绝对不会在一个没有准备好数据的连接上死等。只要检测到这个水管里有真实数据了,才派个线程去读。
🗄️ 3. 数据结构霸主:HashMap
在 ServletConfigMapping 中,你用 HashMap 存下了所有的路由映射(URL -> Servlet实例)。
> 为什么选 HashMap?而不是 List 数组?
- 概念: HashMap 是一种基于"键值对(Key-Value)"存储的数据结构。
- 大白话: 假设你要在 1000 个房间里找一个人。
- 如果用
List,你得从 1 号房挨个敲门问到 1000 号。 - 但用了
HashMap(比如classMapping.get("/first")),底层就像是拥有一本**"哈希魔法字典"**,它的查询时间复杂度是 O(1)!只要你输入房间号,一步就能瞬间拿到你想要的 Servlet,速度快到飞起。这也是整个 Spring 框架核心(IoC 容器底层也是个超大 ConcurrentHashMap)的基石。
- 如果用
🔄 4. 魔法神器:反射机制(Reflection)与 IoC 设计
在 Tomcat 启动时,你并没有手动去写 new MyFirstServlet(),而是通过反射造出来的。
> 反射(Reflection)------ "拆盲盒的 X 光机"
- 到底是什么: Java 的一种机制,允许程序在运行期间,逆向地去获取一个类的所有信息(不仅能看到它的方法和属性,还能强行新建对象、调用方法)。
- 大白话比喻: 就像是在开盲盒时带上了透视眼镜 。正常情况下你是"先有图纸(写死代码),再造汽车"。但在 Tomcat 里,Tomcat 根本不知道你未来会写什么 Servlet,它通过
Class.forName("你的类名")拿到你的蓝图,然后用newInstance()犹如幽灵一般帮你把对象偷偷生出来。
> IoC(Inversion of Control - 控制反转)
- 到底是什么: 这是一种软件设计思想。
- 大白话解释: 在没有框架以前,你要用什么对象,得自己亲手去
new(正向控制)。现在,你只需要在类上贴个标签(@WebServlet),Tomcat(或者 Spring 容器)就会在启动时扫描到你,不仅帮你new好了对象存进 Map 里,甚至在有请求来的时候,它还会反手回来**调用(回调)**你的代码!对象的"生杀大权"被反转交给了框架容器。
🔤 5. 其他高频底层概念
> 字节流 vs 字符流
- 字节流(InputStream/OutputStream): 最原始的数据传输方式。里面流淌的全部是 0和1 组成的二进制数字(Byte)。不管是传图片、传视频还是传文字,底层走网络最终都只能用字节流。
- 字符流(String/Reader/Writer): 人类能看懂的字。在你的 Tomcat 里,有这样一步操作
new String(bytes, 0, read),这就是拿着收到的一串冷冰冰的数字(字节),对照着密码本(编码表如 UTF-8),翻译拼装成了人能看懂的那句:GET /first HTTP/1.1。
> 线程池(ThreadPoolExecutor)
- 为什么用它: 当并发量大的时候,如果来一个请求就
new Thread()造一个线程,一会儿内存就被一万个线程撑爆了。 - 大白话比喻: 线程池就像是一个**"餐厅里的常驻服务员团队"**。我们固定雇佣 10 个服务员。谁空闲谁接待客人。如果瞬间来了 100 个人,服务员忙不过来,剩下的人就先去"等候区(BlockingQueue 阻塞队列)"排队,这样就不会出现人太多把店挤塌了的情况(保证了系统的稳定性)。