dubbo filter扩展 dubbo自定义filter
转载
1 先说解决方案(2.7.3 版本)
<dubbo:consumer filter="filter1,filter2"/>
- 如果是service单独指定可如下配置,consumer端类似
2 为什么?一起来看看,filter过滤链的构造过程(2.7.3 版本)
- 执行流程是:
- org.apache.dubbo.config.ServiceConfig 类加载时jvm 实例化 final protocol
- --> private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); // 类加载时执行
- --> org.apache.dubbo.common.extension.ExtensionLoader // new 关键字实例化 jvm 执行用户自定义构造方法
- --> org.apache.dubbo.common.extension.ExtensionLoader#ExtensionLoader
- --> ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension() // 下面会 对SPI相关的文件对应的类进行加载并缓存
- --> org.apache.dubbo.common.extension.ExtensionLoader#getAdaptiveExtension
- --> org.apache.dubbo.common.extension.ExtensionLoader#createAdaptiveExtension
- --> org.apache.dubbo.common.extension.ExtensionLoader#getAdaptiveExtensionClass // 加载自适应扩展类
- --> org.apache.dubbo.common.extension.ExtensionLoader#getExtensionClasses
- --> org.apache.dubbo.common.extension.ExtensionLoader#loadExtensionClasses // load 同步执行
- --> org.apache.dubbo.common.extension.ExtensionLoader#loadExtensionClasses
- --> org.apache.dubbo.common.extension.ExtensionLoader#loadDirectory // 加载目录文件
- // 主要涉及三个目录
- private static final String SERVICES_DIRECTORY = "META-INF/services/";
- private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
- private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
- // 而默认的所有过滤器都在/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter 里面 2.7.3 默认配置如下
1 cache=org.apache.dubbo.cache.filter.CacheFilter
2 validation=org.apache.dubbo.validation.filter.ValidationFilter
3 echo=org.apache.dubbo.rpc.filter.EchoFilter^M
4 generic=org.apache.dubbo.rpc.filter.GenericFilter^M
5 genericimpl=org.apache.dubbo.rpc.filter.GenericImplFilter^M
6 token=org.apache.dubbo.rpc.filter.TokenFilter^M
7 accesslog=org.apache.dubbo.rpc.filter.AccessLogFilter^M
8 activelimit=org.apache.dubbo.rpc.filter.ActiveLimitFilter^M
9 classloader=org.apache.dubbo.rpc.filter.ClassLoaderFilter^M
10 context=org.apache.dubbo.rpc.filter.ContextFilter^M
11 consumercontext=org.apache.dubbo.rpc.filter.ConsumerContextFilter^M
12 exception=org.apache.dubbo.rpc.filter.ExceptionFilter^M
13 executelimit=org.apache.dubbo.rpc.filter.ExecuteLimitFilter^M
14 deprecated=org.apache.dubbo.rpc.filter.DeprecatedFilter^M
15 compatible=org.apache.dubbo.rpc.filter.CompatibleFilter^M
16 timeout=org.apache.dubbo.rpc.filter.TimeoutFilter
17 trace=org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter
18 future=org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter
19 monitor=org.apache.dubbo.monitor.support.MonitorFilter
- --> org.apache.dubbo.common.extension.ExtensionLoader#loadDirectory
- --> org.apache.dubbo.common.extension.ExtensionLoader#loadResource
- --> org.apache.dubbo.common.extension.ExtensionLoader#loadClass
- --> org.apache.dubbo.common.extension.ExtensionLoader#cacheAdaptiveClass // 该方法缓存所有 org.apache.dubbo.common.extension.Adaptive 注解的类,包含你自定的类。
- // 小结: 上面完成了所有SPI类型相关的缓存。下面就是服务暴露或者引用时,如何抉择Filter 去留的流程了。
- // 决定一个filter能否生效 org.apache.dubbo.common.extension.Activate#value 默认为空,需要一个抓手:org.apache.dubbo.common.extension.ExtensionLoader#isActive 该方法校验 value 为空的话就会默认生效;否则去url中匹配该value(url中的key),如果没有或者key对应的value为空则不能生效该filter。
private boolean isActive(String[] keys, URL url) {
if (keys.length == 0) {
return true;
}
for (String key : keys) {
for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
if ((k.equals(key) || k.endsWith("." + key))
&& ConfigUtils.isNotEmpty(v)) {
return true;
}
}
}
return false;
}
- // Filter总的选择流程:先加载默认Activate和自定义的,但排除xml或者注解中指定的。一般在org/apache/dubbo/dubbo/2.7.3/dubbo-2.7.3.jar!/META-INF/dubbo/internal包下定义好的。
- 再加载xml中指定的filters; 此处一定要注意,如果优选在的加载自己定义的filter必须给filter Activate注解指定value值如下:
- @Activate(group = {CONSUMER, PROVIDER}, order = 100, value = "commonxxFilter"),然后在配置文件或者xml中自行指定该Filter的Id ;;的确有点别扭👀☠️
- // 使用举例:
- 如果注解中指定了value,则需要在url中出现该key并且指定value时才会被加到过滤链中。但是如果xml中指定,就会忽略此value值
3 最后总结:
- 1 全局指定直接使用 就可以了,同时也可以对具体的service,reference进行覆盖;
- 2 其他SPI接口可以做类似的配置;
- 3 filter能否生效主要看org.apache.dubbo.common.extension.Activate 注解的value group等 具体匹配
- 4 由此可以对不同的环境进行拦截,如果结合路由或者loadbalance SPI 也可以做业务上的自定义调用链路。
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。