背景

dubbo 项目需要配置日志信息,显示请求路径、入参、返回值。本来已经用spring的AoP实现了消费者端的日志,但是提供者处不知道如何弄。后来又查到dubbo有自己的方式,通过filter 的方式配置日志(有贴子说dubbo filter 的方式和spring aop 方式冲突,我没有试过)。原生的总是最适合的,所以采用了dubbo的filter 方式。

dubbo配置filter

consumer端

首先定义filter,需要实现com.alibaba.dubbo.rpc.Filter接口:

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
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.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

/**
 * @author aliyu
 * @create 2020-01-14 14:39
 * 类描述:
 */
@Slf4j
// filter 生效的group 设置,value是什么不太清楚。因为不配置也可以就注释掉了
//@Activate(group = {Constants.CONSUMER},value = "dubboconsumerlogfilter")
@Activate
public class DubboConsumerLogFilter implements Filter {
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String name = invoker.getInterface().getName();
        Object[] args = invocation.getArguments();
        String method = invocation.getMethodName();
        String prefix = "日志:"+name+"."+method;
        log.info(prefix+" 入参=>"+ JSONArray.toJSONString(args));
        Result r = invoker.invoke(invocation);
        if(r.hasException()){
            Throwable e = r.getException();
            if(e.getClass().getName().equals("java.lang.RuntimeException")){
                log.error(prefix+" 运行时异常=>"+ JSONObject.toJSONString(r));
            }else{
                log.error(prefix+" 异常=>"+JSONObject.toJSONString(r));
            }
        }else{
            log.info(prefix+" 结果=>"+JSONObject.toJSONString(r));
        }
        return r;
    }
}

对上述filter进行配置(项目使用maven进行构建)

在目录(\src\main\resources\META-INF\dubbo\internal)下建立新建文件com.alibaba.dubbo.rpc.Filter(new file txt)

dubbo filter顺序 dubbo自定义filter_加载


注:有些教程中要新建的目录中没有internal,这个要看自己的dubbo版本,最新的版本有的,可以具体去这个地方看:

从ExtensionLoader类中可以发现,spi加载的目录可以看到,加载了三个目录

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/";

其中DUBBO_INTERNAL_DIRECTORY目录下在源码中有一份com.alibaba.dubbo.rpc.Filter文件,定义了Dubbo内部的默认过滤器,可以采用最简单的方式来处理异常:覆盖默认filter

只需要在项目里定义一个META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Filter,然后覆盖源码中的定义即可

yml中配置过滤器的名称为——dubboconsumerlogfilter(名称可以自定义,但是要和上面面的filter配置文件中=号前面内容对应)。

dubbo filter顺序 dubbo自定义filter_spring_02

出现问题

No such extension XXXFilter for filter/com.alibaba.dubbo.rpc.Filter

检查pom文件中

dubbo filter顺序 dubbo自定义filter_dubbo filter顺序_03


maven构建中需要com.alibaba.dubbo.rpc.Filter,而它的类型是.Filter

dubbo filter顺序 dubbo自定义filter_spring_04


注:所以pom文件加上“Filter” ,只加载需要的文件,多了可能报错。debug ExtensionLoader的loadResource 发现是class.forName出了问题

dubbo filter顺序 dubbo自定义filter_json_05


dubbo filter顺序 dubbo自定义filter_dubbo filter顺序_06


loadClass 点进去,在下图这行报错,所以说是前面的class.forName出了问题

dubbo filter顺序 dubbo自定义filter_加载_07


经过多次试验,发现这个是因为缓存问题。修改pom文件yml文件后,如果出现问题,最好clean 然后install 一下。

其他

dubbo 隐式传参用拦截器的,dubbo日志用 的话。filter会调用清空的方法使得隐式传参失败。