tomcat pipline设计模式
2015-10-29 00:17
597 查看
最近在看tomcat源码,看到其中的Pipline设计模式,觉得很有趣,这里记录一下。
做过java web开发的应该都使用过Servlet和Filter。 当想访问一个Servlet时会经过定义好的一系列Filter,然后再访问到Servlet 。 这里就用到了Pipline管道设计模式。
Pipline的执行流程如下图
其中的Valve就是一个个阀门,Basic就是最后被执行的对象。 可以理解成Valve是Filter,Basic是Servlet 。 执行流程是控制权从第一个Valve一直流向最后一个Valve,最后流向Basic, 然后从Basic开始再将控制权反向流到最前面的Valve。
在Valve中可以让流继续向下执行,也可以终止后面的执行。
下面通过代码来介绍这种模式。
首先定义一个Pipline接口。来代表这样一个管道,可以添加任意多的Valve,也可以设置一个Basic。(这里的Basic叫Target可能更合适一点)
invoke方法就是开始执行这个管道的内容,执行流程就是上面讲的。 方法定义了一个Map类型的参数。 可以类比Servlet和Filter中的Request和Response参数。
接下来定义一个Valve接口。
该接口只有一个方法invoke,注意invoke中的参数,一个是Map类型,用于传递Pipline执行时传设置的参数,另外一个是PiplineContext,该参数描述了Pipline的上下文信息,在invoke方法中如果需要继续执行后面的Valve,可以使用PiplineContext的invokeNext方法。 两个类的定义如下:
接下来实现一个简单的Piplie类。
里面的经典之处就是使用一个内部类SimplePiplineContext实现PiplineContext接口,从而可以通过该内部类操作宿主类SimplePipline实例的方法。
注意看SImplePipline的invoke方法,是实例化了一个内部类SimplePiplineContext对象,然后通过该对象一步一步调用自身的valves数组和basic对象。
接下来写几个类来测试一下。
首先实现一个HelloValve来当作Basic,将参数params都打印出来 (可以理解为一个Servlet)
然后实现一个BeforeValve,在basic前面打印一行内容。(可以理解为一个Filter)
再实现一个AfterValve,在basic后面打印一行内容。(可以理解为一个Filter)
再实现一个AroundValve,在basic的前后都打印一段内容。(可以理解为一个Filter)
然后写个测试类来试试。
执行结果
做过java web开发的应该都使用过Servlet和Filter。 当想访问一个Servlet时会经过定义好的一系列Filter,然后再访问到Servlet 。 这里就用到了Pipline管道设计模式。
Pipline的执行流程如下图
其中的Valve就是一个个阀门,Basic就是最后被执行的对象。 可以理解成Valve是Filter,Basic是Servlet 。 执行流程是控制权从第一个Valve一直流向最后一个Valve,最后流向Basic, 然后从Basic开始再将控制权反向流到最前面的Valve。
在Valve中可以让流继续向下执行,也可以终止后面的执行。
下面通过代码来介绍这种模式。
首先定义一个Pipline接口。来代表这样一个管道,可以添加任意多的Valve,也可以设置一个Basic。(这里的Basic叫Target可能更合适一点)
package tomcat.p4; import java.util.Map; /** * 管道 * @author zhoufeng * */ public interface Pipline{ /** * 这里的basic代表最后要执行的内容(在所有add的Valve执行后执行) * @param basic */ void setBasic(Valve basic); /** * 添加一个阀门 * @param valve */ void addValve(Valve valve); /** * 执行 * 将会以此执行add的所有Valve然后执行basic * @param params 携带的参数 */ void invoke(Map<String, Object> params); }
invoke方法就是开始执行这个管道的内容,执行流程就是上面讲的。 方法定义了一个Map类型的参数。 可以类比Servlet和Filter中的Request和Response参数。
接下来定义一个Valve接口。
该接口只有一个方法invoke,注意invoke中的参数,一个是Map类型,用于传递Pipline执行时传设置的参数,另外一个是PiplineContext,该参数描述了Pipline的上下文信息,在invoke方法中如果需要继续执行后面的Valve,可以使用PiplineContext的invokeNext方法。 两个类的定义如下:
package tomcat.p4; import java.util.Map; /** * 阀门 * @author zhoufeng * */ public interface Valve { /** * 执行阀门里面的内容 * @param params 管道执行时携带过来的参数 * @param context 管道上下文 */ void invoke(Map<String, Object> params , PiplineContext context); }
package tomcat.p4; import java.util.Map; public interface PiplineContext { void invokeNext(Map<String, Object> params); }
接下来实现一个简单的Piplie类。
package tomcat.p4.core; import java.util.Map; import tomcat.p4.Pipline; import tomcat.p4.PiplineContext; import tomcat.p4.Valve; /** * 一个基本的pipline实现 * @author zhoufeng */ public class SimplePipline implements Pipline{ /** * 阀门列表(相当于一系列的Filter) */ private Valve[] valves = new Valve[0]; /** * 最终要执行的内容 */ private Valve basic ; @Override public void setBasic(Valve basic) { this.basic = basic ; } /** * 添加一个阀 */ @Override public void addValve(Valve valve) { Valve[] newValves = new Valve[valves.length + 1]; System.arraycopy(valves, 0, newValves, 0, valves.length); newValves[newValves.length - 1] = valve ; valves = newValves ; } /** * 执行管道中的内容(注意这里使用内部类实例SimplePiplineContext实现) */ @Override public void invoke(Map<String, Object> params) { new SimplePiplineContext().invokeNext(params); } /** * 这里使用一个私有的内部类实现PiplineContext,用于线性的依次执行pipline中的valves,然后执行basic * @author zhoufeng * */ private class SimplePiplineContext implements PiplineContext{ /** * 记录当前正在执行到哪个valve */ private int step = 0 ; @Override public void invokeNext(Map<String, Object> params) { int curStep = step ; step++; if(curStep < valves.length){ valves[curStep].invoke(params , this); }else if(curStep == valves.length){ if(SimplePipline.this.basic != null){ SimplePipline.this.basic.invoke(params, this); } }else{ throw new RuntimeException("no valve fond"); } } } }
里面的经典之处就是使用一个内部类SimplePiplineContext实现PiplineContext接口,从而可以通过该内部类操作宿主类SimplePipline实例的方法。
注意看SImplePipline的invoke方法,是实例化了一个内部类SimplePiplineContext对象,然后通过该对象一步一步调用自身的valves数组和basic对象。
接下来写几个类来测试一下。
首先实现一个HelloValve来当作Basic,将参数params都打印出来 (可以理解为一个Servlet)
package tomcat.p4.test.valve; import java.util.Map; import java.util.Map.Entry; import tomcat.p4.PiplineContext; import tomcat.p4.Valve; public class HelloValve implements Valve{ @Override public void invoke(Map<String, Object> params, PiplineContext context) { System.out.println("--------------Hello Servlet :--------------"); if(params != null && params.size() > 0){ for (Entry<String, Object> entry : params.entrySet()) { System.out.printf("key:%s\tvalue:%s\n",entry.getKey() , entry.getValue()); } } } }
然后实现一个BeforeValve,在basic前面打印一行内容。(可以理解为一个Filter)
package tomcat.p4.test.valve; import java.util.Map; import tomcat.p4.PiplineContext; import tomcat.p4.Valve; public class BeforeValve implements Valve{ @Override public void invoke(Map<String, Object> params, PiplineContext context) { System.out.println("----------------BeforeValve-----------------"); context.invokeNext(params); } }
再实现一个AfterValve,在basic后面打印一行内容。(可以理解为一个Filter)
package tomcat.p4.test.valve; import java.util.Map; import tomcat.p4.PiplineContext; import tomcat.p4.Valve; public class AfterValve implements Valve{ @Override public void invoke(Map<String, Object> params, PiplineContext context) { context.invokeNext(params); System.out.println("----------------AfterValve-----------------"); } }
再实现一个AroundValve,在basic的前后都打印一段内容。(可以理解为一个Filter)
package tomcat.p4.test.valve; import java.util.Map; import tomcat.p4.PiplineContext; import tomcat.p4.Valve; public class AroundValve implements Valve{ @Override public void invoke(Map<String, Object> params, PiplineContext context) { System.out.println("----------------AroundValve before-----------------"); context.invokeNext(params); System.out.println("----------------AroundValve after-----------------"); } }
然后写个测试类来试试。
package tomcat.p4.test; import java.util.HashMap; import java.util.Map; import tomcat.p4.Pipline; import tomcat.p4.Valve; import tomcat.p4.core.SimplePipline; import tomcat.p4.test.valve.AfterValve; import tomcat.p4.test.valve.AroundValve; import tomcat.p4.test.valve.BeforeValve; import tomcat.p4.test.valve.HelloValve; public class Startup { public static void main(String[] args) { Pipline pipline = new SimplePipline(); Valve helloValve = new HelloValve(); Valve beforeValve = new BeforeValve(); Valve afterValve = new AfterValve(); Valve aroundValve = new AroundValve(); pipline.setBasic(helloValve); pipline.addValve(beforeValve); pipline.addValve(afterValve); pipline.addValve(aroundValve); Map<String, Object> params = new HashMap<String , Object>(); params.put("a", 1); params.put("b", 2); params.put("c", 3); pipline.invoke(params); } }
执行结果
----------------BeforeValve----------------- ----------------AroundValve before----------------- --------------Hello Servlet :-------------- key:a value:1 key:b value:2 key:c value:3 ----------------AroundValve after----------------- ----------------AfterValve-----------------
相关文章推荐
- Tomcat学习之Request/Response封装
- Linux 配置jdk和tomcat
- Tomcat ShutDown出现 Insufficient space for shared memory file:
- nginx+tomcat
- 关于apache tomcat的几个版本
- Tomcat 基础知识
- 设置Tomcat的UTF-8编码
- Tomcat内存溢出
- tomcat基础
- tomcat
- linux下apache tomcat的安装
- tomcat虚拟目录
- Linux下启动停止查看杀死Tomcat进程
- 如何在Linux下查看TOMCAT控制台
- tomcat服务器介绍之二 、session服务器实现方法
- JAVA中文乱码解决办法/修改TOMCAT默认编码
- Tomcat SSL配置 Connector attribute SSLCertificateFile must be defined when using SSL with APR解决 作者:孤风一
- Tomcat 启动两次的问题(ServletContextListener的contextInitialized被执行两次的问题)
- Tomcat下使用war包发布项目
- Tomcat 下配置一个ip绑定多个域名