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

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


The following commit(s) were added to refs/heads/2.7.3-release by this push:
     new 1bf5fce  Nacos registry enhancement & register reference bean (#4454)
1bf5fce is described below

commit 1bf5fceb13e6332c83332a6d991eebcedb60666b
Author: Mercy Ma <[email protected]>
AuthorDate: Thu Jul 4 09:39:58 2019 +0800

    Nacos registry enhancement & register reference bean (#4454)
    
    fixes #4439, #4455
---
 dubbo-bom/pom.xml                                  |   4 +-
 .../org/apache/dubbo/common/bytecode/Proxy.java    |   2 +-
 .../dubbo/common/extension/ExtensionLoader.java    |   2 +-
 .../org/apache/dubbo/common/utils/NetUtils.java    |   2 +-
 .../apache/dubbo/config/annotation/Reference.java  |  25 ++-
 .../AnnotationInjectedBeanPostProcessor.java       |   8 +-
 .../ReferenceAnnotationBeanPostProcessor.java      |  92 +++++++-
 .../ReferenceAnnotationBeanPostProcessorTest.java  |  22 +-
 .../spring/context/annotation/EnableDubboTest.java |   5 +
 .../annotation/consumer/ConsumerConfiguration.java |  12 ++
 .../consumer/test/TestConsumerConfiguration.java   |   8 +
 .../DubboComponentScanRegistrarTest.java           |   2 +
 .../registry/multicast/MulticastRegistry.java      |   4 +-
 .../apache/dubbo/registry/nacos/NacosRegistry.java | 100 +++++----
 .../dubbo/registry/nacos/NacosRegistryFactory.java |   2 +-
 .../dubbo/registry/nacos/NacosServiceName.java     | 239 +++++++++++++++++++++
 .../consumer/DemoServiceConsumerXmlBootstrap.java  |  10 +-
 .../dubbo/registry/nacos/NacosServiceNameTest.java | 123 +++++++++++
 .../META-INF/spring/dubbo-consumer-context.xml     |  14 +-
 .../META-INF/spring/dubbo-provider-context.xml     |   3 +-
 .../apache/dubbo/rpc/filter/ActiveLimitFilter.java |   4 +-
 21 files changed, 622 insertions(+), 61 deletions(-)

diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml
index 3ba9eb2..5ab6604 100644
--- a/dubbo-bom/pom.xml
+++ b/dubbo-bom/pom.xml
@@ -44,8 +44,8 @@
         <url>https://github.com/apache/dubbo</url>
         <connection>scm:git:https://github.com/apache/dubbo.git</connection>
         
<developerConnection>scm:git:https://github.com/apache/dubbo.git</developerConnection>
-      <tag>HEAD</tag>
-  </scm>
+        <tag>HEAD</tag>
+    </scm>
     <mailingLists>
         <mailingList>
             <name>Development List</name>
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
index 2da2818..808a859 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
@@ -102,7 +102,7 @@ public abstract class Proxy {
         String key = sb.toString();
 
         // get cache by class loader.
-        Map<String, Object> cache;
+        final Map<String, Object> cache;
         synchronized (PROXY_CACHE_MAP) {
             cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new HashMap<>());
         }
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index ff1f6d6..c09d493 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@ -342,7 +342,7 @@ public class ExtensionLoader<T> {
         if ("true".equals(name)) {
             return getDefaultExtension();
         }
-        Holder<Object> holder = getOrCreateHolder(name);
+        final Holder<Object> holder = getOrCreateHolder(name);
         Object instance = holder.get();
         if (instance == null) {
             synchronized (holder) {
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
index bef5183..c3884e0 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
@@ -37,9 +37,9 @@ import java.util.concurrent.ThreadLocalRandom;
 import java.util.regex.Pattern;
 
 import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static 
org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
 import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
 import static 
org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
-import static 
org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
 
 /**
  * IP and Port Helper for RPC
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Reference.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Reference.java
index f5d09d3..d7d9046 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Reference.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/annotation/Reference.java
@@ -30,6 +30,7 @@ import java.lang.annotation.Target;
  * Reference
  *
  * @export
+ * @since 2.7.0
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
@@ -228,32 +229,35 @@ public @interface Reference {
     String[] parameters() default {};
 
     /**
-     * Application spring bean name
+     * Application associated name
      */
     String application() default "";
 
     /**
-     * Module spring bean name
+     * Module associated name
      */
     String module() default "";
 
     /**
-     * Consumer spring bean name
+     * Consumer associated name
      */
     String consumer() default "";
 
     /**
-     * Monitor spring bean name
+     * Monitor associated name
      */
     String monitor() default "";
 
     /**
-     * Registry spring bean name
+     * Registry associated name
      */
     String[] registry() default {};
 
     /**
-     * Protocol spring bean names
+     * The communication protocol of Dubbo Service
+     *
+     * @return the default value is ""
+     * @since 2.6.6
      */
     String protocol() default "";
 
@@ -264,7 +268,16 @@ public @interface Reference {
 
     /**
      * methods support
+     *
      * @return
      */
     Method[] methods() default {};
+
+    /**
+     * The id
+     *
+     * @return default value is empty
+     * @since 2.7.3
+     */
+    String id() default "";
 }
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
index de56d29..aed3a5a 100644
--- 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
+++ 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java
@@ -26,6 +26,7 @@ import 
org.springframework.beans.factory.BeanCreationException;
 import org.springframework.beans.factory.BeanFactory;
 import org.springframework.beans.factory.BeanFactoryAware;
 import org.springframework.beans.factory.DisposableBean;
+import 
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
 import org.springframework.beans.factory.annotation.InjectionMetadata;
 import org.springframework.beans.factory.config.BeanPostProcessor;
 import 
org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -91,7 +92,12 @@ public abstract class AnnotationInjectedBeanPostProcessor 
extends
 
     private ClassLoader classLoader;
 
-    private int order = Ordered.LOWEST_PRECEDENCE;
+    /**
+     * make sure higher priority than {@link 
AutowiredAnnotationBeanPostProcessor}
+     *
+     * @revision 2.7.3
+     */
+    private int order = Ordered.LOWEST_PRECEDENCE - 3;
 
     /**
      * @param annotationTypes the multiple types of {@link Annotation 
annotations}
diff --git 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
index d477c58..834939a 100644
--- 
a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
+++ 
b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java
@@ -24,6 +24,9 @@ import org.apache.dubbo.config.spring.util.AnnotationUtils;
 
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.annotation.InjectionMetadata;
+import 
org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.ApplicationEvent;
@@ -43,6 +46,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 import static 
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceBeanNameBuilder.create;
+import static org.apache.dubbo.config.spring.util.AnnotationUtils.getAttribute;
+import static org.springframework.util.StringUtils.hasText;
 
 /**
  * {@link org.springframework.beans.factory.config.BeanPostProcessor} 
implementation
@@ -120,13 +125,96 @@ public class ReferenceAnnotationBeanPostProcessor extends 
AnnotationInjectedBean
 
         String referencedBeanName = buildReferencedBeanName(attributes, 
injectedType);
 
-        ReferenceBean referenceBean = 
buildReferenceBeanIfAbsent(referencedBeanName, attributes, injectedType, 
getClassLoader());
+        ReferenceBean referenceBean = 
buildReferenceBeanIfAbsent(referencedBeanName, attributes, injectedType);
+
+        registerReferenceBean(referencedBeanName, referenceBean, attributes, 
injectedType);
 
         cacheInjectedReferenceBean(referenceBean, injectedElement);
 
         return buildProxy(referencedBeanName, referenceBean, injectedType);
     }
 
+    /**
+     * Register an instance of {@link ReferenceBean} as a Spring Bean
+     *
+     * @param referencedBeanName the referenced bean name
+     * @param referenceBean      the instance of {@link ReferenceBean}
+     * @param attributes         the {@link AnnotationAttributes attributes} 
of {@link Reference @Reference}
+     * @param interfaceClass     the {@link Class class} of Service interface
+     * @since 2.7.3
+     */
+    private void registerReferenceBean(String referencedBeanName, 
ReferenceBean referenceBean,
+                                       AnnotationAttributes attributes,
+                                       Class<?> interfaceClass) {
+
+        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
+
+        String beanName = getReferenceBeanName(attributes, interfaceClass);
+
+        if (beanFactory.containsBean(referencedBeanName)) { // If @Service 
bean is local one
+            /**
+             * Get  the @Service's BeanDefinition from {@link BeanFactory}
+             * Refer to {@link 
ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition}
+             */
+            AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) 
beanFactory.getBeanDefinition(referencedBeanName);
+            RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) 
beanDefinition.getPropertyValues().get("ref");
+            // The name of bean annotated @Service
+            String serviceBeanName = runtimeBeanReference.getBeanName();
+            // register Alias rather than a new bean name, in order to reduce 
duplicated beans
+            beanFactory.registerAlias(serviceBeanName, beanName);
+        } else { // Remote @Service Bean
+            if (!beanFactory.containsBean(beanName)) {
+                beanFactory.registerSingleton(beanName, referenceBean);
+            }
+        }
+    }
+
+    /**
+     * Get the bean name of {@link ReferenceBean} if {@link Reference#id() id 
attribute} is present,
+     * or {@link #generateReferenceBeanName(AnnotationAttributes, Class) 
generate}.
+     *
+     * @param attributes     the {@link AnnotationAttributes attributes} of 
{@link Reference @Reference}
+     * @param interfaceClass the {@link Class class} of Service interface
+     * @return non-null
+     * @since 2.7.3
+     */
+    private String getReferenceBeanName(AnnotationAttributes attributes, 
Class<?> interfaceClass) {
+        // id attribute appears since 2.7.3
+        String beanName = getAttribute(attributes, "id");
+        if (!hasText(beanName)) {
+            beanName = generateReferenceBeanName(attributes, interfaceClass);
+        }
+        return beanName;
+    }
+
+    /**
+     * Build the bean name of {@link ReferenceBean}
+     *
+     * @param attributes     the {@link AnnotationAttributes attributes} of 
{@link Reference @Reference}
+     * @param interfaceClass the {@link Class class} of Service interface
+     * @return
+     * @since 2.7.3
+     */
+    private String generateReferenceBeanName(AnnotationAttributes attributes, 
Class<?> interfaceClass) {
+        StringBuilder beanNameBuilder = new StringBuilder("@Reference");
+
+        if (!attributes.isEmpty()) {
+            beanNameBuilder.append('(');
+            for (Map.Entry<String, Object> entry : attributes.entrySet()) {
+                beanNameBuilder.append(entry.getKey())
+                        .append('=')
+                        .append(entry.getValue())
+                        .append(',');
+            }
+            // replace the latest "," to be ")"
+            beanNameBuilder.setCharAt(beanNameBuilder.lastIndexOf(","), ')');
+        }
+
+        beanNameBuilder.append(" ").append(interfaceClass.getName());
+
+        return beanNameBuilder.toString();
+    }
+
     private Object buildProxy(String referencedBeanName, ReferenceBean 
referenceBean, Class<?> injectedType) {
         InvocationHandler handler = buildInvocationHandler(referencedBeanName, 
referenceBean);
         return Proxy.newProxyInstance(getClassLoader(), new 
Class[]{injectedType}, handler);
@@ -199,7 +287,7 @@ public class ReferenceAnnotationBeanPostProcessor extends 
AnnotationInjectedBean
     }
 
     private ReferenceBean buildReferenceBeanIfAbsent(String 
referencedBeanName, AnnotationAttributes attributes,
-                                                     Class<?> referencedType, 
ClassLoader classLoader)
+                                                     Class<?> referencedType)
             throws Exception {
 
         ReferenceBean<?> referenceBean = 
referenceBeanCache.get(referencedBeanName);
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
index 1ee01dc..5e904a6 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
@@ -80,10 +80,27 @@ public class ReferenceAnnotationBeanPostProcessorTest {
         Assert.assertNotNull(testBean.getDemoServiceFromAncestor());
         Assert.assertNotNull(testBean.getDemoServiceFromParent());
         Assert.assertNotNull(testBean.getDemoService());
+        Assert.assertNotNull(testBean.autowiredDemoService);
 
         Assert.assertEquals("Hello,Mercy", 
testBean.getDemoServiceFromAncestor().sayName("Mercy"));
         Assert.assertEquals("Hello,Mercy", 
testBean.getDemoServiceFromParent().sayName("Mercy"));
         Assert.assertEquals("Hello,Mercy", 
testBean.getDemoService().sayName("Mercy"));
+        Assert.assertEquals("Hello,Mercy", 
testBean.autowiredDemoService.sayName("Mercy"));
+
+        DemoService myDemoService = context.getBean("my-reference-bean", 
DemoService.class);
+
+        Assert.assertEquals("Hello,Mercy", myDemoService.sayName("Mercy"));
+
+        Map<String, DemoService> demoServicesMap = 
context.getBeansOfType(DemoService.class);
+
+        Assert.assertEquals(1, demoServicesMap.size());
+
+        for (DemoService demoService1 : demoServicesMap.values()) {
+
+            Assert.assertEquals(myDemoService, demoService1);
+
+            Assert.assertEquals("Hello,Mercy", demoService1.sayName("Mercy"));
+        }
 
     }
 
@@ -194,7 +211,7 @@ public class ReferenceAnnotationBeanPostProcessorTest {
             return demoServiceFromAncestor;
         }
 
-        @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
+        @Reference(id = "my-reference-bean", version = "2.5.7", url = 
"dubbo://127.0.0.1:12345")
         public void setDemoServiceFromAncestor(DemoService 
demoServiceFromAncestor) {
             this.demoServiceFromAncestor = demoServiceFromAncestor;
         }
@@ -223,6 +240,9 @@ public class ReferenceAnnotationBeanPostProcessorTest {
         private DemoService demoService;
 
         @Autowired
+        private DemoService autowiredDemoService;
+
+        @Autowired
         private ApplicationContext applicationContext;
 
         public DemoService getDemoService() {
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
index b611989..077464e 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java
@@ -100,6 +100,11 @@ public class EnableDubboTest {
 
         Assertions.assertEquals("Hello,Mercy", value);
 
+        DemoService autowiredDemoService = 
consumerConfiguration.getAutowiredDemoService();
+
+        Assertions.assertEquals("Hello,Mercy", 
autowiredDemoService.sayName("Mercy"));
+
+
         TestConsumerConfiguration.Child child = 
context.getBean(TestConsumerConfiguration.Child.class);
 
         // From Child
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java
index c12d4d3..47c90e4 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.config.annotation.Reference;
 import org.apache.dubbo.config.spring.api.DemoService;
 import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.PropertySource;
@@ -63,6 +64,9 @@ public class ConsumerConfiguration {
         return registryConfig;
     }
 
+    @Autowired
+    private DemoService autowiredDemoService;
+
     @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
     private DemoService demoService;
 
@@ -111,9 +115,17 @@ public class ConsumerConfiguration {
 
     public static class Child extends Parent {
 
+        @Autowired
+        private DemoService demoService;
+
         @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
         private DemoService demoServiceFromChild;
 
+
+        public DemoService getDemoService() {
+            return demoService;
+        }
+
         public DemoService getDemoServiceFromChild() {
             return demoServiceFromChild;
         }
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java
index 2317545..82960ef 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java
@@ -20,6 +20,7 @@ import org.apache.dubbo.config.annotation.Reference;
 import org.apache.dubbo.config.spring.api.DemoService;
 import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.PropertySource;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -37,6 +38,13 @@ public class TestConsumerConfiguration {
     @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application 
= "dubbo-demo-application")
     private DemoService demoService;
 
+    @Autowired
+    private DemoService autowiredDemoService;
+
+    public DemoService getAutowiredDemoService() {
+        return autowiredDemoService;
+    }
+
     public DemoService getDemoService() {
         return demoService;
     }
diff --git 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java
 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java
index 5d28adf..6ed8a85 100644
--- 
a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java
+++ 
b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java
@@ -86,6 +86,8 @@ public class DubboComponentScanRegistrarTest {
 
         Assertions.assertEquals("Hello,Mercy", value);
 
+        Assertions.assertEquals("Hello,Mercy", 
child.getDemoService().sayName("Mercy"));
+
         // From Parent
 
         demoService = child.getDemoServiceFromParent();
diff --git 
a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java
 
b/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java
index 27aded1..0c28445 100644
--- 
a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java
+++ 
b/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java
@@ -263,7 +263,7 @@ public class MulticastRegistry extends FailbackRegistry {
     }
 
     @Override
-    public void doSubscribe(URL url, NotifyListener listener) {
+    public void doSubscribe(URL url, final NotifyListener listener) {
         if (ANY_VALUE.equals(url.getServiceInterface())) {
             admin = true;
         }
@@ -324,7 +324,7 @@ public class MulticastRegistry extends FailbackRegistry {
                 }
                 urls.add(url);
                 List<URL> list = toList(urls);
-                for (NotifyListener listener : entry.getValue()) {
+                for (final NotifyListener listener : entry.getValue()) {
                     notify(key, listener, list);
                     synchronized (listener) {
                         listener.notify();
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
 
b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
index 24b55c0..c396455 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java
@@ -17,7 +17,6 @@
 package org.apache.dubbo.registry.nacos;
 
 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.UrlUtils;
@@ -36,16 +35,21 @@ import org.apache.commons.lang3.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
+import static java.util.Collections.singleton;
 import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
@@ -56,10 +60,10 @@ import static 
org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
 import static 
org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
 import static 
org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
 import static 
org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
-import static 
org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
 import static 
org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
 import static 
org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;
 import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
+import static org.apache.dubbo.registry.nacos.NacosServiceName.valueOf;
 
 /**
  * Nacos {@link Registry}
@@ -134,10 +138,10 @@ public class NacosRegistry extends FailbackRegistry {
     public List<URL> lookup(final URL url) {
         final List<URL> urls = new LinkedList<>();
         execute(namingService -> {
-            List<String> serviceNames = getServiceNames(url, null);
+            Set<String> serviceNames = getServiceNames(url, null);
             for (String serviceName : serviceNames) {
                 List<Instance> instances = 
namingService.getAllInstances(serviceName);
-                urls.addAll(buildURLs(url, serviceName, instances));
+                urls.addAll(buildURLs(url, instances));
             }
         });
         return urls;
@@ -161,15 +165,15 @@ public class NacosRegistry extends FailbackRegistry {
 
     @Override
     public void doSubscribe(final URL url, final NotifyListener listener) {
-        List<String> serviceNames = getServiceNames(url, listener);
+        Set<String> serviceNames = getServiceNames(url, listener);
         doSubscribe(url, listener, serviceNames);
     }
 
-    private void doSubscribe(final URL url, final NotifyListener listener, 
final List<String> serviceNames) {
+    private void doSubscribe(final URL url, final NotifyListener listener, 
final Set<String> serviceNames) {
         execute(namingService -> {
             for (String serviceName : serviceNames) {
                 List<Instance> instances = 
namingService.getAllInstances(serviceName);
-                notifySubscriber(url, serviceName, listener, instances);
+                notifySubscriber(url, listener, instances);
                 subscribeEventListener(serviceName, url, listener);
             }
         });
@@ -195,15 +199,47 @@ public class NacosRegistry extends FailbackRegistry {
      * @param listener {@link NotifyListener}
      * @return non-null
      */
-    private List<String> getServiceNames(URL url, NotifyListener listener) {
+    private Set<String> getServiceNames(URL url, NotifyListener listener) {
         if (isAdminProtocol(url)) {
             scheduleServiceNamesLookup(url, listener);
             return getServiceNamesForOps(url);
         } else {
-            return doGetServiceNames(url);
+            return getServiceNames0(url);
         }
     }
 
+    private Set<String> getServiceNames0(URL url) {
+        NacosServiceName serviceName = createServiceName(url);
+
+        final Set<String> serviceNames;
+
+        if (serviceName.isConcrete()) { // is the concrete service name
+            serviceNames = singleton(serviceName.toString());
+        } else {
+            serviceNames = filterServiceNames(serviceName);
+        }
+
+        return serviceNames;
+    }
+
+    private Set<String> filterServiceNames(NacosServiceName serviceName) {
+        Set<String> serviceNames = new LinkedHashSet<>();
+
+        execute(namingService -> {
+
+            serviceNames.addAll(namingService.getServicesOfServer(1, 
Integer.MAX_VALUE).getData()
+                    .stream()
+                    .map(NacosServiceName::new)
+                    .filter(serviceName::isCompatible)
+                    .map(NacosServiceName::toString)
+                    .collect(Collectors.toList()));
+
+        });
+
+        return serviceNames;
+    }
+
+
     private boolean isAdminProtocol(URL url) {
         return ADMIN_PROTOCOL.equals(url.getProtocol());
     }
@@ -212,7 +248,7 @@ public class NacosRegistry extends FailbackRegistry {
         if (scheduledExecutorService == null) {
             scheduledExecutorService = 
Executors.newSingleThreadScheduledExecutor();
             scheduledExecutorService.scheduleAtFixedRate(() -> {
-                List<String> serviceNames = getAllServiceNames();
+                Set<String> serviceNames = getAllServiceNames();
                 filterData(serviceNames, serviceName -> {
                     boolean accepted = false;
                     for (String category : ALL_SUPPORTED_CATEGORIES) {
@@ -235,15 +271,15 @@ public class NacosRegistry extends FailbackRegistry {
      * @param url {@link URL}
      * @return non-null
      */
-    private List<String> getServiceNamesForOps(URL url) {
-        List<String> serviceNames = getAllServiceNames();
+    private Set<String> getServiceNamesForOps(URL url) {
+        Set<String> serviceNames = getAllServiceNames();
         filterServiceNames(serviceNames, url);
         return serviceNames;
     }
 
-    private List<String> getAllServiceNames() {
+    private Set<String> getAllServiceNames() {
 
-        final List<String> serviceNames = new LinkedList<>();
+        final Set<String> serviceNames = new LinkedHashSet<>();
 
         execute(namingService -> {
 
@@ -273,15 +309,15 @@ public class NacosRegistry extends FailbackRegistry {
         return serviceNames;
     }
 
-    private void filterServiceNames(List<String> serviceNames, URL url) {
+    private void filterServiceNames(Set<String> serviceNames, URL url) {
 
         final String[] categories = getCategories(url);
 
         final String targetServiceInterface = url.getServiceInterface();
 
-        final String targetVersion = url.getParameter(VERSION_KEY,"");
+        final String targetVersion = url.getParameter(VERSION_KEY, "");
 
-        final String targetGroup = url.getParameter(GROUP_KEY,"");
+        final String targetGroup = url.getParameter(GROUP_KEY, "");
 
         filterData(serviceNames, serviceName -> {
             // split service name to segments
@@ -323,6 +359,7 @@ public class NacosRegistry extends FailbackRegistry {
         collection.removeIf(data -> !filter.accept(data));
     }
 
+    @Deprecated
     private List<String> doGetServiceNames(URL url) {
         String[] categories = getCategories(url);
         List<String> serviceNames = new ArrayList<>(categories.length);
@@ -333,9 +370,9 @@ public class NacosRegistry extends FailbackRegistry {
         return serviceNames;
     }
 
-    private List<URL> buildURLs(URL consumerURL, String serviceName, 
Collection<Instance> instances) {
+    private List<URL> buildURLs(URL consumerURL, Collection<Instance> 
instances) {
         if (instances.isEmpty()) {
-            return emptyURL(consumerURL, serviceName);
+            return Collections.emptyList();
         }
         List<URL> urls = new LinkedList<>();
         for (Instance instance : instances) {
@@ -353,7 +390,7 @@ public class NacosRegistry extends FailbackRegistry {
             EventListener eventListener = event -> {
                 if (event instanceof NamingEvent) {
                     NamingEvent e = (NamingEvent) event;
-                    notifySubscriber(url, serviceName, listener, 
e.getInstances());
+                    notifySubscriber(url, listener, e.getInstances());
                 }
             };
             namingService.subscribe(serviceName, eventListener);
@@ -365,15 +402,14 @@ public class NacosRegistry extends FailbackRegistry {
      * Notify the Healthy {@link Instance instances} to subscriber.
      *
      * @param url       {@link URL}
-     * @param serviceName
      * @param listener  {@link NotifyListener}
      * @param instances all {@link Instance instances}
      */
-    private void notifySubscriber(URL url, String serviceName, NotifyListener 
listener, Collection<Instance> instances) {
+    private void notifySubscriber(URL url, NotifyListener listener, 
Collection<Instance> instances) {
         List<Instance> healthyInstances = new LinkedList<>(instances);
         // Healthy Instances
         filterHealthyInstances(healthyInstances);
-        List<URL> urls = buildURLs(url, serviceName, healthyInstances);
+        List<URL> urls = buildURLs(url, healthyInstances);
         NacosRegistry.this.notify(url, listener, urls);
     }
 
@@ -385,7 +421,7 @@ public class NacosRegistry extends FailbackRegistry {
      */
     private String[] getCategories(URL url) {
         return ANY_VALUE.equals(url.getServiceInterface()) ?
-                ALL_SUPPORTED_CATEGORIES : url.getParameter(CATEGORY_KEY,new 
String[]{DEFAULT_CATEGORY});
+                ALL_SUPPORTED_CATEGORIES : of(DEFAULT_CATEGORY);
     }
 
     private URL buildURL(Instance instance) {
@@ -399,18 +435,6 @@ public class NacosRegistry extends FailbackRegistry {
                 instance.getMetadata());
     }
 
-    private List<URL> emptyURL(URL consumerURL, String serviceName) {
-        int i = serviceName.indexOf(SERVICE_NAME_SEPARATOR);
-        String category = i < 0 ? serviceName : serviceName.substring(0, i);
-        URL empty = URLBuilder.from(consumerURL)
-                .setProtocol(EMPTY_PROTOCOL)
-                .addParameter(CATEGORY_KEY, category)
-                .build();
-        List<URL> result = new ArrayList<URL>();
-        result.add(empty);
-        return result;
-    }
-
     private Instance createInstance(URL url) {
         // Append default category if absent
         String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
@@ -426,6 +450,10 @@ public class NacosRegistry extends FailbackRegistry {
         return instance;
     }
 
+    private NacosServiceName createServiceName(URL url) {
+        return valueOf(url);
+    }
+
     private String getServiceName(URL url) {
         String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
         return getServiceName(url, category);
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java
 
b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java
index d702acf..1e9ed65 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java
@@ -101,7 +101,7 @@ public class NacosRegistryFactory extends 
AbstractRegistryFactory {
 
     private void putPropertyIfAbsent(URL url, Properties properties, String 
propertyName) {
         String propertyValue = url.getParameter(propertyName);
-        if (StringUtils.isNotEmpty(propertyValue)) {
+        if (propertyValue != null && propertyValue.trim().length() != 0) {
             properties.setProperty(propertyName, propertyValue);
         }
     }
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java
 
b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java
new file mode 100644
index 0000000..cae9f19
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosServiceName.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.registry.nacos;
+
+import org.apache.dubbo.common.URL;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Objects;
+
+import static org.apache.commons.lang3.ArrayUtils.getLength;
+import static org.apache.commons.lang3.StringUtils.contains;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.split;
+import static org.apache.commons.lang3.StringUtils.splitPreserveAllTokens;
+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.VERSION_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
+import static 
org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
+
+/**
+ * The service name of Nacos
+ *
+ * @since 2.7.3
+ */
+public class NacosServiceName {
+
+    public static final String NAME_SEPARATOR = ":";
+
+    public static final String VALUE_SEPARATOR = ",";
+
+    public static final String WILDCARD = "*";
+
+    public static final String DEFAULT_PARAM_VALUE = "";
+
+    private static final int CATEGORY_INDEX = 0;
+
+    private static final int SERVICE_INTERFACE_INDEX = 1;
+
+    private static final int SERVICE_VERSION_INDEX = 2;
+
+    private static final int SERVICE_GROUP_INDEX = 3;
+
+    private String category;
+
+    private String serviceInterface;
+
+    private String version;
+
+    private String group;
+
+    private String value;
+
+    public NacosServiceName() {
+    }
+
+    public NacosServiceName(URL url) {
+        serviceInterface = url.getParameter(INTERFACE_KEY);
+        category = isConcrete(serviceInterface) ? DEFAULT_CATEGORY : 
url.getParameter(CATEGORY_KEY);
+        version = url.getParameter(VERSION_KEY, DEFAULT_PARAM_VALUE);
+        group = url.getParameter(GROUP_KEY, DEFAULT_PARAM_VALUE);
+        value = toValue();
+    }
+
+    public NacosServiceName(String value) {
+        this.value = value;
+        String[] segments = splitPreserveAllTokens(value, NAME_SEPARATOR);
+        this.category = segments[CATEGORY_INDEX];
+        this.serviceInterface = segments[SERVICE_INTERFACE_INDEX];
+        this.version = segments[SERVICE_VERSION_INDEX];
+        this.group = segments[SERVICE_GROUP_INDEX];
+    }
+
+    /**
+     * Build an instance of {@link NacosServiceName}
+     *
+     * @param url
+     * @return
+     */
+    public static NacosServiceName valueOf(URL url) {
+        return new NacosServiceName(url);
+    }
+
+    /**
+     * Is the concrete service name or not
+     *
+     * @return if concrete , return <code>true</code>, or <code>false</code>
+     */
+    public boolean isConcrete() {
+        return isConcrete(serviceInterface) && isConcrete(version) && 
isConcrete(group);
+    }
+
+    public boolean isCompatible(NacosServiceName concreteServiceName) {
+
+        if (!concreteServiceName.isConcrete()) { // The argument must be the 
concrete NacosServiceName
+            return false;
+        }
+
+        // Not match comparison
+        if (!StringUtils.equals(this.category, concreteServiceName.category) &&
+                !ArrayUtils.contains(splitPreserveAllTokens(this.category, 
VALUE_SEPARATOR), concreteServiceName.category)) {
+            return false;
+        }
+
+        if (!StringUtils.equals(this.serviceInterface, 
concreteServiceName.serviceInterface)) {
+            return false;
+        }
+
+        // wildcard condition
+        if (isWildcard(this.version)) {
+            return true;
+        }
+
+        if (isWildcard(this.group)) {
+            return true;
+        }
+
+        // range condition
+        if (!StringUtils.equals(this.version, concreteServiceName.version) &&
+                !matchRange(this.version, concreteServiceName.version)) {
+            return false;
+        }
+
+        if (!StringUtils.equals(this.group, concreteServiceName.group) &&
+                !matchRange(this.group, concreteServiceName.group)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean matchRange(String range, String value) {
+        if (isBlank(range)) {
+            return true;
+        }
+        if (!isRange(range)) {
+            return false;
+        }
+        String[] values = split(range, VALUE_SEPARATOR);
+        return ArrayUtils.contains(values, value);
+    }
+
+    private boolean isConcrete(String value) {
+        return !isWildcard(value) && !isRange(value);
+    }
+
+    private boolean isWildcard(String value) {
+        return WILDCARD.equals(value);
+    }
+
+    private boolean isRange(String value) {
+        if (contains(value, VALUE_SEPARATOR)) {
+            String[] values = split(value, VALUE_SEPARATOR);
+            return getLength(values) > 1;
+        }
+        return false;
+    }
+
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+
+    public String getServiceInterface() {
+        return serviceInterface;
+    }
+
+    public void setServiceInterface(String serviceInterface) {
+        this.serviceInterface = serviceInterface;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    public String getValue() {
+        if (value == null) {
+            value = toValue();
+        }
+        return value;
+    }
+
+    private String toValue() {
+        return new StringBuilder(category)
+                .append(NAME_SEPARATOR).append(serviceInterface)
+                .append(NAME_SEPARATOR).append(version)
+                .append(NAME_SEPARATOR).append(group)
+                .toString();
+    }
+
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof NacosServiceName)) return false;
+        NacosServiceName that = (NacosServiceName) o;
+        return Objects.equals(getValue(), that.getValue());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getValue());
+    }
+
+    public String toString() {
+        return getValue();
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
index cc25f8c..8f65faf 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
@@ -32,10 +32,14 @@ public class DemoServiceConsumerXmlBootstrap {
         
context.setConfigLocation("/META-INF/spring/dubbo-consumer-context.xml");
         context.refresh();
         System.out.println("DemoService consumer (XML) is starting...");
-        DemoService demoService = context.getBean("demoService", 
DemoService.class);
-        for (int i = 0; i < 10; i++) {
-            System.out.println(demoService.sayName("小马哥(mercyblitz)"));
+
+        for (int i = 1; i <= 5; i++) {
+            DemoService demoService = context.getBean("demoService" + i, 
DemoService.class);
+            for (int j = 0; j < 10; j++) {
+                System.out.println(demoService.sayName("小马哥(mercyblitz)"));
+            }
         }
+
         System.in.read();
         context.close();
     }
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceNameTest.java
 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceNameTest.java
new file mode 100644
index 0000000..2f8e1c3
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/registry/nacos/NacosServiceNameTest.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.registry.nacos;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static 
org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
+import static org.apache.dubbo.registry.nacos.NacosServiceName.WILDCARD;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link NacosServiceName} Test
+ *
+ * @since 2.7.3
+ */
+public class NacosServiceNameTest {
+
+    private static final String category = DEFAULT_CATEGORY;
+
+    private static final String serviceInterface = 
"org.apache.dubbo.registry.nacos.NacosServiceName";
+
+    private static final String version = "1.0.0";
+
+    private static final String group = "default";
+
+    private final NacosServiceName name = new NacosServiceName();
+
+    @BeforeEach
+    public void init() {
+        name.setCategory(category);
+        name.setServiceInterface(serviceInterface);
+        name.setVersion(version);
+        name.setGroup(group);
+    }
+
+    @Test
+    public void testGetter() {
+        assertEquals(category, name.getCategory());
+        assertEquals(serviceInterface, name.getServiceInterface());
+        assertEquals(version, name.getVersion());
+        assertEquals(group, name.getGroup());
+        
assertEquals("providers:org.apache.dubbo.registry.nacos.NacosServiceName:1.0.0:default",
 name.getValue());
+    }
+
+    @Test
+    public void testToString() {
+        
assertEquals("providers:org.apache.dubbo.registry.nacos.NacosServiceName:1.0.0:default",
 name.toString());
+    }
+
+    @Test
+    public void testIsConcrete() {
+
+        assertTrue(name.isConcrete());
+
+        name.setGroup(WILDCARD);
+        assertFalse(name.isConcrete());
+
+        init();
+        name.setVersion(WILDCARD);
+        assertFalse(name.isConcrete());
+
+        init();
+        name.setGroup(null);
+        name.setVersion(null);
+        assertTrue(name.isConcrete());
+
+    }
+
+    @Test
+    public void testIsCompatible() {
+
+        NacosServiceName concrete = new NacosServiceName();
+
+        assertFalse(name.isCompatible(concrete));
+
+        // set category
+        concrete.setCategory(category);
+        assertFalse(name.isCompatible(concrete));
+
+        concrete.setServiceInterface(serviceInterface);
+        assertFalse(name.isCompatible(concrete));
+
+        concrete.setVersion(version);
+        assertFalse(name.isCompatible(concrete));
+
+        concrete.setGroup(group);
+        assertTrue(name.isCompatible(concrete));
+
+        // wildcard cases
+        name.setGroup(WILDCARD);
+        assertTrue(name.isCompatible(concrete));
+
+        init();
+        name.setVersion(WILDCARD);
+        assertTrue(name.isCompatible(concrete));
+
+        // range cases
+        init();
+        name.setGroup(group + ",2.0.0");
+        assertTrue(name.isCompatible(concrete));
+
+        init();
+        name.setVersion(version + ",2.0.0");
+        assertTrue(name.isCompatible(concrete));
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
 
b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
index 3fa32d7..9054c4f 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
@@ -10,6 +10,18 @@
     <dubbo:registry address="nacos://127.0.0.1:8848"/>
 
     <!-- Reference interface -->
-    <dubbo:reference id="demoService" 
interface="org.apache.dubbo.demo.service.DemoService" version="2.0.0"/>
+    <dubbo:reference id="demoService1" 
interface="org.apache.dubbo.demo.service.DemoService" version="2.0.0"
+                     group="default"/>
+
+    <dubbo:reference id="demoService2" 
interface="org.apache.dubbo.demo.service.DemoService" version="*"
+                     group="default"/>
+
+    <dubbo:reference id="demoService3" 
interface="org.apache.dubbo.demo.service.DemoService" version="2.0.0"
+                     group="default"/>
+
+    <dubbo:reference id="demoService4" 
interface="org.apache.dubbo.demo.service.DemoService" version="2.0.0" 
group="*"/>
+
+    <dubbo:reference id="demoService5" 
interface="org.apache.dubbo.demo.service.DemoService" version="2.0.0"
+                     group="default,test"/>
 
 </beans>
\ No newline at end of file
diff --git 
a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
 
b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
index 36b1267..207ab7b 100644
--- 
a/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
+++ 
b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
@@ -12,7 +12,8 @@
     <!-- Use random port as Dubbo -->
     <dubbo:protocol name="dubbo" port="-1"/>
 
-    <dubbo:service interface="org.apache.dubbo.demo.service.DemoService" 
ref="demoService" version="2.0.0"/>
+    <dubbo:service interface="org.apache.dubbo.demo.service.DemoService" 
ref="demoService" version="2.0.0"
+                   group="default"/>
 
     <bean id="demoService" 
class="org.apache.dubbo.demo.service.DefaultService"/>
 </beans>
\ No newline at end of file
diff --git 
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ActiveLimitFilter.java
 
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ActiveLimitFilter.java
index 27aa1f5..ee760ee 100644
--- 
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ActiveLimitFilter.java
+++ 
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ActiveLimitFilter.java
@@ -57,7 +57,7 @@ public class ActiveLimitFilter extends ListenableFilter {
         URL url = invoker.getUrl();
         String methodName = invocation.getMethodName();
         int max = invoker.getUrl().getMethodParameter(methodName, ACTIVES_KEY, 
0);
-        RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), 
invocation.getMethodName());
+        final RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), 
invocation.getMethodName());
         if (!RpcStatus.beginCount(url, methodName, max)) {
             long timeout = 
invoker.getUrl().getMethodParameter(invocation.getMethodName(), TIMEOUT_KEY, 0);
             long start = System.currentTimeMillis();
@@ -119,7 +119,7 @@ public class ActiveLimitFilter extends ListenableFilter {
             return StringUtils.isNotEmpty(beginTime) ? 
System.currentTimeMillis() - Long.parseLong(beginTime) : 0;
         }
 
-        private void notifyFinish(RpcStatus rpcStatus, int max) {
+        private void notifyFinish(final RpcStatus rpcStatus, int max) {
             if (max > 0) {
                 synchronized (rpcStatus) {
                     rpcStatus.notifyAll();

Reply via email to