Tomcat中按照包含关系一共有四个容器——StandardEngine、StandardHost、StandardContext和StandardWrapper,对这四个容器的详细解析后面会涉及,请求对象及响应对象将分别被此四个容器处理,请求响应对象在四个容器之间通过管道机制进行传递。如下图,请求响应对象先通过StandardEngine的管道,期间经过若干个阀门处理,基础阀门是StandardEngineValve;往下流转到StandardHost的管道,基础阀门为StandardHostValve;类似地通过StandardContext;最后到StandardWrapper完成整个处理流程。
这种设计为每个容器都带来了灵活的机制,可以按照需要对不同容器添加自定义阀门进行不同的逻辑处理,并且tomcat将管道机制做成可配置形式,对于存在的阀门只需通过配置文件即可,还可以自定义阀门并配置就可在相应作用域内生效。四个容器中每个容器都包含自己的管道对象,管道对象用于存放若干阀门对象,他们都有自己的基础阀门,且基础阀门是tomcat默认设置的,一般不可更改之,以免运行时产生问题。
下面分别看看这些基础阀门详细的解析
① StandardEngineValve,此阀门最重要的逻辑如下,调用时它会获取请求对应的主机host对象,同时负责调用host对象中管道的第一个阀门。
public final voidinvoke(Request request, Response response)
throws IOException, ServletException {
Host host = request.getHost();
host.getPipeline().getFirst().invoke(request, response);
}
② StandardHostValve,尽管包含了其他的处理逻辑,但不可缺少的逻辑是获取请求对应的上下文context对象并调用context对象中管道的第一个阀门。
public final voidinvoke(Request request, Response response)
throws IOException, ServletException {
Context context = request.getContext();
触发request初始化事件
context.getPipeline().getFirst().invoke(request, response);
更新会话上次访问时间
}
③ StandardContextValve,上下文基础阀门先会判断是否访问了禁止目录WEB-INF或META-INF,接着获取请求对应的wrapper对象,再向客户端发送通知报文“HTTP/1.1 100 Continue”,最后调用wrapper对象中管道的第一个阀门。
public final voidinvoke(Request request, Response response)
throws IOException, ServletException {
判断访问路径是否包含WEB-INF或META-INF,禁止访问此目录
Wrapper wrapper = request.getWrapper();
向客户端发送"HTTP/1.1 100 Continue"通知
wrapper.getPipeline().getFirst().invoke(request, response);
}
④ StandardWrapperValve,包装器基础阀门负责统计请求次数、统计处理时间、分配Servlet内存、执行servlet过滤器、调用Servlet的service方法、释放Servlet内存。
public final voidinvoke(Request request, Response response)
throws IOException, ServletException {
统计请求次数
StandardWrapper wrapper =(StandardWrapper) getContainer();
Servlet servlet = wrapper.allocate();
执行servlet的过滤器
servlet.service(request, response);
wrapper.deallocate(servlet);
统计处理时间
}