引言
最近在学习tomcat的实现机制,其中提到了tomcat的是通过管道和阀的机制来对各个servlet进行加载的,但是书上说的太晦涩,对我这种新手来说显得很难懂,所以自己另外找了些资料,补充并写了些自己的一些理解。
管道
Tomcat中按照包含关系一共有四个容器——engine,host,context,wrapper;请求对象和响应对象会分别被这四个容器处理,请求响应对象在四个容器之间通过管道机制进行传递。请求响应首先经过engine的管道,期间经过若干个阀门的处理,基础阀门是engineValue,向下流转到host管道,基础阀为hostValue,类似通过context直到通过wrapper完成整个处理流程。
为什么要有这种阀门的机制?因为这样的设计可以针对不同的容器添加不同的阀门(处理逻辑),同时,tomcat将管道机制做成可以通过配置文件进行配置的方式,使得阀门可以自定义。四个容器中每个容器都包含自己的管道对象,管道对象用来存放若干阀门对象,但tomcat会为他们制定一个默认的基础阀门。
阀门
- StandardEngineValue
此阀门在调用时会获取请求主机的host对象,同时负责调用host对象管道中的第一个阀门。
public final void invoke(Request request,Response response) throws IOException, ServletException{
Host host = request.getHost();
host.getPipeline().getFirst().incoke(request,response);
}
StandardHostValue,其中最重要的逻辑是获取请求对应的上下文的context对象并调用context对象中管道的第一个阀门。
//触发request初始化事件
Context context = request.getContext();
//更新上次会话的访问时间
context.getPipeline().getFirst().invoke(request,response);
}StandardContextValue,上下文的基础阀门会判断是否访问了禁止目录WEB-INF或者META-INF,接着获取请求对应的wrapper对象,在向着客户端发送通知报文“HTTP/1/1 100 Continue”,最后调用wrapper对象中管道的第一个阀门。
public final void invoke(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);
}
- StandardWrapperValue,包装器基础阀门负责请求次数、处理统计时间、分配Servlet内存,执行servlet过滤器,调用servlet的service方法,释放servlet内存。
public final void invoke(Request request,Response response) throws IOExcption,ServletException{
//统计请求次数
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = wrapper.allocate();
//执行servlet过滤器
servlet.service(request,response);
wrapper.deallocate(servlet);
//统计处理时间
}