责任链模式之——Pipeline-Valve 管道(Tomcat)分析及仿写
1. Pipeline-Valve 管道(Tomcat)简介
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
Tomcat 中的 Pipeline-Valve 实际上就是责任链模式,责任链模式是指在一个请求处理的过程中有多个处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完成后将处理后的请求返回,再让下一个处理者继续处理,就好像驾车的过程中可能会遇到很多次交警检查,可能有查酒驾的也可能有查违章的,在一次驾车的过程中可能会遇到多次检查,这就是责任链模式,Pipeline 就相当于驾车的过程, Valve 相当于检查的交警。
不过Pipeline-Valve 的管道模型和普通的责任链模式稍微有点不同,区别主要有两点:
- 每个Pipeline 都有特定的Value ,而且是在管道的最后一个执行,这个Valve 叫BaseValve,BaseValve 是不可删除的;
- 在上层容器的管道的BaseValue 中会调用下层容器的管道。4 个容器的BaseValve 分别是StandardEngineValve 、StandardHostValve 、StandardContextValve 和StandardWrapperValve,整个处理的流程如下图:
下面代码即为实现了Value接口的基础类ValveBase,它有一个Valve类型的内部属性next,即同一个Pipeline中的后续Valve的引用。类似于单向链表。继承这个ValveBase针对不同的容器实现了不同版本的阀如StandardEngineValve,StandardHostValve,StandardContextValve,StandardWrapperValve等。他们之间不同的实现就是invoke和event的方法不同。而实际上也就是请求的路由选择,Filter应用和Servlet的处理。
public abstract class ValveBase extends LifecycleMBeanBase implements Contained, Valve { /** * The next Valve in the pipeline this Valve is a component of. */ protected Valve next = null; @Override public Container getContainer() { return (container); } @Override public void setContainer(Container container) { this.container = container; } @Override public Valve getNext() { return (next); } @Override public void setNext(Valve valve) { this.next = valve; } @Override public abstract void invoke(Request request, Response response) throws IOException, ServletException; @Override public void event(Request request, Response response, CometEvent event) throws IOException, ServletException { // Perform the request getNext().event(request, response, event); } }
2. Pipeline-Valve责任链设计
实现写博客需求,设计如下:
Pipeline 为一条管道,Valve是一个个阀门,BasicValve是最后一个阀门,业务从第一个阀门进入,依次流经每个阀门进行业务处理,之后依次返回。
代码如下:
2.1 Pipeline管道设计:
定义一个Pipeline接口:
import com.zang.pipelinevalve.valve.Valve; public interface Pipeline { /** * 后置阀门设置 * @param basic */ void setBasic(Valve basic); /** * 设置后面阀门 * @param valve */ void addValve(Valve valve); /** * pipeline的执行方法 * @param i */ void invoke(int i); }
创建写博客Pipeline管道实现
import com.zang.pipelinevalve.pipeline.Pipeline; import com.zang.pipelinevalve.valve.Valve; /** * 写博客责任链管道 */ public class BloggingPipeline implements Pipeline { /** * 第一个阀门 */ protected Valve first = null; /** * 最后一个阀门 */ protected Valve basic = null; @Override public void setBasic(Valve valve) { Valve oldBasic = this.basic; Valve current = first; while (current != null) { if (current.getNext() == oldBasic) { current.setNext(valve); break; } current = current.getNext(); } this.basic = valve; } public Valve getFirst() { if (first != null) { return first; } return basic; } @Override public void addValve(Valve valve) { 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(); } } } @Override public void invoke(int i) { Valve valve = getFirst(); if (valve!=null) { valve.invoke(i); return; } throw new RuntimeException("责任链上没有阀门"); } }
2.2 Valve阀门设计
定义一个Valve接口:
public interface Valve { void invoke(int i); void setNext(Valve valve); Valve getNext(); }
有多个阀门实现,我们将一些通用的变量方法放入 基础阀门 中。
public abstract class BaseValve implements Valve{ /** * 下一个阀门 */ protected Valve next = null; @Override public void setNext(Valve valve) { this.next = valve; } @Override public Valve getNext() { return next; } }
具体阀门类
public class ComputerOperationValve extends BaseValve{ @Override public void invoke(int i) { System.out.println("开机:"+i++); this.next.invoke(i); System.out.println("关机:"+--i); } } public class BrowserOperationValve extends BaseValve{ @Override public void invoke(int i) { System.out.println("打开浏览器:"+i++); this.next.invoke(i); System.out.println("关闭浏览器:"+ --i); } } public class WebsiteOperationValve extends BaseValve{ @Override public void invoke(int i) { System.out.println("登录网页:"+i++); this.next.invoke(i); System.out.println("登出网页:"+--i); } } public class BlogOperationValve extends BaseValve{ @Override public void invoke(int i) { System.out.println("\n完成博客: "+i +"\n"); } }
2.3 测试
//创建管道 BloggingPipeline pipeline = new BloggingPipeline(); //创建阀门 ComputerOperationValve computerOperationValve = new ComputerOperationValve(); BrowserOperationValve browserOperationValve = new BrowserOperationValve(); WebsiteOperationValve websiteOperationValve = new WebsiteOperationValve(); BlogOperationValve blogOperationValve = new BlogOperationValve(); //管道执行 pipeline.addValve(computerOperationValve); pipeline.addValve(browserOperationValve); pipeline.addValve(websiteOperationValve); pipeline.setBasic(blogOperationValve); pipeline.invoke(0);
结果:
代码结构供参考: