最近在做项目的时候,因为要调试,所以选择了直连dubbo
按照官方文档给出的配置
配置为:
<dubbo:reference id="xxxService" interface="com.alibaba.xxx.XxxService" url="dubbo://localhost:20890" />
但是使用的时候还是报错,堆栈信息如下:
com.alibaba.dubbo.rpc.RpcException: Forbid consumer xx.xx.xx.xx access service xx.xx.xxx.xxx.xxx.xxx from registry 127.0.0.1:2181 use dubbo version 2.5.3, Please check registry access list (whitelist/blacklist). at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579) ~[dubbo-2.5.3.jar:2.5.3] at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73) ~[dubbo-2.5.3.jar:2.5.3] at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:260) ~[dubbo-2.5.3.jar:2.5.3] at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:219) ~[dubbo-2.5.3.jar:2.5.3] at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72) ~[dubbo-2.5.3.jar:2.5.3] at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52) ~[dubbo-2.5.3.jar:2.5.3] at com.alibaba.dubbo.common.bytecode.proxy2.refundOrderAllMoney(proxy2.java) ~[na:2.5.3] at .....
百思不得其解:不是都直连了么,怎么还有一个注册中心啊?
排查:
官方给出的配置应该没错啊。构建一个demo程序,按照上面的配置直连服务提供者,连接成功,没报错。那么问题就出在我的代码里面了
仔细检查dubbo配置文件,以及错误日志,终于发现问题:同一个服务引用我定义了两次!!!!!只有其中一个配置了直连,另一个没有配置直连,就去注册中心查找服务,注册中心没有服务自然就报错了。
解决:
删除掉重复的服务引用,问题解决
其他:
因为代码重复引起的问题我已经遇到过三次了,每次都很蛋疼,看代码看到死都看不出来问题。因为问题代码根本就不在那里。所以呢,下次如果遇到这种代码明显没问题,但是执行结果有问题的情况,可以考虑去查下是不是存在代码重复的问题。也许代码执行的是另一个地方呢。
代码重复包括:代码方法定义重复、配置重复、类加载重复、代码版本错误等等等等
---------------------------------------------------------------------------------------------------
(下面的这坨不用看了,本来想写扩展点的,写着写着就不知道在写啥了)
网上有一个文档叫做:《dubbo源码解析2.0.pdf》写得很详细,想了解dubbo实现的可以看看这个文档
扩展:
直连式怎么做到的呢?怎么跳过注册中心的呢?
1) 配置直连服务提供者的时候
在ReferenceConfig.createProxy方法中回去判断引用有没有指定url
if (url != null && url.length() > 0) { // 用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL
String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);
if (us != null && us.length > 0) {
for (String u : us) {
URL url = URL.valueOf(u);
if (url.getPath() == null || url.getPath().length() == 0) {
url = url.setPath(interfaceName);
}
if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
} else {
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
}
假设,我们只指定了一个url,并且这个url不是注册中心的url,那么执行这段代码后urls里面就只有一个url,为指定的服务提供者的地址,紧接着上面的代码在下面有这么一句代码
if (urls.size() == 1) {
invoker = refprotocol.refer(interfaceClass, urls.get(0));
}
此时的refprotocol.refer在代理类里面执行的时候,会根据url去匹配到对应的Protocol。
直连服务提供者的时候,这里我们配置的url是dubbo://xx.xxx.xxx.xxx:xxxx;那么他的协议时dubbo,就会找到对应的DubboProtocol类,去执行refer方法,在DubboProtocol方法中他就直接根据url创建了客户端,生产了Invoke了
2)没有配置直连服务提供者
没有配置直连服务提供者的时候,在ReferenceConfig.createProxy方法中是执行的这一段路径
else { // 通过注册中心配置拼装URL
List<URL> us = loadRegistries(false);
if (us != null && us.size() > 0) {
for (URL u : us) {
URL monitorUrl = loadMonitor(u);
if (monitorUrl != null) {
map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
}
}
if (urls == null || urls.size() == 0) {
throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
}
}
从注册中心去获取可用的服务提供者的url,获取到了之后再依次对这些服务提供者的url进行refer,创建连接,invoker