于每个Java工程师而言,tomcat这只小橘猫算是咱们的老朋友了,同时tomcat做为一款服务器中间件具有了很强的扩展性,内部对于Request和Response的逻辑处理都是何种方式来实现的呢?本文将主要介绍tomcat的Pipeline-Valve设计来一窥究竟。java
首先咱们看看Valve接口设计模式
能够从Valve看到不少链表的影子,咱们能够根据Valve来构造一条Valve链。接下来看看Pipeline接口tomcat
Pipeline接口的主要方法服务器
能够看到Pipeline的主要方法提供了对Valve的增删查改操做,其中有两个关键的方法setBasic(Valve)与addValve(Valve)咱们跟进源码看一看。其中StandardPipeline是Pipeline接口的实现类,下面我截取了setBasic最核心的逻辑,能够看出basic实际上就是Pipeline维护的Valve链里最末尾的一个Valve架构
Valve current = first;
while (current != null) {
if (current.getNext() == oldBasic) {
current.setNext(valve);
break;
}
current = current.getNext();
}
this.basic = valve;
复制代码
一样的咱们来看一看addValve的源码,如下是最核心的部分app
Valve current = first;
while (current != null) {
if (current.getNext() == basic) {
current.setNext(valve);
valve.setNext(basic);
break;
}
复制代码
经过addValve添加的Valve被加在了basic的前一个,也就是说basic永远指向Valve链里的最后一个Valve,不会被轻易替代,那么这种设计有什么意义呢?待会给出答案~负载均衡
上图都是Valve接口的实现类,包含了负载均衡、单点登陆等tomcat容器自己的逻辑。经过查看Valve接口invoke方法的实现能够知道,每个Valve的invoke方法主要作两件事情ide
这是很经典的责任链设计模式。简单的说一个valve就是一个逻辑体。this
能够看到setBasic的使用方主要是tomcat内置的四大容器,Context、Engine、Host以及Wrapper,先简单对四大容器作个介绍spa
下面是关于四大容器一个简单的类图关系
那么四大容器是如何被关联在一块儿的呢?StandardEngineValve是Engine容器的basic valve,笔者简化了代码实现,保留最主要的逻辑
@Override
public final void invoke(Request request, Response response) throws IOException, ServletException {
// Select the Host to be used for this Request
Host host = request.getHost();
...
// Ask this Host to process this request
host.getPipeline().getFirst().invoke(request, response);
}
复制代码
能够看到Engine容器的basic valve负责触发host容器pipeline 答案出来了:每一个容器的basic valve会去触发子容器的pipeline,因此basic做为一个valve不只要执行自身相应的逻辑,同时也扮演了一个外交官的角色负责去和其子容器逻辑的对接。