Filter 的实现原理

欢迎光临我的个人博客:https://www.jelliclecat.cn/

一. Filter原理

最近刚刚接触dubbo,瞬间被dubbo的简洁和扩展性圈粉了,用郭大爷的话来说就是又勾勾又丢丢,一想之美。代码算上测试一共短短12W行,没有像spring那么复杂的继承结构,但是对各种设计模式和架构设计理念的运用又极度的优雅。

跑题了,这里主要记录一下Filter的作用原理。Filter在很多地方都有用到,比如Servlet。Dubbo中也不例外,在一个Invoker被调用之前,可以配置多个Filter去过滤一次调用。Filter的作用可以看做一个AOP,在真正调用的前后做一些工作,并且Filter可以非常方便的层层嵌套。

    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {

        if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
            return protocol.refer(type, url);
        }
        return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
    }
    
    private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (filters.size() > 0) {
            for (int i = filters.size() - 1; i >= 0; i --) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    public Class<T> getInterface() {
                        return invoker.getInterface();
                    }

                    public URL getUrl() {
                        return invoker.getUrl();
                    }

                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }

                    public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);
                    }

                    public void destroy() {
                        invoker.destroy();
                    }

                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
        return last;
    }

这段代码可以非常清晰的看到filter是如何被一层一层组装的。

二. 自己模拟实现

image

目录结构如上,Filter和Invoker也超级简单:

public interface Filter {
  int invoke(Invoker invoker, int i);
}

public interface Invoker {
  int result(int i);
}

看看实现类:

public class InvokerImpl implements Invoker {

  @Override
  public int result(int i) {
    System.out.println("invoker impl");
    return i * 2;
  }
}

public class FilterA implements Filter{

  @Override
  public int invoke(Invoker invoker, int i) {
    try {
      System.out.println("Filter A");
      int result = invoker.result(i);
      System.out.println("after Filter A");
      return result;
    }catch (Exception e) {
      throw e;
    }
  }
}

public class FilterB implements Filter {

  @Override
  public int invoke(Invoker invoker, int i) {
    try {
      System.out.println("Filter B");
      int result = invoker.result(i);
      System.out.println("after Filter B");
      return result;
    } catch (Exception e) {
      throw e;
    }
  }
}

组装filter并测试:

public class Test {

  public static void main(String[] args) {
    Filter filter1 = new FilterA();
    Filter filter2 = new FilterB();

    List<Filter> filters = new ArrayList<>();
    filters.addAll(Arrays.asList(filter1, filter2));

    Invoker last = new InvokerImpl();

    // 注意顺序,filter2 -> filter1 -> invoker
    for(Filter filter : filters) {
      final Invoker next = last;
      last = (i) -> filter.invoke(next, i);
    }

    System.out.println(last.result(1));
  }

}

这里要注意组装的顺序,决定最后先调用那个filter。

看看最后的运行结果:

Filter B
Filter A
invoker impl
after Filter A
after Filter B
2

结合以上代码,不难看出filter的执行顺序,filter其实就是一个硬编码的栈,用户可以决定在栈的什么地方做一个操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容