Tomcat Container的管道机制:责任链模式

📅 2026/6/26 8:43:36
Tomcat Container的管道机制:责任链模式
Tomcat总计架构图中Pipeline和Vavle我们在上文Engine中有一块Pipline没有解释为什么Tomcat要引入Pipline呢它要解决什么问题呢下文将向你详细阐述。知识准备在弄清楚管道机制前你需要一些基础知识和其它软件设计中的应用场景。责任链模式管道机制在设计模式上属于责任链模式如果你不理解请参看如下文章责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。FilterChain在软件开发的常接触的责任链模式是FilterChain它体现在很多软件设计中比如Spring Security框架中比如HttpServletRequest处理的过滤器中当一个request过来的时候需要对这个request做一系列的加工使用责任链模式可以使每个加工组件化减少耦合。也可以使用在当一个request过来的时候需要找到合适的加工方式。当一个加工方式不适合这个request的时候传递到下一个加工方法该加工方式再尝试对request加工。网上找了图这里我们后文将通过Tomcat请求处理向你阐述。Pipline机制为什么要有管道机制在一个比较复杂的大型系统中如果一个对象或数据流需要进行繁杂的逻辑处理我们可以选择在一个大的组件中直接处理这些繁杂的业务逻辑 这个方式虽然达到目的但扩展性和可重用性较差 因为可能牵一发而动全身。更好的解决方案是采用管道机制用一条管道把多个对象(阀门部件)连接起来整体看起来就像若干个阀门嵌套在管道中一样而处理逻辑放在阀门上。Vavle接口设计理解它的设计第一步就是阀门设计javapublic interface Valve { // 因为需要传递给下个Valve处理所以有next public Valve getNext(); public void setNext(Valve valve); // 设计这个方法便于执行周期任务比如重新加载组件。此方法将在该容器的类加载上下文中调用。 public void backgroundProcess(); // 这个方法很容易理解阀门中处理的执行方法传入Request和Response进行处理 public void invoke(Request request, Response response) throws IOException, ServletException; // 此阀门是否支持Servlet 3 异步的请求 public boolean isAsyncSupported(); }Pipline接口设计由于Pipline是为容器设计的所以它在设计时加入了一个Containerd接口, 就是为了制定当前Pipline所属的容器javapublic interface Contained { Container getContainer(); void setContainer(Container container); }我们接着看下Pipline接口设计javapublic interface Pipeline extends Contained { // 基础的处理阀 public Valve getBasic(); public void setBasic(Valve valve); // 对节点阀门增删查 public void addValve(Valve valve); public Valve[] getValves(); public void removeValve(Valve valve); // 获取第一个节点遍历的起点所以需要有这方法 public Valve getFirst(); // 是否所有节点阀门都支持处理Servlet3异步处理 public boolean isAsyncSupported(); // 找到所有不支持Servlet3异步处理的阀门 public void findNonAsyncValves(SetString result); }BaseVavle设计由于Valve也是组件需要生命周期管理所以实现LifecycleMBeanBase同时集成Contained和Valvejavapublic abstract class ValveBase extends LifecycleMBeanBase implements Contained, Valve { protected static final StringManager sm StringManager.getManager(ValveBase.class); //------------------------------------------------------ Constructor public ValveBase() { this(false); } public ValveBase(boolean asyncSupported) { this.asyncSupported asyncSupported; } //------------------------------------------------------ Instance Variables /** * Does this valve support Servlet 3 async requests? */ protected boolean asyncSupported; /** * The Container whose pipeline this Valve is a component of. */ protected Container container null; /** * Container log */ protected Log containerLog null; /** * The next Valve in the pipeline this Valve is a component of. */ protected Valve next null; //-------------------------------------------------------------- Properties /** * Return the Container with which this Valve is associated, if any. */ Override public Container getContainer() { return container; } /** * Set the Container with which this Valve is associated, if any. * * param container The new associated container */ Override public void setContainer(Container container) { this.container container; } Override public boolean isAsyncSupported() { return asyncSupported; } public void setAsyncSupported(boolean asyncSupported) { this.asyncSupported asyncSupported; } /** * Return the next Valve in this pipeline, or codenull/code if this * is the last Valve in the pipeline. */ Override public Valve getNext() { return next; } /** * Set the Valve that follows this one in the pipeline it is part of. * * param valve The new next valve */ Override public void setNext(Valve valve) { this.next valve; } //---------------------------------------------------------- Public Methods /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ Override public void backgroundProcess() { // NOOP by default } Override protected void initInternal() throws LifecycleException { super.initInternal(); containerLog getContainer().getLogger(); } /** * Start this component and implement the requirements * of {link org.apache.catalina.util.LifecycleBase#startInternal()}. * * exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ Override protected synchronized void startInternal() throws LifecycleException { setState(LifecycleState.STARTING); } /** * Stop this component and implement the requirements * of {link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ Override protected synchronized void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); } /** * Return a String rendering of this object. */ Override public String toString() { return ToStringUtil.toString(this); } // -------------------- JMX and Registration -------------------- Override public String getObjectNameKeyProperties() { StringBuilder name new StringBuilder(typeValve); Container container getContainer(); name.append(container.getMBeanKeyProperties()); int seq 0; // Pipeline may not be present in unit testing Pipeline p container.getPipeline(); if (p ! null) { for (Valve valve : p.getValves()) { // Skip null valves if (valve null) { continue; } // Only compare valves in pipeline until we find this valve if (valve this) { break; } if (valve.getClass() this.getClass()) { // Duplicate valve earlier in pipeline // increment sequence number seq ; } } } if (seq 0) { name.append(,seq); name.append(seq); } String className this.getClass().getName(); int period className.lastIndexOf(.); if (period 0) { className className.substring(period 1); } name.append(,name); name.append(className); return name.toString(); } Override public String getDomainInternal() { Container c getContainer(); if (c null) { return null; } else { return c.getDomain(); } } }StandardPipline实现里面方法很简单就直接贴代码了。它必然是继承LifecycleBase同时实现Pipline.贴个图方面你理解