这篇文章是阅读了《How Tomcat Works》第五章后的总结。
本章主要讲了tomcat的container,而tomcat的container接口又有四个子接口:Engine,Host,Context,Wapper。
对应的标准实现类分别是ContainerBase,StandardEngine,StandardHost,StandardContext,StandardWapper。其中ContainerBase是其他四个的父类。
类图如下:
四个子接口分别对应:
1. Engine对应Catalina的 servlet引擎
2. Host代表拥有多个Context的虚拟主机
3. Context代表一个应用
4. Wapper代表一个具体的servlet
他们之间的关系是一个container可以有0或多个子container。
例如:
一个host可以有0或多个context,一个context可以有1或多个wapper。
而本章主要讲了Context和Wapper。
其实本章和上一张基本一样,唯一不一样的是Container,这里把上一章的SimpleContainer替换成了SimpleWapper,另外本章还介绍了Pipeline,这其实也是SimpleWapper和SimpleContainer最大的不同。
Pipeline
其实就是管道的意思,其实没啥神秘的,就是一个责任链模式的实现。主要包含了如下几个类:Pipeline,Valve,ValveContext和Contained。
其中Valve就是责任链中的一个个”节点“(相当于一个filter),最主要的方法就是invoke(),执行当前valve并且唤醒下一个valve执行。
而Pipeline则是一个链模型,保存了所有的Valve。
ValveContext的作用是当责任链运行的时候,保存责任链的上下文,以保证任何时候都能知道当前的Valve是哪个,下一个Valve是哪个以及是否还有下一个Valve。
这里需要注意的一点是,Pipeline的valve链中只保存了可插拔的一些valve,其实还有一个basic的valve并不在valve链中,无论valve链中有或者没有valve,最后basic的Vavle都会运行,而且在baseValve中就是执行指定servlet的service方法。
这里有个特别的地方,虽然valve链的顺序是按照第一个到最后一个这样的执行,但是其实可以像书中的例子那样在valve的invoke方法中首先调用ValveContext的invokeNext()方法控制先执行下一个valve,然后再执行当前valve中的code
public void invoke(Request request, Response response, ValveContext valveContext)
throws IOException, ServletException {
// Pass this request on to the next valve in our pipeline
valveContext.invokeNext(request, response);//这里先调用了invokeNext()方法
System.out.println("Client IP Logger Valve");
ServletRequest sreq = request.getRequest();
System.out.println(sreq.getRemoteAddr());
System.out.println("------------------------------------");
}
还有一个就是 Contained了,这里主要是为了解耦Pipeline和Container之间的关系。为了使得Pipeline可以与上面提到的任何一种Conrainer组合,所以Valve都实现了Contained接口,该接口只有一对set和get方法用来设置和获取Container。
下一章将通过一段代码来解释一下一个Wapper和Context的运行。