现象
在用dubbo回声测试机制做回声测试时返回异常信息"NumberFormatException:null"
cause: org.apache.dubbo.remoting.RemotingException: java.util.concurrent.CompletionException: java.lang.NumberFormatException: null java.util.concurrent.CompletionException: java.lang.NumberFormatException: null at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:292)
分析
异常是RemotingException说明不是消费者端抛的,大概率是提供者端抛的异常。因为在测试环境必现,所以直接用debug调试跟踪了一下代码,发现抛异常的地方是在org.apache.dubbo.monitor.support.MonitorFilter.MonitorListener#onResponse位置
断点位置invocation.getAttachment(MONITOR_FILTER_START_TIME)返回值是null。
再跟一下源码发现org.apache.dubbo.monitor.support.MonitorFilter#invoke里对MONITOR_FILTER_START_TIME赋值
停下来思考下,回声测试这个地方为啥没有设置值?我们知道回声测试是利用EchoFilter来实现,EchoFilter发现请求对方法名是"$echo"就直接返回接口并且终止Dubbo的Invoker链(即后面的Filter以及真正的服务方法都不会执行到)。很巧,EchoFilter优先级比MonitorFilter优先级高,也就是回声测试MonitorFilter没有执行到,也就没用给invocation设置"MONITOR_FILTER_START_TIME"。 但是在invoke完成后会再次遍历所有的Filter,如果是ListenableFilter则执行org.apache.dubbo.rpc.Filter.Listener#onResponse。MonitorFilter也继承了ListenableFilter从而中招。
方案
最好是dubbo源码修改一下。再不修改源码的情况下,可用以下两种方式规避:
1 去除monitor参数
笔者查看源码发现只有URL中带了monitor参数才会执行到抛异常的地方,所以只要我们关闭monitor特性即可。
2 重写MonitorFilter
- 自定义CustomMonitorFilter继承MonitorFilter,在抛异常的位置加一个判断
- 配置Dubbo SPI加载customMonitor=xx.xx.xx.CustomMonitorFilter
- 在dubbo:provider的配置上加上"filter=-monitor,customMonitor"(提供者去除默认的MonitorFilter,加上自定义的CustomMonitorFilter)
引申思考
再思考下Dubbo这样实现的合理性,"只有被执行了Filter,它的listener才被执行" 这样是不是更合理