实现一:servlet 经典模式
该模式特点:多线程环境环境下,需要每一个客户端请求,new 一个ConcreteFilterChain对象。如果对象太大,增加cpu和gc的负担。
代码demo
import java.io.IOException;public interface Filter { public void doFilter(Context ctx, FilterChain chain) throws IOException;}
import java.io.IOException;public interface FilterChain { void doFilter(Context ctx) throws IOException;}
import java.io.IOException;public class PrintOne implements Filter { @Override public void doFilter(Context ctx, FilterChain chain) throws IOException { System.out.println(Thread.currentThread().getId()+ " 1"); chain.doFilter(ctx); }}import java.io.IOException;public class PrintTwo implements Filter { @Override public void doFilter(Context ctx, FilterChain chain) throws IOException { System.out.println(Thread.currentThread().getId()+" 2"); chain.doFilter(ctx); }}import java.io.IOException;public class PrintThree implements Filter { @Override public void doFilter(Context ctx, FilterChain chain) throws IOException { System.out.println(Thread.currentThread().getId()+" 3"); chain.doFilter(ctx); }}
import java.io.IOException;import java.util.List;public class DefaultFilterChain implements FilterChain { public DefaultFilterChain(Listlist) { this.list = list; } List list; int pos = 0; @Override public void doFilter(Context ctx) throws IOException { if(pos < list.size()){ Filter filter = list.get(pos); pos++; filter.doFilter(ctx,this); } }}
测试程序
import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestMain { static ExecutorService executorService = Executors.newFixedThreadPool(5); public static void main(String args[]){ Listlist = new ArrayList (); list.add(new PrintOne()); list.add(new PrintTwo()); list.add(new PrintThree()); FilterChain filterChain = new DefaultFilterChain(list); for(int i=0;i<2;i++) { executorService.submit(new Event(filterChain)); } } public static class Event implements Runnable{ public Event(FilterChain filterChain) { this.filterChain = filterChain; } FilterChain filterChain; @Override public void run() { Context ctx = new Context(); try { filterChain.doFilter(ctx); } catch (IOException e) { e.printStackTrace(); } } }}
注意:该测试程序是有bug的,多线程共享filterChain会导致filter的游标定位错误。要解决这个问题,要么每个请求new一个DefaultFilterChain对象。
实现二
参考netty pipeline的实现
该实现的优点:多线程环境下,不需要每一个客户的请求都new一个DefaultFilterChain.该算法的巧妙之处在于:将handler跟filterchain 组成成一个节点。 通过handler驱动节点的扭转
上代码
public class Context {}public interface Handler { void handle(Context ctx,FilterChain filterChain);}public class PrintOne implements Handler { @Override public void handle(Context ctx, FilterChain filterChain) { System.out.println(Thread.currentThread().getId()+" 1"); filterChain.fireNext(ctx); }}public class PrintTwo implements Handler{ @Override public void handle(Context ctx, FilterChain filterChain) { System.out.println(Thread.currentThread().getId()+" 2"); filterChain.fireNext(ctx); }}public class PrintThree implements Handler { @Override public void handle(Context ctx, FilterChain filterChain) { System.out.println(Thread.currentThread().getId()+" 3"); filterChain.fireNext(ctx); }}
FilterChain和DefaultFilterChain
public interface FilterChain { void handler(Context ctx); void fireNext(Context ctx);}public class DefaultFilterChain implements FilterChain { private FilterChain next; private Handler handler; public DefaultFilterChain(FilterChain next, Handler handler) { this.next = next; this.handler = handler; } @Override public void handler(Context ctx) { handler.handle(ctx,this); } public void fireNext(Context ctx){ FilterChain next_ = this.next; if(next_ != null){ next_ .handler(ctx); } }}
测试代码
import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class FilterChainTest { static ExecutorService executorService = Executors.newFixedThreadPool(3); public static void main(String args[]){ Handler h1 = new PrintOne(); Handler h2 = new PrintTwo(); Handler h3 = new PrintThree(); FilterChain filterChain3 = new DefaultFilterChain(null,h3); FilterChain filterChain2 = new DefaultFilterChain(filterChain3,h2); FilterChain filterChain1 = new DefaultFilterChain(filterChain2,h1); Context ctx = new Context(); for(int i=0;i<3;i++){ executorService.execute(new RunPrintEcho(filterChain1,ctx)); } } public static class RunPrintEcho implements Runnable{ FilterChain filterChain; Context ctx; public RunPrintEcho(FilterChain filterChain, Context ctx) { this.filterChain = filterChain; this.ctx = ctx; } @Override public void run() { filterChain.handler(this.ctx); } }}
大功告成!