【dubbo源码解析】--- dubbo的过滤器链底层原理探析

本文对应源码地址:https://github.com/nieandsun/dubbo-study



1 dubbo的过滤器链集成进RPC链条的底层原理

Filter(过滤器) 在很多框架中都有使用过这个概念, 基本上的作用都是类似的, 在请求处理前或者处理后做一些通用的逻辑, 而且 Filter 可以有多个, 支持层层嵌套。

Dubbo 的 Filter 实现入口是在ProtocolFilterWrapper, 因为ProtocolFilterWrapper 是 Protocol 的包装类, 所以会在 SPI 加载Extension 的时候被自动包装进来。


这里简单提一下,其实我在《【dubbo源码解析】 — dubbo spi 机制(@SPI、@Adaptive)详解》、《【dubbo源码解析】 — dubbo spi 机制之@Activate简介》这两篇文章的开头都提到过一句话 — dubbo 要求SPI扩展点的实现类必须要有一个无参构造,除了Wrapper实现类之外

那这个Wrapper实现类是怎么回事呢???其实是这样的,以ProtocolFilterWrapper为例:

  • 首先Protocol要是dubbo的一个扩展点 —> 即Protocol接口上被@SPI注解标记
  • 其次Wrapper类要有如下的数据结构 ,
  • 那么通过SPI机制选定的最终生效的实现类会被包装到(或者set到)这个Wrapper类里 —》 也就是说你以为你获取的是你通过SPI选择的具体的实现类,其实不并不是 —> 而是一个包装了你选择的实现类的Wrapper类。

当然最后不得不提的一点是这个Wrapper类也要像其他扩展接口的实现类一样在MATE-INF/dubbo文件夹下进行指定。
在这里插入图片描述


当然 filter 要发挥作用, 必定还是要在嵌入到 RPC 的调用链条中 —> 你应该可以马上反应过来, 嵌入的办法就是包装成一个个的Invoker。

那它到底是怎么搞得呢?其实dubbo是这么玩的:
ProtocolFilterWrapper 作为包装类, 会成为其它 protocol 的修饰加强外层。 当调用 protocol 的 export 和 refer 方法, 它首先会调用ProtocolFilterWrapper 类的这两个方法。

ProtocolFilterWrapper类中暴露服务的代码如下:

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

ProtocolFilterWrapper类中引入服务的代码如下:

@Override
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);
}

可以看到, 两者原来的 invoker 对象, 都由 buildInvokerChain 做了一层包装。来看一下 filterChain 的逻辑:

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    //通过SPI获取到所有的Filter,注意这里用到的是getActivateExtension --->对应的注解为@Activate
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    if (!filters.isEmpty()) {
        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();
                }

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

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

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

上面的逻辑还是比较简单的,即:

  • (1)先获取所有的Filter,由《【dubbo源码解析】 — dubbo spi 机制之@Activate简介》这篇文章可知,Filter的顺序是按照各个Filter上的Order来指定的。
  • (2)将所有 的filter 包装进 invoker 对象中, invoke 方法直接调对应的 filter.invoke
  • (3) filter 对象首尾相联, 前一个 filter.invoke 参数, 传入后一个 filter 的 invoker对象
  • (4) 最后一个 filter.invoke 参数中, 直接传原始的 invoker 对象

2 dubbo过滤器链封装为Invoker的好处

首先在说其好处之前,肯定要先明白过滤器 (Filter)到底是干什么用的 —》 其实很简单就是 在请求处理前或者处理后做一些通用的逻辑,如打印日志、异常处理等。

理清了这些之后我们再把dubbo将过滤器链嵌入到 RPC 的调用链条中逻辑用一个简图进行整理一下(以消费端为例):
在这里插入图片描述
再用反正法说一下其好处:

  • (1)首先通过前面几篇文章应该知道,其实在dubbo内基本所有的组件都被封装成了Invoker,这样的话,各个组件之间的调用方式就变成统一的了,因此将Filter也封装成Invoker便于dubbo的整体性。
  • (2)如果不把Filter封装为Invoker,则Filter可能就得散落在其他的Invoker里,这样到底哪个Invoker里需要哪几个Filter就会变得异常难以处理。
  • (3)易于整体的扩展性。将Filter封装为Invoker后,这样无论是容错组件、负载均衡组件等都是一个个的Invoker,想要进行其他扩展的话,只需要将这些Invoker进行相应的嵌套封装,然后嵌套到RPC的链条中就好了 —> 可以说为Dubbo的扩展性提供了无限可能!!!

最后在放一张《【dubbo源码解析】— dubbo中Invoker嵌套调用底层原理》文章中给出的 dubbo的RPC调用简图,相信你会更有感触!!!
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值