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:09 UTC

[dubbo] branch cloud-native updated (edd37e3 -> 4cf629d)

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

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


    from edd37e3  Dubbo cloud native (#4949)
     new 5817ac7  Dubbo works as client and call native SC
     new 0b0b83f  Merge remote-tracking branch 'origin/cloud-native' into cloud-native
     new f4d72ea  generate urls directly for non-dubbo service instances.
     new 3707e1d  Merge remote-tracking branch 'origin/cloud-native' into cloud-native
     new 4cf629d  generate urls directly for non-dubbo service instances.

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/dubbo/bootstrap/DubboBootstrap.java | 38 +++++++--
 .../bootstrap/DubboServiceConsumerBootstrap.java   | 11 +--
 .../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  | 89 +++++++++++++++-------
 .../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, 335 insertions(+), 142 deletions(-)


[dubbo] 03/05: generate urls directly for non-dubbo service instances.

Posted by li...@apache.org.
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 f4d72ea3ece8a503088d578bd1a166079c97a49b
Author: ken.lj <ke...@gmail.com>
AuthorDate: Tue Aug 27 09:16:58 2019 +0800

    generate urls directly for non-dubbo service instances.
---
 .../registry/client/ServiceDiscoveryRegistry.java  | 26 +++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

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 d41e4bc..0cfa520 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
@@ -38,8 +38,8 @@ import org.apache.dubbo.registry.support.FailbackRegistry;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -52,8 +52,9 @@ import java.util.stream.Collectors;
 import static java.lang.String.format;
 import static java.util.Collections.emptyList;
 import static java.util.stream.Stream.of;
-import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
 import static org.apache.dubbo.common.URLBuilder.from;
+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;
@@ -365,10 +366,25 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
 
         expungeStaleRevisionExportedURLs(serviceInstances);
 
-        initTemplateURLs(subscribedURL, serviceInstances);
+        List<URL> subscribedURLs = new LinkedList<>();
+        if (ServiceInstanceMetadataUtils.isDubboServiceInstance(serviceInstances.get(0))) {
+            initTemplateURLs(subscribedURL, serviceInstances);
+            // Clone the subscribed URLs from the template URLs
+            subscribedURLs = cloneSubscribedURLs(subscribedURL, serviceInstances);
+        } 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());
+            }
+        }
 
-        // Clone the subscribed URLs from the template URLs
-        List<URL> subscribedURLs = cloneSubscribedURLs(subscribedURL, serviceInstances);
         // clear local service instances
         serviceInstances.clear();
         return subscribedURLs;


[dubbo] 02/05: Merge remote-tracking branch 'origin/cloud-native' into cloud-native

Posted by li...@apache.org.
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 0b0b83f962877cbf4d84df4b7ce862cf6d924e7a
Merge: 5817ac7 27ba1c7
Author: ken.lj <ke...@gmail.com>
AuthorDate: Mon Aug 26 21:15:16 2019 +0800

    Merge remote-tracking branch 'origin/cloud-native' into cloud-native
    
    # Conflicts:
    #	dubbo-bootstrap/src/test/java/org/apache/dubbo/bootstrap/DubboServiceConsumerBootstrap.java
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java

 .../DubboServiceProviderMinimumBootstrap.java      |  10 +-
 .../NacosDubboServiceConsumerBootstrap.java        |   4 +-
 .../NacosDubboServiceProviderBootstrap.java        |   4 +-
 ...=> ZookeeperDubboServiceConsumerBootstrap.java} |  20 +-
 ...=> ZookeeperDubboServiceProviderBootstrap.java} |  16 +-
 .../support/nacos/NacosDynamicConfiguration.java   |  71 +++-
 .../nacos/NacosDynamicConfigurationTest.java       |  13 +
 .../dubbo/registry/client/ServiceDiscovery.java    |  13 +-
 .../registry/client/ServiceDiscoveryRegistry.java  | 371 ++++++++++++++-------
 .../CompositeMetadataServiceURLBuilder.java        |   4 +-
 .../metadata/ProtocolPortsMetadataCustomizer.java  |  51 +++
 .../metadata/ServiceInstanceMetadataUtils.java     | 112 ++++---
 .../StandardMetadataServiceURLBuilder.java         |  20 +-
 .../client/metadata/URLRevisionResolver.java       |  58 +++-
 .../metadata/proxy/MetadataServiceProxy.java       | 122 -------
 .../selector/RandomServiceInstanceSelector.java    |   2 +-
 ...dubbo.registry.client.ServiceInstanceCustomizer |   1 +
 dubbo-registry/dubbo-registry-eureka/pom.xml       |  13 +
 18 files changed, 561 insertions(+), 344 deletions(-)

diff --cc dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
index af7ec91,84b5a75..d41e4bc
--- 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
@@@ -37,10 -37,9 +37,9 @@@ import org.apache.dubbo.registry.suppor
  
  import java.util.ArrayList;
  import java.util.Collection;
- import java.util.Collections;
  import java.util.HashMap;
- import java.util.Iterator;
 -import java.util.HashSet;
  import java.util.LinkedHashMap;
++import java.util.HashSet;
  import java.util.LinkedHashSet;
  import java.util.LinkedList;
  import java.util.List;
@@@ -51,13 -51,15 +51,14 @@@ 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.URLBuilder.from;
  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.PID_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.SIDE_KEY;
@@@ -303,7 -297,7 +310,7 @@@ public class ServiceDiscoveryRegistry e
          subscribeURLs(url, listener, serviceName, serviceInstances);
  
          // register ServiceInstancesChangedListener
-         registerServiceInstancesChangedListener(new ServiceInstancesChangedListener(serviceName, subscribedServices.get(serviceName)) {
 -        registerServiceInstancesChangedListener(url, new ServiceInstancesChangedListener(serviceName) {
++        registerServiceInstancesChangedListener(url, new ServiceInstancesChangedListener(serviceName, subscribedServices.get(serviceName)) {
  
              @Override
              public void onEvent(ServiceInstancesChangedEvent event) {
@@@ -336,59 -336,29 +349,28 @@@
          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<>();
- 
          // local service instances could be mutable
          List<ServiceInstance> serviceInstances = instances.stream()
                  .filter(ServiceInstance::isEnabled)
                  .filter(ServiceInstance::isHealthy)
 -                .filter(ServiceInstanceMetadataUtils::isDubboServiceInstance)
                  .collect(Collectors.toList());
  
-         /**
-          * A caches all revisions of exported services in different {@link ServiceInstance}s
-          * associating with the {@link URL urls}
-          */
-         Map<String, List<URL>> revisionURLsCache = new HashMap<>();
- 
-         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;
-                 }
-             }
+         int size = serviceInstances.size();
  
-             // 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());
-             }
+         if (size == 0) {
+             return emptyList();
          }
+ 
+         expungeStaleRevisionExportedURLs(serviceInstances);
+ 
+         initTemplateURLs(subscribedURL, serviceInstances);
+ 
+         // Clone the subscribed URLs from the template URLs
+         List<URL> subscribedURLs = cloneSubscribedURLs(subscribedURL, serviceInstances);
          // clear local service instances
          serviceInstances.clear();
- 
          return subscribedURLs;
      }
  
diff --cc dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java
index 98f9d14,a180cb7..31a3e1d
--- 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
@@@ -28,11 -29,14 +29,14 @@@ import java.util.LinkedHashMap
  import java.util.List;
  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.constants.CommonConstants.APPLICATION_KEY;
+ import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+ import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
  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;
+ import static org.apache.dubbo.rpc.Constants.DEPRECATED_KEY;
  
  /**
   * The Utilities class for the {@link ServiceInstance#getMetadata() metadata of the service instance}


[dubbo] 04/05: Merge remote-tracking branch 'origin/cloud-native' into cloud-native

Posted by li...@apache.org.
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 3707e1de5be96a7a53c778aced37f6cdc42c4868
Merge: f4d72ea edd37e3
Author: ken.lj <ke...@gmail.com>
AuthorDate: Tue Aug 27 09:23:47 2019 +0800

    Merge remote-tracking branch 'origin/cloud-native' into cloud-native
    
    # Conflicts:
    #	dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java

 .../NacosDubboServiceConsumerBootstrap.java        | 13 +---
 .../registry/client/ServiceDiscoveryRegistry.java  | 64 ++++++++++++---
 .../RestProtocolSubscribedURLsSynthesizer.java     | 91 ++++++++++++++++++++++
 .../client/metadata/SubscribedURLsSynthesizer.java | 53 +++++++++++++
 ...istry.client.metadata.SubscribedURLsSynthesizer |  1 +
 5 files changed, 203 insertions(+), 19 deletions(-)

diff --cc dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java
index 0cfa520,581e388..5368b56
--- 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
@@@ -345,12 -341,32 +354,32 @@@ public class ServiceDiscoveryRegistry e
              return;
          }
  
-         List<URL> subscribedURLs = getSubscribedURLs(subscribedURL, serviceInstances, serviceName);
+         List<URL> subscribedURLs = new LinkedList<>();
+ 
+         /**
+          * Add the exported URLs from {@link MetadataService}
+          */
 -        subscribedURLs.addAll(getExportedURLs(subscribedURL, serviceInstances));
++        subscribedURLs.addAll(getExportedURLs(subscribedURL, serviceInstances, serviceName));
+ 
+         if (subscribedURLs.isEmpty()) { // If empty, try to synthesize
+             /**
+              * Add the subscribed URLs that were synthesized
+              */
+             subscribedURLs.addAll(synthesizeSubscribedURLs(subscribedURL, serviceInstances));
+         }
  
          listener.notify(subscribedURLs);
      }
  
-     private List<URL> getSubscribedURLs(URL subscribedURL, Collection<ServiceInstance> instances, String serviceName) {
+     /**
+      * Get the exported {@link URL URLs} from the  {@link MetadataService} in the specified
+      * {@link ServiceInstance service instances}
+      *
+      * @param subscribedURL the subscribed {@link URL url}
+      * @param instances     {@link ServiceInstance service instances}
+      * @return the exported {@link URL URLs} if present, or <code>{@link Collections#emptyList() empty list}</code>
+      */
 -    private List<URL> getExportedURLs(URL subscribedURL, Collection<ServiceInstance> instances) {
++    private List<URL> getExportedURLs(URL subscribedURL, Collection<ServiceInstance> instances, String serviceName) {
  
          // local service instances could be mutable
          List<ServiceInstance> serviceInstances = instances.stream()
@@@ -683,13 -685,28 +712,28 @@@
          return exportedURLs;
      }
  
+     /**
+      * Synthesize new subscribed {@link URL URLs} from old one
+      *
+      * @param subscribedURL
+      * @param serviceInstances
+      * @return non-null
+      */
+     private Collection<? extends URL> synthesizeSubscribedURLs(URL subscribedURL, Collection<ServiceInstance> serviceInstances) {
+         return subscribedURLsSynthesizers.stream()
+                 .filter(synthesizer -> synthesizer.supports(subscribedURL))
+                 .map(synthesizer -> synthesizer.synthesize(subscribedURL, serviceInstances))
+                 .flatMap(Collection::stream)
+                 .collect(Collectors.toList());
+     }
+ 
  
 -    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;
      }
  
      /**


[dubbo] 05/05: generate urls directly for non-dubbo service instances.

Posted by li...@apache.org.
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 4cf629d96a520d7afea0ac15256e273ab3ca669a
Author: ken.lj <ke...@gmail.com>
AuthorDate: Tue Aug 27 09:26:55 2019 +0800

    generate urls directly for non-dubbo service instances.
---
 .../org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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 5368b56..e728727 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
@@ -76,6 +76,7 @@ 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.DubboServiceLoader.loadServices;
 import static org.apache.dubbo.common.utils.StringUtils.isBlank;
 import static org.apache.dubbo.metadata.WritableMetadataService.DEFAULT_EXTENSION;
 import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension;
@@ -399,7 +400,7 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
         if (ServiceInstanceMetadataUtils.isDubboServiceInstance(serviceInstances.get(0))) {
             initTemplateURLs(subscribedURL, serviceInstances);
             // Clone the subscribed URLs from the template URLs
-            subscribedURLs = cloneSubscribedURLs(subscribedURL, serviceInstances);
+            subscribedURLs = cloneExportedURLs(subscribedURL, serviceInstances);
         } else {
             for (ServiceInstance instance : serviceInstances) {
                 URLBuilder builder = new URLBuilder(


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

Posted by li...@apache.org.
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