Dubbo过滤器是dubbo提供的常见扩展机制之一,用于支持用户在dubbo的生命周期里面进行统一的拦截处理和特色定制,而不需要对上层业务代码大动干戈。
从原理和设计理念上来讲,Dubbo的过滤器是必须要能够做到上层业务无感和免配置的,否则咋进行统一拦截,咋偷偷摸摸干坏事呢。但是常见的DubboFilter相关文档和实践说明时,往往只说了半截和最初级的Filter开发知识,包括Dubbo官网的Filter教程。
官网Filter教程:https://cn.dubbo.apache.org/zh-cn/overview/tasks/extensibility/filter/
导致大家出现误解,只能在比如provider或者consumer的配置中,或者service的配置中,配置了具体的filter,才能生效。这真是个天大的误解。要是这样的话,dubbo自己的内置的一堆filter怎么串进去的?奇迹么?
这里就要提到一个注解:@Activate,官方的一个使用例子如下:
https://cn.dubbo.apache.org/zh-cn/blog/2018/07/01/%E7%AC%AC%E4%B8%80%E4%B8%AA-dubbo-filter
但是使用@Activate的时候千万要注意几个属性的用法,一不小心就不是自动激活了。
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.extension;
import org.apache.dubbo.common.URL;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Activate. This annotation is useful for automatically activate certain extensions with the given criteria,
* for examples: <code>@Activate</code> can be used to load certain <code>Filter</code> extension when there are
* multiple implementations.
* <ol>
* <li>{@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values.
* <li>{@link Activate#value()} specifies parameter key in {@link URL} criteria.
* </ol>
* SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated
* extensions with the given criteria.
*
* @see SPI
* @see URL
* @see ExtensionLoader
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
/**
* Activate the current extension when one of the groups matches. The group passed into
* {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
*
* @return group names to match
* @see ExtensionLoader#getActivateExtension(URL, String, String)
*/
String[] group() default {};
/**
* Activate the current extension when the specified keys appear in the URL's parameters.
* <p>
* For example, given <code>@Activate("cache, validation")</code>, the current extension will be return only when
* there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.
* </p>
*
* @return URL parameter keys
* @see ExtensionLoader#getActivateExtension(URL, String)
* @see ExtensionLoader#getActivateExtension(URL, String, String)
*/
String[] value() default {};
/**
* Relative ordering info, optional
* Deprecated since 2.7.0
*
* @return extension list which should be put before the current one
*/
@Deprecated
String[] before() default {};
/**
* Relative ordering info, optional
* Deprecated since 2.7.0
*
* @return extension list which should be put after the current one
*/
@Deprecated
String[] after() default {};
/**
* Absolute ordering info, optional
*
* Ascending order, smaller values will be in the front o the list.
*
* @return absolute ordering info
*/
int order() default 0;
/**
* Activate loadClass when the current extension when the specified className all match
* @return className names to all match
*/
String[] onClass() default {};
}
最后一个属性,在老版本中没有,先不用管。
两个过期的before,after也不要管。order用来排序的。group使用来进行分组匹配的,常见的分组有
org.apache.dubbo.common.constants.CommonConstants.CONSUMER
org.apache.dubbo.common.constants.CommonConstants.PROVIDER
public interface CommonConstants {
String DUBBO = "dubbo";
String TRIPLE = "tri";
String PROVIDER = "provider";
String CONSUMER = "consumer";
在Filter的进行如下注解
@Activate(group = {CONSUMER, PROVIDER})
public class CacheFilter implements Filter {
看一下dubbo代码中的是否激活的匹配条件,可以看到group要进行匹配,然后value也会进行匹配。如果不符合条件则不激活。
所以,如果你加了这个注解,还不生效,看看是不是自己画蛇添足,写了个value吧?如果不了解value的用法,不要随便写。写上就无法激活。
if (isMatchGroup(group, activateGroup)
&& !namesSet.contains(name)
&& !namesSet.contains(REMOVE_VALUE_PREFIX + name)
&& isActive(cachedActivateValues.get(name), url)) {
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
}
另外提示Filter开发过程避坑
1、确保META-INF/dubbo这两级是用创建目录的方式建立起来的,别用创建包的方式建立,不确定的话,就去文件系统上老实创建。
2、确保以上资源文件,被正确打包进了jar包中。通常需要注意maven的resource配置,确认包含了如上目录。
3、Filter的异常处理,一定要充分,自己代码写得不好报错不要紧,别把整体带崩了。