Tomcat中 pipeline valve机制

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内存等.

猜你喜欢

转载自blog.csdn.net/yangsnow_rain_wind/article/details/80053703