diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java index 6e31d7fe6f..ce0acbdc28 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java @@ -172,11 +172,11 @@ public interface DynamicConfiguration extends Configuration, AutoCloseable { * @param key * @param group * @param content - * @param stat + * @param ticket * @return * @throws UnsupportedOperationException */ - default boolean publishConfigCas(String key, String group, String content, Object stat) throws UnsupportedOperationException { + default boolean publishConfigCas(String key, String group, String content, Object ticket) throws UnsupportedOperationException { return false; } @@ -266,13 +266,4 @@ public interface DynamicConfiguration extends Configuration, AutoCloseable { default boolean removeConfig(String key, String group) { return true; } - - /** - * support cas or not. - * - * @return - */ - default boolean hasSupportCas() { - return false; - } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java index c33a15d9b9..061385412f 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/wrapper/CompositeDynamicConfiguration.java @@ -40,6 +40,11 @@ public class CompositeDynamicConfiguration implements DynamicConfiguration { } } + public Set getInnerConfigurations() { + return configurations; + } + + @Override public void addListener(String key, String group, ConfigurationListener listener) { iterateListenerOperation(configuration -> configuration.addListener(key, group, listener)); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java index c6cb112bc9..14db8b2be0 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java @@ -199,8 +199,6 @@ public interface CommonConstants { String METADATA_KEY = "metadata-type"; - String MAPPING_KEY = "mapping-type"; - String CONFIG_MAPPING_TYPE = "config"; String METADATA_MAPPING_TYPE = "metadata"; diff --git a/dubbo-compatible/pom.xml b/dubbo-compatible/pom.xml index 9d6f462ecd..eb1a2b5e92 100644 --- a/dubbo-compatible/pom.xml +++ b/dubbo-compatible/pom.xml @@ -28,11 +28,6 @@ ${project.artifactId} The compatible module of dubbo project - - org.apache.dubbo - dubbo-filter-cache - ${project.parent.version} - org.apache.dubbo dubbo-config-spring diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index a18416b93d..a72caaca66 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java @@ -34,9 +34,8 @@ import org.apache.dubbo.config.bootstrap.DubboBootstrap; import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.config.utils.ConfigValidationUtils; -import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.metadata.ServiceNameMapping; -import org.apache.dubbo.metadata.ServiceNameMappingHandler; +import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.registry.client.metadata.MetadataUtils; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; @@ -71,7 +70,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND; import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE; -import static org.apache.dubbo.common.constants.CommonConstants.MAPPING_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY; import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY; @@ -219,9 +217,8 @@ public class ServiceConfig extends ServiceConfigBase { public void exported() { List exportedURLs = this.getExportedUrls(); exportedURLs.forEach(url -> { - Map parameters = getApplication().getParameters(); - ServiceNameMapping serviceNameMapping = ServiceNameMapping.getExtension(parameters != null ? parameters.get(MAPPING_KEY) : null); - ServiceNameMappingHandler.map(serviceNameMapping, url); + ServiceNameMapping serviceNameMapping = ServiceNameMapping.getDefaultExtension(); + serviceNameMapping.map(url); }); } diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockServiceDiscovery.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockServiceDiscovery.java index 33f1a16aef..3044dcb179 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockServiceDiscovery.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/mock/MockServiceDiscovery.java @@ -17,38 +17,37 @@ package org.apache.dubbo.config.mock; import org.apache.dubbo.common.URL; -import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.AbstractServiceDiscovery; import org.apache.dubbo.registry.client.ServiceInstance; import java.util.HashSet; import java.util.Set; -public class MockServiceDiscovery implements ServiceDiscovery { +public class MockServiceDiscovery extends AbstractServiceDiscovery { private URL registryURL; - private ServiceInstance serviceInstance; @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { this.registryURL = registryURL; } @Override - public void destroy() throws Exception { + public void doDestroy() throws Exception { } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { + public void doRegister(ServiceInstance serviceInstance) throws RuntimeException { this.serviceInstance = serviceInstance; } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { + public void doUpdate(ServiceInstance serviceInstance) throws RuntimeException { this.serviceInstance = serviceInstance; } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { this.serviceInstance = null; } @@ -61,9 +60,4 @@ public class MockServiceDiscovery implements ServiceDiscovery { public URL getUrl() { return registryURL; } - - @Override - public ServiceInstance getLocalInstance() { - return serviceInstance; - } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml index 341a5fabca..4af3753d18 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer/dubbo-consumer.xml @@ -28,7 +28,6 @@ - diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml index 7748e0e08b..7836817905 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/consumer2/dubbo-consumer.xml @@ -28,7 +28,6 @@ - diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml index cb97cbd1e9..fca1aa5218 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/propertyconfigurer/provider/dubbo-provider.xml @@ -31,7 +31,6 @@ - diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockServiceDiscovery.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockServiceDiscovery.java index 1511b0e4ab..e77719da3b 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockServiceDiscovery.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/registry/MockServiceDiscovery.java @@ -17,39 +17,35 @@ package org.apache.dubbo.config.spring.registry; import org.apache.dubbo.common.URL; -import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.AbstractServiceDiscovery; import org.apache.dubbo.registry.client.ServiceInstance; import java.util.HashSet; import java.util.Set; -public class MockServiceDiscovery implements ServiceDiscovery { +public class MockServiceDiscovery extends AbstractServiceDiscovery { private URL registryURL; - private ServiceInstance serviceInstance; @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { this.registryURL = registryURL; } @Override - public void destroy() throws Exception { + public void doDestroy() throws Exception { } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = serviceInstance; + public void doRegister(ServiceInstance serviceInstance) throws RuntimeException { } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = serviceInstance; + public void doUpdate(ServiceInstance serviceInstance) throws RuntimeException { } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = null; + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { } @Override @@ -61,9 +57,4 @@ public class MockServiceDiscovery implements ServiceDiscovery { public URL getUrl() { return registryURL; } - - @Override - public ServiceInstance getLocalInstance() { - return serviceInstance; - } } diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosConfigServiceWrapper.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosConfigServiceWrapper.java new file mode 100644 index 0000000000..4ac0a789ca --- /dev/null +++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosConfigServiceWrapper.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.configcenter.support.nacos; + +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; + +import static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR; +import static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR; + +public class NacosConfigServiceWrapper { + + private static final String INNERCLASS_SYMBOL = "$"; + + private static final String INNERCLASS_COMPATIBLE_SYMBOL = "___"; + + private static final long DEFAULT_TIMEOUT = 3000L; + + private ConfigService configService; + + public NacosConfigServiceWrapper(ConfigService configService) { + this.configService = configService; + } + + public ConfigService getConfigService() { + return configService; + } + + public void addListener(String dataId, String group, Listener listener) throws NacosException { + configService.addListener(handleInnerSymbol(dataId), handleInnerSymbol(group), listener); + } + + public String getConfig(String dataId, String group) throws NacosException { + return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), DEFAULT_TIMEOUT); + } + + public String getConfig(String dataId, String group, long timeout) throws NacosException { + return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), timeout); + } + + public boolean publishConfig(String dataId, String group, String content) throws NacosException { + return configService.publishConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), content); + } + + public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException { + return configService.publishConfigCas(handleInnerSymbol(dataId), handleInnerSymbol(group), content, casMd5); + } + + public boolean removeConfig(String dataId, String group) throws NacosException { + return configService.removeConfig(handleInnerSymbol(dataId), handleInnerSymbol(group)); + } + + /** + * see {@link com.alibaba.nacos.client.config.utils.ParamUtils#isValid(java.lang.String)} + */ + private String handleInnerSymbol(String data) { + if (data == null) { + return null; + } + return data.replace(INNERCLASS_SYMBOL, INNERCLASS_COMPATIBLE_SYMBOL).replace(SLASH_CHAR, HYPHEN_CHAR); + } +} diff --git a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java index ac46c7e287..53c8845077 100644 --- a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java @@ -37,27 +37,27 @@ import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.AbstractSharedListener; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.client.config.http.HttpAgent; +import com.alibaba.nacos.common.http.HttpRestResult; import java.lang.reflect.Field; +import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; import java.util.stream.Stream; -import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; +import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE; import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; -import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME; +import static java.util.Collections.emptyMap; import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; import static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of; import static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR; import static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR; -import static org.apache.dubbo.common.utils.StringUtils.isBlank; /** * The nacos implementation of {@link DynamicConfiguration} @@ -77,23 +77,23 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { /** * The nacos configService */ - private final ConfigService configService; + private final NacosConfigServiceWrapper configService; private HttpAgent httpAgent; /** * The map store the key to {@link NacosConfigListener} mapping */ - private final ConcurrentMap watchListenerMap; + private final Map watchListenerMap; NacosDynamicConfiguration(URL url) { this.nacosProperties = buildNacosProperties(url); this.configService = buildConfigService(url); - this.httpAgent = getHttpAgent(configService); + this.httpAgent = getHttpAgent(configService.getConfigService()); watchListenerMap = new ConcurrentHashMap<>(); } - private ConfigService buildConfigService(URL url) { + private NacosConfigServiceWrapper buildConfigService(URL url) { ConfigService configService = null; try { configService = NacosFactory.createConfigService(nacosProperties); @@ -103,7 +103,7 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { } throw new IllegalStateException(e); } - return configService; + return new NacosConfigServiceWrapper(configService); } private HttpAgent getHttpAgent(ConfigService configService) { @@ -141,14 +141,10 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { } private static void setProperties(URL url, Properties properties) { - putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME); - // Get the parameters from constants Map parameters = url.getParameters(of(PropertyKeyConst.class)); // Put all parameters properties.putAll(parameters); - - putPropertyIfAbsent(url, properties, NAMING_LOAD_CACHE_AT_START, "true"); } private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) { @@ -182,13 +178,12 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { @Override public void addListener(String key, String group, ConfigurationListener listener) { - String resolvedGroup = resolveGroup(group); String listenerKey = buildListenerKey(key, group); NacosConfigListener nacosConfigListener = - watchListenerMap.computeIfAbsent(listenerKey, k -> createTargetListener(key, resolvedGroup)); + watchListenerMap.computeIfAbsent(listenerKey, k -> createTargetListener(key, group)); nacosConfigListener.addListener(listener); try { - configService.addListener(key, resolvedGroup, nacosConfigListener); + configService.addListener(key, group, nacosConfigListener); } catch (NacosException e) { logger.error(e.getMessage()); } @@ -205,13 +200,12 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { @Override public String getConfig(String key, String group, long timeout) throws IllegalStateException { - String resolvedGroup = resolveGroup(group); try { long nacosTimeout = timeout < 0 ? getDefaultTimeout() : timeout; - if (StringUtils.isEmpty(resolvedGroup)) { - resolvedGroup = DEFAULT_GROUP; + if (StringUtils.isEmpty(group)) { + group = DEFAULT_GROUP; } - return configService.getConfig(key, resolvedGroup, nacosTimeout); + return configService.getConfig(key, group, nacosTimeout); } catch (NacosException e) { logger.error(e.getMessage()); } @@ -241,9 +235,8 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { @Override public boolean publishConfig(String key, String group, String content) { boolean published = false; - String resolvedGroup = resolveGroup(group); try { - published = configService.publishConfig(key, resolvedGroup, content); + published = configService.publishConfig(key, group, content); } catch (NacosException e) { logger.error(e.getErrMsg(), e); } @@ -251,18 +244,16 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { } @Override - public boolean publishConfigCas(String key, String group, String content, Object stat) { - boolean published = false; - String resolvedGroup = resolveGroup(group); + public boolean publishConfigCas(String key, String group, String content, Object ticket) { try { - if (!(null != stat && stat instanceof String)) { - throw new IllegalArgumentException("nacos publishConfigCas requires stat of string type"); + if (!(ticket instanceof String)) { + throw new IllegalArgumentException("nacos publishConfigCas requires string type ticket"); } - published = configService.publishConfigCas(key, resolvedGroup, content, (String) stat); + return configService.publishConfigCas(key, group, content, (String) ticket); } catch (NacosException e) { - logger.error(e.getErrMsg(), e); + logger.warn("nacos publishConfigCas failed.", e); + return false; } - return published; } @Override @@ -280,9 +271,29 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { public SortedSet getConfigKeys(String group) { // TODO use Nacos Client API to replace HTTP Open API SortedSet keys = new TreeSet<>(); + try { + + Map paramsValues = new HashMap<>(); + paramsValues.put("search", "accurate"); + paramsValues.put("dataId", ""); + paramsValues.put("group", group.replace(SLASH_CHAR, HYPHEN_CHAR)); + paramsValues.put("pageNo", "1"); + paramsValues.put("pageSize", String.valueOf(Integer.MAX_VALUE)); + + String encoding = getProperty(ENCODE, "UTF-8"); + + HttpRestResult result = httpAgent.httpGet(GET_CONFIG_KEYS_PATH, emptyMap(), paramsValues, encoding, 5 * 1000); + Stream keysStream = toKeysStream(result.getData()); + keysStream.forEach(keys::add); + } catch (Exception e) { + if (logger.isErrorEnabled()) { + logger.error(e.getMessage(), e); + } + } return keys; } + @Override public boolean removeConfig(String key, String group) { boolean removed = false; @@ -361,15 +372,6 @@ public class NacosDynamicConfiguration implements DynamicConfiguration { } protected String buildListenerKey(String key, String group) { - return key + HYPHEN_CHAR + resolveGroup(group); - } - - protected String resolveGroup(String group) { - return isBlank(group) ? group : group.replace(SLASH_CHAR, HYPHEN_CHAR); - } - - @Override - public boolean hasSupportCas() { - return true; + return key + HYPHEN_CHAR + group; } } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java index 6787a8c18b..0ab06d2fb9 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java @@ -26,6 +26,8 @@ import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; +import org.apache.zookeeper.data.Stat; + import java.util.Collection; import java.util.Set; import java.util.concurrent.Executor; @@ -49,7 +51,6 @@ public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration private static final int DEFAULT_QUEUE = 10000; private static final Long THREAD_KEEP_ALIVE_TIME = 0L; - ZookeeperDynamicConfiguration(URL url, ZookeeperTransporter zookeeperTransporter) { super(url); this.url = url; @@ -92,10 +93,18 @@ public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration } @Override - public boolean publishConfigCas(String key, String group, String content, Object stat) { - String pathKey = buildPathKey(group, key); - zkClient.createOrUpdate(pathKey, content, false, stat); - return true; + public boolean publishConfigCas(String key, String group, String content, Object ticket) { + try { + if (ticket != null && !(ticket instanceof Stat)) { + throw new IllegalArgumentException("zookeeper publishConfigCas requires stat type ticket"); + } + String pathKey = buildPathKey(group, key); + zkClient.createOrUpdate(pathKey, content, false, ticket == null ? 0 : ((Stat) ticket).getVersion()); + return true; + } catch (Exception e) { + logger.warn("zookeeper publishConfigCas failed.", e); + return false; + } } @Override @@ -134,9 +143,4 @@ public class ZookeeperDynamicConfiguration extends TreePathDynamicConfiguration zkClient.removeDataListener(pathKey, cacheListener); } } - - @Override - public boolean hasSupportCas() { - return true; - } } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java index 85eba3837a..175eef8a73 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java @@ -42,6 +42,7 @@ import java.util.concurrent.CountDownLatch; import static java.util.Arrays.asList; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -150,11 +151,7 @@ public class ZookeeperDynamicConfigurationTest { configItem = configuration.getConfigItem(key, group); assertEquals("test", configItem.getContent()); assertTrue(configuration.publishConfigCas(key, group, "newtest", configItem.getStat())); - try { - configuration.publishConfigCas(key, group, "newtest2", configItem.getStat()); - } catch (Exception e) { - assertTrue(e.getMessage().contains("KeeperErrorCode = BadVersion")); - } + assertFalse(configuration.publishConfigCas(key, group, "newtest2", configItem.getStat())); assertEquals("newtest", configuration.getConfigItem(key, group).getContent()); } diff --git a/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.java b/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.java index 65b2ff5aab..2cab1b276c 100644 --- a/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.java +++ b/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.java @@ -47,7 +47,6 @@ public class GenericApplication { ApplicationConfig applicationConfig = new ApplicationConfig("demo-consumer"); Map parameters = new HashMap<>(); - parameters.put("mapping-type", "metadata"); applicationConfig.setParameters(parameters); MetadataReportConfig metadataReportConfig = new MetadataReportConfig(); diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml index 3bf2035854..917d10849f 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml @@ -30,10 +30,6 @@ true - - org.apache.dubbo - dubbo-metadata-report-zookeeper - org.apache.dubbo dubbo-demo-interface @@ -63,6 +59,14 @@ org.apache.dubbo dubbo-configcenter-nacos + + org.apache.dubbo + dubbo-metadata-report-zookeeper + + + org.apache.dubbo + dubbo-metadata-report-nacos + org.apache.dubbo dubbo-config-spring diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml index 481c9b42da..46bf9eb0ec 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml +++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml @@ -22,10 +22,9 @@ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> - - + diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml index eda09798a9..f9e6c5fb99 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml @@ -66,6 +66,10 @@ org.apache.dubbo dubbo-metadata-report-zookeeper + + org.apache.dubbo + dubbo-metadata-report-nacos + org.apache.dubbo dubbo-rpc-dubbo diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml index 386be3c8a8..d1596271fc 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml +++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml @@ -22,7 +22,6 @@ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> - diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 2953239a93..0e32c87059 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -283,6 +283,13 @@ compile true + + org.apache.dubbo + dubbo-metadata-report-nacos + ${project.version} + compile + true + org.apache.dubbo dubbo-metadata-report-redis @@ -427,6 +434,7 @@ org.apache.dubbo:dubbo-metadata-api org.apache.dubbo:dubbo-metadata-report-redis org.apache.dubbo:dubbo-metadata-report-zookeeper + org.apache.dubbo:dubbo-metadata-report-nacos org.apache.dubbo:dubbo-qos org.apache.dubbo:dubbo-auth org.apache.dubbo:dubbo-filter-cache diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index 47d138f6db..ae7db74781 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -233,6 +233,11 @@ dubbo-metadata-report-zookeeper ${project.version} + + org.apache.dubbo + dubbo-metadata-report-nacos + ${project.version} + org.apache.dubbo dubbo-metadata-report-redis diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java deleted file mode 100644 index 44b8000f9d..0000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dubbo.metadata; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.config.configcenter.ConfigItem; -import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.StringUtils; - -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import static java.lang.String.valueOf; -import static java.util.Arrays.asList; -import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR; -import static org.apache.dubbo.common.utils.CollectionUtils.ofSet; -import static org.apache.dubbo.rpc.model.ApplicationModel.getName; - -/** - * The {@link ServiceNameMapping} implementation based on {@link DynamicConfiguration} - */ -public class DynamicConfigurationServiceNameMapping implements ServiceNameMapping { - - private static final List IGNORED_SERVICE_INTERFACES = asList(MetadataService.class.getName()); - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private static final int PUBLISH_CONFIG_RETRY_TIMES = 6; - - @Override - public void map(URL url) { - String serviceInterface = url.getServiceInterface(); - String group = url.getGroup(); - String version = url.getVersion(); - String protocol = url.getProtocol(); - - if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) { - return; - } - - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); - - // the Dubbo Service Key as group - // the service(application) name as key - // It does matter whatever the content is, we just need a record - String key = getName(); - String content = valueOf(System.currentTimeMillis()); - - execute(() -> { - dynamicConfiguration.publishConfig(key, ServiceNameMapping.buildGroup(serviceInterface, group, version, protocol), content); - if (logger.isDebugEnabled()) { - logger.info(String.format("Dubbo service[%s] mapped to interface name[%s].", - group, serviceInterface)); - } - }); - } - - @Override - public void mapWithCas(URL url) { - String serviceInterface = url.getServiceInterface(); - if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) { - return; - } - execute(() -> { - publishConfigCas(serviceInterface, DEFAULT_MAPPING_GROUP, getName()); - }); - } - - @Override - public Set getAndListen(URL url, MappingListener mappingListener) { - String serviceInterface = url.getServiceInterface(); - String group = url.getGroup(); - String version = url.getVersion(); - String protocol = url.getProtocol(); - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); - - Set serviceNames = new LinkedHashSet<>(); - execute(() -> { - Set keys = dynamicConfiguration - .getConfigKeys(ServiceNameMapping.buildGroup(serviceInterface, group, version, protocol)); - serviceNames.addAll(keys); - }); - return Collections.unmodifiableSet(serviceNames); - } - - @Override - public Set getAndListenWithNewStore(URL url, MappingListener mappingListener) { - String serviceInterface = url.getServiceInterface(); - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); - Set serviceNames = new LinkedHashSet<>(); - execute(() -> { - String configContent = dynamicConfiguration.getConfig(serviceInterface, DEFAULT_MAPPING_GROUP); - if (null != configContent) { - String[] split = StringUtils.split(configContent, CommonConstants.COMMA_SEPARATOR_CHAR); - serviceNames.addAll(ofSet(split)); - } - }); - return Collections.unmodifiableSet(serviceNames); - } - - /** - * publish config with cas. - * - * @param key - * @param group - * @param appName - * @return - */ - private boolean publishConfigCas(String key, String group, String appName) { - int currentRetryTimes = 1; - boolean result = false; - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); - String newConfigContent = appName; - do { - ConfigItem configItem = dynamicConfiguration.getConfigItem(key, group); - String oldConfigContent = configItem.getContent(); - if (StringUtils.isNotEmpty(oldConfigContent)) { - boolean contains = StringUtils.isContains(configItem.getContent(), appName); - if (contains) { - return true; - } - newConfigContent = oldConfigContent + COMMA_SEPARATOR + appName; - } - result = dynamicConfiguration.publishConfigCas(key, group, newConfigContent, configItem.getStat()); - } while (!result && currentRetryTimes++ <= PUBLISH_CONFIG_RETRY_TIMES); - - return result; - } - - private void execute(Runnable runnable) { - try { - runnable.run(); - } catch (Throwable e) { - if (logger.isWarnEnabled()) { - logger.warn(e.getMessage(), e); - } - } - } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingChangedEvent.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingChangedEvent.java index 88476ab012..a1c40f0f91 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingChangedEvent.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MappingChangedEvent.java @@ -19,30 +19,26 @@ package org.apache.dubbo.metadata; import java.util.Set; public class MappingChangedEvent { - private String serviceKey; - private Set apps; + + private final String serviceKey; + private final Set apps; + + public MappingChangedEvent(String serviceKey, Set apps) { + this.serviceKey = serviceKey; + this.apps = apps; + } public String getServiceKey() { return serviceKey; } - public void setServiceKey(String serviceKey) { - this.serviceKey = serviceKey; - } - public Set getApps() { return apps; } - public void setApps(Set apps) { - this.apps = apps; - } - @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("{serviceKey: ").append(serviceKey).append(", apps: "); - sb.append(apps.toString()).append("}"); - return sb.toString(); + return "{serviceKey: " + serviceKey + ", apps: " + + apps.toString() + "}"; } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java index 288712ee9f..7a2d29b805 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMapping.java @@ -18,13 +18,14 @@ package org.apache.dubbo.metadata; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.utils.StringUtils; -import java.util.Collections; +import java.util.Arrays; +import java.util.HashSet; import java.util.Set; -import static org.apache.dubbo.common.constants.CommonConstants.CONFIG_MAPPING_TYPE; -import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; -import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; +import static java.util.Collections.emptySet; +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR; import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; import static org.apache.dubbo.common.utils.StringUtils.SLASH; @@ -33,8 +34,9 @@ import static org.apache.dubbo.common.utils.StringUtils.SLASH; * * @since 2.7.5 */ -@SPI("config") +@SPI("metadata") public interface ServiceNameMapping { + String DEFAULT_MAPPING_GROUP = "mapping"; /** @@ -42,15 +44,6 @@ public interface ServiceNameMapping { */ void map(URL url); - /** - * Map the specified Dubbo service interface, group, version and protocol to current Dubbo service name with cas. - * - * @param url - */ - default void mapWithCas(URL url) { - - } - /** * Get the service names from the specified Dubbo service interface, group, version and protocol * @@ -59,51 +52,31 @@ public interface ServiceNameMapping { Set getAndListen(URL url, MappingListener mappingListener); /** - * service name mapping new store structure. - * interface(key) - * -- mapping(group) - * --appName1,appName2,appName3(content) - * @param url - * @param mappingListener - * @return + * Get the default extension of {@link ServiceNameMapping} + * + * @return non-null {@link ServiceNameMapping} */ - default Set getAndListenWithNewStore(URL url, MappingListener mappingListener){ - return Collections.emptySet(); - }; + static ServiceNameMapping getDefaultExtension() { + return getExtensionLoader(ServiceNameMapping.class).getDefaultExtension(); + } - default Set get(URL url) { - return getAndListen(url, null); + static String buildMappingKey(URL url) { + return buildGroup(url.getServiceInterface()); + } + + static String buildGroup(String serviceInterface) { + //the issue : https://github.com/apache/dubbo/issues/4671 + return DEFAULT_MAPPING_GROUP + SLASH + serviceInterface; } static String toStringKeys(Set serviceNames) { return serviceNames.toString(); } - /** - * Get the default extension of {@link ServiceNameMapping} - * - * @return non-null {@link ServiceNameMapping} - * @see DynamicConfigurationServiceNameMapping - */ - static ServiceNameMapping getDefaultExtension() { - return getExtensionLoader(ServiceNameMapping.class).getDefaultExtension(); - } - - static ServiceNameMapping getExtension(String name) { - return getExtensionLoader(ServiceNameMapping.class).getExtension(name == null ? CONFIG_MAPPING_TYPE : name); - } - - static String buildMappingKey(URL url) { - return buildGroup(url.getServiceInterface(), url.getGroup(), url.getVersion(), url.getParameter(PROTOCOL_KEY, DUBBO)); - } - - static String buildGroup(String serviceInterface, String group, String version, String protocol) { - // the issue : https://github.com/apache/dubbo/issues/4671 - // StringBuilder groupBuilder = new StringBuilder(serviceInterface) - // .append(KEY_SEPARATOR).append(defaultString(group)) - // .append(KEY_SEPARATOR).append(defaultString(version)) - // .append(KEY_SEPARATOR).append(defaultString(protocol)); - // return groupBuilder.toString(); - return DEFAULT_MAPPING_GROUP + SLASH + serviceInterface; + static Set getAppNames(String content) { + if (StringUtils.isBlank(content)) { + return emptySet(); + } + return new HashSet<>(Arrays.asList(content.split(COMMA_SEPARATOR))); } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMappingHandler.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMappingHandler.java deleted file mode 100644 index 12479f266b..0000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMappingHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.dubbo.metadata; - -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; - -public class ServiceNameMappingHandler { - public static final String DUBBO_SERVICENAME_STORE = "dubbo.application.service-name.store"; - private static final Logger logger = LoggerFactory.getLogger(ServiceNameMappingHandler.class); - private static final ServiceNameMappingStoreEnum DEFAULT_STORE_TYPE = ServiceNameMappingStoreEnum.BOTH_STORAGE; - - private final ServiceNameMapping serviceNameMapping; - private final URL url; - - public ServiceNameMappingHandler(ServiceNameMapping serviceNameMapping, URL url) { - this.serviceNameMapping = serviceNameMapping; - this.url = url; - } - - public static void map(ServiceNameMapping serviceNameMapping, URL url) { - new ServiceNameMappingHandler(serviceNameMapping, url).init(); - } - - public void init() { - DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration(); - - ServiceNameMappingStoreEnum storeType = DEFAULT_STORE_TYPE; - boolean hasSupportCas = dynamicConfiguration.hasSupportCas(); - if (!hasSupportCas) { - storeType = ServiceNameMappingStoreEnum.APPLICANT_INTERFACE_STORAGE; - } - doMap(storeType); - } - - public void doMap(ServiceNameMappingStoreEnum storeType) { - if (null == storeType) { - throw new IllegalStateException("storeType of serviceNameMapping cannot be null"); - } - switch (storeType) { - case INTERFACE_APPLICATION_STORAGE: - serviceNameMapping.mapWithCas(url); - break; - case APPLICANT_INTERFACE_STORAGE: - serviceNameMapping.map(url); - break; - case BOTH_STORAGE: - serviceNameMapping.map(url); - serviceNameMapping.mapWithCas(url); - break; - default: - serviceNameMapping.map(url); - } - } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMappingStoreEnum.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMappingStoreEnum.java deleted file mode 100644 index 2aa5b9d4f4..0000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceNameMappingStoreEnum.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.dubbo.metadata; - -import java.util.HashMap; -import java.util.Map; - -public enum ServiceNameMappingStoreEnum { - - INTERFACE_APPLICATION_STORAGE("interface_application_storage"), - APPLICANT_INTERFACE_STORAGE("applicant_interface_storage"), - BOTH_STORAGE("both_storage"); - - private String storeType; - - private static final Map storeMap = new HashMap<>(); - - static { - for (ServiceNameMappingStoreEnum serviceNameMappingStoreEnum : values()) { - storeMap.put(serviceNameMappingStoreEnum.getStoreType(), serviceNameMappingStoreEnum); - } - } - - - ServiceNameMappingStoreEnum(String storeType) { - this.storeType = storeType; - } - - public String getStoreType() { - return this.storeType; - } - - public static ServiceNameMappingStoreEnum getStoreEnumByStoreType(String storeType) { - return storeMap.get(storeType); - } -} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java index 3b5822dcc7..ea3e7c8310 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReport.java @@ -18,6 +18,7 @@ package org.apache.dubbo.metadata.report; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.ConfigItem; import org.apache.dubbo.metadata.MappingListener; import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.metadata.definition.model.ServiceDefinition; @@ -48,17 +49,6 @@ public interface MetadataReport { return null; } - /** - * Service<-->Application Mapping -- START - **/ - default Set getServiceAppMapping(String serviceKey, MappingListener listener, URL url) { - return Collections.emptySet(); - } - - default void registerServiceAppMapping(String serviceKey, String application, URL url) { - return; - } - /** * deprecated or need triage **/ @@ -76,4 +66,18 @@ public interface MetadataReport { List getSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier); + default ConfigItem getConfigItem(String key, String group) { + return new ConfigItem(); + } + + default boolean registerServiceAppMapping(String serviceInterface, String defaultMappingGroup, String newConfigContent, Object ticket) { + return false; + } + + /** + * Service<-->Application Mapping -- START + **/ + default Set getServiceAppMapping(String serviceKey, MappingListener listener, URL url) { + return Collections.emptySet(); + } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping deleted file mode 100644 index b991bc3cd6..0000000000 --- a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.ServiceNameMapping +++ /dev/null @@ -1 +0,0 @@ -config=org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping \ No newline at end of file diff --git a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java index e4b4c1e512..709dc18a12 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/test/java/org/apache/dubbo/metadata/ServiceNameMappingTest.java @@ -34,7 +34,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY; -import static org.apache.dubbo.metadata.DynamicConfigurationServiceNameMapping.buildGroup; +import static org.apache.dubbo.common.config.configcenter.DynamicConfigurationServiceNameMapping.buildGroup; import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml b/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml new file mode 100644 index 0000000000..2c07e58543 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-report-nacos/pom.xml @@ -0,0 +1,43 @@ + + + + + org.apache.dubbo + dubbo-metadata + ${revision} + ../pom.xml + + 4.0.0 + + dubbo-metadata-report-nacos + + + + org.apache.dubbo + dubbo-metadata-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-configcenter-nacos + ${project.parent.version} + + + diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosConfigServiceWrapper.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosConfigServiceWrapper.java new file mode 100644 index 0000000000..54bfa60178 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosConfigServiceWrapper.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata.store.nacos; + +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; + +import static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR; +import static org.apache.dubbo.common.utils.StringUtils.SLASH_CHAR; + +public class NacosConfigServiceWrapper { + + private static final String INNERCLASS_SYMBOL = "$"; + + private static final String INNERCLASS_COMPATIBLE_SYMBOL = "___"; + + private static final long DEFAULT_TIMEOUT = 3000L; + + private ConfigService configService; + + public NacosConfigServiceWrapper(ConfigService configService) { + this.configService = configService; + } + + public ConfigService getConfigService() { + return configService; + } + + public void addListener(String dataId, String group, Listener listener) throws NacosException { + configService.addListener(handleInnerSymbol(dataId), handleInnerSymbol(group), listener); + } + + public String getConfig(String dataId, String group) throws NacosException { + return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), DEFAULT_TIMEOUT); + } + + public String getConfig(String dataId, String group, long timeout) throws NacosException { + return configService.getConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), timeout); + } + + public boolean publishConfig(String dataId, String group, String content) throws NacosException { + return configService.publishConfig(handleInnerSymbol(dataId), handleInnerSymbol(group), content); + } + + public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException { + return configService.publishConfigCas(handleInnerSymbol(dataId), handleInnerSymbol(group), content, casMd5); + } + + public boolean removeConfig(String dataId, String group) throws NacosException { + return configService.removeConfig(handleInnerSymbol(dataId), handleInnerSymbol(group)); + } + + /** + * see {@link com.alibaba.nacos.client.config.utils.ParamUtils#isValid(java.lang.String)} + */ + private String handleInnerSymbol(String data) { + if (data == null) { + return null; + } + return data.replace(INNERCLASS_SYMBOL, INNERCLASS_COMPATIBLE_SYMBOL).replace(SLASH_CHAR, HYPHEN_CHAR); + } + +} diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java new file mode 100644 index 0000000000..401b159976 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReport.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dubbo.metadata.store.nacos; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.ConfigChangeType; +import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent; +import org.apache.dubbo.common.config.configcenter.ConfigItem; +import org.apache.dubbo.common.config.configcenter.ConfigurationListener; +import org.apache.dubbo.common.utils.MD5Utils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.metadata.MappingChangedEvent; +import org.apache.dubbo.metadata.MappingListener; +import org.apache.dubbo.metadata.ServiceNameMapping; +import org.apache.dubbo.metadata.MetadataInfo; +import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; +import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; +import org.apache.dubbo.metadata.report.support.AbstractMetadataReport; +import org.apache.dubbo.rpc.RpcException; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.api.config.listener.AbstractSharedListener; +import com.alibaba.nacos.api.exception.NacosException; +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.Executor; + +import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; +import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; +import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; +import static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of; +import static org.apache.dubbo.common.utils.StringUtils.HYPHEN_CHAR; +import static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP; +import static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames; + +/** + * metadata report impl for nacos + */ +public class NacosMetadataReport extends AbstractMetadataReport { + + private NacosConfigServiceWrapper configService; + + private Gson gson = new Gson(); + + /** + * The group used to store metadata in Nacos + */ + private String group; + + private Map watchListenerMap = new ConcurrentHashMap<>(); + + private Map casListenerMap = new ConcurrentHashMap<>(); + + + public NacosMetadataReport(URL url) { + super(url); + this.configService = buildConfigService(url); + group = url.getParameter(GROUP_KEY, DEFAULT_ROOT); + } + + public NacosConfigServiceWrapper buildConfigService(URL url) { + Properties nacosProperties = buildNacosProperties(url); + try { + configService = new NacosConfigServiceWrapper(NacosFactory.createConfigService(nacosProperties)); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getErrMsg(), e); + } + throw new IllegalStateException(e); + } + return configService; + } + + private Properties buildNacosProperties(URL url) { + Properties properties = new Properties(); + setServerAddr(url, properties); + setProperties(url, properties); + return properties; + } + + private void setServerAddr(URL url, Properties properties) { + StringBuilder serverAddrBuilder = + new StringBuilder(url.getHost()) // Host + .append(":") + .append(url.getPort()); // Port + // Append backup parameter as other servers + String backup = url.getParameter(BACKUP_KEY); + if (backup != null) { + serverAddrBuilder.append(",").append(backup); + } + String serverAddr = serverAddrBuilder.toString(); + properties.put(SERVER_ADDR, serverAddr); + } + + private static void setProperties(URL url, Properties properties) { + // Get the parameters from constants + Map parameters = url.getParameters(of(PropertyKeyConst.class)); + // Put all parameters + properties.putAll(parameters); + } + + private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName) { + String propertyValue = url.getParameter(propertyName); + if (StringUtils.isNotEmpty(propertyValue)) { + properties.setProperty(propertyName, propertyValue); + } + } + + private static void putPropertyIfAbsent(URL url, Properties properties, String propertyName, String defaultValue) { + String propertyValue = url.getParameter(propertyName); + if (StringUtils.isNotEmpty(propertyValue)) { + properties.setProperty(propertyName, propertyValue); + } else { + properties.setProperty(propertyName, defaultValue); + } + } + + @Override + public void publishAppMetadata(SubscriberMetadataIdentifier identifier, MetadataInfo metadataInfo) { + String content = gson.toJson(metadataInfo); + try { + configService.publishConfig(identifier.getApplication(), identifier.getRevision(), content); + } catch (NacosException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + @Override + public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map instanceMetadata) { + try { + String content = configService.getConfig(identifier.getApplication(), identifier.getRevision(), 3000L); + return gson.fromJson(content, MetadataInfo.class); + } catch (NacosException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + @Override + protected void doStoreProviderMetadata(MetadataIdentifier providerMetadataIdentifier, String serviceDefinitions) { + this.storeMetadata(providerMetadataIdentifier, serviceDefinitions); + } + + @Override + protected void doStoreConsumerMetadata(MetadataIdentifier consumerMetadataIdentifier, String value) { + this.storeMetadata(consumerMetadataIdentifier, value); + } + + @Override + protected void doSaveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier, URL url) { + storeMetadata(serviceMetadataIdentifier, URL.encode(url.toFullString())); + } + + @Override + protected void doRemoveMetadata(ServiceMetadataIdentifier serviceMetadataIdentifier) { + deleteMetadata(serviceMetadataIdentifier); + } + + @Override + protected List doGetExportedURLs(ServiceMetadataIdentifier metadataIdentifier) { + String content = getConfig(metadataIdentifier); + if (StringUtils.isEmpty(content)) { + return Collections.emptyList(); + } + return new ArrayList(Arrays.asList(URL.decode(content))); + } + + @Override + protected void doSaveSubscriberData(SubscriberMetadataIdentifier subscriberMetadataIdentifier, String urlListStr) { + storeMetadata(subscriberMetadataIdentifier, urlListStr); + } + + @Override + protected String doGetSubscribedURLs(SubscriberMetadataIdentifier subscriberMetadataIdentifier) { + return getConfig(subscriberMetadataIdentifier); + } + + @Override + public String getServiceDefinition(MetadataIdentifier metadataIdentifier) { + return getConfig(metadataIdentifier); + } + + @Override + public boolean registerServiceAppMapping(String key, String group, String content, Object ticket) { + try { + if (!(ticket instanceof String)) { + throw new IllegalArgumentException("nacos publishConfigCas requires string type ticket"); + } + return configService.publishConfigCas(key, group, content, (String) ticket); + } catch (NacosException e) { + logger.warn("nacos publishConfigCas failed.", e); + return false; + } + } + + @Override + public ConfigItem getConfigItem(String key, String group) { + String content = getConfig(key, group); + String casMd5 = ""; + if (StringUtils.isNotEmpty(content)) { + casMd5 = MD5Utils.getMd5(content); + } + return new ConfigItem(content, casMd5); + } + + @Override + public Set getServiceAppMapping(String serviceKey, MappingListener listener, URL url) { + String group = DEFAULT_MAPPING_GROUP; + + if (null == casListenerMap.get(buildListenerKey(serviceKey, group))) { + addCasServiceMappingListener(serviceKey, group, listener); + } + String content = getConfig(serviceKey, group); + return ServiceNameMapping.getAppNames(content); + } + + private String getConfig(String dataId, String group) { + try { + return configService.getConfig(dataId, group); + } catch (NacosException e) { + logger.error(e.getMessage()); + } + return null; + } + + private void addCasServiceMappingListener(String serviceKey, String group, MappingListener listener) { + MappingDataListener mappingDataListener = casListenerMap.computeIfAbsent(buildListenerKey(serviceKey, group), k -> new MappingDataListener(serviceKey, group)); + mappingDataListener.addListeners(listener); + addListener(serviceKey, DEFAULT_MAPPING_GROUP, mappingDataListener); + } + + public void addListener(String key, String group, ConfigurationListener listener) { + String listenerKey = buildListenerKey(key, group); + NacosConfigListener nacosConfigListener = + watchListenerMap.computeIfAbsent(listenerKey, k -> createTargetListener(key, group)); + nacosConfigListener.addListener(listener); + try { + configService.addListener(key, group, nacosConfigListener); + } catch (NacosException e) { + logger.error(e.getMessage()); + } + } + + private NacosConfigListener createTargetListener(String key, String group) { + NacosConfigListener configListener = new NacosConfigListener(); + configListener.fillContext(key, group); + return configListener; + } + + private String buildListenerKey(String key, String group) { + return key + HYPHEN_CHAR + group; + } + + + private void storeMetadata(BaseMetadataIdentifier identifier, String value) { + try { + boolean publishResult = configService.publishConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, value); + if (!publishResult) { + throw new RuntimeException("publish nacos metadata failed"); + } + } catch (Throwable t) { + logger.error("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t); + throw new RpcException("Failed to put " + identifier + " to nacos " + value + ", cause: " + t.getMessage(), t); + } + } + + private void deleteMetadata(BaseMetadataIdentifier identifier) { + try { + boolean publishResult = configService.removeConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group); + if (!publishResult) { + throw new RuntimeException("remove nacos metadata failed"); + } + } catch (Throwable t) { + logger.error("Failed to remove " + identifier + " from nacos , cause: " + t.getMessage(), t); + throw new RpcException("Failed to remove " + identifier + " from nacos , cause: " + t.getMessage(), t); + } + } + + private String getConfig(BaseMetadataIdentifier identifier) { + try { + return configService.getConfig(identifier.getUniqueKey(KeyTypeEnum.UNIQUE_KEY), group, 3000L); + } catch (Throwable t) { + logger.error("Failed to get " + identifier + " from nacos , cause: " + t.getMessage(), t); + throw new RpcException("Failed to get " + identifier + " from nacos , cause: " + t.getMessage(), t); + } + } + + public class NacosConfigListener extends AbstractSharedListener { + + private Set listeners = new CopyOnWriteArraySet<>(); + /** + * cache data to store old value + */ + private Map cacheData = new ConcurrentHashMap<>(); + + @Override + public Executor getExecutor() { + return null; + } + + /** + * receive + * + * @param dataId data ID + * @param group group + * @param configInfo content + */ + @Override + public void innerReceive(String dataId, String group, String configInfo) { + String oldValue = cacheData.get(dataId); + ConfigChangedEvent event = new ConfigChangedEvent(dataId, group, configInfo, getChangeType(configInfo, oldValue)); + if (configInfo == null) { + cacheData.remove(dataId); + } else { + cacheData.put(dataId, configInfo); + } + listeners.forEach(listener -> listener.process(event)); + } + + void addListener(ConfigurationListener configurationListener) { + + this.listeners.add(configurationListener); + } + + void removeListener(ConfigurationListener configurationListener) { + this.listeners.remove(configurationListener); + } + + private ConfigChangeType getChangeType(String configInfo, String oldValue) { + if (StringUtils.isBlank(configInfo)) { + return ConfigChangeType.DELETED; + } + if (StringUtils.isBlank(oldValue)) { + return ConfigChangeType.ADDED; + } + return ConfigChangeType.MODIFIED; + } + } + + static class MappingDataListener implements ConfigurationListener { + + private String dataId; + + private String groupId; + + private String serviceKey; + + private Set listeners; + + public MappingDataListener(String dataId, String groupId) { + this.serviceKey = dataId; + this.dataId = dataId; + this.groupId = groupId; + this.listeners = new HashSet<>(); + } + + public void addListeners(MappingListener mappingListener) { + listeners.add(mappingListener); + } + + @Override + public void process(ConfigChangedEvent event) { + if (ConfigChangeType.DELETED == event.getChangeType()) { + return; + } + if (!dataId.equals(event.getKey()) || !groupId.equals(event.getGroup())) { + return; + } + + Set apps = getAppNames(event.getContent()); + + MappingChangedEvent mappingChangedEvent = new MappingChangedEvent(serviceKey, apps); + + listeners.forEach(listener -> listener.onEvent(mappingChangedEvent)); + } + } +} diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java new file mode 100644 index 0000000000..2cff74c9a1 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/java/org/apache/dubbo/metadata/store/nacos/NacosMetadataReportFactory.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dubbo.metadata.store.nacos; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.metadata.report.MetadataReport; +import org.apache.dubbo.metadata.report.support.AbstractMetadataReportFactory; + +/** + * metadata report factory impl for nacos + */ +public class NacosMetadataReportFactory extends AbstractMetadataReportFactory { + @Override + protected MetadataReport createMetadataReport(URL url) { + return new NacosMetadataReport(url); + } +} diff --git a/dubbo-metadata/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory new file mode 100644 index 0000000000..de3b50a4b4 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-report-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.report.MetadataReportFactory @@ -0,0 +1 @@ +nacos=org.apache.dubbo.metadata.store.nacos.NacosMetadataReportFactory diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml b/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml index fa614a09f0..9a9fc34c27 100644 --- a/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml +++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/pom.xml @@ -17,8 +17,8 @@ - dubbo-metadata org.apache.dubbo + dubbo-metadata ${revision} ../pom.xml diff --git a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java index f06cca380a..cbc22244af 100644 --- a/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java +++ b/dubbo-metadata/dubbo-metadata-report-zookeeper/src/main/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReport.java @@ -17,9 +17,9 @@ package org.apache.dubbo.metadata.store.zookeeper; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.configcenter.ConfigItem; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metadata.MappingChangedEvent; import org.apache.dubbo.metadata.MappingListener; @@ -30,16 +30,16 @@ import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; import org.apache.dubbo.metadata.report.support.AbstractMetadataReport; -import org.apache.dubbo.remoting.zookeeper.ChildListener; +import org.apache.dubbo.remoting.zookeeper.DataListener; +import org.apache.dubbo.remoting.zookeeper.EventType; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; import com.google.gson.Gson; +import org.apache.zookeeper.data.Stat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -47,6 +47,8 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; +import static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP; +import static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames; /** * ZookeeperMetadataReport @@ -61,7 +63,8 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport { private Gson gson = new Gson(); - private Map listenerMap = new ConcurrentHashMap<>(); + private Map casListenerMap = new ConcurrentHashMap<>(); + public ZookeeperMetadataReport(URL url, ZookeeperTransporter zookeeperTransporter) { super(url); @@ -76,7 +79,7 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport { zkClient = zookeeperTransporter.connect(url); } - String toRootDir() { + protected String toRootDir() { if (root.equals(PATH_SEPARATOR)) { return root; } @@ -109,7 +112,7 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport { if (StringUtils.isEmpty(content)) { return Collections.emptyList(); } - return new ArrayList(Arrays.asList(URL.decode(content))); + return new ArrayList<>(Collections.singletonList(URL.decode(content))); } @Override @@ -143,16 +146,6 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport { } } - @Override - public void registerServiceAppMapping(String serviceKey, String application, URL url) { - String path = toRootDir() + serviceKey + PATH_SEPARATOR + application; - if (StringUtils.isBlank(zkClient.getContent(path))) { - Map value = new HashMap<>(); - value.put("timestamp", String.valueOf(System.currentTimeMillis())); - zkClient.create(path, gson.toJson(value), false); - } - } - @Override public MetadataInfo getAppMetadata(SubscriberMetadataIdentifier identifier, Map instanceMetadata) { String content = zkClient.getContent(getNodePath(identifier)); @@ -161,33 +154,51 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport { @Override public Set getServiceAppMapping(String serviceKey, MappingListener listener, URL url) { - Set appNameSet = new HashSet<>(); - String path = toRootDir() + serviceKey; - List appNameList = zkClient.getChildren(path); - if (!CollectionUtils.isEmpty(appNameList)) { - appNameSet.addAll(appNameList); + String path = buildPathKey(DEFAULT_MAPPING_GROUP, serviceKey); + if (null == casListenerMap.get(path)) { + addCasServiceMappingListener(path, serviceKey, listener); } - - if (null == listenerMap.get(path)) { - zkClient.create(path, false); - addServiceMappingListener(path, serviceKey, listener); - } - - return appNameSet; + return getAppNames(zkClient.getContent(path)); } - private void addServiceMappingListener(String path, String serviceKey, MappingListener listener) { - MappingChildListener mappingChildListener = listenerMap.computeIfAbsent(path, _k -> new MappingChildListener(serviceKey, path)); - mappingChildListener.addListener(listener); - zkClient.addChildListener(path, mappingChildListener); + @Override + public ConfigItem getConfigItem(String serviceKey, String group) { + String path = buildPathKey(group, serviceKey); + return zkClient.getConfigItem(path); } - private static class MappingChildListener implements ChildListener { + @Override + public boolean registerServiceAppMapping(String key, String group, String content, Object ticket) { + try { + if (ticket != null && !(ticket instanceof Stat)) { + throw new IllegalArgumentException("zookeeper publishConfigCas requires stat type ticket"); + } + String pathKey = buildPathKey(group, key); + zkClient.createOrUpdate(pathKey, content, false, ticket == null ? 0 : ((Stat) ticket).getVersion()); + return true; + } catch (Exception e) { + logger.warn("zookeeper publishConfigCas failed.", e); + return false; + } + } + + private String buildPathKey(String group, String serviceKey) { + return toRootDir() + group + PATH_SEPARATOR + serviceKey; + } + + private void addCasServiceMappingListener(String path, String serviceKey, MappingListener listener) { + MappingDataListener mappingDataListener = casListenerMap.computeIfAbsent(path, _k -> new MappingDataListener(serviceKey, path)); + mappingDataListener.addListener(listener); + zkClient.addDataListener(path, mappingDataListener); + } + + private static class MappingDataListener implements DataListener { + private String serviceKey; private String path; private Set listeners; - public MappingChildListener(String serviceKey, String path) { + public MappingDataListener(String serviceKey, String path) { this.serviceKey = serviceKey; this.path = path; this.listeners = new HashSet<>(); @@ -198,10 +209,18 @@ public class ZookeeperMetadataReport extends AbstractMetadataReport { } @Override - public void childChanged(String path, List children) { - MappingChangedEvent event = new MappingChangedEvent(); - event.setServiceKey(serviceKey); - event.setApps(null != children ? new HashSet<>(children) : null); + public void dataChanged(String path, Object value, EventType eventType) { + if (!this.path.equals(path)) { + return; + } + if (EventType.NodeCreated != eventType && EventType.NodeDataChanged != eventType) { + return; + } + + Set apps = getAppNames((String) value); + + MappingChangedEvent event = new MappingChangedEvent(serviceKey, apps); + listeners.forEach(mappingListener -> mappingListener.onEvent(event)); } } diff --git a/dubbo-metadata/pom.xml b/dubbo-metadata/pom.xml index 9119e09488..9fdffe93f0 100644 --- a/dubbo-metadata/pom.xml +++ b/dubbo-metadata/pom.xml @@ -33,6 +33,7 @@ dubbo-metadata-processor dubbo-metadata-report-zookeeper dubbo-metadata-report-redis + dubbo-metadata-report-nacos diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java index e9a48cbabd..5f3ba63e0f 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/AbstractServiceDiscovery.java @@ -16,27 +16,75 @@ */ package org.apache.dubbo.registry.client; +import org.apache.dubbo.common.URL; import org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.isInstanceUpdated; +import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.resetInstanceUpdateKey; + public abstract class AbstractServiceDiscovery implements ServiceDiscovery { + private volatile boolean isDestroy; + protected ServiceInstance serviceInstance; @Override - public ServiceInstance getLocalInstance() { + public final ServiceInstance getLocalInstance() { return serviceInstance; } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = serviceInstance; + public final void initialize(URL registryURL) throws Exception { + doInitialize(registryURL); + } + + public abstract void doInitialize(URL registryURL) throws Exception; + + @Override + public final void register(ServiceInstance serviceInstance) throws RuntimeException { if (ServiceInstanceMetadataUtils.getExportedServicesRevision(serviceInstance) == null) { ServiceInstanceMetadataUtils.calInstanceRevision(this, serviceInstance); } - } - - @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { + doRegister(serviceInstance); this.serviceInstance = serviceInstance; } + + public abstract void doRegister(ServiceInstance serviceInstance) throws RuntimeException; + + + @Override + public final void update(ServiceInstance serviceInstance) throws RuntimeException { + if (this.serviceInstance == null) { + this.register(serviceInstance); + return; + } + if (!isInstanceUpdated(serviceInstance)) { + return; + } + doUpdate(serviceInstance); + resetInstanceUpdateKey(serviceInstance); + this.serviceInstance = serviceInstance; + } + + public abstract void doUpdate(ServiceInstance serviceInstance) throws RuntimeException; + + @Override + public final void unregister(ServiceInstance serviceInstance) throws RuntimeException { + doUnregister(serviceInstance); + } + + public abstract void doUnregister(ServiceInstance serviceInstance); + + @Override + public final void destroy() throws Exception { + isDestroy = true; + doDestroy(); + } + + public abstract void doDestroy() throws Exception; + + @Override + public final boolean isDestroy() { + return isDestroy; + } } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java index af8cac4ddb..aebc4bff57 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/FileSystemServiceDiscovery.java @@ -52,7 +52,7 @@ import static org.apache.dubbo.common.config.configcenter.file.FileSystemDynamic * @see FileSystemDynamicConfiguration * @since 2.7.5 */ -public class FileSystemServiceDiscovery implements ServiceDiscovery { +public class FileSystemServiceDiscovery extends AbstractServiceDiscovery { private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -60,10 +60,8 @@ public class FileSystemServiceDiscovery implements ServiceDiscovery { private FileSystemDynamicConfiguration dynamicConfiguration; - private ServiceInstance serviceInstance; - @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { dynamicConfiguration = createDynamicConfiguration(registryURL); registerDubboShutdownHook(); registerListener(); @@ -86,7 +84,7 @@ public class FileSystemServiceDiscovery implements ServiceDiscovery { } @Override - public void destroy() throws Exception { + public void doDestroy() throws Exception { dynamicConfiguration.close(); releaseAndRemoveRegistrationFiles(); } @@ -128,13 +126,9 @@ public class FileSystemServiceDiscovery implements ServiceDiscovery { return null; } - @Override - public ServiceInstance getLocalInstance() { - return serviceInstance; - } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { + public void doRegister(ServiceInstance serviceInstance) throws RuntimeException { this.serviceInstance = serviceInstance; String serviceInstanceId = getServiceInstanceId(serviceInstance); String serviceName = getServiceName(serviceInstance); @@ -168,12 +162,12 @@ public class FileSystemServiceDiscovery implements ServiceDiscovery { } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { + public void doUpdate(ServiceInstance serviceInstance) throws RuntimeException { register(serviceInstance); } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { String key = getServiceInstanceId(serviceInstance); String group = getServiceName(serviceInstance); releaseFileLock(key, group); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/SelfHostMetaServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/SelfHostMetaServiceDiscovery.java index d33040addd..47794f5ed9 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/SelfHostMetaServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/SelfHostMetaServiceDiscovery.java @@ -49,6 +49,8 @@ import java.util.concurrent.TimeUnit; public abstract class SelfHostMetaServiceDiscovery implements ServiceDiscovery { + private volatile boolean isDestroy; + private final Logger logger = LoggerFactory.getLogger(getClass()); private URL registryURL; @@ -124,12 +126,18 @@ public abstract class SelfHostMetaServiceDiscovery implements ServiceDiscovery { @Override public void destroy() throws Exception { + isDestroy = true; doDestroy(); metadataMap.clear(); serviceInstanceRevisionMap.clear(); echoCheckExecutor.shutdown(); } + @Override + public boolean isDestroy() { + return isDestroy; + } + private void updateMetadata(ServiceInstance serviceInstance) { WritableMetadataService metadataService = WritableMetadataService.getDefaultExtension(); String metadataString = JSONObject.toJSONString(serviceInstance.getMetadata()); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java index c6b17835a0..d97f66b89a 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscovery.java @@ -61,6 +61,8 @@ public interface ServiceDiscovery extends Prioritized { */ void destroy() throws Exception; + boolean isDestroy(); + // ==================================================================================== // // =================================== Registration =================================== // diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java index b7599a369a..c9a6ad4ed2 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java @@ -56,7 +56,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.DUBBO; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.MAPPING_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; @@ -234,8 +233,6 @@ public class ServiceDiscoveryRegistry implements Registry { logger.warn("Cannot find app mapping for service " + url.getServiceInterface() + ", will not migrate.", e); } - Set serviceNames = writableMetadataService.getCachedMapping(url); - if (CollectionUtils.isEmpty(subscribedServices)) { if (check) { throw new IllegalStateException("Should has at least one way to know which services this interface belongs to, subscription url: " + url); @@ -292,7 +289,7 @@ public class ServiceDiscoveryRegistry implements Registry { @Override public boolean isAvailable() { - return !serviceDiscovery.getServices().isEmpty(); + return !serviceDiscovery.isDestroy() && !serviceDiscovery.getServices().isEmpty(); } @Override @@ -468,9 +465,8 @@ public class ServiceDiscoveryRegistry implements Registry { protected Set findMappedServices(URL registryURL, URL subscribedURL, MappingListener listener) { Set result = new LinkedHashSet<>(); - ServiceNameMapping serviceNameMapping = ServiceNameMapping.getExtension(registryURL.getParameter(MAPPING_KEY)); + ServiceNameMapping serviceNameMapping = ServiceNameMapping.getDefaultExtension(); result.addAll(serviceNameMapping.getAndListen(subscribedURL, listener)); - result.addAll(serviceNameMapping.getAndListenWithNewStore(subscribedURL, listener)); return result; } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java index 38a887f445..2994c9bc24 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java @@ -169,7 +169,7 @@ public class ServiceInstancesChangedListener { public synchronized void addListenerAndNotify(String serviceKey, NotifyListener listener) { this.listeners.put(serviceKey, listener); - List urls = getAddresses(serviceKey, listener.getConsumerUrl()); + List urls = getAddresses(serviceKey); if (CollectionUtils.isNotEmpty(urls)) { listener.notify(urls); } @@ -253,14 +253,12 @@ public class ServiceInstancesChangedListener { if (revisionToMetadata == null) { return false; } - boolean result = false; for (Map.Entry entry : revisionToMetadata.entrySet()) { if (entry.getValue() == MetadataInfo.EMPTY) { - result = true; - break; + return true; } } - return result; + return false; } protected MetadataInfo getRemoteMetadata(ServiceInstance instance, String revision, Map> localServiceToRevisions, List subInstances) { @@ -351,14 +349,14 @@ public class ServiceInstancesChangedListener { return urls; } - protected List getAddresses(String serviceProtocolKey, URL consumerURL) { + protected List getAddresses(String serviceProtocolKey) { return (List) serviceUrls.get(serviceProtocolKey); } protected void notifyAddressChanged() { listeners.forEach((key, notifyListener) -> { //FIXME, group wildcard match - List urls = toUrlsWithEmpty(getAddresses(key, notifyListener.getConsumerUrl())); + List urls = toUrlsWithEmpty(getAddresses(key)); logger.info("Notify service " + key + " with urls " + urls.size()); notifyListener.notify(urls); }); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java index 5c83825cb6..4db6fa6d34 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java @@ -17,59 +17,72 @@ package org.apache.dubbo.registry.client.metadata; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.config.configcenter.ConfigItem; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metadata.MappingListener; -import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.metadata.ServiceNameMapping; +import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.metadata.report.MetadataReport; import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.registry.client.RegistryClusterIdentifier; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import static java.util.Arrays.asList; +import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; import static org.apache.dubbo.rpc.model.ApplicationModel.getName; public class MetadataServiceNameMapping implements ServiceNameMapping { - private static final List IGNORED_SERVICE_INTERFACES = asList(MetadataService.class.getName()); + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private static final List IGNORED_SERVICE_INTERFACES = Collections.singletonList(MetadataService.class.getName()); + + private static final int CAS_RETRY_TIMES = 6; @Override public void map(URL url) { - String serviceInterface = url.getServiceInterface(); - String group = url.getGroup(); - String version = url.getVersion(); - String protocol = url.getProtocol(); + execute(() -> { + String serviceInterface = url.getServiceInterface(); + if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) { + return; + } + String registryCluster = getRegistryCluster(url); + MetadataReport metadataReport = MetadataReportInstance.getMetadataReport(registryCluster); - if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) { - return; - } - String registryCluster = getRegistryCluster(url); - MetadataReport metadataReport = MetadataReportInstance.getMetadataReport(registryCluster); - metadataReport.registerServiceAppMapping(ServiceNameMapping.buildGroup(serviceInterface, group, version, protocol), getName(), url); + int currentRetryTimes = 1; + boolean success; + String newConfigContent = getName(); + do { + ConfigItem configItem = metadataReport.getConfigItem(serviceInterface, DEFAULT_MAPPING_GROUP); + String oldConfigContent = configItem.getContent(); + if (StringUtils.isNotEmpty(oldConfigContent)) { + boolean contains = StringUtils.isContains(oldConfigContent, getName()); + if (contains) { + break; + } + newConfigContent = oldConfigContent + COMMA_SEPARATOR + getName(); + } + success = metadataReport.registerServiceAppMapping(serviceInterface, DEFAULT_MAPPING_GROUP, newConfigContent, configItem.getStat()); + } while (!success && currentRetryTimes++ <= CAS_RETRY_TIMES); + }); } @Override public Set getAndListen(URL url, MappingListener mappingListener) { - String serviceInterface = url.getServiceInterface(); - String group = url.getGroup(); - String version = url.getVersion(); - String protocol = url.getProtocol(); - - String mappingKey = ServiceNameMapping.buildGroup(serviceInterface, group, version, protocol); Set serviceNames = new LinkedHashSet<>(); - String registryCluster = getRegistryCluster(url); - MetadataReport metadataReport = MetadataReportInstance.getMetadataReport(registryCluster); - Set apps = metadataReport.getServiceAppMapping( - mappingKey, - mappingListener, - url); - if (CollectionUtils.isNotEmpty(apps)) { + execute(() -> { + String serviceInterface = url.getServiceInterface(); + String registryCluster = getRegistryCluster(url); + MetadataReport metadataReport = MetadataReportInstance.getMetadataReport(registryCluster); + Set apps = metadataReport.getServiceAppMapping(serviceInterface, mappingListener, url); serviceNames.addAll(apps); - } - + }); return serviceNames; } @@ -84,4 +97,14 @@ public class MetadataServiceNameMapping implements ServiceNameMapping { } return registryCluster; } + + private void execute(Runnable runnable) { + try { + runnable.run(); + } catch (Throwable e) { + if (logger.isWarnEnabled()) { + logger.warn(e.getMessage(), e); + } + } + } } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java index aeda3b0b02..5a183d74b1 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java @@ -217,7 +217,7 @@ public class ServiceInstanceMetadataUtils { * @return if not found, return null */ public static Endpoint getEndpoint(ServiceInstance serviceInstance, String protocol) { - List endpoints = ((DefaultServiceInstance)serviceInstance).getEndpoints(); + List endpoints = ((DefaultServiceInstance) serviceInstance).getEndpoints(); if (endpoints != null) { for (Endpoint endpoint : endpoints) { if (endpoint.getProtocol().equals(protocol)) { @@ -229,14 +229,14 @@ public class ServiceInstanceMetadataUtils { } public static void calInstanceRevision(ServiceDiscovery serviceDiscovery, ServiceInstance instance) { - String registryCluster = serviceDiscovery.getUrl().getParameter(REGISTRY_CLUSTER_KEY); + String registryCluster = serviceDiscovery.getUrl() == null ? DEFAULT_KEY : serviceDiscovery.getUrl().getParameter(REGISTRY_CLUSTER_KEY); if (registryCluster == null) { registryCluster = DEFAULT_KEY; } WritableMetadataService writableMetadataService = WritableMetadataService.getDefaultExtension(); MetadataInfo metadataInfo = writableMetadataService.getMetadataInfos().get(registryCluster); if (metadataInfo == null) { - metadataInfo = ((InMemoryWritableMetadataService)writableMetadataService).getDefaultMetadataInfo(); + metadataInfo = ((InMemoryWritableMetadataService) writableMetadataService).getDefaultMetadataInfo(); } if (metadataInfo != null) { String existingInstanceRevision = instance.getMetadata().get(EXPORTED_SERVICES_REVISION_PROPERTY_NAME); @@ -253,6 +253,10 @@ public class ServiceInstanceMetadataUtils { return "true".equals(instance.getExtendParams().get(INSTANCE_REVISION_UPDATED_KEY)); } + public static void resetInstanceUpdateKey(ServiceInstance instance) { + instance.getExtendParams().remove(INSTANCE_REVISION_UPDATED_KEY); + } + public static void refreshMetadataAndInstance(ServiceInstance serviceInstance) { RemoteMetadataServiceImpl remoteMetadataService = MetadataUtils.getRemoteMetadataService(); remoteMetadataService.publishMetadata(ApplicationModel.getName()); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java index 6b27202dbb..7a5fb8f2b7 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/InMemoryWritableMetadataService.java @@ -153,9 +153,7 @@ public class InMemoryWritableMetadataService implements WritableMetadataService String[] clusters = getRegistryCluster(url).split(","); for (String cluster : clusters) { - MetadataInfo metadataInfo = metadataInfos.computeIfAbsent(cluster, k -> { - return new MetadataInfo(ApplicationModel.getName()); - }); + MetadataInfo metadataInfo = metadataInfos.computeIfAbsent(cluster, k -> new MetadataInfo(ApplicationModel.getName())); metadataInfo.addService(new ServiceInfo(url)); } metadataSemaphore.release(); @@ -182,7 +180,7 @@ public class InMemoryWritableMetadataService implements WritableMetadataService return removeURL(exportedServiceURLs, url); } - private String getRegistryCluster(URL url){ + private String getRegistryCluster(URL url) { String registryCluster = RegistryClusterIdentifier.getExtension(url).providerKey(url); if (StringUtils.isEmpty(registryCluster)) { registryCluster = DEFAULT_KEY; diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java index 5b6fbc0fa7..4ed9cf8cd9 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/DynamicDirectory.java @@ -239,7 +239,7 @@ public abstract class DynamicDirectory extends AbstractDirectory implement registry.unsubscribe(getSubscribeUrl(), this); } } catch (Throwable t) { - logger.warn("unexpected error when unsubscribe service " + serviceKey + "from registry" + registry.getUrl(), t); + logger.warn("unexpected error when unsubscribe service " + serviceKey + "from registry " + registry.getUrl(), t); } ExtensionLoader addressListenerExtensionLoader = ExtensionLoader.getExtensionLoader(AddressListener.class); diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/InMemoryServiceDiscovery.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/InMemoryServiceDiscovery.java index 172d917f86..b8d0d31bed 100644 --- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/InMemoryServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/InMemoryServiceDiscovery.java @@ -36,12 +36,10 @@ import static java.util.Collections.emptyList; * * @since 2.7.5 */ -public class InMemoryServiceDiscovery implements ServiceDiscovery { +public class InMemoryServiceDiscovery extends AbstractServiceDiscovery { private Map> repository = new HashMap<>(); - private ServiceInstance serviceInstance; - private URL registryURL; @Override @@ -75,18 +73,12 @@ public class InMemoryServiceDiscovery implements ServiceDiscovery { return registryURL; } - @Override - public ServiceInstance getLocalInstance() { - return serviceInstance; - } - public String toString() { return "InMemoryServiceDiscovery"; } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = serviceInstance; + public void doRegister(ServiceInstance serviceInstance) throws RuntimeException { String serviceName = serviceInstance.getServiceName(); List serviceInstances = repository.computeIfAbsent(serviceName, s -> new LinkedList<>()); if (!serviceInstances.contains(serviceInstance)) { @@ -95,24 +87,24 @@ public class InMemoryServiceDiscovery implements ServiceDiscovery { } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { + public void doUpdate(ServiceInstance serviceInstance) throws RuntimeException { unregister(serviceInstance); register(serviceInstance); } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { String serviceName = serviceInstance.getServiceName(); List serviceInstances = repository.computeIfAbsent(serviceName, s -> new LinkedList<>()); serviceInstances.remove(serviceInstance); } @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { this.registryURL = registryURL; } @Override - public void destroy() { + public void doDestroy() { } } diff --git a/dubbo-registry/dubbo-registry-kubernetes/src/main/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscovery.java b/dubbo-registry/dubbo-registry-kubernetes/src/main/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscovery.java index 9719820baa..43262c7765 100644 --- a/dubbo-registry/dubbo-registry-kubernetes/src/main/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-kubernetes/src/main/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscovery.java @@ -20,8 +20,8 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.registry.client.AbstractServiceDiscovery; import org.apache.dubbo.registry.client.DefaultServiceInstance; -import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.client.ServiceInstance; import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener; @@ -52,15 +52,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; -public class KubernetesServiceDiscovery implements ServiceDiscovery { +public class KubernetesServiceDiscovery extends AbstractServiceDiscovery { private final Logger logger = LoggerFactory.getLogger(getClass()); private KubernetesClient kubernetesClient; private String currentHostname; - private ServiceInstance localServiceInstance; - private URL registryURL; private String namespace; @@ -78,7 +76,7 @@ public class KubernetesServiceDiscovery implements ServiceDiscovery { private final static ConcurrentHashMap SERVICE_UPDATE_TIME = new ConcurrentHashMap<>(64); @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { Config config = KubernetesConfigUtils.createKubernetesConfig(registryURL); this.kubernetesClient = new DefaultKubernetesClient(config); this.currentHostname = System.getenv("HOSTNAME"); @@ -102,7 +100,7 @@ public class KubernetesServiceDiscovery implements ServiceDiscovery { } @Override - public void destroy() throws Exception { + public void doDestroy() throws Exception { SERVICE_WATCHER.forEach((k, v) -> v.close()); SERVICE_WATCHER.clear(); @@ -116,15 +114,13 @@ public class KubernetesServiceDiscovery implements ServiceDiscovery { } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { - localServiceInstance = serviceInstance; - + public void doRegister(ServiceInstance serviceInstance) throws RuntimeException { if (enableRegister) { kubernetesClient .pods() .inNamespace(namespace) .withName(currentHostname) - .edit(pod-> + .edit(pod -> new PodBuilder(pod) .editOrNewMetadata() .addToAnnotations(KUBERNETES_PROPERTIES_KEY, JSONObject.toJSONString(serviceInstance.getMetadata())) @@ -138,14 +134,12 @@ public class KubernetesServiceDiscovery implements ServiceDiscovery { } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { + public void doUpdate(ServiceInstance serviceInstance) throws RuntimeException { register(serviceInstance); } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { - localServiceInstance = null; - + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { if (enableRegister) { kubernetesClient .pods() @@ -175,11 +169,6 @@ public class KubernetesServiceDiscovery implements ServiceDiscovery { .collect(Collectors.toSet()); } - @Override - public ServiceInstance getLocalInstance() { - return localServiceInstance; - } - @Override public List getInstances(String serviceName) throws NullPointerException { Endpoints endpoints = diff --git a/dubbo-registry/dubbo-registry-kubernetes/src/test/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscoveryTest.java b/dubbo-registry/dubbo-registry-kubernetes/src/test/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscoveryTest.java index 15e9b1a88e..4dc43e8290 100644 --- a/dubbo-registry/dubbo-registry-kubernetes/src/test/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscoveryTest.java +++ b/dubbo-registry/dubbo-registry-kubernetes/src/test/java/org/apache/dubbo/registry/kubernetes/KubernetesServiceDiscoveryTest.java @@ -162,7 +162,7 @@ public class KubernetesServiceDiscoveryTest { Thread.sleep(5000); ArgumentCaptor eventArgumentCaptor = ArgumentCaptor.forClass(ServiceInstancesChangedEvent.class); - Mockito.verify(mockListener, Mockito.times(2)).onEvent(eventArgumentCaptor.capture()); + Mockito.verify(mockListener, Mockito.times(1)).onEvent(eventArgumentCaptor.capture()); Assertions.assertEquals(1, eventArgumentCaptor.getValue().getServiceInstances().size()); serviceDiscovery.unregister(serviceInstance); diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscovery.java b/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscovery.java index 234fdcb284..2c78284302 100644 --- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastServiceDiscovery.java @@ -17,7 +17,7 @@ package org.apache.dubbo.registry.multicast; import org.apache.dubbo.common.URL; -import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.AbstractServiceDiscovery; import org.apache.dubbo.registry.client.ServiceInstance; import java.util.Collections; @@ -26,32 +26,29 @@ import java.util.Set; /** * TODO: make multicast protocol support Service Discovery */ -public class MulticastServiceDiscovery implements ServiceDiscovery { +public class MulticastServiceDiscovery extends AbstractServiceDiscovery { private URL registryURL; - private ServiceInstance serviceInstance; @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { this.registryURL = registryURL; } @Override - public void destroy() throws Exception { + public void doDestroy() throws Exception { } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = serviceInstance; + public void doRegister(ServiceInstance serviceInstance) throws RuntimeException { } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { - this.serviceInstance = serviceInstance; + public void doUpdate(ServiceInstance serviceInstance) throws RuntimeException { } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { this.serviceInstance = null; } @@ -65,8 +62,4 @@ public class MulticastServiceDiscovery implements ServiceDiscovery { return registryURL; } - @Override - public ServiceInstance getLocalInstance() { - return serviceInstance; - } } diff --git a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java index 15bf2d1c63..8f5338f2eb 100644 --- a/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-multiple/src/main/java/org/apache/dubbo/registry/multiple/MultipleServiceDiscovery.java @@ -40,6 +40,7 @@ public class MultipleServiceDiscovery implements ServiceDiscovery { private URL registryURL; private ServiceInstance serviceInstance; private String applicationName; + private volatile boolean isDestroy; @Override public void initialize(URL registryURL) throws Exception { @@ -65,11 +66,17 @@ public class MultipleServiceDiscovery implements ServiceDiscovery { @Override public void destroy() throws Exception { + this.isDestroy = true; for (ServiceDiscovery serviceDiscovery : serviceDiscoveries.values()) { serviceDiscovery.destroy(); } } + @Override + public boolean isDestroy() { + return isDestroy; + } + @Override public void register(ServiceInstance serviceInstance) throws RuntimeException { this.serviceInstance = serviceInstance; diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java new file mode 100644 index 0000000000..536d9dc028 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosNamingServiceWrapper.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.nacos; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.EventListener; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; + +import java.util.List; + +public class NacosNamingServiceWrapper { + + private static final String INNERCLASS_SYMBOL = "$"; + + private static final String INNERCLASS_COMPATIBLE_SYMBOL = "___"; + + private NamingService namingService; + + public NacosNamingServiceWrapper(NamingService namingService) { + this.namingService = namingService; + } + + + public String getServerStatus() { + return namingService.getServerStatus(); + } + + public void subscribe(String serviceName, EventListener eventListener) throws NacosException { + namingService.subscribe(handleInnerSymbol(serviceName), eventListener); + } + + public void subscribe(String serviceName, String group, EventListener eventListener) throws NacosException { + namingService.subscribe(handleInnerSymbol(serviceName), group, eventListener); + } + + public List getAllInstances(String serviceName, String group) throws NacosException { + return namingService.getAllInstances(handleInnerSymbol(serviceName), group); + } + + public void registerInstance(String serviceName, String group, Instance instance) throws NacosException { + namingService.registerInstance(handleInnerSymbol(serviceName), group, instance); + } + + public void deregisterInstance(String serviceName, String group, String ip, int port) throws NacosException { + namingService.deregisterInstance(handleInnerSymbol(serviceName), group, ip, port); + } + + + public void deregisterInstance(String serviceName, String group, Instance instance) throws NacosException { + namingService.deregisterInstance(handleInnerSymbol(serviceName), group, instance); + } + + public ListView getServicesOfServer(int pageNo, int pageSize, String parameter) throws NacosException { + return namingService.getServicesOfServer(pageNo, pageSize, parameter); + } + + public List selectInstances(String serviceName, boolean healthy) throws NacosException { + return namingService.selectInstances(handleInnerSymbol(serviceName), healthy); + } + + public void shutdown() throws NacosException { + this.namingService.shutDown(); + } + + /** + * see https://github.com/apache/dubbo/issues/7129 + * nacos service name just support `0-9a-zA-Z-._:`, grpc interface is inner interface, need compatible. + */ + private String handleInnerSymbol(String serviceName) { + if (serviceName == null) { + return null; + } + return serviceName.replace(INNERCLASS_SYMBOL, INNERCLASS_COMPATIBLE_SYMBOL); + } +} diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java index bab85a3eaf..b0c2113b60 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java @@ -125,9 +125,9 @@ public class NacosRegistry extends FailbackRegistry { private final Logger logger = LoggerFactory.getLogger(getClass()); - private final NamingService namingService; + private final NacosNamingServiceWrapper namingService; - public NacosRegistry(URL url, NamingService namingService) { + public NacosRegistry(URL url, NacosNamingServiceWrapper namingService) { super(url); this.namingService = namingService; } @@ -607,7 +607,7 @@ public class NacosRegistry extends FailbackRegistry { * @param namingService {@link NamingService} * @throws NacosException */ - void callback(NamingService namingService) throws NacosException; + void callback(NacosNamingServiceWrapper namingService) throws NacosException; } diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java index 7a346fa2a6..3d8da64d3f 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceDiscovery.java @@ -27,7 +27,6 @@ import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedLi import org.apache.dubbo.registry.nacos.util.NacosNamingServiceUtils; import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.listener.NamingEvent; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ListView; @@ -54,25 +53,24 @@ public class NacosServiceDiscovery extends AbstractServiceDiscovery { private String group; - private NamingService namingService; + private NacosNamingServiceWrapper namingService; private URL registryURL; @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { this.namingService = createNamingService(registryURL); this.group = getGroup(registryURL); this.registryURL = registryURL; } @Override - public void destroy() { - this.namingService = null; + public void doDestroy() throws Exception { + this.namingService.shutdown(); } @Override - public void register(ServiceInstance serviceInstance) throws RuntimeException { - super.register(serviceInstance); + public void doRegister(ServiceInstance serviceInstance) { execute(namingService, service -> { Instance instance = toInstance(serviceInstance); service.registerInstance(instance.getServiceName(), group, instance); @@ -80,19 +78,14 @@ public class NacosServiceDiscovery extends AbstractServiceDiscovery { } @Override - public void update(ServiceInstance serviceInstance) throws RuntimeException { - // TODO: Nacos should support - if (this.serviceInstance == null) { - register(serviceInstance); - } else { - unregister(serviceInstance); - register(serviceInstance); - this.serviceInstance = serviceInstance; - } + public void doUpdate(ServiceInstance serviceInstance) { + ServiceInstance oldInstance = this.serviceInstance; + unregister(oldInstance); + register(serviceInstance); } @Override - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { execute(namingService, service -> { Instance instance = toInstance(serviceInstance); service.deregisterInstance(instance.getServiceName(), group, instance); diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java index abc7467347..a7fc79cff2 100644 --- a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/util/NacosNamingServiceUtils.java @@ -22,6 +22,7 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.registry.client.DefaultServiceInstance; import org.apache.dubbo.registry.client.ServiceInstance; +import org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper; import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.PropertyKeyConst; @@ -36,6 +37,7 @@ import java.util.Properties; import static com.alibaba.nacos.api.PropertyKeyConst.NAMING_LOAD_CACHE_AT_START; import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; +import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME; import static org.apache.dubbo.common.constants.RemotingConstants.BACKUP_KEY; import static org.apache.dubbo.common.utils.StringConstantFieldValuePredicate.of; @@ -99,7 +101,7 @@ public class NacosNamingServiceUtils { * @return {@link NamingService} * @since 2.7.5 */ - public static NamingService createNamingService(URL connectionURL) { + public static NacosNamingServiceWrapper createNamingService(URL connectionURL) { Properties nacosProperties = buildNacosProperties(connectionURL); NamingService namingService; try { @@ -110,7 +112,7 @@ public class NacosNamingServiceUtils { } throw new IllegalStateException(e); } - return namingService; + return new NacosNamingServiceWrapper(namingService); } private static Properties buildNacosProperties(URL url) { @@ -137,6 +139,8 @@ public class NacosNamingServiceUtils { } private static void setProperties(URL url, Properties properties) { + putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME); + // @since 2.7.8 : Refactoring // Get the parameters from constants Map parameters = url.getParameters(of(PropertyKeyConst.class)); diff --git a/dubbo-registry/dubbo-registry-xds/pom.xml b/dubbo-registry/dubbo-registry-xds/pom.xml index 7e1ca4ae8e..e18435b288 100644 --- a/dubbo-registry/dubbo-registry-xds/pom.xml +++ b/dubbo-registry/dubbo-registry-xds/pom.xml @@ -95,6 +95,7 @@ org.xolstice.maven.plugins protobuf-maven-plugin + 0.6.1 com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier} grpc-java diff --git a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java index 723a7ad835..c2bfb35e99 100644 --- a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java +++ b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscovery.java @@ -44,7 +44,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import static org.apache.dubbo.common.function.ThrowableFunction.execute; -import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.isInstanceUpdated; import static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.ROOT_PATH; import static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.build; import static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.buildCuratorFramework; @@ -73,7 +72,7 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery { private final Map watcherCaches = new ConcurrentHashMap<>(); @Override - public void initialize(URL registryURL) throws Exception { + public void doInitialize(URL registryURL) throws Exception { this.registryURL = registryURL; this.curatorFramework = buildCuratorFramework(registryURL); this.rootPath = ROOT_PATH.getParameterValue(registryURL); @@ -86,12 +85,12 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery { return registryURL; } - public void destroy() throws Exception { + public void doDestroy() throws Exception { serviceDiscovery.close(); } - public void register(ServiceInstance serviceInstance) throws RuntimeException { - super.register(serviceInstance); + @Override + public void doRegister(ServiceInstance serviceInstance) { try { serviceDiscovery.registerService(build(serviceInstance)); } catch (Exception e) { @@ -99,19 +98,18 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery { } } - public void update(ServiceInstance serviceInstance) throws RuntimeException { - if (this.serviceInstance == null) { - this.register(serviceInstance); - } else if (isInstanceUpdated(serviceInstance)) { - this.unregister(this.serviceInstance); - this.register(serviceInstance); - this.serviceInstance = serviceInstance; - } + @Override + public void doUpdate(ServiceInstance serviceInstance) { + ServiceInstance oldInstance = this.serviceInstance; + this.unregister(oldInstance); + this.register(serviceInstance); } - public void unregister(ServiceInstance serviceInstance) throws RuntimeException { + @Override + public void doUnregister(ServiceInstance serviceInstance) throws RuntimeException { doInServiceRegistry(serviceDiscovery -> serviceDiscovery.unregisterService(build(serviceInstance))); - } + }; + @Override public Set getServices() { @@ -180,11 +178,14 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery { @Override public void removeServiceInstancesChangedListener(ServiceInstancesChangedListener listener) throws IllegalArgumentException { listener.getServiceNames().forEach(serviceName -> { - ZookeeperServiceDiscoveryChangeWatcher watcher = watcherCaches.remove(serviceName); - watcher.stopWatching(); + ZookeeperServiceDiscoveryChangeWatcher watcher = watcherCaches.remove(buildServicePath(serviceName)); + if (watcher != null) { + watcher.stopWatching(); + } }); } + private void doInServiceRegistry(ThrowableConsumer consumer) { ThrowableConsumer.execute(serviceDiscovery, s -> consumer.accept(s)); } @@ -194,7 +195,7 @@ public class ZookeeperServiceDiscovery extends AbstractServiceDiscovery { } protected void registerServiceWatcher(String serviceName, ServiceInstancesChangedListener listener) { - String path = buildServicePath(serviceName); + String path = buildServicePath(serviceName); try { curatorFramework.create().creatingParentsIfNeeded().forPath(path); } catch (KeeperException.NodeExistsException e) { diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java index 3b960e2901..04db0f8b96 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java @@ -61,7 +61,7 @@ public interface ZookeeperClient { void create(String path, String content, boolean ephemeral); - void createOrUpdate(String path, String content, boolean ephemeral, Object stat); + void createOrUpdate(String path, String content, boolean ephemeral, int ticket); String getContent(String path); diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java index 559feef3a1..0f6f973575 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java @@ -58,7 +58,7 @@ public class CuratorZookeeperClient extends AbstractZookeeperClient nodeCacheMap = new ConcurrentHashMap<>(); @@ -149,25 +149,20 @@ public class CuratorZookeeperClient extends AbstractZookeeperClient 0) { create(path.substring(0, i), false); } if (ephemeral) { - createOrUpdateEphemeral(path, content, stat); + createOrUpdateEphemeral(path, content, version); } else { - createOrUpdatePersistent(path, content, stat); + createOrUpdatePersistent(path, content, version); } } @@ -207,9 +207,6 @@ public abstract class AbstractZookeeperClient