You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2019/08/27 01:27:10 UTC

[dubbo] 01/05: Dubbo works as client and call native SC

This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch cloud-native
in repository https://gitbox.apache.org/repos/asf/dubbo.git

commit 5817ac705ff97e94590add9f1a9151c8ec9955c7
Author: ken.lj <ke...@gmail.com>
AuthorDate: Mon Aug 26 21:05:08 2019 +0800

    Dubbo works as client and call native SC
---
 .../org/apache/dubbo/bootstrap/DubboBootstrap.java |  38 +++++--
 .../bootstrap/DubboServiceConsumerBootstrap.java   |   7 +-
 .../cluster/loadbalance/AbstractLoadBalance.java   |   3 +-
 .../support/registry/ZoneAwareClusterInvoker.java  |   6 +-
 .../file/FileSystemDynamicConfiguration.java       |  11 +-
 .../dubbo/common/constants/CommonConstants.java    |   2 +-
 .../dubbo/common/constants/QosConstants.java       |   6 --
 .../dubbo/common/constants/RegistryConstants.java  |   2 +
 .../org/apache/dubbo/common/utils/StringUtils.java |  83 ++++++++++++++
 .../org/apache/dubbo/config/AbstractConfig.java    |   6 +-
 .../org/apache/dubbo/config/ApplicationConfig.java |   9 +-
 .../org/apache/dubbo/config/RegistryConfig.java    |   2 +-
 .../apache/dubbo/config/context/ConfigManager.java |  68 ++++++------
 ...DubboLifecycleComponentApplicationListener.java |   9 +-
 .../zookeeper/ZookeeperDynamicConfiguration.java   |   2 +-
 .../dubbo/metadata/WritableMetadataService.java    |  14 +--
 ...g.apache.dubbo.metadata.WritableMetadataService |   2 +-
 .../client/DefaultServiceDiscoveryFactory.java     |   2 +-
 .../registry/client/ServiceDiscoveryRegistry.java  | 120 +++++++++++++--------
 .../client/event/ServiceInstancesChangedEvent.java |   1 +
 .../listener/ServiceInstancesChangedListener.java  |   8 +-
 .../metadata/ServiceInstanceMetadataUtils.java     |   8 +-
 .../ServiceInstancesChangedListenerTest.java       |   2 +-
 .../registry/consul/ConsulServiceDiscovery.java    |  84 ++++++++++++---
 .../registry/eureka/EurekaServiceDiscovery.java    |   4 +-
 .../zookeeper/ZookeeperServiceDiscoveryTest.java   |   3 +-
 .../java/org/apache/dubbo/rpc/ZoneDetector.java    |   2 +-
 27 files changed, 352 insertions(+), 152 deletions(-)

diff --git a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
index 21fb318..03df012 100644
--- a/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
+++ b/dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java
@@ -21,9 +21,12 @@ import org.apache.dubbo.common.config.Environment;
 import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
 import org.apache.dubbo.common.config.configcenter.wrapper.CompositeDynamicConfiguration;
 import org.apache.dubbo.common.context.Lifecycle;
+import org.apache.dubbo.common.lang.ShutdownHookCallback;
+import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 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.config.ApplicationConfig;
 import org.apache.dubbo.config.ConfigCenterConfig;
 import org.apache.dubbo.config.ConsumerConfig;
@@ -58,6 +61,7 @@ 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.ServiceDiscoveryInitializingEvent;
+import org.apache.dubbo.registry.support.AbstractRegistryFactory;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -79,6 +83,7 @@ import static java.util.Collections.sort;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
 import static org.apache.dubbo.common.config.configcenter.DynamicConfiguration.getDynamicConfiguration;
+import static org.apache.dubbo.common.constants.CommonConstants.METADATA_DEFAULT;
 import static org.apache.dubbo.common.constants.CommonConstants.METADATA_REMOTE;
 import static org.apache.dubbo.common.function.ThrowableAction.execute;
 import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
@@ -137,6 +142,15 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
     private volatile List<ServiceDiscovery> serviceDiscoveries = new LinkedList<>();
 
     public DubboBootstrap() {
+        ShutdownHookCallbacks.INSTANCE.addCallback(new ShutdownHookCallback() {
+            @Override
+            public void callback() throws Throwable {
+                DubboBootstrap.this.destroy();
+            }
+        });
+    }
+
+    public void registerShutdownHook() {
         DubboShutdownHook.getDubboShutdownHook().register();
     }
 
@@ -159,7 +173,11 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
     }
 
     private String getMetadataType() {
-        return configManager.getApplicationOrElseThrow().getMetadataType();
+        String type = configManager.getApplicationOrElseThrow().getMetadataType();
+        if (StringUtils.isEmpty(type)) {
+            type = METADATA_DEFAULT;
+        }
+        return type;
     }
 
     public DubboBootstrap metadataReport(MetadataReportConfig metadataReportConfig) {
@@ -465,16 +483,14 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
     }
 
     private void startMetadataReport() {
-        ApplicationConfig applicationConfig = configManager.getApplication().orElseThrow(
-                () -> new IllegalStateException("There's no ApplicationConfig specified.")
-        );
+        ApplicationConfig applicationConfig = configManager.getApplicationOrElseThrow();
 
         String metadataType = applicationConfig.getMetadataType();
         // FIXME, multiple metadata config support.
         Collection<MetadataReportConfig> metadataReportConfigs = configManager.getMetadataConfigs();
         if (CollectionUtils.isEmpty(metadataReportConfigs)) {
             if (METADATA_REMOTE.equals(metadataType)) {
-                throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when set 'metadata=remote'.");
+                throw new IllegalStateException("No MetadataConfig found, you must specify the remote Metadata Center address when 'metadata=remote' is enabled.");
             }
             return;
         }
@@ -590,7 +606,9 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
             initialize();
         }
         if (!isStarted()) {
-
+            if (logger.isInfoEnabled()) {
+                logger.info(NAME + " is starting...");
+            }
             // 1. export Dubbo Services
             exportServices();
 
@@ -608,7 +626,7 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
             started = true;
 
             if (logger.isInfoEnabled()) {
-                logger.info(NAME + " is starting...");
+                logger.info(NAME + " has started.");
             }
         }
         return this;
@@ -826,6 +844,8 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
 
         stop();
 
+        destroyRegistries();
+
         destroyProtocols();
 
         destroyReferences();
@@ -846,6 +866,10 @@ public class DubboBootstrap extends GenericEventListener implements Lifecycle {
         }
     }
 
+    private void destroyRegistries() {
+        AbstractRegistryFactory.destroyAll();
+    }
+
     private void destroyReferences() {
         configManager.getReferences().forEach(ReferenceConfig::destroy);
         if (logger.isDebugEnabled()) {
diff --git a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
index 4b5fd4b..8427f80 100644
--- a/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
+++ b/dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.bootstrap;
 
 import org.apache.dubbo.bootstrap.rest.UserService;
+import org.apache.dubbo.config.MetadataReportConfig;
 import org.apache.dubbo.config.ReferenceConfig;
 import org.apache.dubbo.config.context.ConfigManager;
 
@@ -33,11 +34,11 @@ public class DubboServiceConsumerBootstrap {
                 .application("dubbo-consumer-demo")
                 .protocol(builder -> builder.port(20887).name("dubbo"))
                 // Eureka
-                .registry(builder -> builder.address("eureka://127.0.0.1:8761?registry-type=service&subscribed-services=dubbo-provider-demo"))
+//                .registry(builder -> builder.address("eureka://127.0.0.1:8761?registry-type=service&subscribed-services=dubbo-provider-demo"))
 
                 // Zookeeper
-                // .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo"))
-                // .metadataReport(new MetadataReportConfig("zookeeper://127.0.0.1:2181"))
+                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo"))
+                .metadataReport(new MetadataReportConfig("zookeeper://127.0.0.1:2181"))
 
                 // Nacos
                 // .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry.type=service&subscribed.services=dubbo-provider-demo"))
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
index 81fd210..d611c7c 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
@@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.cluster.LoadBalance;
 import java.util.List;
 
 import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
 import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP;
 import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT;
 import static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;
@@ -75,7 +76,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
         URL url = invoker.getUrl();
         // Multiple registry scenario, load balance among multiple registries.
         if (url.getServiceInterface().equals("org.apache.dubbo.registry.RegistryService")) {
-            weight = url.getParameter("registry.weight", DEFAULT_WEIGHT);
+            weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT);
         } else {
             weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
             if (weight > 0) {
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
index 9ea9723..b94329a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/registry/ZoneAwareClusterInvoker.java
@@ -30,7 +30,7 @@ import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_KEY;
 import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
 import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE;
 import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_ZONE_FORCE;
@@ -56,9 +56,9 @@ public class ZoneAwareClusterInvoker<T> extends AbstractClusterInvoker<T> {
     @Override
     @SuppressWarnings({"unchecked", "rawtypes"})
     public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
-        // First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'default' key.
+        // First, pick the invoker (XXXClusterInvoker) that comes from the local registry, distinguish by a 'preferred' key.
         for (Invoker<T> invoker : invokers) {
-            if (invoker.isAvailable() && invoker.getUrl().getParameter(REGISTRY_KEY + "." + DEFAULT_KEY, false)) {
+            if (invoker.isAvailable() && invoker.getUrl().getParameter(REGISTRY_KEY + "." + PREFERRED_KEY, false)) {
                 return invoker.invoke(invocation);
             }
         }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
index 603356d..bfd7062 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/file/FileSystemDynamicConfiguration.java
@@ -445,9 +445,14 @@ public class FileSystemDynamicConfiguration extends AbstractDynamicConfiguration
 
     @Override
     public SortedSet<String> getConfigKeys(String group) {
-        return Stream.of(groupDirectory(group).listFiles(File::isFile))
-                .map(File::getName)
-                .collect(TreeSet::new, Set::add, Set::addAll);
+        File[] files = groupDirectory(group).listFiles(File::isFile);
+        if (files == null) {
+            return new TreeSet<>();
+        } else {
+            return Stream.of(files)
+                    .map(File::getName)
+                    .collect(TreeSet::new, Set::add, Set::addAll);
+        }
     }
 
 
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 740d519..9481d5d 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
@@ -167,7 +167,7 @@ public interface CommonConstants {
 
     String METADATA_KEY = "metadata";
 
-    String METADATA_DEFAULT = "default";
+    String METADATA_DEFAULT = "local";
 
     String METADATA_REMOTE = "remote";
 
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java
index cabac0e..62d090e 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/QosConstants.java
@@ -27,10 +27,4 @@ public interface QosConstants {
     String QOS_PORT = "qos.port";
 
     String ACCEPT_FOREIGN_IP = "qos.accept.foreign.ip";
-
-    String QOS_ENABLE_COMPATIBLE = "qos-enable";
-
-    String QOS_PORT_COMPATIBLE = "qos-port";
-
-    String ACCEPT_FOREIGN_IP_COMPATIBLE = "qos-accept-foreign-ip";
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
index eb95169..03eb9b2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/RegistryConstants.java
@@ -81,6 +81,8 @@ public interface RegistryConstants {
      */
     String SUBSCRIBED_SERVICE_NAMES_KEY = "subscribed-services";
 
+    String SUBSCRIBED_PROTOCOL_DEFAULT = "rest";
+
 
     /**
      * The request size of service instances
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
index b51c1bc..53557a3 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
@@ -830,4 +830,87 @@ public final class StringUtils {
             return false;
         }
     }
+
+    public static String[] delimitedListToStringArray(String str, String delimiter) {
+        return delimitedListToStringArray(str, delimiter, (String) null);
+    }
+
+    public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) {
+        if (str == null) {
+            return new String[0];
+        } else if (delimiter == null) {
+            return new String[]{str};
+        } else {
+            List<String> result = new ArrayList();
+            int pos;
+            if ("".equals(delimiter)) {
+                for (pos = 0; pos < str.length(); ++pos) {
+                    result.add(deleteAny(str.substring(pos, pos + 1), charsToDelete));
+                }
+            } else {
+                int delPos;
+                for (pos = 0; (delPos = str.indexOf(delimiter, pos)) != -1; pos = delPos + delimiter.length()) {
+                    result.add(deleteAny(str.substring(pos, delPos), charsToDelete));
+                }
+
+                if (str.length() > 0 && pos <= str.length()) {
+                    result.add(deleteAny(str.substring(pos), charsToDelete));
+                }
+            }
+
+            return toStringArray((Collection) result);
+        }
+    }
+
+    public static String arrayToDelimitedString(Object[] arr, String delim) {
+        if (ArrayUtils.isEmpty(arr)) {
+            return "";
+        } else if (arr.length == 1) {
+            return nullSafeToString(arr[0]);
+        } else {
+            StringBuilder sb = new StringBuilder();
+
+            for (int i = 0; i < arr.length; ++i) {
+                if (i > 0) {
+                    sb.append(delim);
+                }
+
+                sb.append(arr[i]);
+            }
+
+            return sb.toString();
+        }
+    }
+
+    public static String deleteAny(String inString, String charsToDelete) {
+        if (isNotEmpty(inString) && isNotEmpty(charsToDelete)) {
+            StringBuilder sb = new StringBuilder(inString.length());
+
+            for (int i = 0; i < inString.length(); ++i) {
+                char c = inString.charAt(i);
+                if (charsToDelete.indexOf(c) == -1) {
+                    sb.append(c);
+                }
+            }
+
+            return sb.toString();
+        } else {
+            return inString;
+        }
+    }
+
+    public static String[] toStringArray(Collection<String> collection) {
+        return (String[]) collection.toArray(new String[0]);
+    }
+
+    public static String nullSafeToString(Object obj) {
+        if (obj == null) {
+            return "null";
+        } else if (obj instanceof String) {
+            return (String) obj;
+        } else {
+            String str = obj.toString();
+            return str != null ? str : "";
+        }
+    }
 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
index d729644..97984f1 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java
@@ -137,7 +137,7 @@ public abstract class AbstractConfig implements Serializable {
         return value;
     }
 
-    private static String getTagName(Class<?> cls) {
+    public static String getTagName(Class<?> cls) {
         String tag = cls.getSimpleName();
         for (String suffix : SUFFIXES) {
             if (tag.endsWith(suffix)) {
@@ -203,7 +203,9 @@ public abstract class AbstractConfig implements Serializable {
                     if (map != null && map.size() > 0) {
                         String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : "");
                         for (Map.Entry<String, String> entry : map.entrySet()) {
-                            parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());
+                            // TODO, compatibility breaking
+                            // parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue());
+                            parameters.put(pre + entry.getKey(), entry.getValue());
                         }
                     }
                 }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
index bc5b137..5aa46ab 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ApplicationConfig.java
@@ -38,11 +38,8 @@ import static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;
 import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
 import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
-import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP_COMPATIBLE;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
-import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE_COMPATIBLE;
 import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;
-import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT_COMPATIBLE;
 import static org.apache.dubbo.config.Constants.ARCHITECTURE;
 import static org.apache.dubbo.config.Constants.DEVELOPMENT_ENVIRONMENT;
 import static org.apache.dubbo.config.Constants.ENVIRONMENT;
@@ -343,7 +340,7 @@ public class ApplicationConfig extends AbstractConfig {
      *
      * @return
      */
-    @Parameter(key = QOS_ENABLE_COMPATIBLE, excluded = true)
+    @Parameter(key = "qos-enable", excluded = true)
     public Boolean getQosEnableCompatible() {
         return getQosEnable();
     }
@@ -352,7 +349,7 @@ public class ApplicationConfig extends AbstractConfig {
         setQosEnable(qosEnable);
     }
 
-    @Parameter(key = QOS_PORT_COMPATIBLE, excluded = true)
+    @Parameter(key = "qos-port", excluded = true)
     public Integer getQosPortCompatible() {
         return getQosPort();
     }
@@ -361,7 +358,7 @@ public class ApplicationConfig extends AbstractConfig {
         this.setQosPort(qosPort);
     }
 
-    @Parameter(key = ACCEPT_FOREIGN_IP_COMPATIBLE, excluded = true)
+    @Parameter(key = "qos-accept-foreign-ip", excluded = true)
     public Boolean getQosAcceptForeignIpCompatible() {
         return this.getQosAcceptForeignIp();
     }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
index d20c1ab..6f6c0b8 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java
@@ -222,7 +222,7 @@ public class RegistryConfig extends AbstractConfig {
                 updateIdIfAbsent(url.getProtocol());
                 updateProtocolIfAbsent(url.getProtocol());
                 updatePortIfAbsent(url.getPort());
-                setParameters(url.getParameters());
+                updateParameters(url.getParameters());
             } catch (Exception ignored) {
             }
         }
diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
index abb0b0c..edee5ff 100644
--- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
+++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java
@@ -53,6 +53,7 @@ import static java.util.Optional.ofNullable;
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY;
 import static org.apache.dubbo.common.utils.ReflectUtils.getProperty;
 import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
+import static org.apache.dubbo.config.AbstractConfig.getTagName;
 import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
 import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
 
@@ -96,7 +97,7 @@ public class ConfigManager {
 
     private static final ConfigManager CONFIG_MANAGER = new ConfigManager();
 
-    private final Map<Class<? extends AbstractConfig>, Map<String, AbstractConfig>> configsCache = newMap();
+    private final Map<String, Map<String, AbstractConfig>> configsCache = newMap();
 
     private final ReadWriteLock lock = new ReentrantReadWriteLock();
 
@@ -114,7 +115,7 @@ public class ConfigManager {
     }
 
     public Optional<ApplicationConfig> getApplication() {
-        return ofNullable(getConfig(ApplicationConfig.class));
+        return ofNullable(getConfig(getTagName(ApplicationConfig.class)));
     }
 
     public ApplicationConfig getApplicationOrElseThrow() {
@@ -128,7 +129,7 @@ public class ConfigManager {
     }
 
     public Optional<MonitorConfig> getMonitor() {
-        return ofNullable(getConfig(MonitorConfig.class));
+        return ofNullable(getConfig(getTagName(MonitorConfig.class)));
     }
 
     // ModuleConfig correlative methods
@@ -138,7 +139,7 @@ public class ConfigManager {
     }
 
     public Optional<ModuleConfig> getModule() {
-        return ofNullable(getConfig(ModuleConfig.class));
+        return ofNullable(getConfig(getTagName(ModuleConfig.class)));
     }
 
     public void setMetrics(MetricsConfig metrics) {
@@ -146,7 +147,7 @@ public class ConfigManager {
     }
 
     public Optional<MetricsConfig> getMetrics() {
-        return ofNullable(getConfig(MetricsConfig.class));
+        return ofNullable(getConfig(getTagName(MetricsConfig.class)));
     }
 
     // ConfigCenterConfig correlative methods
@@ -160,11 +161,11 @@ public class ConfigManager {
     }
 
     public ConfigCenterConfig getConfigCenter(String id) {
-        return getConfig(ConfigCenterConfig.class, id);
+        return getConfig(getTagName(ConfigCenterConfig.class), id);
     }
 
     public Collection<ConfigCenterConfig> getConfigCenters() {
-        return getConfigs(ConfigCenterConfig.class);
+        return getConfigs(getTagName(ConfigCenterConfig.class));
     }
 
     // MetadataReportConfig correlative methods
@@ -178,7 +179,7 @@ public class ConfigManager {
     }
 
     public Collection<MetadataReportConfig> getMetadataConfigs() {
-        return getConfigs(MetadataReportConfig.class);
+        return getConfigs(getTagName(MetadataReportConfig.class));
     }
 
     // MetadataReportConfig correlative methods
@@ -192,7 +193,7 @@ public class ConfigManager {
     }
 
     public Optional<ProviderConfig> getProvider(String id) {
-        return ofNullable(getConfig(ProviderConfig.class, id));
+        return ofNullable(getConfig(getTagName(ProviderConfig.class), id));
     }
 
     public Optional<ProviderConfig> getDefaultProvider() {
@@ -200,7 +201,7 @@ public class ConfigManager {
     }
 
     public Collection<ProviderConfig> getProviders() {
-        return getConfigs(ProviderConfig.class);
+        return getConfigs(getTagName(ProviderConfig.class));
     }
 
     // ConsumerConfig correlative methods
@@ -214,7 +215,7 @@ public class ConfigManager {
     }
 
     public Optional<ConsumerConfig> getConsumer(String id) {
-        return ofNullable(getConfig(ConsumerConfig.class, id));
+        return ofNullable(getConfig(getTagName(ConsumerConfig.class), id));
     }
 
     public Optional<ConsumerConfig> getDefaultConsumer() {
@@ -222,7 +223,7 @@ public class ConfigManager {
     }
 
     public Collection<ConsumerConfig> getConsumers() {
-        return getConfigs(ConsumerConfig.class);
+        return getConfigs(getTagName(ConsumerConfig.class));
     }
 
     // ProtocolConfig correlative methods
@@ -238,15 +239,15 @@ public class ConfigManager {
     }
 
     public Optional<ProtocolConfig> getProtocol(String id) {
-        return ofNullable(getConfig(ProtocolConfig.class, id));
+        return ofNullable(getConfig(getTagName(ProtocolConfig.class), id));
     }
 
     public List<ProtocolConfig> getDefaultProtocols() {
-        return getDefaultConfigs(getConfigsMap(ProtocolConfig.class));
+        return getDefaultConfigs(getConfigsMap(getTagName(ProtocolConfig.class)));
     }
 
     public Collection<ProtocolConfig> getProtocols() {
-        return getConfigs(ProtocolConfig.class);
+        return getConfigs(getTagName(ProtocolConfig.class));
     }
 
     public Set<String> getProtocolIds() {
@@ -256,7 +257,7 @@ public class ConfigManager {
         protocolIds.addAll(getSubProperties(Environment.getInstance()
                 .getAppExternalConfigurationMap(), PROTOCOLS_SUFFIX));
 
-        protocolIds.addAll(getConfigIds(ProtocolConfig.class));
+        protocolIds.addAll(getConfigIds(getTagName(ProtocolConfig.class)));
         return unmodifiableSet(protocolIds);
     }
 
@@ -274,15 +275,15 @@ public class ConfigManager {
     }
 
     public Optional<RegistryConfig> getRegistry(String id) {
-        return ofNullable(getConfig(RegistryConfig.class, id));
+        return ofNullable(getConfig(getTagName(RegistryConfig.class), id));
     }
 
     public List<RegistryConfig> getDefaultRegistries() {
-        return getDefaultConfigs(getConfigsMap(RegistryConfig.class));
+        return getDefaultConfigs(getConfigsMap(getTagName(RegistryConfig.class)));
     }
 
     public Collection<RegistryConfig> getRegistries() {
-        return getConfigs(RegistryConfig.class);
+        return getConfigs(getTagName(RegistryConfig.class));
     }
 
     public Set<String> getRegistryIds() {
@@ -292,7 +293,7 @@ public class ConfigManager {
         registryIds.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(),
                 REGISTRIES_SUFFIX));
 
-        registryIds.addAll(getConfigIds(RegistryConfig.class));
+        registryIds.addAll(getConfigIds(getTagName(RegistryConfig.class)));
         return unmodifiableSet(registryIds);
     }
 
@@ -307,11 +308,11 @@ public class ConfigManager {
     }
 
     public Collection<ServiceConfig> getServices() {
-        return getConfigs(ServiceConfig.class);
+        return getConfigs(getTagName(ServiceConfig.class));
     }
 
     public <T> ServiceConfig<T> getService(String id) {
-        return getConfig(ServiceConfig.class, id);
+        return getConfig(getTagName(ServiceConfig.class), id);
     }
 
     // ReferenceConfig correlative methods
@@ -325,11 +326,11 @@ public class ConfigManager {
     }
 
     public Collection<ReferenceConfig> getReferences() {
-        return getConfigs(ReferenceConfig.class);
+        return getConfigs(getTagName(ReferenceConfig.class));
     }
 
     public <T> ReferenceConfig<T> getReference(String id) {
-        return getConfig(ReferenceConfig.class, id);
+        return getConfig(getTagName(ReferenceConfig.class), id);
     }
 
     protected static Set<String> getSubProperties(Map<String, String> properties, String prefix) {
@@ -375,29 +376,28 @@ public class ConfigManager {
         if (config == null) {
             return;
         }
-        Class<? extends AbstractConfig> configType = config.getClass();
         write(() -> {
-            Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(configType, type -> newMap());
+            Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> newMap());
             addIfAbsent(config, configsMap, unique);
         });
     }
 
-    protected <C extends AbstractConfig> Map<String, C> getConfigsMap(Class<? extends C> configType) {
-        return read(() -> (Map) configsCache.getOrDefault(configType, emptyMap()));
+    protected <C extends AbstractConfig> Map<String, C> getConfigsMap(String configType) {
+        return (Map<String, C>) read(() -> configsCache.getOrDefault(configType, emptyMap()));
     }
 
-    protected <C extends AbstractConfig> Collection<C> getConfigs(Class<C> configType) {
-        return read(() -> getConfigsMap(configType).values());
+    protected <C extends AbstractConfig> Collection<C> getConfigs(String configType) {
+        return (Collection<C>) read(() -> getConfigsMap(configType).values());
     }
 
-    protected <C extends AbstractConfig> C getConfig(Class<C> configType, String id) {
+    protected <C extends AbstractConfig> C getConfig(String configType, String id) {
         return read(() -> {
             Map<String, C> configsMap = (Map) configsCache.getOrDefault(configType, emptyMap());
             return configsMap.get(id);
         });
     }
 
-    protected <C extends AbstractConfig> C getConfig(Class<C> configType) throws IllegalStateException {
+    protected <C extends AbstractConfig> C getConfig(String configType) throws IllegalStateException {
         return read(() -> {
             Map<String, C> configsMap = (Map) configsCache.getOrDefault(configType, emptyMap());
             int size = configsMap.size();
@@ -405,14 +405,14 @@ public class ConfigManager {
 //                throw new IllegalStateException("No such " + configType.getName() + " is found");
                 return null;
             } else if (size > 1) {
-                throw new IllegalStateException("The expected single matching " + configType.getName() + " but found " + size + " instances");
+                throw new IllegalStateException("The expected single matching " + configType + " but found " + size + " instances");
             } else {
                 return configsMap.values().iterator().next();
             }
         });
     }
 
-    protected <C extends AbstractConfig> Collection<String> getConfigIds(Class<C> configType) {
+    protected <C extends AbstractConfig> Collection<String> getConfigIds(String configType) {
         return getConfigs(configType)
                 .stream()
                 .map(AbstractConfig::getId)
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java
index 11dd51c..d1a71b1 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboLifecycleComponentApplicationListener.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.config.spring.context;
 
 
 import org.apache.dubbo.common.context.Lifecycle;
+import org.apache.dubbo.config.DubboShutdownHook;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationEvent;
@@ -66,7 +67,7 @@ public class DubboLifecycleComponentApplicationListener implements ApplicationLi
     }
 
     protected void onContextClosedEvent(ContextClosedEvent event) {
-        destroyLifecycleComponents();
+        DubboShutdownHook.getDubboShutdownHook().doDestroy();
     }
 
     private void initLifecycleComponents(ContextRefreshedEvent event) {
@@ -92,9 +93,9 @@ public class DubboLifecycleComponentApplicationListener implements ApplicationLi
         lifecycleComponents.forEach(Lifecycle::start);
     }
 
-    private void destroyLifecycleComponents() {
-        lifecycleComponents.forEach(Lifecycle::destroy);
-    }
+//    private void destroyLifecycleComponents() {
+//        lifecycleComponents.forEach(Lifecycle::destroy);
+//    }
 
     /**
      * the specified {@link ApplicationEvent event} must be {@link ApplicationContextEvent} and
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 b36c023..01ab36b 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
@@ -112,7 +112,7 @@ public class ZookeeperDynamicConfiguration implements DynamicConfiguration {
 
     @Override
     public boolean publishConfig(String key, String group, String content) {
-        String path = getPathKey(key, group);
+        String path = getPathKey(group, key);
         zkClient.create(path, content, true);
         return true;
     }
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java
index 67ec3b7..7cfa45c 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/WritableMetadataService.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.metadata.store.InMemoryWritableMetadataService;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 
+import static org.apache.dubbo.common.constants.CommonConstants.METADATA_DEFAULT;
 import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
 
 /**
@@ -30,19 +31,8 @@ import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoad
  *
  * @since 2.7.4
  */
-@SPI("default")
+@SPI(METADATA_DEFAULT)
 public interface WritableMetadataService extends MetadataService {
-
-    /**
-     * The default storage type value as the extension name
-     */
-    public static String DEFAULT_METADATA_STORAGE_TYPE = "default";
-
-    /**
-     * The remote storage type value as the extension name
-     */
-    public static String REMOTE_METADATA_STORAGE_TYPE = "remote";
-
     /**
      * Gets the current Dubbo Service name
      *
diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService
index bf1b63c..1e85044 100644
--- a/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService
+++ b/dubbo-metadata/dubbo-metadata-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metadata.WritableMetadataService
@@ -1,2 +1,2 @@
-default=org.apache.dubbo.metadata.store.InMemoryWritableMetadataService
+local=org.apache.dubbo.metadata.store.InMemoryWritableMetadataService
 remote=org.apache.dubbo.metadata.store.RemoteWritableMetadataServiceDelegate
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceDiscoveryFactory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceDiscoveryFactory.java
index 68e9d86..fd6d770 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceDiscoveryFactory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/DefaultServiceDiscoveryFactory.java
@@ -44,6 +44,6 @@ public class DefaultServiceDiscoveryFactory extends AbstractServiceDiscoveryFact
     protected ServiceDiscovery createDiscovery(URL registryURL) {
         String protocol = registryURL.getProtocol();
         ExtensionLoader<ServiceDiscovery> loader = getExtensionLoader(ServiceDiscovery.class);
-        return loader.getOrDefaultExtension(protocol);
+        return loader.getExtension(protocol);
     }
 }
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 b4ba206..af7ec91 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
@@ -17,6 +17,7 @@
 package org.apache.dubbo.registry.client;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.URLBuilder;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.StringUtils;
@@ -39,6 +40,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -49,11 +51,11 @@ import java.util.stream.Collectors;
 
 import static java.lang.String.format;
 import static java.util.Collections.emptyList;
-import static java.util.Collections.emptySet;
-import static java.util.Collections.unmodifiableSet;
-import static java.util.stream.Collectors.toSet;
 import static java.util.stream.Stream.of;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPERATOR;
 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.PROTOCOL_KEY;
@@ -62,10 +64,12 @@ import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
 import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
 import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;
+import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_PROTOCOL_DEFAULT;
 import static org.apache.dubbo.common.constants.RegistryConstants.SUBSCRIBED_SERVICE_NAMES_KEY;
 import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
 import static org.apache.dubbo.common.function.ThrowableAction.execute;
 import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
+import static org.apache.dubbo.common.utils.CollectionUtils.isEmptyMap;
 import static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty;
 import static org.apache.dubbo.common.utils.StringUtils.isBlank;
 import static org.apache.dubbo.metadata.WritableMetadataService.DEFAULT_EXTENSION;
@@ -99,7 +103,7 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
 
     private final ServiceDiscovery serviceDiscovery;
 
-    private final Set<String> subscribedServices;
+    private final Map<String, String> subscribedServices;
 
     private final ServiceNameMapping serviceNameMapping;
 
@@ -122,13 +126,25 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
      * @param registryURL the specified registry {@link URL url}
      * @return non-null
      */
-    public static Set<String> getSubscribedServices(URL registryURL) {
+    public static Map<String, String> getSubscribedServices(URL registryURL) {
+        Map<String, String> services = new HashMap<>();
         String subscribedServiceNames = registryURL.getParameter(SUBSCRIBED_SERVICE_NAMES_KEY);
-        return isBlank(subscribedServiceNames) ? emptySet() :
-                unmodifiableSet(of(subscribedServiceNames.split(","))
-                        .map(String::trim)
-                        .filter(StringUtils::isNotEmpty)
-                        .collect(toSet()));
+        if (isBlank(subscribedServiceNames)) {
+            return services;
+        } else {
+            of(COMMA_SPLIT_PATTERN.split(subscribedServiceNames))
+                    .map(String::trim)
+                    .filter(StringUtils::isNotEmpty)
+                    .forEach(serviceProtocol -> {
+                        String[] arr = serviceProtocol.split(GROUP_CHAR_SEPERATOR);
+                        if (arr.length > 1) {
+                            services.put(arr[0], arr[1]);
+                        } else {
+                            services.put(arr[0], SUBSCRIBED_PROTOCOL_DEFAULT);
+                        }
+                    });
+        }
+        return services;
     }
 
     /**
@@ -274,9 +290,9 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
 
         writableMetadataService.subscribeURL(url);
 
-        Set<String> serviceNames = getServices(url);
+        Map<String, String> services = getServices(url);
 
-        serviceNames.forEach(serviceName -> subscribeURLs(url, listener, serviceName));
+        services.forEach((name, proto) -> subscribeURLs(url, listener, name));
 
     }
 
@@ -287,7 +303,7 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
         subscribeURLs(url, listener, serviceName, serviceInstances);
 
         // register ServiceInstancesChangedListener
-        registerServiceInstancesChangedListener(new ServiceInstancesChangedListener(serviceName) {
+        registerServiceInstancesChangedListener(new ServiceInstancesChangedListener(serviceName, subscribedServices.get(serviceName)) {
 
             @Override
             public void onEvent(ServiceInstancesChangedEvent event) {
@@ -315,12 +331,12 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
             return;
         }
 
-        List<URL> subscribedURLs = getSubscribedURLs(subscribedURL, serviceInstances);
+        List<URL> subscribedURLs = getSubscribedURLs(subscribedURL, serviceInstances, serviceName);
 
         listener.notify(subscribedURLs);
     }
 
-    private List<URL> getSubscribedURLs(URL subscribedURL, Collection<ServiceInstance> instances) {
+    private List<URL> getSubscribedURLs(URL subscribedURL, Collection<ServiceInstance> instances, String serviceName) {
 
         List<URL> subscribedURLs = new LinkedList<>();
 
@@ -328,7 +344,6 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
         List<ServiceInstance> serviceInstances = instances.stream()
                 .filter(ServiceInstance::isEnabled)
                 .filter(ServiceInstance::isHealthy)
-                .filter(ServiceInstanceMetadataUtils::isDubboServiceInstance)
                 .collect(Collectors.toList());
 
         /**
@@ -337,26 +352,40 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
          */
         Map<String, List<URL>> revisionURLsCache = new HashMap<>();
 
-        // try to get the exported URLs from every instance until it's successful.
-        for (int i = 0; i < serviceInstances.size(); i++) {
-            // select a instance of {@link ServiceInstance}
-            ServiceInstance selectedInstance = selectServiceInstance(serviceInstances);
-            List<URL> templateURLs = getTemplateURLs(subscribedURL, selectedInstance, revisionURLsCache);
-            if (isNotEmpty(templateURLs)) {
-                // add templateURLs into subscribedURLs
-                subscribedURLs.addAll(templateURLs);
-                // remove the selected ServiceInstance in this time, it remains N - 1 elements.
-                serviceInstances.remove(selectedInstance);
-                break;
+        if (ServiceInstanceMetadataUtils.isDubboServiceInstance(serviceInstances.get(0))) {
+            // try to get the exported URLs from every instance until it's successful.
+            for (int i = 0; i < serviceInstances.size(); i++) {
+                // select a instance of {@link ServiceInstance}
+                ServiceInstance selectedInstance = selectServiceInstance(serviceInstances);
+                List<URL> templateURLs = getTemplateURLs(subscribedURL, selectedInstance, revisionURLsCache);
+                if (isNotEmpty(templateURLs)) {
+                    // add templateURLs into subscribedURLs
+                    subscribedURLs.addAll(templateURLs);
+                    // remove the selected ServiceInstance in this time, it remains N - 1 elements.
+                    serviceInstances.remove(selectedInstance);
+                    break;
+                }
             }
-        }
 
-        // Clone the subscribed URLs from the template URLs
-        List<URL> clonedURLs = cloneSubscribedURLs(subscribedURL, serviceInstances, revisionURLsCache);
-        // Add all cloned URLs into subscribedURLs
-        subscribedURLs.addAll(clonedURLs);
-        // clear all revisions
-        revisionURLsCache.clear();
+            // Clone the subscribed URLs from the template URLs
+            List<URL> clonedURLs = cloneSubscribedURLs(subscribedURL, serviceInstances, revisionURLsCache);
+            // Add all cloned URLs into subscribedURLs
+            subscribedURLs.addAll(clonedURLs);
+            // clear all revisions
+            revisionURLsCache.clear();
+        } else {
+            for (ServiceInstance instance : serviceInstances) {
+                URLBuilder builder = new URLBuilder(
+                        subscribedServices.get(serviceName),
+                        instance.getHost(),
+                        instance.getPort(),
+                        subscribedURL.getServiceInterface(),
+                        instance.getMetadata()
+                );
+                builder.addParameter(APPLICATION_KEY, serviceName);
+                subscribedURLs.add(builder.build());
+            }
+        }
         // clear local service instances
         serviceInstances.clear();
 
@@ -506,12 +535,12 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
     }
 
 
-    protected Set<String> getServices(URL subscribedURL) {
-        Set<String> serviceNames = getSubscribedServices();
-        if (isEmpty(serviceNames)) {
-            serviceNames = findMappedServices(subscribedURL);
+    protected Map<String, String> getServices(URL subscribedURL) {
+        Map<String, String> services = getSubscribedServices();
+        if (isEmptyMap(services)) {
+            services = findMappedServices(subscribedURL);
         }
-        return serviceNames;
+        return services;
     }
 
     /**
@@ -519,22 +548,29 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
      *
      * @return non-null
      */
-    public Set<String> getSubscribedServices() {
+    public Map<String, String> getSubscribedServices() {
         return subscribedServices;
     }
 
     /**
      * Get the mapped services name by the specified {@link URL}
      *
+     * Only native Dubbo services rely on this mapping.
+     *
      * @param subscribedURL
      * @return
      */
-    protected Set<String> findMappedServices(URL subscribedURL) {
+    protected Map<String, String> findMappedServices(URL subscribedURL) {
         String serviceInterface = subscribedURL.getServiceInterface();
         String group = subscribedURL.getParameter(GROUP_KEY);
         String version = subscribedURL.getParameter(VERSION_KEY);
         String protocol = subscribedURL.getParameter(PROTOCOL_KEY, DUBBO_PROTOCOL);
-        return serviceNameMapping.get(serviceInterface, group, version, protocol);
+
+        Map<String, String> services = new LinkedHashMap<>();
+        serviceNameMapping.get(serviceInterface, group, version, protocol).forEach(s -> {
+            services.put(s, protocol);
+        });
+        return services;
     }
 
     /**
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/ServiceInstancesChangedEvent.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/ServiceInstancesChangedEvent.java
index daeb8aa..d7d5d4e 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/ServiceInstancesChangedEvent.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/ServiceInstancesChangedEvent.java
@@ -54,6 +54,7 @@ public class ServiceInstancesChangedEvent extends Event {
         return serviceName;
     }
 
+
     /**
      * @return all {@link ServiceInstance service instances}
      */
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 196e322..1377ddd 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
@@ -31,9 +31,11 @@ import java.util.Objects;
 public abstract class ServiceInstancesChangedListener implements ConditionalEventListener<ServiceInstancesChangedEvent> {
 
     private final String serviceName;
+    private final String protocol;
 
-    protected ServiceInstancesChangedListener(String serviceName) {
+    protected ServiceInstancesChangedListener(String serviceName, String protocol) {
         this.serviceName = serviceName;
+        this.protocol = protocol;
     }
 
     /**
@@ -52,6 +54,10 @@ public abstract class ServiceInstancesChangedListener implements ConditionalEven
         return serviceName;
     }
 
+    public String getProtocol() {
+        return protocol;
+    }
+
     /**
      * @param event {@link ServiceInstancesChangedEvent event}
      * @return If service name matches, return <code>true</code>, or <code>false</code>
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 e3f3e4d..98f9d14 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
@@ -30,8 +30,8 @@ import java.util.Map;
 
 import static java.lang.String.valueOf;
 import static java.util.Collections.emptyMap;
+import static org.apache.dubbo.common.constants.CommonConstants.METADATA_DEFAULT;
 import static org.apache.dubbo.common.utils.StringUtils.isBlank;
-import static org.apache.dubbo.metadata.WritableMetadataService.DEFAULT_METADATA_STORAGE_TYPE;
 import static org.apache.dubbo.registry.integration.RegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS;
 
 /**
@@ -187,10 +187,9 @@ public class ServiceInstanceMetadataUtils {
      *
      * @param registryURL the {@link URL} to connect the registry
      * @return if not found in {@link URL#getParameters() parameters} of {@link URL registry URL}, return
-     * {@link WritableMetadataService#DEFAULT_METADATA_STORAGE_TYPE}
      */
     public static String getMetadataStorageType(URL registryURL) {
-        return registryURL.getParameter(METADATA_STORAGE_TYPE_PROPERTY_NAME, DEFAULT_METADATA_STORAGE_TYPE);
+        return registryURL.getParameter(METADATA_STORAGE_TYPE_PROPERTY_NAME, METADATA_DEFAULT);
     }
 
     /**
@@ -198,11 +197,10 @@ public class ServiceInstanceMetadataUtils {
      *
      * @param serviceInstance the specified {@link ServiceInstance}
      * @return if not found in {@link ServiceInstance#getMetadata() metadata} of {@link ServiceInstance}, return
-     * {@link WritableMetadataService#DEFAULT_METADATA_STORAGE_TYPE}
      */
     public static String getMetadataStorageType(ServiceInstance serviceInstance) {
         Map<String, String> metadata = serviceInstance.getMetadata();
-        return metadata.getOrDefault(METADATA_STORAGE_TYPE_PROPERTY_NAME, DEFAULT_METADATA_STORAGE_TYPE);
+        return metadata.getOrDefault(METADATA_STORAGE_TYPE_PROPERTY_NAME, METADATA_DEFAULT);
     }
 
     /**
diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
index c4eedf1..6d167e8 100644
--- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListenerTest.java
@@ -44,7 +44,7 @@ public class ServiceInstancesChangedListenerTest {
 
         AtomicReference<Event> eventRef = new AtomicReference<>();
 
-        eventDispatcher.addEventListener(new ServiceInstancesChangedListener("test") {
+        eventDispatcher.addEventListener(new ServiceInstancesChangedListener("test", "rest") {
             @Override
             public void onEvent(ServiceInstancesChangedEvent event) {
                 eventRef.set(event);
diff --git a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java
index d2ee2bc..6ed9871 100644
--- a/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-consul/src/main/java/org/apache/dubbo/registry/consul/ConsulServiceDiscovery.java
@@ -19,13 +19,14 @@ package org.apache.dubbo.registry.consul;
 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.CollectionUtils;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
+import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.event.EventListener;
 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.metadata.ServiceInstanceMetadataUtils;
 
 import com.ecwid.consul.v1.ConsulClient;
 import com.ecwid.consul.v1.QueryParams;
@@ -34,10 +35,11 @@ import com.ecwid.consul.v1.agent.model.NewService;
 import com.ecwid.consul.v1.health.HealthServicesRequest;
 import com.ecwid.consul.v1.health.model.HealthService;
 
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
@@ -48,14 +50,13 @@ import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import static java.util.concurrent.Executors.newCachedThreadPool;
+import static org.apache.dubbo.common.constants.CommonConstants.SEMICOLON_SPLIT_PATTERN;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.CHECK_PASS_INTERVAL;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_CHECK_PASS_INTERVAL;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_DEREGISTER_TIME;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_PORT;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEFAULT_WATCH_TIMEOUT;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.DEREGISTER_AFTER;
-import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.SERVICE_TAG;
-import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.URL_META_KEY;
 import static org.apache.dubbo.registry.consul.AbstractConsulRegistry.WATCH_TIMEOUT;
 
 /**
@@ -65,6 +66,11 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
 
     private static final Logger logger = LoggerFactory.getLogger(ConsulServiceDiscovery.class);
 
+    private static final String QUERY_TAG = "consul_query_tag";
+    private static final String REGISTER_TAG = "consul_register_tag";
+
+    private List<String> registeringTags = new ArrayList<>();
+    private String tag;
     private ConsulClient client;
     private ExecutorService notifierExecutor = newCachedThreadPool(
             new NamedThreadFactory("dubbo-consul-notifier", true));
@@ -85,7 +91,17 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
         checkPassInterval = url.getParameter(CHECK_PASS_INTERVAL, DEFAULT_CHECK_PASS_INTERVAL);
         client = new ConsulClient(host, port);
         ttlScheduler = new TtlScheduler(checkPassInterval, client);
-        this.url = url;
+        this.tag = registryURL.getParameter(QUERY_TAG);
+        this.registeringTags.addAll(getRegisteringTags(url));
+    }
+
+    private List<String> getRegisteringTags(URL url) {
+        List<String> tags = new ArrayList<>();
+        String rawTag = url.getParameter(REGISTER_TAG);
+        if (StringUtils.isNotEmpty(rawTag)) {
+            tags.addAll(Arrays.asList(SEMICOLON_SPLIT_PATTERN.split(rawTag)));
+        }
+        return tags;
     }
 
     @Override
@@ -125,13 +141,12 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
     private List<ServiceInstance> convert(List<HealthService> services) {
         return services.stream()
                 .map(HealthService::getService)
-                .filter(service -> Objects.nonNull(service) && service.getMeta().containsKey(ServiceInstanceMetadataUtils.METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME))
                 .map(service -> {
                     ServiceInstance instance = new DefaultServiceInstance(
                             service.getService(),
                             service.getAddress(),
                             service.getPort());
-                    instance.getMetadata().putAll(service.getMeta());
+                    instance.getMetadata().putAll(getMetadata(service));
                     return instance;
                 })
                 .collect(Collectors.toList());
@@ -139,13 +154,47 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
 
     private Response<List<HealthService>> getHealthServices(String service, long index, int watchTimeout) {
         HealthServicesRequest request = HealthServicesRequest.newBuilder()
-                .setTag(SERVICE_TAG)
+                .setTag(tag)
                 .setQueryParams(new QueryParams(watchTimeout, index))
                 .setPassing(true)
                 .build();
         return client.getHealthServices(service, request);
     }
 
+    private Map<String, String> getMetadata(HealthService.Service service) {
+        Map<String, String> metadata = service.getMeta();
+        if (CollectionUtils.isEmptyMap(metadata)) {
+            metadata = getScCompatibleMetadata(service.getTags());
+        }
+        return metadata;
+    }
+
+    private Map<String, String> getScCompatibleMetadata(List<String> tags) {
+        LinkedHashMap<String, String> metadata = new LinkedHashMap<>();
+        if (tags != null) {
+            for (String tag : tags) {
+                String[] parts = StringUtils.delimitedListToStringArray(tag, "=");
+                switch (parts.length) {
+                    case 0:
+                        break;
+                    case 1:
+                        metadata.put(parts[0], parts[0]);
+                        break;
+                    case 2:
+                        metadata.put(parts[0], parts[1]);
+                        break;
+                    default:
+                        String[] end = Arrays.copyOfRange(parts, 1, parts.length);
+                        metadata.put(parts[0], StringUtils.arrayToDelimitedString(end, "="));
+                        break;
+                }
+
+            }
+        }
+
+        return metadata;
+    }
+
     private NewService buildService(ServiceInstance serviceInstance) {
         NewService service = new NewService();
         service.setAddress(serviceInstance.getHost());
@@ -154,7 +203,7 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
         service.setName(serviceInstance.getServiceName());
         service.setCheck(buildCheck(serviceInstance));
         service.setTags(buildTags(serviceInstance));
-        service.setMeta(Collections.singletonMap(URL_META_KEY, serviceInstance.toString()));
+        service.setMeta(buildMetadata(serviceInstance));
         return service;
     }
 
@@ -167,10 +216,19 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
         List<String> tags = params.keySet().stream()
                 .map(k -> k + "=" + params.get(k))
                 .collect(Collectors.toList());
-        tags.add(SERVICE_TAG);
+        tags.addAll(registeringTags);
         return tags;
     }
 
+    private Map<String, String> buildMetadata(ServiceInstance serviceInstance) {
+        Map<String, String> metadata = new LinkedHashMap<>();
+        metadata.putAll(getScCompatibleMetadata(registeringTags));
+        if (CollectionUtils.isNotEmptyMap(serviceInstance.getMetadata())) {
+            metadata.putAll(serviceInstance.getMetadata());
+        }
+        return metadata;
+    }
+
     private NewService.Check buildCheck(ServiceInstance serviceInstance) {
         NewService.Check check = new NewService.Check();
         check.setTtl((checkPassInterval / 1000) + "s");
@@ -278,8 +336,8 @@ public class ConsulServiceDiscovery implements ServiceDiscovery, EventListener<S
             @Override
             public void run() {
                 TtlScheduler.this.client.agentCheckPass(this.checkId);
-                if (logger.isInfoEnabled()) {
-                    logger.info("Sending consul heartbeat for: " + this.checkId);
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Sending consul heartbeat for: " + this.checkId);
                 }
             }
 
diff --git a/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java b/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java
index 07fc37d..26c9345 100644
--- a/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java
+++ b/dubbo-registry/dubbo-registry-eureka/src/main/java/org/apache/dubbo/registry/eureka/EurekaServiceDiscovery.java
@@ -60,7 +60,7 @@ public class EurekaServiceDiscovery implements ServiceDiscovery {
 
     private EurekaClient eurekaClient;
 
-    private Set<String> subscribedServices;
+    private Map<String, String> subscribedServices;
 
     /**
      * last apps hash code is used to identify the {@link Applications} is changed or not
@@ -184,7 +184,7 @@ public class EurekaServiceDiscovery implements ServiceDiscovery {
     }
 
     private void dispatchServiceInstancesChangedEvent() {
-        subscribedServices.forEach(serviceName -> {
+        subscribedServices.forEach((serviceName, protocol) -> {
             eventDispatcher.dispatch(new ServiceInstancesChangedEvent(serviceName, getInstances(serviceName)));
         });
     }
diff --git a/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java b/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java
index 5dd975d..6642f1f 100644
--- a/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java
+++ b/dubbo-registry/dubbo-registry-zookeeper/src/test/java/org/apache/dubbo/registry/zookeeper/ZookeeperServiceDiscoveryTest.java
@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
 import static java.util.Arrays.asList;
+import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
 import static org.apache.dubbo.common.utils.NetUtils.getAvailablePort;
 import static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkUtils.generateId;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -126,7 +127,7 @@ public class ZookeeperServiceDiscoveryTest {
         CountDownLatch latch = new CountDownLatch(1);
 
         // Add Listener
-        discovery.addServiceInstancesChangedListener(new ServiceInstancesChangedListener(SERVICE_NAME) {
+        discovery.addServiceInstancesChangedListener(new ServiceInstancesChangedListener(SERVICE_NAME, DUBBO) {
             @Override
             public void onEvent(ServiceInstancesChangedEvent event) {
                 serviceInstances.addAll(event.getServiceInstances());
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ZoneDetector.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ZoneDetector.java
index 934d9d5..9f842f4 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ZoneDetector.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ZoneDetector.java
@@ -19,7 +19,7 @@ package org.apache.dubbo.rpc;
 import org.apache.dubbo.common.extension.SPI;
 
 /**
- * Extend and provide your owen implementation if you want to distribute traffic around registries.
+ * Extend and provide your own implementation if you want to distribute traffic around registries.
  * Please, name it as 'default'
  */
 @SPI