您的位置:首页 > 运维架构 > Tomcat

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可能更合适一点)

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-----------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: