前一篇FilterPattern的范式,基本和Tomcat实现的filter chain是一样的;
这里介绍一下我看完dubbo关于Filter Pattern的实现思路,自己抽象出来的代码,以及理解
相关类的UML图:
可以从上图中看到这里的Invoker
对应原来的Servlet
,这里的Filter
和原来的Filter
只有参数签名上的区别;
Filter
的第一个参数由FilterChain
变成了Invoker
;
Invoker
和原来的Servlet
的函数签名到是一点都没变,可以理解,只是名字不一样,功能性和原来一样(这里起名Invoker是为了和dubbo中的invoker保持一致)
原先的Filter调用链路是有FilterChain来串联起来,现在FilterChain变成了Invoker,可以简单的猜想,现在由Invoker串起Filter调用链路;(这里你肯定想Invoker不是用来执行具体业务逻辑的吗,怎么能串的起Filter调用链路呢,具体可以往后看)
至于是如何串起的,就要看FilterWrapper
和相关Filter
的代码了
public class FilterWrapper {
private List<Filter> filterList;
public FilterWrapper(List<Filter> filterList) {
this.filterList = filterList;
}
public Invoker buildInvokerChain(final Invoker invoker){
Invoker last = invoker;
//倒序遍历filterList,保证index最小的在最外层执行
for (int i = filterList.size() - 1; i >= 0 ; i--) {
final Invoker next = last;
Filter filter = filterList.get(i);
last = new Invoker() {
//用匿名内部类,把filter包装成invoker,为了方便理解,就没有写成lambda表达式了
@Override
public Response invoke(Request request) {
return filter.invoke(next, request);
}
};
}
return last;
}
}
public class PrintFilter implements Filter {
@Override
public Response invoke(Invoker invoker, Request request) {
System.out.println("PrintFilter: request:" + request.getData());
return invoker.invoke(request);
}
}
public class ModifyDataFilter implements Filter {
@Override
public Response invoke(Invoker invoker, Request request) {
request.setData(request.getData() + " modified by ModifyDataFilter!");
return invoker.invoke(request);
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Filter> filterList = new ArrayList<>();
filterList.add(new ModifyDataFilter());
filterList.add(new PrintFilter());
FilterWrapper filterWrapper = new FilterWrapper(filterList);
Invoker invoker = filterWrapper.buildInvokerChain(new HttpInvoker());
Request request = new Request("hello word!");
Response response = invoker.invoke(request);
System.out.println(response.getData());
}
}
从上面的代码可以看到,实际上是用Invoker的匿名内部类来实现调用链路的串联,就我浅薄的理解,buildInvokerInvokerChain实现的invoker应该算是柯里化
然而这样写Filter Chain有什么优点呢?
- Filter签名参数再也不用带着FilterChain了,Invoker接口单一,更加安全