Dubbo过滤器的使用
文章目录
如何使用?
通过实现Dubbo的Filter,重写里面的Invoke方法就可以了,在Invoke方法中写自己的要做的逻辑。
@Component
public class XXFilter implements Filter {
@Resource
private XXService xxService;
//如果在@Resource时出现注入的service为空,则加上这个
public void setXXService(BillingService billingService){
this.XXService = xxService;
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//获取要过滤的方法的参数
Object[] params = invocation.getArguments();
//有需要返回值的业务逻辑
return new RpcResult(XXX);
//做自己的逻辑
return invoker.invoke(invocation);
}
}
逻辑写完之后,我们要在Resource的MATA-INF文件的Dubbo文件下新建一个com.alibaba.dubbo.rpc.Filter文件。
里面的内容是你的过滤器的路径:
xxFilter=路径.XXFilter
Dubbo在加载过滤器的时候会查找META-INF/dubbo下的所有名字为com.alibaba.dubbo.rpc.Filter的文件并且读取文件内容,将文件内容以键值对的形式保存下来。
接下来要在DUBBO的XML文件中加上要使用该过滤器的接口或者使用@Active注解,要指定某接口只能在dubbo暴露接口的XML文件中进行。
下面是指定某个接口进行过滤:
<dubbo:service interface="该Service所在路径.XXService"
ref="xxService"
filter="xxFilter"
version="${项目名.dubbo.version}"
/>
下面是在XML中对所有Provider或者Consumer进行过滤:
<dubbo:provider filter="xxService"/>
<dubbo:consumer filter="xxService"/>
当有多个自定义的Filter的时候,如何定义其实现顺序?
//执行顺序:Dubbo自带Filter-Filter1-Filter2
<dubbo:reference filter="filter1,filter2"/>
//执行顺序:Filter1-Filter2-Dubbo自带Filter
<dubbo:reference filter="filter1,filter2,default"/>
//执行顺序:Filter1-Dubbo自带Filter-Filter2,通过'-'符号去掉名为token的过滤器
<dubbo:service filter="filter1,default,filter2,-token"/>
dubbo是如何通过用’-'符号就可以去掉名为XXX的过滤器?
//Constants.REMOVE_VALUE_PREFIX = "-"
if(! name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)){
}
下面是通过@Active注解实现:
写在自己实现过滤器的类上面。
其中:
- group:表示过滤器要作用的组
- order:多个Filter的执行顺序 (越小越早)
@Activate(group = {Constants.PROVIDER},order=-2000)
@Activate(group = {Constants.CONSUMER},order=-3000)
源码解析
整体的流程:
代码分析:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//如果是向注册中心引用服务,则不进行Filter调用链
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
//获取所有已激活的Filter(已经排好序的)
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
//构建Filter调用链
final Invoker<T> next = last;
//这里只是构造一个最简化的Invoker作为调用链的载体Invoker
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
上面的代码主要是进行构造已激活的Filter链。
//获取已激活的Filter key:dubbo.filter group:provider
public List<T> getActivateExtension(URL url, String key, String group) {
String value = url.getParameter(key);
return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
}
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<T>();
List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
//Constants.REMOVE_VALUE_PREFIX="-" 名字中不包括 ”-default“ 的,则加载
if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
//加载扩展信息
getExtensionClasses();
for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Activate activate = entry.getValue();
//group区分是在Provider端还是Consumer端生效
if (isMatchGroup(group, activate.group())) {
T ext = getExtension(name);
/**
* 三个条件判断:
*(1)用户配置的Filter列表中不包含当前的name
*(2)用户配置的Filter列表中不包含当前的 -name
*(3)如果用户的配置信息(url中体现)中有可以激活的配置key并且数据不为0,false,null,N/A,也就是说有正常的使用
* N/A:not Application
**/
if (! names.contains(name)
&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)
&& isActive(activate, url)) {
exts.add(ext);
}
}
}
//根据@Active注解上的order来进行排序
Collections.sort(exts, ActivateComparator.COMPARATOR);
}
//处理用户自定义的Filter
List<T> usrs = new ArrayList<T>();
for (int i = 0; i < names.size(); i ++) {
String name = names.get(i);
//如果不是以"-"开头或者不包含“-name”,则加载
if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
//可以通过default关键字替换Dubbo原生的Filter链,主要用来控制调用链顺序
if (Constants.DEFAULT_KEY.equals(name)) {
if (usrs.size() > 0) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
//加入用户自定义的Filter
T ext = getExtension(name);
usrs.add(ext);
}
}
}
if (usrs.size() > 0) {
exts.addAll(usrs);
}
return exts;
}
上面这段代码解释了Filter是如何被加载进来的。通过判断"-"符号来进行是否加载这个Filter,通过关键字default判断,将原生的Filter链是否覆盖。