Tomcat中按照包含关系一共有四个容器——engine,host,context,wrapper;
四个容器中每个容器都包含自己的管道对象,管道对象用来存放若干阀门对象,但tomcat会为他们制定一个默认的基础阀门【StandardEngineValve,StandardHostValve,StandardContextValve ,StandardWrapperValve】。四个基础阀门放在各自容器管道的最后一位,用于查找下一级容器的管道.
Valve是Tomcat中责任链模式的实现
1 .StandardEngineValue
此阀门在调用时会获取请求主机的host对象,同时负责调用host对象管道中的第一个阀门。
public final void invoke(Request request,Response response) throws IOException, ServletException{
Host host = request.getHost();
host.getPipeline().getFirst().incoke(request,response);
}
2.StandardHostValue:
获取请求对应的上下文的context对象并调用context对象中管道的第一个阀门。
//触发request初始化事件
Context context = request.getContext();
//更新上次会话的访问时间
context.getPipeline().getFirst().invoke(request,response);
}
3.StandardContextValue
获取请求对应的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);
}
4.StandardWrapperValue,
请求在管道中最后到达StandardWrapperValve, 源码如下:
public final void invoke(Request request, Response response)
throws IOException, ServletException {
......
requestCount++;
//定位wrapper
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
......
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
//加载servlet
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
......
}
......
// 根据配置建立一个filter-servlet的处理链表,servlet在链表的尾端
ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain =
factory.createFilterChain(request, wrapper, servlet);
// Reset comet flag value after creating the filter chain
request.setComet(false);
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
try {
String jspFile = wrapper.getJspFile();
if (jspFile != null)
request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
else
request.removeAttribute(Globals.JSP_FILE_ATTR);
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (comet) {
filterChain.doFilterEvent(request.getEvent());
request.setComet(true);
} else {
//调用filter-servlet链表
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (comet) {
request.setComet(true);
filterChain.doFilterEvent(request.getEvent());
} else {
//调用filter-servlet链表
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}
}
request.removeAttribute(Globals.JSP_FILE_ATTR);
} catch (ClientAbortException e) {
request.removeAttribute(Globals.JSP_FILE_ATTR);
throwable = e;
exception(request, response, e);
}
......
}
可以清晰的看到,注释部分里,先是能拿到相应的wrapper对象;然后完成加载wrapper对象中的servlet,再然后执行servlet过滤器,调用servlet的service方法,释放servlet内存等.