dubbo 异常Please check registry access list (whitelist/blacklist)的分析

排查:
官方给出的配置应该没错啊。构建一个demo程序,按照上面的配置直连服务提供者,连接成功,没报错。那么问题就出在我的代码里面了
仔细检查dubbo配置文件,以及错误日志,终于发现问题:同一个服务引用我定义了两次!!!!!只有其中一个配置了直连,另一个没有配置直连,就去注册中心查找服务,注册中心没有服务自然就报错了。

解决:
删除掉重复的服务引用,问题解决

其他:
因为代码重复引起的问题我已经遇到过三次了,每次都很蛋疼,看代码看到死都看不出来问题。因为问题代码根本就不在那里。所以呢,下次如果遇到这种代码明显没问题,但是执行结果有问题的情况,可以考虑去查下是不是存在代码重复的问题。也许代码执行的是另一个地方呢。
代码重复包括:代码方法定义重复、配置重复、类加载重复、代码版本错误等等等等

出现这个问题,抛出的异常如下所示。
com.alibaba.dubbo.rpc.RpcException: Forbid consumer 192.168.1.101 access service service.DemoService from registry 127.0.0.1:2181 use dubbo version 2.8.4, Please check registry access list (whitelist/blacklist).
at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579)
at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:260)
at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:219)
at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
at com.alibaba.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
at service.Client.main(Client.java:15)

根据抛出的异常,很容易定位到抛出异常的位置。
com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579)
进入到源码579行位置处可以看到抛出该异常是因为forbidden变量被设为true导致。
if (forbidden) {
throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "Forbid consumer " + NetUtils.getLocalHost() + " access service " + getInterface().getName() + " from registry " + getUrl().getAddress() + " use dubbo version " + Version.getVersion() + “, Please check registry access list (whitelist/blacklist).”);
}
由于这是消费者一端使用服务导致,下面以最简单的一个消费者代码看看是什么原因forbidden变量被设置为true。
消费端代码如下。
public class Client {
public static void main(String[] args) throws InterruptedException {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
“classpath:dubboClient.xml”);
DemoService demoService = (DemoService) ctx.getBean(“demoService”);
String ret = demoService.sayHello(“Check white list/black list”);
System.out.println(demoService + “:” + ret);
ctx.close();
}
}
在上述代码ctx.getBean设置断点,一路跟踪可以得到如下的调用栈。
dubbo 异常Please check registry access list (whitelistblacklist)的分析
dubbo 异常Please check registry access list (whitelistblacklist)的分析

这里创建了一个监听器,如果孩子结点状态发生变化改方法会被调用。
而这个调用中toUrlsWithEmpty(url, parentPath, currentChilds)方法中,如果服务提供者列表为空,那么请求协议会被设置为empty。
private List toUrlsWithEmpty(URL consumer, String path, List providers) {
List urls = toUrlsWithoutEmpty(consumer, providers);
if (urls.isEmpty()) {
int i = path.lastIndexOf(’/’);
String category = i < 0 ? path : path.substring(i + 1);
URL empty = consumer.setProtocol(Constants.EMPTY_PROTOCOL).addParameter(Constants.CATEGORY_KEY, category);
urls.add(empty);
}
return urls;
}
随后上图中notify方法被调用。接着进入notify方法,
AbstractRegistry:notify(URL url, NotifyListener listener, List urls)会被调用。该方法中第449中调用 listener.notify(categoryList);而这个方法中会调用refreshInvoker(invokerUrls);
dubbo 异常Please check registry access list (whitelistblacklist)的分析
可以看到当协议为empty,且最终在这个方法中变量被设置为true,导致消费者一方调用方法时抛出check registry access list (whitelist/blacklist)。
而监听器的调用路径可以通过IDE查看得到。那么注册的监听器方法什么时候被触发呢?通过名字可以猜测到,对应的Zookeeper上的结点发生变化时触发。这个可通过在消费端运行时将服务端关闭,对应的Zookeeper上的注册信息删除后,触发对应的Zk结点变更事件该方法被触发,从而导致forbidden变量被设置为true,最后抛出whitelist/blacklist异常。
dubbo 异常Please check registry access list (whitelistblacklist)的分析

推荐阅读
●Java构架师之路
●计算机教程汇总
●Java面试大全
●网站推荐
●软件推荐
●点击加入QQ群874514813交流学习,或获取更多资料

相关文章: