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

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

出现这个问题,抛出的异常如下所示。

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设置断点,一路跟踪可以得到如下的调用栈。

调用栈

这里写图片描述
这里创建了一个监听器,如果孩子结点状态发生变化改方法会被调用。
而这个调用中toUrlsWithEmpty(url, parentPath, currentChilds)方法中,如果服务提供者列表为空,那么请求协议会被设置为empty。

    private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
        List<URL> 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);

这里写图片描述

可以看到当协议为empty,且最终在这个方法中变量被设置为true,导致消费者一方调用方法时抛出check registry access list (whitelist/blacklist)。

而监听器的调用路径可以通过IDE查看得到。那么注册的监听器方法什么时候被触发呢?通过名字可以猜测到,对应的Zookeeper上的结点发生变化时触发。这个可通过在消费端运行时将服务端关闭,对应的Zookeeper上的注册信息删除后,触发对应的Zk结点变更事件该方法被触发,从而导致forbidden变量被设置为true,最后抛出whitelist/blacklist异常。

这里写图片描述

你可能感兴趣的:(dubbo)