Dubbo过滤器概述

Dubbo中的过滤器和Web应用中的过滤器的概念是一样的,提供了在服务调用前后插入自定义逻辑的途径。过滤器是整个Dubbo框架中非常重要的组成部分,Dubbo中很多功能都是基于过滤器扩展而来的。过滤器提供了服务提供者和消费者调用过程的拦截,即每次都执行RPC调用的时候,对应的过滤器都会生效。虽然过滤器的功能强大,但由于每次调用时都会执行,因此在使用的时候需要注意它对性能的影响。

过滤器的使用
  • 一种方式是使用@Active注解默认启用;
  • 一种方式是在配置文件中配置;
<!-- 消费方调用过程拦截 -->
<dubbo:reference filter="xxx, yyy" />

<!-- 消费方调用过程默认拦截器,将拦截所有reference -->
<dubbo:consumer filter="xxx, yyy" />

<!-- 服务提供方调用过程拦截 -->
<dubbo:service filter="xxx, yyy" />

<!-- 服务提供方调用过程默认拦截器,将拦截所有service -->
<dubbo:provider filter="xxx, yyy" />

配置上的“潜规则”:

  1. 过滤器顺序:
  • 用户自定义的过滤器的顺序默认会在框架内置过滤器之后,可以使用filter="xxx, default"这种配置方式让自定义的过滤器顺序靠前。
  • 我们在配置filter="xxx, yyy"时,写在前面的xxx会比yyy的顺序要靠前。
  1. 剔除过滤器。对于一些默认的过滤器或自动激活的过滤器,有些方法不想使用这些过滤器,可以使用"-"加过滤器名称来过滤,如filter="-xxFilter"会让xxFilter不生效。如果不想使用所有默认启用的过滤器,则可以配置filter="-default"来进行剔除。
  2. 过滤器的叠加。如果服务提供者、消费者端都配置了过滤器,则两边的过滤器不会相互覆盖,而是互相叠加,都会生效。如果需要覆盖,则可以在消费方使用"-"的方式剔除对应的过滤器。
过滤器的总体结构

dubbo 接口 过滤器 dubbo过滤器原理_过滤器

所有的内置过滤器中除了CompatibleFilter特别突出,只继承了Filter接口,既不会被默认激活,其他的内置过滤器都使用了Activate注解,即默认被激活。Filter接口上有@SPI注解,说明过滤器是一个扩展点,用户可以基于这个扩展点接口实现自己的过滤器。

所有的过滤器会被分为消费者和服务提供者两种类型,消费者类型的过滤器只会在服务引用时被加入Inoker,服务提供者类型的过滤器只会在服务暴露的时候被加入对应的Invoker。MonitorFilter比较特殊,它会同时在暴露和引用被加入Invoker。

过滤器名

作用

使用方

AccessLogFilter

打印每一次请求的访问日志。如果需要访问的日志只出现在指定的appender中,则可以在log的配置文件中配置additivity

服务提供者

ActiveLimitFilter

用于限制消费者端对服务的最大并行调用数

消费者

ExecuteLimitFilter

同上,用于限制服务端的最大并行调用数」服务提供者

ClassLoaderFilter

用于切换不同线程的类加载器,服务调用完成后会还原回去

服务提供者

CompatibleFilter

用户使返回值与调用程序的对象版本兼容,默认不启用。如果启用,则会把JSON或fastjson类型的返回值转换为Map类型;如果返回类型和本地接口中定义的不同,则会做POJO的转换

-

ConsumerContextFilter

为消费者把一些上下文信息设置到当前线程的RpcContext对象中,包括invocation、localhost、remote host等

消费者

ContextFilter

同上,但是为服务提供者服务

服务提供者

DeprecatedFilter

如果调用的方法被标记位已弃用,那么DeprecatedFilter将记录一个错误消息

消费者

EchoFilter

用于echo测试

服务提供者

ExceptionFilter

用于统一的异常处理,防止出现序列化失败

服务提供者

GenericFilter

用于服务提供者端,实现泛化调用,实现序列化的检查和处理

服务提供者

GenericImplFilter

同上,但用于消费者端

消费者

TimeoutFilter

如果某些服务调用超时,则自动记录告警日志

服务提供者

TokenFilter

服务提供者下令发牌给消费者,通常用于防止消费者绕过注册中心直接调用服务提供者

服务提供者

TpsLimitFilter

用于服务端的限流,注意与ExecuteLimitFilter

消费者

FutureFilter

在发起invoke或得到返回值、出现异常的时候触发回调事件

消费者

TraceFilter

Trace指令的使用

服务提供者

MonitorFilter

监控并统计所有的接口的调用情况,如成功、失败、耗时。后续DubboMonitor会定时把该过滤器收集的数据发送到Dubbo-Monitor服务上

服务提供者+消费者

每个过滤器的使用方不一样,有的是服务提供者使用,有的是消费者使用。Dubbo是如何保证服务提供者不会使用消费者的过滤器的呢?答案就在@Activate注解上,该注解可以设置过滤器激活的条件和顺序,如@Activate(group = Constants.PROVIDER, order = -110000)表示在服务提供端扩展点实现才有效,并且过滤器的顺序是 -110000.

过滤器初始化的实现原理

服务的暴露与引用会使用Protocol层,而ProtocolFilterWrapper包装类则实现了过滤器链的组装。在服务的暴露与引用过程中,会使用ProtocolFilterWrapper#buildInvokerChain方法组装整个过滤器链:

dubbo 接口 过滤器 dubbo过滤器原理_Dubbo_02

buildInvokerChain方法构造调用链的步骤:

  1. 获取并遍历所有过滤器。通过ExtensionLoader#getActivateExtension方法获取所有的过滤器并遍历。
  2. 使用装饰器模式,增强原有Invoker,组装过滤器链。使用装饰器模式,像俄罗斯套娃一样,把过滤器一个又一个套到Invoker上。

dubbo 接口 过滤器 dubbo过滤器原理_服务提供者_03

为什么要倒排遍历呢?

因为是通过从里到外构造匿名类的方式构造Invoekr的,所以只有倒排,最外层的Invoker才能是第一个过滤器。