使用 Filter 过滤器动态拦截请求(request)或响应(response)
使用 Filter 过滤器动态拦截请求(request)或响应(response)以转换或使用请求或响应中包含的信息。
Filter 过滤器动态拦截请求(request)或响应(response)以转换或使用请求或响应中包含的信息。过滤器本身通常不会创建响应,而是提供可以“附加”到任何一次 RPC 请求的通用函数。Dubbo Filter 是可插拔的,我们可以在一次 RPC 请求中插入任意类型的、任意多个 Filter。
Filter 工作原理如下图所示:
可以通过 Filter 实现的一些典型能力如下:
- 记录请求参数、响应结果等到日志文件
- 为 RPC 请求添加认证或校验逻辑
- 在发送或执行请求之前,格式化请求体或 header 参数
- 压缩响应结果
- 对请求数据进行埋点,统计调用耗时、成功、失败次数等
- 监测并发执行的请求数量,实现限流降级能力
使用方式
如上图所示,Dubbo 代理会自动加载 Filter 实现并将它们组装到调用链路。Filter 是一个标准的 SPI 定义,框架按照一定的激活规则自动加载 Filter 实现。
@SPI(scope = ExtensionScope.MODULE)
public interface Filter extends BaseFilter {}
Filter 的默认激活状态可在定义中通过 @Activate
注解设置,如以下定义表示该 Filter 在提供者端执行 RPC 请求时自动开启(在消费端不开启)。@Activate
支持多种条件控制,包括 classpath 下有某个类的定义时开启,URL 中有哪个参数值时开启等,具体可参见 SPI 扩展 Activate 介绍。
@Activate(group = PROVIDER)
public class AccessLogFilter implements Filter {}
关闭自动加载
如想关闭某个 filter 加载,在不修改 Filter 定义的情况下,可通过以下几种配置关闭。
全局关闭 filter,所有 rpc 调用均不启用 filter
dubbo:
consumer:
filter: "-accesslog,-tps"
某个服务调用过程不执行 filter
@DubboReference(filter="-accesslog,-tps")
private DemoService demoService;
开启自动加载
如想开启某个 filter 加载,在不修改 Filter 定义的情况下,可通过以下几种配置开启。
全局开启 filter,所有 rpc 调用均启用 filter
dubbo:
consumer:
filter: "accesslog,tps"
某个服务调用过程执行该 filter
@DubboReference(filter="accesslog,tps")
private DemoService demoService;
内置实现
以下是 Dubbo 框架中内置的一些 Filter 实现,作为某些功能的底层实现原理,大部分情况下用户不需要关心这些 Filter 实现。这里列出来作为参考,方便用户了解如何开启某个特定功能,以及他们背后的工作原理:
具体定义
以下是关于 Filter 过滤器具体定义与实现的一些细节,对于扩展 Filter 的用户可作为参考。
Filter定义
Dubbo Filter 的定义如下:
public interface BaseFilter {
/**
* Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
*/
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
/**
* This callback listener applies to both synchronous and asynchronous calls, please put logics that need to be executed
* on return of rpc result in onResponse or onError respectively based on it is normal return or exception return.
* <p>
* There's something that needs to pay attention on legacy synchronous style filer refactor, the thing is, try to move logics
* previously defined in the 'finally block' to both onResponse and onError.
*/
interface Listener {
/**
* This method will only be called on successful remote rpc execution, that means, the service in on remote received
* the request and the result (normal or exceptional) returned successfully.
*/
void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation);
/**
* This method will be called on detection of framework exceptions, for example, TimeoutException, NetworkException
* Exception raised in Filters, etc.
*/
void onError(Throwable t, Invoker<?> invoker, Invocation invocation);
}
}
基于以上 BaseFilter 定义,Dubbo 定义了两个 SPI 接口:ClusterFilter 与 Filter。这两个 SPI 实现能实现的效果基本是一致的,之所以定义两个主要是出于性能优化考虑,建议用户关注 Filter SPI 即可,仅在有严苛性能需求的情况下(如集群 provider 提供者实例数量庞大)才关注 ClusterFilter。
@SPI(scope = ExtensionScope.MODULE)
public interface Filter extends BaseFilter {}
@SPI(scope = ExtensionScope.MODULE)
public interface ClusterFilter extends BaseFilter {}
扩展Filter
可参考 使用教程 - 自定义扩展 学习具体示例。
最后修改 September 13, 2024: Refactor website structure (#2860) (1a4b998f54b)