美文网首页dubbo
dubbo的Filter机制

dubbo的Filter机制

作者: 北交吴志炜 | 来源:发表于2019-08-04 12:56 被阅读0次

1.dubbo调用过程

以dubbo官方demo为例,在provider端,从netty接收到消息,递交给业务线程池处理开始,到真正调用到业务方法sayHello()结束,中间经过了十几个Filter的处理。见下图


屏幕快照 2019-08-04 下午1.04.21.png

那么这些Filter是如何初始化的,调用的时候又是如何执行的呢?接下来一步一步介绍。

2.dubbo服务导出过程

dubbo在进行服务导出时主要做了如下一些工作


屏幕快照 2019-08-04 下午12.55.24.png

可以看到:第二步中核心工作就包括Filter的初始化。见下ProtocolFilterWrapper#export方法

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
    }

其中有一步是buildInvokerChain,从名字上也可以看出,这是初始化一个责任链,对应设计模式中的责任链模式。接着看这个责任链是怎么初始化的(ProtocolFilterWrapper#buildInvokerChain)

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        //利用dubbo spi得到实现了Filter接口的所有实例,形成List<Filter>
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);

        if (!filters.isEmpty()) {
            //遍历这个List<Filter>,形成一个Invoker链表
            for (int i = filters.size() - 1; i >= 0; i--) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

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

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

                    @Override
                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }
                    //执行责任链上某个节点的invoke逻辑时,同时会传入next节点信息,以支持链式执行
                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
                        Result asyncResult;
                        try {
                            asyncResult = filter.invoke(next, invocation);
                        } catch (Exception e) {
                            // onError callback
                            if (filter instanceof ListenableFilter) {
                                Filter.Listener listener = ((ListenableFilter) filter).listener();
                                if (listener != null) {
                                    listener.onError(e, invoker, invocation);
                                }
                            }
                            throw e;
                        }
                        return asyncResult;
                    }

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

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

        return new CallbackRegistrationInvoker<>(last, filters);
    }

可以看到这个Filter的责任链初始化过程
1.通过dubbo spi机制,取得所有Filter实例形成一个ArrayList<Filter>
2.遍历这个ArrayList,以next指针初始化一个Invoker的链表InvokerList
3.Invoker执行逻辑即执行Filter的invoke方法的同时,将next指针作为参数传入,以支持链式调用

整个过程结束之后,会有两个List,一个ArrayList<Filter>,一个以NEXT指针形成的InvokerList,这两个List就是dubbo Filter机制的基础。

3.Filter接口

@SPI
public interface Filter {
    /**
     * Does not need to override/implement this method.
     */
    Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;

     interface Listener {

        void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation);

        void onError(Throwable t, Invoker<?> invoker, Invocation invocation);
    }

}

Filter接口提供了一个invoke方法,另一个是Listener接口,有onResponse,onError两个方法。
这两部分对应着Filter对请求和响应的处理逻辑
请求的处理以AccessLogFilter#invoke的实现为例,可以看到,其首先进行AccessLog的处理,然后调用
invoker.invoke().这个invoker即之前Filter初始化的时候,以Next指针形成的那个InvokerList链表中的节点。这样一来,整个链表中的节点都会得到顺序执行。

@Override
    public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
        try {
            String accessLogKey = invoker.getUrl().getParameter(ACCESS_LOG_KEY);
            if (ConfigUtils.isNotEmpty(accessLogKey)) {
                AccessLogData logData = buildAccessLogData(invoker, inv);
                log(accessLogKey, logData);
            }
        } catch (Throwable t) {
            logger.warn("Exception in AccessLogFilter of service(" + invoker + " -> " + inv + ")", t);
        }
        return invoker.invoke(inv);
    }

响应的处理可以见CallbackRegistrationInvoker#invoke

asyncResult = asyncResult.whenCompleteWithContext((r, t) -> {
                for (int i = filters.size() - 1; i >= 0; i--) {
                    Filter filter = filters.get(i);
                    // onResponse callback
                    if (filter instanceof ListenableFilter) {
                        Filter.Listener listener = ((ListenableFilter) filter).listener();
                        if (listener != null) {
                            if (t == null) {
                                listener.onResponse(r, filterInvoker, invocation);
                            } else {
                                listener.onError(t, filterInvoker, invocation);
                            }
                        }
                    } else {
                        filter.onResponse(r, filterInvoker, invocation);
                    }
                }
            });

之前Filter初始化的时候,会形成两个list,next指针形成的那个链表用于对请求的处理,另一个ArrayList<Filter> 就是在此时执行,拿到结果之后,遍历这个ArrayList,执行其onResponse或者onError方法,如此一来,请求和响应应就会经过所有生效的Filter处理。

总结:dubbo的Filter机制是一种典型的责任链模式,这个链的基础即上述两个list。如果我们在自己的业务场景中,需要对请求或者响应做一些通用的处理,那么也很简单,直接基于dubbo spi( https://www.jianshu.com/p/d4d7ebc8f7bb
),自定义逻辑实现Filter接口的相应方法即可。

相关文章

  • dubbo的Filter机制

    1.dubbo调用过程 以dubbo官方demo为例,在provider端,从netty接收到消息,递交给业务线程...

  • 利用dubbo扩展打印log

    原理 利用dubbo 的spi扩展机制 实现 实现Filter接口此处需要关注下注解@Activate,其中的参数...

  • dubbo源码系列之filter的前生

    为什么说dubbo的声明式缓存不好用!!! dubbo源码系列之filter的今世 dubbo的filter类似于...

  • Dubbo provider Filter链原理

    开篇  在dubbo的使用过程中会在标签中会配置filter变量,但是filter具...

  • Dubbo Filter 原理分析

    Dubbo Version: 2.7.7 在Dubbo中Consumer, Provider的Filter都是在P...

  • Dubbo Filter详解

    Dubbo的Filter在使用的过程中是我们扩展最频繁的内容,而且Dubbo的很多特性实现也都离不开Filter的...

  • 怎么玩转Dubbo Filter

    在resources下新建META-INF/dubbo/com.alibaba.dubbo.rpc.Filter文...

  • dubbo技术内幕十三 Filter

    dubbo里面的过滤器机制能够让用户实现很好的定制扩展,就像tomcat里面的Filter的实现一样。我们看下在d...

  • Dubbo Filter

    文档整理 官方文档 http://dubbo.apache.org/zh-cn/docs/dev/impls/f...

  • 如何让dubbo自动加载自定义Filter

    Dubbo的Filter机制,是专门为服务提供方和服务消费方调用过程进行拦截设计的,每次远程方法执行,该拦截都会被...

网友评论

    本文标题:dubbo的Filter机制

    本文链接:https://www.haomeiwen.com/subject/wtzedctx.html