博客讲Filter大多都是结合Servlet写的,那么不用servlet就不能用filter了吗。
Filter理解起来应该不难,就是在一个请求调用链中间加了一段通用的处理逻辑,比如编码转换,日志记录等。
下面来看个例子
:首先要有一个能把过滤器串起来的对象,我们这里取名Invoker(从dubbo中抽出来的代码),Servlet使用的是FilterChain
:然后是一个能够传递参数和返回值的对象,我们这里使用Invocation和Result来作参数和返回值,Servlet的doFilter方法是void,但是用了request和response作入参和返回值
Invoker
把所有Filter串起来,当作参数传递
public interface Invoker<T> {
Result invoke(Invocation invocation);
}
Filer
这里可以看到Invoker参数,在真正的实现里面还需要把invoker传递给下一个调用,下面在buildFilterChain里能看到
public interface Filter {
Result invoke(Invoker<?> invoker, Invocation invocation);
}
CharactorFiler
这里我们仅仅是打印些日志供调试和显示用,不做任何处理
public class CharactorFiler implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) {
System.out.println("CharactorFiler: " + System.currentTimeMillis());
return invoker.invoke(invocation);
}
}
LogFilter
public class LogFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) {
System.out.println("LogFilter: " + System.currentTimeMillis());
return invoker.invoke(invocation);
}
}
Test
public static void main(String[] args) {
// TestInvoker是需要执行的逻辑,通过buildInvokerChain方法在执行真正的方法前插入filter逻辑
Invoker<Object> invoker = buildInvokerChain(new TestInvoker<Object>());
invoker.invoke(new TestInvocation());
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker) {
Invoker<T> last = invoker;
List<Filter> filters = getFilters();
if (filters.size() > 0) {
// i--决定filter的顺序
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
// 在这里把调用串成一个链,后一个invoker作为前一个invoker的参数传递
final Invoker<T> next = last;
last = new Invoker<T>() {
@Override
public Result invoke(Invocation invocation) {
return filter.invoke(next, invocation);
}
};
}
}
return last;
}
/** 获取所有的过滤器,真是使用的时候过滤器是从配置文件或者其他集中管理的地方去取的,
比如Servlet的Filter是从web.xml中取的,如果需要加过滤器就要在web.xml中配置,
这里我们只做测试,写在代码里 */
private static List<Filter> getFilters() {
List<Filter> filters = new ArrayList<Filter>();
Filter f1 = new CharactorFiler();
Filter f2 = new LogFilter();
filters.add(f1);
filters.add(f2);
return filters;
}
Invocation和Result的代码没有贴出来,对程序没有影响。
从框架中剥离出来的Filter代码还是比较好理解的。