管道组件 - 969251639/study GitHub Wiki

管道跟流一样,可有由多个管道拼接而成,而管道的每个拼接点叫阀门,在tomcat中叫Base,Base需要调用下一个管道的First,所有管道最后组成一条单向链表。它可以用来将tomcat的多个内部组件流转起来,然后到每个组件的尽头都会有一个阀门去连接下一段管道

注:tomcat管道的开头都是first,结尾都是base

管道的起点是当tomcat连接请求时在工作线程池里会调用SocketProccess的run方法,run方法中会从Connector组件开始,逐步流向内部组件

public class CoyoteAdapter implements Adapter {
    ...
    @SuppressWarnings("deprecation")
    @Override
    public void service(org.apache.coyote.Request req,
                        org.apache.coyote.Response res)
        throws Exception {
        ...
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
        ...
    }
    ...
}

找到最顶的的pipeline,也就是service中的container,也就是Engine,标准实现类是StandardEngine

public class StandardEngine extends ContainerBase implements Engine {
    ...
    public StandardEngine() {

        super();
        pipeline.setBasic(new StandardEngineValve());
        /* Set the jmvRoute using the system property jvmRoute */
        try {
            setJvmRoute(System.getProperty("jvmRoute"));
        } catch(Exception ex) {
            log.warn(sm.getString("standardEngine.jvmRouteFail"));
        }
        // By default, the engine will hold the reloading thread
        backgroundProcessorDelay = 10;

    }
    ...
}

初始化时设置了管道的阀门StandardEngineValve

其中管道的创建都是在它的父类ContainerBase中创建

public abstract class ContainerBase extends LifecycleMBeanBase
        implements Container {
    ...
    protected final Pipeline pipeline = new StandardPipeline(this);
    ...
}

接下来看StandardEngineValve的invoke方法


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

        // Select the Host to be used for this Request
        Host host = request.getHost();
        if (host == null) {
            response.sendError
                (HttpServletResponse.SC_BAD_REQUEST,
                 sm.getString("standardEngine.noHost",
                              request.getServerName()));
            return;
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(host.getPipeline().isAsyncSupported());
        }

        // Ask this Host to process this request
        host.getPipeline().getFirst().invoke(request, response);

    }

基本上不做什么操作,就是将request和response交给下一个管道处理(也就是host组件),接下来的几个组件都是类似,不断的通过管道留给下一个组件

从上图可以看到tomcat的管道流向: engine -> host -> context -> wrapper

其实我们也可以自定管道,然后插入到上面的任何一个点中,比如tomcat自带的一个请求日志

在上面的host节点中,配置了一个valve,valve就是tomcat可以在管道处理的一个节点,我们也可以自定义自己的一个valve,插入到想要流入的节点上,只要继承ValveBase类即可,然后重写invoke方法实现自己的逻辑,最后在server.xml配上自己的管道