我们知道如果要设计一个系统,首先是要了解需求。 Tomcat 要实现 2 个核心功能:
从图上你可以看到,最顶层是 Server,这里的 Server 指的就是一个 Tomcat 实例。一个 Server 中有一个或者多个 Service,一个 Service 中有多个连接器和一个容器。连接器与容器之间通过标准的 ServletRequest 和 ServletResponse 通信。
连接器对 Servlet 容器屏蔽了协议及 I/O 模型等的区别,无论是 HTTP 还是 AJP,在容器中获取到的都是一个标准的 ServletRequest 对象。
监听网络端口。 接受网络连接请求。 读取网络请求字节流。 根据具体应用层协议(HTTP/AJP)解析字节流,生成统一的 Tomcat Request 对象。 将 Tomcat Request 对象转成标准的 ServletRequest。 调用 Servlet 容器,得到 ServletResponse。 将 ServletResponse 转成 Tomcat Response 对象。 将 Tomcat Response 转成网络字节流。 将响应字节流写回给浏览器。
通过分析连接器的详细功能列表,我们发现连接器需要完成 3 个高内聚的功能:
ProtocolHandler 组件是将EndPoint和Processor两个组件进行了封装 下图为两个维度不同的组合
Endpoint 接收到 Socket 连接后, 生成一个 SocketProcessor 任务提交到线程池去处理, SocketProcessor 的 run 方法会调用 Processor 组件去解析应用层协议, Processor 通过解析生成 Request 对象后, 会调用 Adapter 的 Service 方法。
Adapter 组件完成 Tomcat Request ->Servlet Request的转换 CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法。
问题:在processor直接转换为容器的servletrequest和servletresponse不是更好,为什么要先转化Tomcat的request和response,再用adapter做一层转换消耗性能?
回答:如果连接器直接创建ServletRequest和ServletResponse对象的话,就和Servlet协议耦合了,设计者认为连接器尽量保持独立性,它不一定要跟Servlet容器工作的。另外对象转化的性能消耗还是比较少的,Tomcat对HTTP请求体采取了延迟解析的策略,也就是说,TomcatRequest对象转化成ServletRequest的时候,请求体的内容都还没读取呢,直到容器处理这个请求的时候才读取的。
Nginx/Apche一般做反向代理和处理静态HTML资源,做的事情相对来说简单,KPI就是要快,因此用C语言实现,直接调用操作系统API,充分利用操作系统的高级特性。
而Tomcat用来处理动态请求,还需要跑Java应用,因此用Java实现,因此”快“不是它主要的KPI。Java调用操作系统API要通过JNI,无形中有性能损耗。另外Tomcat通过使用Apache APR本地库来做I/O通信,性能已经跟Apache、Nginx接近了。
可以的,在server.xml配置多个service,或者同一个service里配置多个connector
omcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。
一个 Tomcat 实例包含一个service 一个 Service 包含一个 Engine和多个连接器, 一个 Engine 包含多个 Host, 一个 Host包 含多个Context 一个 Context包含多个 Wrapper 一个 Wrapper包含一个servlet
由 Mapper 组件完成, Mapper 组件保存了容器组件与访问路径的映射关系, 根据请求的 URL 进行定位
在各个层次定位过程中, 都会对请求做一些处理
Tomcat 内的 Context 组件跟 Servlet 规范中的 ServletContext 接口有什么区别?跟 Spring 中的 ApplicationContext 又有什么关系?
Basic valve 有些疑惑。比如engine容器下有多个host容器,那engine容器的basic valve是怎么知道要指向哪个host容器的value呢?
Mapper组件在映射请求的时候,会在Request对象中存储相应的Host、Context等对象,这些选定的容器用来处理这个特定的请求,因此Engine中的Valve是从Request对象拿到Host容器的。
生产环境中, 配的都是一个 tomcat 对应一个应用, 多个应用就用多个tomcat ,它和一个 tomcat 加载多个应用有什么区别么?
在同一个Tomcat实例里部署多个Web应用是为了节省内存等资源,不过配置部署有点复杂,应用之间互相影响,加上现在硬件成本将低,多应用部署比较少见了。