
什么是 dubbo 过滤器
学过servlet 或 spring mvc 的同学都知道有一个叫作过滤器的东西。顾名思义他就是用于过滤的。它本身不产生请求或者响应,它只是修改对某一资源的请求,或者修改某一资源的响应。
为什么需要 dubbo 过滤器
对于有些操作,我们可能每个接口都需要使用。比如打印接口调用的请求与响应信息,计算接口调用的时间。或者字符编码的转换。再或者就接口的权限判断。。。不胜枚举。对于这些通用且是大多数接口都会使用的内容。如果在第一个接口里面去实现或者调用,就太过于麻烦。这个时候就可以把它抽到一个调用接口时都会经过的地方去。这个地方就是过滤器。其实可以简单理解成接口层面的 AOP。
什么时候运行
一般情况下过滤器不只一个。比如说有一个编码转换的过滤器,一个接口调用日志的过滤器,两个同时存在。因为打印日志时是使用一个固定编码的。所以为了防止打印时不产生乱码,必须要在编码转换过滤器之后运行。这种情况下我们就需要一个顺序。这也就形成了常说的过滤器链。至于如何控制顺序,会在下文介绍。
在哪种场景下使用
主要是一些通用的操作
接口的调用日志打印
接口权限判断
编码转换
相关角色有哪些
对于 servlet 来说,一个是接口的调用方比如浏览器,爬虫。。。。,一个是提供的接口。对于dubbo 来说,一个是生产者,一个是消费者。
怎么去使用 dubbo 过滤器
- 继承com.alibaba.dubbo.rpc.Filter并且实现它的 invoke 方法。
package com.fshows.fsframework.extend.dubbo.filter;import com.alibaba.dubbo.rpc.Filter;import com.alibaba.dubbo.rpc.Invocation;import com.alibaba.dubbo.rpc.Invoker;import com.alibaba.dubbo.rpc.Result;import com.alibaba.dubbo.rpc.RpcException;import com.fshows.fsframework.core.utils.SystemClock;import lombok.extern.slf4j.Slf4j;/*** @author buhao* @version LogFilter.java, v 0.1 2018-09-18 20:40 buhao*/@Slf4jpublic class LogFilter implements Filter {@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {// 获得 RPC 方法名String methodName = invoker.getUrl().getPath();// 获得开始时间long startTime = SystemClock.millisClock().now();// 打印调用前日志// 获得参数Object[] arguments = invocation.getArguments();log.info("RPC 接口开始 methodName = {}, agruments = {}", methodName, arguments);// 调用接口Result result = invoker.invoke(invocation);// 打印调用后日志// 抛出的异常Throwable exception = result.getException();// 返回结果Object value = result.getValue();// 打印结束日志if (exception != null) {log.info("RPC 接口异常结束 methodName = {}, exception = {}, time = {}ms ", methodName, exception, SystemClock.millisClock().now() - startTime);} else {log.info("RPC 接口结束 methodName = {}, result ={}, time = {}ms ", methodName, value, SystemClock.millisClock().now() - startTime);}return result;}}
配置过滤器
在 resources 目录下创建一个名为 META-INF 的目录
在 META-INF 的目录下创建一个名为 dubbo 目录
在 dubbo 目录下创建一个名为 com.alibaba.dubbo.rpc.Filter 的文本文件
在文本中配置自定义的过滤器
文件目录如下:

com.alibaba.dubbo.rpc.Filter文件内容如下:
内容: 过滤器名称=过滤器全限定名
logFilter=com.fshows.fsframework.extend.dubbo.filter.LogFilter
至于为什么要这些写?因为这里使用的是 SPI 机制。类似于 spring 的 IOC,详情可以看理解的Java中SPI机制
- 指定过滤器的拦截对象与过滤器顺序
通过@Adaptive去指定
- Adaptive 源码
@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})public @interface Activate {/*** Group过滤条件。* <br />* 包含{@link ExtensionLoader#getActivateExtension}的group参数给的值,则返回扩展。* <br />* 如没有Group设置,则不过滤。*/String[] group() default {};/*** Key过滤条件。包含{@link ExtensionLoader#getActivateExtension}的URL的参数Key中有,则返回扩展。* <p/>* 示例:<br/>* 注解的值 <code>@Activate("cache,validatioin")</code>,* 则{@link ExtensionLoader#getActivateExtension}的URL的参数有<code>cache</code>Key,或是<code>validatioin</code>则返回扩展。* <br/>* 如没有设置,则不过滤。*/String[] value() default {};/*** 排序信息,可以不提供。*/String[] before() default {};/*** 排序信息,可以不提供。*/String[] after() default {};/*** 排序信息,可以不提供。*/int order() default 0;}
用法
指定过滤器使用方
group
例子 - 指定生产者使用
@Activate(group = {Constants.PROVIDER})
指定特定参数
value
例子 - 指定参数 accessToken=123的参数使用
@Activate("accessToken=123")
例子 - 指定有 accessToken参数使用
@Activate("accessToken")
指定过滤器顺序
order
例子 - 数字越小优先级越高
@Activate(order = -1)
