天天看点

Tomcat源码分析(三):PipelinePipeline

Pipeline

首先看下pipeline是什么

Tomcat源码分析(三):PipelinePipeline

Tomcat中的容器是有层级结构的,每层容器关注点不同

当请求到来时,会将请求交给最上层的容器,当上层容器处理完之后,会交给下层容器

每层容器都有一个Pipeline对象,Piple中包含了多个Valve,每个Valve代表了对请求的处理逻辑

并且每层容器的Pipeline中都会有一个Basic Valve,这个Valve总是在该层Pipeline中最后一个执行,在该Valve中会将请求交给子容器的Pipeline,从而将不同层次的容器的执行处理逻辑连接起来

下面先看下Pipeline和Valve是怎么执行的

Pipeline

这里主要看下实现类StandardPipeline,该实现类不仅实现了Pipeline接口,并且实现了Lifecycle接口,因此也具有生命周期

Tomcat源码分析(三):PipelinePipeline

startInternal

这个类的initInternal为空,因此我们主要看下startInternal

protected synchronized void startInternal() throws LifecycleException {

    // Start the Valves in our pipeline (including the basic), if any
    Valve current = first;
    if (current == null) {
        current = basic;
    }
    while (current != null) {
        if (current instanceof Lifecycle)
            ((Lifecycle) current).start();
        current = current.getNext();
    }

    setState(LifecycleState.STARTING);
}
           

这个方法主要是遍历所有的valve,然后分别启动这些valve

addValve

通过addValve方法来向pipeline中添加valve

并且维护valve的前后关系,并且永远确保base valve是最后一个valve

public void addValve(Valve valve) {

    // Validate that we can add this Valve
    if (valve instanceof Contained)
        ((Contained) valve).setContainer(this.container);

    // Start the new component if necessary
    if (getState().isAvailable()) {
        if (valve instanceof Lifecycle) {
            try {
                ((Lifecycle) valve).start();
            } catch (LifecycleException e) {
                log.error(sm.getString("standardPipeline.valve.start"), e);
            }
        }
    }

    // Add this Valve to the set associated with this Pipeline
    if (first == null) {
        first = valve;
        valve.setNext(basic);
    } else {
        Valve current = first;
        while (current != null) {
            if (current.getNext() == basic) {
                current.setNext(valve);
                valve.setNext(basic);
                break;
            }
            current = current.getNext();
        }
    }

    container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve);
}
           

Valve

Tomcat源码分析(三):PipelinePipeline

这里看下StandardContextValve做了哪些操作,是如何将请求传递到子容器的

可以看到在通过请求获取到请求对应的wrapper之后,会调用wrapper的pipeline中第一个valve,从而将当前的处理逻辑和子容器的处理逻辑串起来

public final void invoke(Request request, Response response)
        throws IOException, ServletException {

    // Disallow any direct access to resources under WEB-INF or META-INF
    MessageBytes requestPathMB = request.getRequestPathMB();
    if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
            || (requestPathMB.equalsIgnoreCase("/META-INF"))
            || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
            || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }

    // Select the Wrapper to be used for this Request
    Wrapper wrapper = request.getWrapper();
    if (wrapper == null || wrapper.isUnavailable()) {
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }

    // Acknowledge the request
    try {
        response.sendAcknowledgement(ContinueResponseTiming.IMMEDIATELY);
    } catch (IOException ioe) {
        container.getLogger().error(sm.getString(
                "standardContextValve.acknowledgeException"), ioe);
        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        return;
    }

    if (request.isAsyncSupported()) {
        request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
    }
    wrapper.getPipeline().getFirst().invoke(request, response);
}