Server
从最基本的功能讲,可以将服务器描述为一个应用,通常情况下最简单的服务器设计如下:
通过start()方法启动服务器,打开socket链接,监听服务器端口,负责再接收到客户端请求的时候进行处理并返回响应。同时提供一个stop()方法来停止服务并释放网络资源。
Connector和Container
请求监听和请求处理放到一起扩展性差,比如想适配多种网络协议但是请求处理却相同的时候。Tomcat独立部署的时,我们选择使用HTTP协议,当和apache进行集群部署的时候,使用AJP协议进行链接。如果Tomcat在两种架构进行切换的时候,应确保web应用不做任何处理,如果从面向对象的方式来解决,如图所示:
一个Server可以包含多个Connector(链接器)和Container(容器)。Connector负责开启Socket并监听客户端请求,返回响应数据;Container负责具体的请求处理。他们分别拥有自己的start()和stop()方法加载和释放资源。
既然Server可以包含多个Connector和Container,又怎么知道来自某个的Connector请求由哪个Container处理?
合理的设计如下:
一个Server包含多个Service(相互独立,只是共享一个JVM系统类库),一个Service负责维护多个Connector和一个Container,这样Connector请求就只能由它所属的Service维护的Container处理。
在Tomcat中,Container是一个通用的概念,为了与Tomcat中的组件命名一致,将Container命名为Engine,用以表示整个Servlet引擎:
以上的设计解决了网络协议和容器的解耦,我们需要在Engine容器中支持管理web应用,收到Connector请求处理时,Engine容器能够找到一个合适的web应用来处理,使用Context来表示一个web应用,一个Engine可以包含多个Context:
假如我们一台主机,承担了多个域名服务,但是我们又希望运行一个服务实例呢,又改怎么办呢?
用Host表示主机的概念,一个Host可以包含多个Context。
在Servlet规范中,在一个web应用中,可以包含多个Servlet实例,在Tomcat中,Servlet定义被称为Wrapper:
容器的含义,有时候指Context,有时候指Engine,代表了一类组件,其作用就是处理接收客户端的请求并且返回响应数据,尽管具体操作可能会委派到子组件,但是从行为定义上,它们是一致的:
容易发现,所有组件都有启动、停止等生命周期方法,针对有生命周期的特性抽象出一个Lifecycle通用接口,定义了生命周期管理的核心方法:
Init():初始化组件。
start():启动组件。
stop():停止组件。
destroy():销毁组件。
Tomcat定义了Pipeline(管道)和Valve(阀)两个接口,前者用于构造责任链,后者代表责任链上的每个处理器。
Tomcat组件的灵活之处在于,每个层级的容器(Engine、Host、Context、Wrapper)均有对应的基础Valve实现,同时维护了一个Pipeline实例,也就是说,可以在任何层级容器上针对请求处理进行扩展。
Connector设计:
要想与Container配合实现一个完成的服务器功能,Connector至少要完成如下几个功能:
1、监听服务端口,读取来自客户端的请求;
2、将请求数据按照指定协议进行解析;
3、根据请求地址匹配正确的容器进行处理;
4、将响应返回客户端;
我们知道Tomcat支持多协议,默认支持HTTP和AJP。同时还支持多种I/O方式,包括BIO、NIO、APR。而且在Tomcat8之后新增了对NIO2和HTTP/2协议的支持。
链接器的设计如下:
ProtocolHandler表示协议处理器,针对不用的协议和I/O方式,提供不同的实现,ProtocolHandler包含一个Endpoint用于启动Socket监听,该接口按照I/O方式进行分类实现;还包含一个Processor用于按照指定协议读取数据,并将请求交由容器处理。
Processor读取客户端请求后,需要按照请求地址映射到具体的容器进行处理,这个过程即为请求映射。由于Tomcat各个组件采用通用的生命周期管理,而且可以通过管理工具进行状态变更,因此请求映射除考虑映射规则的实现外,还要考虑容器组件的注册与销毁。
Tomcat通过Mapper和MapperListener两个类实现上述功能,前者用于维护容器映射信息,同时按照映射规则查找容器。后者实现了在组件状态发生变更时,注册或者取消对应的容器映射信息。
Tomcat通过适配器模式实现了Connector与Mapper、Container的解耦,Tomcat默认的Connector实现(Coyote)对应的适配器为CoyoteAdapter。
Executor
Tomcat并行执行方案,提供了Executor接口来表示一个可以在组件间共享的线程池,同样也实现了Lifecycle接口。
在Tomcat中Executor由Service维护,因此同一个Service中的组件可以共享一个线程池。
如果没有定义审核线程池,相关组件Endpoint会自动创建线程池,此时,线程池不再共享。
添加Executor之后,总体设计如下:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13811.html