上一篇简单介绍了什么是Tomcat以及Web应用,这次介绍Tomcat是如何实现它的功能,整体架构是什么样子的。
org.apache.catalina.startup.Bootstrap
和VM options参数,启动之后访问localhost:8080💡:上述步骤完成之后启动还会有一些问题,解决方案和具体配置信息可以参考我已经编译好的项目debug-tomcat9,这里不再赘述。
在上一篇介绍了 Tomcat 的主要功能是 HTTP 服务器 + Servlet 容器,也就是: 1、处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。2、加载和管理 Servlet,以及具体处理 Request 请求。 在 Tomcat 中设计了两个组件连接器 Connector 和容器 Container 来实现这两个功能
在Connector中有两个比较重要的组件:
/** * Coyote protocol handler. */ protected final ProtocolHandler protocolHandler; /** * Coyote adapter. */ protected Adapter adapter = null; 复制代码
@Override public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); …… …… } 复制代码
这里涉及到的I/O模型有三种:
支持的应用层协议:
具体实现可能不同,但是整体的流程是一致的,AbstractEndpoint负责处理网络请求提供字节流给Processor,Processor负责解析应用层协议提供Tomcat Request对象给Adapter,Adapter负责将Tomcat Request对象转换为ServletRequest对象调用容器。
AbstractEndpoint:是一个抽象类,对传输层协议的抽象,是具体的Socket接收和发送处理器。而AbstractEndpoint的具体子类,比如在NioEndpoint和Nio2Endpoint 中,有两个重要的子组件:Acceptor(在AbstractEndpoint中,Nio2Endpoint也有自己的实现)和SocketProcessor。Acceptor用于监听Socket连接请求,SocketProcessor用于处理接收到的Socket请求。
Processor:是对应用层协议的抽象,Processor接收来自Endpoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理,它的抽象实现类AbstractProcessor对一些协议共有的属性进行封装,具体的实现有AjpProcessor、Http11Processor等实现了特定协议的解析方法和请求处理方式。
容器就是用来装载Servlet的,在Tomcat中有四种容器:Engine、Host、Context、Wrapper,它们之间是采用组合模式的父子关系Engine(Host(Context(Wrapper)))。Engine表示引擎用来管理多个虚拟站点,一个Service最多只能有一个Engine。Host代表的是一个虚拟站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟站点下可以部署多个Web应用程序;Context表示一个Web应用程序;Wrapper表示一个Servlet;
Tomcat是用Mapper组件来确定请求由哪个Wrapper容器里的Servlet来处理请求的。Mapper组件的功能是将用户请求的URL定位到一个Servlet,它保存了容器组件与访问路径的映射关系:Host容器里配置的域名、Context容器里的Web应用路径、Wrapper容器里Servlet映射的路径,可以理解为这些配置信息就是一个多层次Map(由Mapper中的hosts、ContextVersion中的几个Wrappers等组成)。当一个请求到来时,Mapper组件通过解析请求URL里的域名和路径到Map里去查找定位到一个Servlet。