Dubbo过滤器

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链是否覆盖。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Dubbo服务过滤器可以用于在Dubbo服务调用的过程中对请求和响应进行预处理和后处理,例如权限控制、日志记录、统计信息等。在Dubbo中,可以通过配置<provider>或<consumer>标签下的<filter>元素来添加服务过滤器。具体的配置方法如下: 1. 创建一个服务过滤器类,实现org.apache.dubbo.common.extension.Activate接口,并重写filter方法。例如: ```java @Activate(group = "provider") public class MyFilter implements Filter { @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { // 在这里添加过滤器的逻辑 return invoker.invoke(invocation); } } ``` 2. 在服务提供者或服务消费者的配置文件中,添加<filter>元素来引用服务过滤器。例如: ```xml <!-- 服务提供者配置 --> <dubbo:service interface="com.example.SomeService" ref="someService"> <dubbo:method name="someMethod" timeout="5000"> <dubbo:filter ref="myFilter" /> </dubbo:method> </dubbo:service> <!-- 服务消费者配置 --> <dubbo:reference id="someService" interface="com.example.SomeService"> <dubbo:method name="someMethod" timeout="5000"> <dubbo:filter ref="myFilter" /> </dubbo:method> </dubbo:reference> ``` 注意,<filter>元素必须放在<method>元素内部,以便对每个方法都应用过滤器。如果想要对所有方法都应用过滤器,则可以将<filter>元素放在<service>或<reference>元素内部。另外,如果服务过滤器需要传递参数,则可以通过<parameter>元素来配置。例如: ```xml <dubbo:filter ref="myFilter"> <dubbo:parameter key="param1" value="value1" /> <dubbo:parameter key="param2" value="value2" /> </dubbo:filter> ``` 在服务过滤器中可以通过调用invocation.getAttachment(key)方法来获取这些参数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值