Tomcat 之手写连接器
没有人永远年轻,但永远有人年轻
之前手写了一个能解析Servlet的简单的Servlet容器,但是我们的目标可不能止于这些,把Tomcat写出来才是我们最终的目标~
- 相关代码已同步Github
概述
我们知道Catalina
中有两个主要的板块,一个是connector
,另外一个是container
。
- 连接器负责将请求和容器关联,它为每一个Http请求创建一个request和response对象。然后把这两个对象交给容器
- 容器接收到对象之后,调用request请求的servlet的service方法。之后,把处理的结果以response返回回去
连接器主要类
相对于上一篇博客的服务器,我们把要写的类分为以下几个类型:
- 启动类:
Bootstrap
- 连接器类
-
HttpConnector
和HttpProcessor
上一章是HttpServer-
HttpConnector
等待Http请求 -
HttpProcessor
创建HttpRequest
和HttpResponse
实例
-
-
HttpRequest
和其支持类 上一章是Request -
HttpResponse
和其支持类 上一章是Response - Http的外观类(之前已经实现过)
- 常量类
-
HttpHeader
主要用于解析请求头 -
HttpRequestLine
主要用于解析请求行 -
Constants
主要是路径
-
-
- 核心模块
ServletProcessor
StaticResourceProcessor
处理流程
本程序的服务器流程是:
- 先是
Boostrap
启动服务器,然后HttpConnect
等待客户端的请求。 - 当请求到达时,服务器会新开一个线程接收该请求,拿到
socket
后,把socket
传给HttpProcessor
,同时HttpProcessor
处理该socket。 -
HttpProcessor
会执行四个操作,创建HttpRequest
对象和HttpResponse
对象,解析Http请求的请求行和请求头信息,填充HttpRequest
对象。 -
HttpRequest
会去获得参数,而不是通过HttpProcessor
来获取,因为我们不知道servlet是否需要这些参数,这样可以减少资源消耗 - 之后,将
HttpRequest
对象和HttpResponse
对象传递给ServletProcessor
或者StaticResourceProcessor
的process()
方法。对于前者来说,其process方法会先找到自定义的Servlet类,然后调用其service方法;对于后者说,其process方法会直接读取静态文件。 - 之后,把内容填充到
HttpResponse
中,返回给客户端
UML类图
其中,
org.apache.catelina.util.StringManager
类用于处理不同模块的错误消息和国际化操作
- 同一个包下的类共用一个StringManager实例 通过单例模式实现
- 每个包使用一个
properties
来说明该包中任何类可能出现的异常信息,每个异常信息都是kv的形式