
1. 为什么需要手写Tomcat作为Java开发者我们每天都在使用Tomcat但很少有人真正理解它的内部工作原理。三年前我第一次尝试手写简化版Tomcat时才发现原来一个Web容器最核心的功能可以用不到500行代码实现。这种造轮子的练习不仅能加深对HTTP协议和Servlet规范的理解更能培养系统设计思维。2. 核心架构设计2.1 最小化架构设计一个最基础的Tomcat需要包含以下组件连接器(Connector)处理Socket连接和HTTP协议解析容器(Container)管理Servlet生命周期和请求分发线程池处理并发请求public class MiniTomcat { private ServerSocket serverSocket; private ThreadPoolExecutor executor; private ServletContainer container; public void start() throws IOException { serverSocket new ServerSocket(8080); executor new ThreadPoolExecutor(...); container new ServletContainer(); while (true) { Socket socket serverSocket.accept(); executor.execute(new RequestHandler(socket, container)); } } }2.2 关键设计决策BIO vs NIO选择教学演示建议用BIO代码简单生产级实现应该用NIO性能更好线程模型每个请求一个线程简单但并发能力有限Reactor模式复杂但高性能类加载机制需要实现独立的WebAppClassLoader支持热加载功能3. 连接器实现细节3.1 HTTP协议解析核心是解析请求行和请求头// 示例请求行解析 String requestLine readLine(inputStream); String[] parts requestLine.split( ); String method parts[0]; String uri parts[1]; String protocol parts[2];3.2 请求参数处理需要处理三种情况URL参数/test?namevalueForm表单application/x-www-form-urlencoded文件上传multipart/form-data特别注意URL解码需要使用UTF-8编码否则中文会出现乱码4. 容器实现要点4.1 Servlet生命周期管理标准流程加载Servlet类调用init()方法处理service()请求调用destroy()释放资源public class ServletWrapper { private Servlet instance; public void init() throws ServletException { Class? clazz classLoader.loadClass(className); instance (Servlet) clazz.newInstance(); instance.init(config); } }4.2 请求分发机制需要实现URL模式匹配精确匹配、路径匹配、扩展名匹配过滤器链调用会话管理Cookie/Session5. 性能优化技巧5.1 对象池技术高频创建的对象应该复用Socket处理器实例请求/响应对象字节缓冲区5.2 缓存策略静态资源缓存编译后的Servlet类缓存解析后的URL映射缓存6. 常见问题排查6.1 内存泄漏场景未正确关闭的文件流数据库连接线程静态集合持有请求对象6.2 线程阻塞问题典型症状请求响应变慢CPU使用率低但吞吐量下降排查工具jstack查看线程栈Arthas监控方法执行时间7. 扩展功能实现7.1 支持JSP需要添加JSP编译器将JSP转换为Servlet热加载机制7.2 集群支持关键点会话复制分布式锁共享存储手写Tomcat最困难的部分不是代码实现而是对Servlet规范各种边界条件的处理。建议先实现核心流程再逐步添加过滤器、监听器等扩展功能。我在第三次重构时才真正理解为什么Tomcat的源码要设计得如此复杂 - 都是为了处理各种现实中的特殊情况。