背景
Dubbo Admin 0.5,外部Dubbo为Dubbo3.2.0,注册中心zookeeper.
问题
无法显示外部dubbo元数据
解决方案
依照官方文档所说增加/dubbo/config/dubbo/dubbo.properties文件并设置内容。
设置方式有以下几种:
Dubbo Admin控制台
打开Dubbo Admin控制台,配置管理菜单项,创建配置(应用名为global,增加注册中心及元数据中心配置)
代码操作
在Dubbo Admin源码dubbo-admin-server模块下,ConfigCenter类中增加以下代码,也可放在其他类中被SpringIOC容器管理即可。
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
/**
*
* 解决dubbo admin无法查看外部dubbo服务元数据信息
* @throws Exception
*/
@PostConstruct
void addConfig() throws Exception {
CuratorFramework zkClient = CuratorFrameworkFactory.builder().
connectString("127.0.0.1:2181").
retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
zkClient.start();
if (zkClient.checkExists().forPath("/dubbo/config/dubbo/dubbo.properties") == null) {
zkClient.create().creatingParentsIfNeeded().forPath("/dubbo/config/dubbo/dubbo.properties");
}
zkClient.setData().forPath("/dubbo/config/dubbo/dubbo.properties", ("dubbo.registry.address=zookeeper://127.0.0.1:2181\n" +
"dubbo.metadata-report.address=zookeeper://127.0.0.1:2181").getBytes());
}
使用ZookeeperInspector
下载地址:
https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip 解压后,在build目录下找到jar包并运行。
连接后,可操作节点
源码解读
为什么必须在/dubbo/config/dubbo/dubbo.properties增加注册中心与元数据中心地址?
源码如下:该类为ConfigCenter类, getDynamicConfiguration()方法中会判断是否设置了配置中心地址。若未设置,直接使用注册地址作为配置中心地址。若设置了配置中心地址,读取/dubbo/config/dubbo/dubbo.properties内容,获取其中注册中心与元数据中心地址值并设置到本类的注册中心与元数据中心。
getServiceMapping(ServiceDiscovery serviceDiscovery, InstanceRegistryCache instanceRegistryCache)方法与元数据服务改变有变,当元数据中心为空时,不会监听元数据中心。
所以,当未设置/dubbo/config/dubbo/dubbo.properties值时,不会监控元数据中心值导致Dubbo Admin中显示无法加载元数据。
/*
* generate dynamic configuration client
*/
@Bean("governanceConfiguration")
GovernanceConfiguration getDynamicConfiguration() {
GovernanceConfiguration dynamicConfiguration = null;
if (StringUtils.isNotEmpty(configCenter)) {
// 设置配置中心url
configCenterUrl = formUrl(configCenter, configCenterGroup, configCenterGroupNameSpace, username, password);
logger.info("Admin using config center: " + configCenterUrl);
// GovernanceConfigurationd的实现
dynamicConfiguration = ExtensionLoader.getExtensionLoader(GovernanceConfiguration.class).getDefaultExtension();
dynamicConfiguration.setUrl(configCenterUrl);
dynamicConfiguration.init();
// 获取/dubbo/config/dubbo/dubbo.properties内容
String config = dynamicConfiguration.getConfig(Constants.DUBBO_PROPERTY);
// 不为空设置注册中心及元数据中心地址
if (StringUtils.isNotEmpty(config)) {
Arrays.stream(config.split("\n")).forEach(s -> {
if (s.startsWith(Constants.REGISTRY_ADDRESS)) {
String registryAddress = removerConfigKey(s);
registryUrl = formUrl(registryAddress, registryGroup, registryNameSpace, username, password);
} else if (s.startsWith(Constants.METADATA_ADDRESS)) {
metadataUrl = formUrl(removerConfigKey(s), metadataGroup, metadataGroupNameSpace, username, password);
}
logger.info("Registry address found from config center: " + registryUrl);
//logger.info("Metadata address found from config center: " + registryUrl);
logger.info("Metadata address found from config center: " + metadataUrl);
});
}
}
// 没有配置 配置中心地址,将注册中心地址作为配置中心
if (dynamicConfiguration == null) {
if (StringUtils.isNotEmpty(registryAddress)) {
registryUrl = formUrl(registryAddress, registryGroup, registryNameSpace, username, password);
dynamicConfiguration = ExtensionLoader.getExtensionLoader(GovernanceConfiguration.class).getDefaultExtension();
dynamicConfiguration.setUrl(registryUrl);
dynamicConfiguration.init();
logger.warn("you are using dubbo.registry.address, which is not recommend, please refer to: https://github.com/apache/dubbo-admin/wiki/Dubbo-Admin-configuration");
} else {
throw new ConfigurationException("Either config center or registry address is needed, please refer to https://github.com/apache/dubbo-admin/wiki/Dubbo-Admin-configuration");
//throw exception
}
}
return dynamicConfiguration;
}
/**
*
* 与元数据中心监控服务变化有关
* @param serviceDiscovery
* @param instanceRegistryCache
* @return
*/
@Bean
@DependsOn("metaDataCollector")
ServiceMapping getServiceMapping(ServiceDiscovery serviceDiscovery, InstanceRegistryCache instanceRegistryCache) {
ServiceMapping serviceMapping = new NoOpServiceMapping();
if (metadataUrl == null) {
return serviceMapping;
}
MappingListener mappingListener = new AdminMappingListener(serviceDiscovery, instanceRegistryCache);
serviceMapping = ExtensionLoader.getExtensionLoader(ServiceMapping.class).getExtension(metadataUrl.getProtocol());
serviceMapping.addMappingListener(mappingListener);
serviceMapping.init(metadataUrl);
return serviceMapping;
}