Valve这个系列类,在Tomcat中出现的频率非常高,其主要的作用就是在整个Tomcat流程中起到过滤器的作用,其次还可以作为AOP的切面,进行调入之前和调入之后的环绕监视,还可以起到一些给request,reponse这个传输对象分层次加工的作用;
总之,Valve是Tomcat必须要掌握的组件。
1.什么是Valve
Valve,英文名称就是阀门,阀就是门栓,如果把一个组件比作一个房子,也就是当我们进入一个组件之前,我们需要经过这个门栓,这个形象的比喻就是Valve;
可以使用下图进行形象的比喻,以Tomcat后端的为例,我们理想的流程是这样的:
而真实的流程是,在每一个组件中加上一个门栓:
当组件执行之前,首先调用到该组件的Valve,然后通过Valve的代码对组件进行调用,并安排下一次调用链条给下一个组件;
Tomcat中的Valve有很多,但是其实质的ValveBase是所有Valve的基类:
ValveBase实现了2个接口一个抽象类,Valve没什么可说的,Contained说明Valve也是容器的组件,上述的这张图比较老了,LifecycleMBeanBase,这说明Valve也可以通过Mbean进行注册和监控;
下面的这些类其实不是很全,如果要总结有多少个valve的话,可以看下面的图:
基本上可以分成两类,一类是核心的Valve,这些组件都是Tomcat主线请求调用流程和关键容器核心组件的,这些Valve串起了Tomcat的容器调用链;
另外一类是一些功能类的valve,这些Valve可以作为一个组件加在不同的Tomcat核心组件层级中;
其实还有一类,就是我们可以基于server.xml插入我们自己定义的Valve,这就是Valve的扩展;
从上面的文字描述来看,其实每个核心容器组件的Valve都不止1个,这就是下面我们要讲的Tomcat后端容器的Valve集合与Pipeline了;
2.核心valve与pipeline
Tomcat后端容器的核心组件,如果每一个组件只有一个Basic的valve,也就是自身的Valve的话,那么其实是呈下列的示意图:
可以看到,每一个组件都维护着一个Pipeline:
这个Pipeline其实很简单,它持有三个比较重要的属性:
a.这个pipeline所属是哪个容器组件,例如StandardWrapper的pipeline实例,那么这个container就指向的是StandardWrapper
b.basic属性指的是基础Valve,以StandardWrapper为例,指的就是StandardWrapperValve
c.first是一个Pipeline的第一个valve,而这个Pipeline也就是责任链模式,我们在server.xml中可以添加n个valve,而这些valve可以一个调用一个,在Pipeline中持有第一个valve
通过这种关系,我们将这些Tomcat自带的这些Valve和自定义的Valve,和上述的核心Valve组合在一块,有下面的图:
最开始的容器后端的出发点是CoyoteAdaptor,我们可以看到代码最开始拿的是StandardService,这个服务实际上就是StandardEngine中的Service对象,这样就调用到了StandardEngine的pipeline中的第一个firstValve;
从而按照上图的顺序,从firstValve,调用到secondValve,当pipeline的Tomcat内置valve和自定义的Valve调用完了,最后会流转到Basic Valve中来,StandardEngine的basic Valve实际上也就是StandardEngineValve;
我们可以推测出来,实际上这个StandardEngineValve中必然有对StandardHost的pipeline的调用:
按照这个时序,从Tomcat的容器组件一直到StandardWrapperValve中,在StandardWrapperValve会组装其filter的调用链,也就是我们上一节关注的:
最终执行到Servlet;
整个上述的流程就是Tomcat后端容器的调用链;
总结:
可以总结,Valve,pipeline,核心容器组件,这三个元素撑起了Tomcat后端容器的“脊梁”!