发布于 

简单过滤链的实现思路

模仿SpringMVVC的FilterChain方式,使用过滤链的思路实现功能逻辑。

概述

有点类似springMVC中的filter,多个filter形成一条过滤链,依次处理一个请求,并传给下一个filter,最后才分发到各个controller进行业务处理。

现在想实现的是这样一种功能,使用一个过滤链处理一个请求:

  1. 时间过滤器在请求开始时记录时间,结束后统计请求时间并打印;
  2. 日志过滤器在请求发送到服务器前打印请求的数据,数据从服务器返回后打印返回的数据;
  3. 其他…

思路

  1. 首先写好fiter和filterChain的接口类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface Filter {
    void init();
    void doFilter(FilterChain chain) throws TException;
    void destory();
    }

    public interface FilterChain {
    void doFilter() throws TException;
    Object getAttribute(String name);
    void setAttribute(String name, Object value);
    }
  2. 实现一个过滤链类,implemts FilterChain:

    1. 首先定义一个静态的Filter列表,在向这个列表添加filter之后,所有请求共用这个列表,被filters列表中的filter依次处理;
    2. 定义一个变量Map<String, Object>attributes = new HashMap<>(),每个请求new一个FilterChain,以此保存每个请求各自的一些参数,并将该FilterChain作为参数传递给Filter的doFilter方法,这样,Filter处理不同的请求时,就能从attributes中拿到每个请求不同的参数;
    3. 实现doFilter方法:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      protected int index = -1;
      protected Filter lastFilter;

      @Override
      public void doFilter() throws TException {
      next().doFilter(this);
      }

      public Filter next() {
      Filter filter = nextFilter();
      return filter == null ? lastFilter : filter;
      }

      protected Filter nextFilter() {
      if (++index >= filters.size())
      return null;
      else {
      Filter filter = null;
      try {
      filter = filters.get(index);
      } catch (IndexOutOfBoundsException e) {
      }
      return filter;
      }
      }
      注意这里index不是静态的,所以对于每个请求来说,它都是从第一个开始依次拿到filters列表中的Filter,并用这个Filter处理这个过滤链(通过this/fiterChain将attributes传递给每一个Filter),如果静态的filter拿完了,就拿最后一个-每个请求自己定义的-Filter,这个过滤链就算完成了。
  3. 实现共用的Filter,以计时过滤器TimeFilter为例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    public void doFilter(FilterChain chain) throws TException {
    final long startTime = System.currentTimeMillis();

    try {
    chain.doFilter();
    } finally {
    LOGGER.info("耗时:{}ms", System.currentTimeMillis() - startTime);
    }
    }

    当请求调用过滤链filterChain.doFilter()方法时,该请求线程从filters列表中拿到第一个Filter(即此时TimeFilter),记录下当前时间,然后在try中使用该filterChain继续拿下一个Filter并处理请求…一直传递下去,直到最后一个Filter(即请求自定义的Filter),在该Filter中,不再继续向下传递,而是完成实际想要完成的操作。后面的操作结束后,终于轮到时间过滤器TimeFilter中的finally块,记录整个操作的时间。

  4. 实现自定义的业务Filter和方法:

    不同的请求有不同的业务需求,因此,先实现一个具体的业务方法,并将这个方法作为参数放入filterChain中的attributes中。每个过滤链中的最后一个Filter,就负责从filter中拿到这个方法,使用这个方法完成业务逻辑,至于方法需要的参数,已经保存在attributes中了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    final StubFilterChain stubFilterChain = new StubFilterChain();
    stubFilterChain.setLastFilter(new SendMessageFilter());

    stubFilterChain.setAttribute("request", request);
    stubFilterChain.setAttribute("sendMessage", (SendMessageFilter.SendMessageAction)(chain) -> {

    RESP resp = {...};
    chain.setAttribute("response", resp);
    });

    stubFilterChain.doFilter();
    return (RESP) stubFilterChain.getAttribute("response");

    SendMessageFilter:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class SendMessageFilter implements Filter {

    public interface SendMessageAction {
    void doAction(FilterChain chain) throws TException;
    }

    @Override
    public void doFilter(FilterChain chain) throws TException {
    SendMessageAction action = (SendMessageAction) chain.getAttribute("sendMessage");
    action.doAction(chain);
    }
    ......

    可以看到,SendMessageFilter做的事情,就是从FilterChain实例的attributes中拿到实现的SendMessageAction的实例,并调用这个Action实例中的doAction完成业务逻辑。这个Action实例就是上面new并set进去的,在Action方法中,经过一系列操作,得到了结果response,并将结果放入attributes,这条过滤链处理完后,即调用完filterChain.doFilter()后,就可以通过filterChain.getAttribute(“response”)将action放进去的结果拿出来了。