Filter Pattern
1.什么是Filter Pattern?
    Filter Pattern 也可以叫Intercepting Filter Pattern(拦截过滤器模式),这个范式可以让你在执行原有逻辑(核心逻辑)之前和之后额外执行一系列逻辑,像这样:


2.这个范式能给我们的代码带来什么好处?
    Filter Pattern最广为人知的应用莫过于web应用中的servlet filter的,通过filter我们可以实现鉴权逻辑(哪些请求可以被执行下去,哪些不可以),access日志输出(对每个请求都输出日志参数)等。这些filter可以让系统在不修改核心业务逻辑的基础上,按照一定顺序添加切面功能,也就是Aspect Oriented Programming,实现功能的解耦合。
3.如何设计一个Filter Pattern?
首先任何设计模式都离不开应用场景,这里我们我们假定一个典型的http请求响应的逻辑:
public class HttpServlet implements Servlet{
    @Override
    public Response service(Request request){
        Response response = new Response();
        response.setData( "RESPONSE OF " + request.getData());
        return response;
    }
}
此时想在这个service逻辑上层添加print request的逻辑,以及modify request的逻辑,粗放的写法象这样:
public class HttpServlet implements Servlet{
    @Override
    public Response service(Request request){
        System.out.println(request.getData());
        request.setData("modify " + request.getData());        
        Response response = new Response();
        response.setData( "RESPONSE OF " + request.getData());
        return response;
    }
}
这样当然能实现功能,但是代码的可维护性,可读性都会变得很差;于是把print 和 modify功能单独抽取出来like this;
public class HttpServlet implements Servlet{
    /**
     * 执行filterList,并执行service
     * @param request
     * @return
     */
    public Response doFilter(Request request) {
        List<SimpleFilter> simpleFilterList = buildFilterList();
        for (SimpleFilter simpleFilter : simpleFilterList) {
            simpleFilter.doBefore(request);
        }
        Response response = this.service(request);
        for (SimpleFilter simpleFilter : simpleFilterList) {
            simpleFilter.doAfter(response);
        }
        return response;
    }
    /**
     * 构建Filter List
     */
    private List<SimpleFilter> buildFilterList() {
        List<SimpleFilter> filterList = new ArrayList<>();
        SimpleFilter printFilter = new SimpleFilter() {
            @Override
            public void doBefore(Request request) {
                System.out.println(request);
            }
            @Override
            public void doAfter(Response response) {
                //do noting
            }
        };
        SimpleFilter modifyFilter = new SimpleFilter() {
            @Override
            public void doBefore(Request request) {
                request.setData("modify " + request.getData());
            }
            @Override
            public void doAfter(Response response) {
                //do noting
            }
        };
        filterList.add(printFilter);
        filterList.add(modifyFilter);
        return filterList;
    }
    @Override
    public Response service(Request request){
        Response response = new Response();
        response.setData( "RESPONSE OF " + request.getData());
        return response;
    }
    public interface SimpleFilter {
        void doBefore(Request request);
        void doAfter(Response response);
    }
}
    这里实现的逻辑和HandlerInterceptor的思想很像,有兴趣的话可以看看org.springframework.web.servlet.HandlerInterceptor相关的实现,都是在核心代码的前后循环调用interceptor的函数;
但是这里有一个问题,当前版本的代码,SimpleFilter的doBefore方法无法控制流程是否往下走,无法实现类似流控,鉴权相关的功能;当然硬要在此基础上去改也能改出来,只不过不是很优雅,下面尝试另一个东西FilterChain:
4.FilterChain
    FilterChain顾名思义,肯定包含一个Filter List并且是用过addFilter方法构建的, 有一个返回参数为Response的doFilter方法,看来是核心入口;看看它的实现类:
public interface FilterChain {
    Response doFilter(Request request);
    void addFilter(Filter filter);
}
public class ApplicationFilterChain implements FilterChain {
    private List<Filter> filters;
    //当前执行待执行filter的位置
    private int position;
    private Servlet servlet;
    public ApplicationFilterChain() {
        filters = new LinkedList<>();
        position = 0;
        servlet = new HttpServlet();
    }
    @Override
    public Response doFilter(Request request) {
        Filter currentFilter;
        if (position < filters.size()){
            currentFilter = filters.get(position);
            position ++;
            //顺序执行filter list
            return currentFilter.doFilter(this, request);
        }else {
            //执行真正的service方法
            return servlet.service(request);
        }
    }
    @Override
    public void addFilter(Filter filter) {
        this.filters.add(filter);
    }
}
     ApplicationFilterChain 的代码总体符合猜想,但是多了servlet,position属性,position用来定位执行filter的执行位置,servlet放的是核心业务逻辑;
但是doFilter又是串起所有filter和servlet的呢?看一下新的Filter接口参数,以及实现类:
public interface Filter {
    Response doFilter(FilterChain filterChain, Request request);
}
public class PrintFilter implements Filter {
    @Override
    public Response doFilter(FilterChain filterChain, Request request) {
        //do my filter
        System.out.println("realFilter.doFilter: " + request.getData());
        return filterChain.doFilter(request);
    }
}
public class ModifyFilter implements Filter {
    @Override
    public Response doFilter(FilterChain filterChain, Request request) {
        request.setData("modified " + request.getData());
        return filterChain.doFilter(request);
    }
}
    doFilter签名是FilterChain和Request,这里的FilterChain的用法是filterChain.doFilter(request),是用来串起所有filter list;
所以最后的代码执行时序是这样的(算是套了两个函数的递归调用)
filterChain.doFilter -> filter.doFilter -> filterChain.doFilter -> filter.doFilter -> filterChain.doFilter -> servlet.service
    Main方法如下:
public class Main {
    public static void main(String[] args) {
        FilterChain filterChain = buildFilterChain();
        Response response = filterChain.doFilter(new Request("request"));
        System.out.println(response.getData());
    }
    /**
     * 构建filterChain
     * @return
     */
    private static FilterChain buildFilterChain() {
        FilterChain filterChain = new ApplicationFilterChain();
        //修改请求数据filter
        Filter modifyDataFilter = new ModifyFilter();
        //打印请求数据filter
        PrintFilter printFilter = new PrintFilter();
        filterChain.addFilter(modifyDataFilter);
        filterChain.addFilter(printFilter);
        return filterChain;
    }
}
     debug的线程栈如下图

    在这个范式里面主要是FilterChain和Filter两个类的doFilter方法实现逻辑的串联,FilterChain控制每次执行第几个Filter,而Filter执行filter逻辑,并调用FilterChain去执行下一个Filter,如果这个Filter没有调用FilterChain而是直接return了,那么链路就会从当前Filter返回回去。

5.参考文献
posted on 2021-01-28 21:06 mindSucker 阅读(108) 评论(0) 收藏 举报
                    
                
                
            
        
浙公网安备 33010602011771号