(beanNames.length);
+
+ for (String beanName : beanNames) {
+ if (containsElement(allBeanNames, beanName)) {
+ beans.add(beanFactory.getBean(beanName, beanType));
+ }
+ }
+
+ return Collections.unmodifiableList(beans);
+ }
+
}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java
index 671d63f277b..08a13acaa66 100644
--- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/BeanRegistrar.java
@@ -25,7 +25,7 @@
*
* @since 2.5.7
*/
-public class BeanRegistrar {
+public abstract class BeanRegistrar {
/**
* Register Infrastructure Bean
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java
new file mode 100644
index 00000000000..6bb1d81d417
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ClassUtils.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.util;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * {@link Class} Utilities
+ *
+ * The source code is cloned from
+ * https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/ClassUtils.java
+ *
+ * @since 2.6.6
+ */
+public abstract class ClassUtils {
+
+ public static Class resolveGenericType(Class> declaredClass) {
+ ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass();
+ Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+ return (Class) actualTypeArguments[0];
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java
new file mode 100644
index 00000000000..abb981febd1
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/ObjectUtils.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.util;
+
+/**
+ * Object Utilities
+ *
+ * @since 2.6.6
+ */
+public abstract class ObjectUtils {
+
+ /**
+ * Convert from variable arguments to array
+ *
+ * @param values variable arguments
+ * @param The class
+ * @return array
+ */
+ public static T[] of(T... values) {
+ return values;
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java
new file mode 100644
index 00000000000..06c707781d7
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtils.java
@@ -0,0 +1,112 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.util;
+
+import org.springframework.core.env.AbstractEnvironment;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.env.PropertySources;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Properties;
+
+
+/**
+ * {@link PropertySources} Utilities
+ *
+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/PropertySourcesUtils.java
+ *
+ * @since 2.6.6
+ */
+public abstract class PropertySourcesUtils {
+
+ /**
+ * Get Sub {@link Properties}
+ *
+ * @param propertySources {@link PropertySource} Iterable
+ * @param prefix the prefix of property name
+ * @return Map
+ * @see Properties
+ */
+ public static Map getSubProperties(Iterable> propertySources, String prefix) {
+
+ // Non-Extension AbstractEnvironment
+ AbstractEnvironment environment = new AbstractEnvironment() {
+ };
+
+ MutablePropertySources mutablePropertySources = environment.getPropertySources();
+
+ for (PropertySource> source : propertySources) {
+ mutablePropertySources.addLast(source);
+ }
+
+ return getSubProperties(environment, prefix);
+
+ }
+
+ /**
+ * Get Sub {@link Properties}
+ *
+ * @param environment {@link ConfigurableEnvironment}
+ * @param prefix the prefix of property name
+ * @return Map
+ * @see Properties
+ */
+ public static Map getSubProperties(ConfigurableEnvironment environment, String prefix) {
+
+ Map subProperties = new LinkedHashMap();
+
+ MutablePropertySources propertySources = environment.getPropertySources();
+
+ String normalizedPrefix = normalizePrefix(prefix);
+
+ for (PropertySource> source : propertySources) {
+ if (source instanceof EnumerablePropertySource) {
+ for (String name : ((EnumerablePropertySource>) source).getPropertyNames()) {
+ if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
+ String subName = name.substring(normalizedPrefix.length());
+ if (!subProperties.containsKey(subName)) { // take first one
+ Object value = source.getProperty(name);
+ if (value instanceof String) {
+ // Resolve placeholder
+ value = environment.resolvePlaceholders((String) value);
+ }
+ subProperties.put(subName, value);
+ }
+ }
+ }
+ }
+ }
+
+ return Collections.unmodifiableMap(subProperties);
+
+ }
+
+ /**
+ * Normalize the prefix
+ *
+ * @param prefix the prefix
+ * @return the prefix
+ */
+ public static String normalizePrefix(String prefix) {
+ return prefix.endsWith(".") ? prefix : prefix + ".";
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
index 1feb2bd5223..367ad9e37c8 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/api/HelloService.java
@@ -17,6 +17,13 @@
package com.alibaba.dubbo.config.spring.api;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+@Path("/hello-service")
public interface HelloService {
- String sayHello(String name);
+
+ @GET
+ String sayHello(@QueryParam("name") String name);
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java
new file mode 100644
index 00000000000..28c53ccd06a
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.config.spring.api.DemoService;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.util.ReflectionUtils;
+
+import static com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.GROUP;
+import static com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.VERSION;
+
+/**
+ * {@link AnnotationBeanNameBuilder} Test
+ *
+ * @see AnnotationBeanNameBuilder
+ * @since 2.6.6
+ */
+@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION,
+ application = "application", module = "module", registry = {"1", "2", "3"})
+public class AnnotationBeanNameBuilderTest {
+
+ @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "${dubbo.version}",
+ application = "application", module = "module", registry = {"1", "2", "3"})
+ static final Class> INTERFACE_CLASS = DemoService.class;
+
+ static final String GROUP = "DUBBO";
+
+ static final String VERSION = "1.0.0";
+
+ private MockEnvironment environment;
+
+ @Before
+ public void prepare() {
+ environment = new MockEnvironment();
+ environment.setProperty("dubbo.version", "1.0.0");
+ }
+
+ @Test
+ public void testServiceAnnotation() {
+ Service service = AnnotationUtils.getAnnotation(AnnotationBeanNameBuilderTest.class, Service.class);
+ AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, INTERFACE_CLASS);
+ Assert.assertEquals("providers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
+ builder.build());
+
+ builder.environment(environment);
+ Assert.assertEquals("providers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
+ builder.build());
+ }
+
+ @Test
+ public void testReferenceAnnotation() {
+ Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(AnnotationBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class);
+ AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, INTERFACE_CLASS);
+ Assert.assertEquals("consumers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:${dubbo.version}:DUBBO",
+ builder.build());
+
+ builder.environment(environment);
+ Assert.assertEquals("consumers:dubbo:com.alibaba.dubbo.config.spring.api.DemoService:1.0.0:DUBBO",
+ builder.build());
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java
index b98364b1cff..818eadecabe 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessorTest.java
@@ -17,51 +17,55 @@
package com.alibaba.dubbo.config.spring.beans.factory.annotation;
import com.alibaba.dubbo.config.ApplicationConfig;
+import com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer;
import com.alibaba.dubbo.config.spring.context.properties.DefaultDubboConfigBinder;
-import com.alibaba.dubbo.config.spring.context.properties.DubboConfigBinder;
-
import org.junit.Assert;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.PropertySource;
-
-import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
/**
* {@link DubboConfigBindingBeanPostProcessor}
*/
-@PropertySource({"classpath:/META-INF/config.properties"})
-@Configuration
+@RunWith(SpringRunner.class)
+@ContextConfiguration(classes = {
+ DefaultDubboConfigBinder.class,
+ NamePropertyDefaultValueDubboConfigBeanCustomizer.class,
+ DubboConfigBindingBeanPostProcessorTest.class
+})
+@TestPropertySource(properties = {
+ "dubbo.application.id = dubbo-demo-application",
+ "dubbo.application.owner = mercyblitz",
+ "dubbo.application.organization = Apache",
+
+})
public class DubboConfigBindingBeanPostProcessorTest {
- @Bean("applicationBean")
+ @Bean("dubbo-demo-application")
public ApplicationConfig applicationConfig() {
return new ApplicationConfig();
}
@Bean
- public DubboConfigBinder dubboConfigBinder() {
- return new DefaultDubboConfigBinder();
+ public DubboConfigBindingBeanPostProcessor bindingBeanPostProcessor() {
+ return new DubboConfigBindingBeanPostProcessor("dubbo.application", "dubbo-demo-application");
}
+ @Autowired
+ private ApplicationContext applicationContext;
+
@Test
public void test() {
- final AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
-
- applicationContext.register(getClass());
-
- Class> processorClass = DubboConfigBindingBeanPostProcessor.class;
-
- applicationContext.registerBeanDefinition("DubboConfigBindingBeanPostProcessor", rootBeanDefinition(processorClass).addConstructorArgValue("dubbo.application").addConstructorArgValue("applicationBean").getBeanDefinition());
-
- applicationContext.refresh();
-
ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
-
+ Assert.assertEquals("mercyblitz", applicationConfig.getOwner());
+ Assert.assertEquals("Apache", applicationConfig.getOrganization());
}
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
index a48a85eb75c..dcb4127cf53 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java
@@ -124,7 +124,7 @@ public void testGetInjectedFieldReferenceBeanMap() {
InjectionMetadata.InjectedElement injectedElement = entry.getKey();
- Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement",
+ Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement",
injectedElement.getClass().getName());
ReferenceBean> referenceBean = entry.getValue();
@@ -152,7 +152,7 @@ public void testGetInjectedMethodReferenceBeanMap() {
InjectionMetadata.InjectedElement injectedElement = entry.getKey();
- Assert.assertEquals("com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement",
+ Assert.assertEquals("com.alibaba.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement",
injectedElement.getClass().getName());
ReferenceBean> referenceBean = entry.getValue();
@@ -229,7 +229,7 @@ public DemoService getDemoService() {
return demoService;
}
- @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345")
+ @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", protocol = "dubbo")
public void setDemoService(DemoService demoService) {
this.demoService = demoService;
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java
new file mode 100644
index 00000000000..54b1b9741ea
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.spring.ReferenceBean;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
+import static org.springframework.util.ReflectionUtils.findField;
+
+/**
+ * {@link ReferenceBeanBuilder} Test
+ *
+ * @author Mercy
+ * @see ReferenceBeanBuilder
+ * @see Reference
+ * @since 2.6.4
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = ReferenceBeanBuilderTest.class)
+public class ReferenceBeanBuilderTest {
+
+ @Reference(
+ interfaceClass = CharSequence.class,
+ interfaceName = "java.lang.CharSequence",
+ version = "1.0.0", group = "TEST_GROUP", url = "dubbo://localhost:12345",
+ client = "client", generic = true, injvm = true,
+ check = false, init = false, lazy = true,
+ stubevent = true, reconnect = "reconnect", sticky = true,
+ proxy = "javassist", stub = "java.lang.CharSequence", cluster = "failover",
+ connections = 3, callbacks = 1, onconnect = "onconnect", ondisconnect = "ondisconnect",
+ owner = "owner", layer = "layer", retries = 1,
+ loadbalance = "random", async = true, actives = 3,
+ sent = true, mock = "mock", validation = "validation",
+ timeout = 3, cache = "cache", filter = {"echo", "generic", "accesslog"},
+ listener = {"deprecated"}, parameters = {"n1=v1 ", "n2 = v2 ", " n3 = v3 "},
+ application = "application",
+ module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"}
+ )
+ private static final Object TEST_FIELD = new Object();
+
+ @Autowired
+ private ApplicationContext context;
+
+ @Test
+ public void testBuild() throws Exception {
+ Reference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), Reference.class);
+ ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(reference, context.getClassLoader(), context);
+ beanBuilder.interfaceClass(CharSequence.class);
+ ReferenceBean referenceBean = beanBuilder.build();
+ Assert.assertEquals(CharSequence.class, referenceBean.getInterfaceClass());
+ Assert.assertEquals("1.0.0", referenceBean.getVersion());
+ Assert.assertEquals("TEST_GROUP", referenceBean.getGroup());
+ Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl());
+ Assert.assertEquals("client", referenceBean.getClient());
+ Assert.assertEquals(true, referenceBean.isGeneric());
+ Assert.assertEquals(true, referenceBean.isInjvm());
+ Assert.assertEquals(false, referenceBean.isCheck());
+ Assert.assertEquals(null, referenceBean.isInit());
+ Assert.assertEquals(true, referenceBean.getLazy());
+ Assert.assertEquals(true, referenceBean.getStubevent());
+ Assert.assertEquals("reconnect", referenceBean.getReconnect());
+ Assert.assertEquals(true, referenceBean.getSticky());
+ Assert.assertEquals("javassist", referenceBean.getProxy());
+ Assert.assertEquals("java.lang.CharSequence", referenceBean.getStub());
+ Assert.assertEquals("failover", referenceBean.getCluster());
+ Assert.assertEquals(Integer.valueOf(3), referenceBean.getConnections());
+ Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks());
+ Assert.assertEquals("onconnect", referenceBean.getOnconnect());
+ Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect());
+ Assert.assertEquals("owner", referenceBean.getOwner());
+ Assert.assertEquals("layer", referenceBean.getLayer());
+ Assert.assertEquals(Integer.valueOf(1), referenceBean.getRetries());
+ Assert.assertEquals("random", referenceBean.getLoadbalance());
+ Assert.assertEquals(true, referenceBean.isAsync());
+ Assert.assertEquals(Integer.valueOf(3), referenceBean.getActives());
+ Assert.assertEquals(true, referenceBean.getSent());
+ Assert.assertEquals("mock", referenceBean.getMock());
+ Assert.assertEquals("validation", referenceBean.getValidation());
+ Assert.assertEquals(Integer.valueOf(3), referenceBean.getTimeout());
+ Assert.assertEquals("cache", referenceBean.getCache());
+ Assert.assertEquals("echo,generic,accesslog", referenceBean.getFilter());
+ Assert.assertEquals("deprecated", referenceBean.getListener());
+
+ // parameters
+ Map parameters = new HashMap();
+ parameters.put("n1", "v1");
+ parameters.put("n2", "v2");
+ parameters.put("n3", "v3");
+ Assert.assertEquals(parameters, referenceBean.getParameters());
+
+ // Asserts Null fields
+ Assert.assertNull(referenceBean.getApplication());
+ Assert.assertNull(referenceBean.getModule());
+ Assert.assertNull(referenceBean.getConsumer());
+ Assert.assertNull(referenceBean.getMonitor());
+ Assert.assertEquals(Collections.emptyList(), referenceBean.getRegistries());
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
index 84451bcaf4a..91b4b7043aa 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java
@@ -37,6 +37,7 @@
*/
@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION,
application = "application", module = "module", registry = {"1", "2", "3"})
+@Deprecated
public class ServiceBeanNameBuilderTest {
@Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0",
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java
new file mode 100644
index 00000000000..05c08e72e17
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/EmbeddedZooKeeper.java
@@ -0,0 +1,252 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple;
+
+
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.SmartLifecycle;
+import org.springframework.util.ErrorHandler;
+import org.springframework.util.SocketUtils;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Properties;
+import java.util.UUID;
+
+/**
+ * from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
+ *
+ * Helper class to start an embedded instance of standalone (non clustered) ZooKeeper.
+ *
+ * NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
+ * org.springframework.xd.dirt.server.singlenode.SingleNodeApplication
+ *
+ * @author Patrick Peralta
+ * @author Mark Fisher
+ * @author David Turanski
+ */
+public class EmbeddedZooKeeper implements SmartLifecycle {
+
+ /**
+ * Logger.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.class);
+
+ /**
+ * ZooKeeper client port. This will be determined dynamically upon startup.
+ */
+ private final int clientPort;
+
+ /**
+ * Whether to auto-start. Default is true.
+ */
+ private boolean autoStartup = true;
+
+ /**
+ * Lifecycle phase. Default is 0.
+ */
+ private int phase = 0;
+
+ /**
+ * Thread for running the ZooKeeper server.
+ */
+ private volatile Thread zkServerThread;
+
+ /**
+ * ZooKeeper server.
+ */
+ private volatile ZooKeeperServerMain zkServer;
+
+ /**
+ * {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
+ */
+ private ErrorHandler errorHandler;
+
+ private boolean daemon = true;
+
+ /**
+ * Construct an EmbeddedZooKeeper with a random port.
+ */
+ public EmbeddedZooKeeper() {
+ clientPort = SocketUtils.findAvailableTcpPort();
+ }
+
+ /**
+ * Construct an EmbeddedZooKeeper with the provided port.
+ *
+ * @param clientPort port for ZooKeeper server to bind to
+ */
+ public EmbeddedZooKeeper(int clientPort, boolean daemon) {
+ this.clientPort = clientPort;
+ this.daemon = daemon;
+ }
+
+ /**
+ * Returns the port that clients should use to connect to this embedded server.
+ *
+ * @return dynamically determined client port
+ */
+ public int getClientPort() {
+ return this.clientPort;
+ }
+
+ /**
+ * Specify whether to start automatically. Default is true.
+ *
+ * @param autoStartup whether to start automatically
+ */
+ public void setAutoStartup(boolean autoStartup) {
+ this.autoStartup = autoStartup;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isAutoStartup() {
+ return this.autoStartup;
+ }
+
+ /**
+ * Specify the lifecycle phase for the embedded server.
+ *
+ * @param phase the lifecycle phase
+ */
+ public void setPhase(int phase) {
+ this.phase = phase;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getPhase() {
+ return this.phase;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isRunning() {
+ return (zkServerThread != null);
+ }
+
+ /**
+ * Start the ZooKeeper server in a background thread.
+ *
+ * Register an error handler via {@link #setErrorHandler} in order to handle
+ * any exceptions thrown during startup or execution.
+ */
+ @Override
+ public synchronized void start() {
+ if (zkServerThread == null) {
+ zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
+ zkServerThread.setDaemon(daemon);
+ zkServerThread.start();
+ }
+ }
+
+ /**
+ * Shutdown the ZooKeeper server.
+ */
+ @Override
+ public synchronized void stop() {
+ if (zkServerThread != null) {
+ // The shutdown method is protected...thus this hack to invoke it.
+ // This will log an exception on shutdown; see
+ // https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
+ try {
+ Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod("shutdown");
+ shutdown.setAccessible(true);
+ shutdown.invoke(zkServer);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ // It is expected that the thread will exit after
+ // the server is shutdown; this will block until
+ // the shutdown is complete.
+ try {
+ zkServerThread.join(5000);
+ zkServerThread = null;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
+ // abandoning zk thread
+ zkServerThread = null;
+ }
+ }
+ }
+
+ /**
+ * Stop the server if running and invoke the callback when complete.
+ */
+ @Override
+ public void stop(Runnable callback) {
+ stop();
+ callback.run();
+ }
+
+ /**
+ * Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
+ * is provided, only error-level logging will occur.
+ *
+ * @param errorHandler the {@link ErrorHandler} to be invoked
+ */
+ public void setErrorHandler(ErrorHandler errorHandler) {
+ this.errorHandler = errorHandler;
+ }
+
+ /**
+ * Runnable implementation that starts the ZooKeeper server.
+ */
+ private class ServerRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ try {
+ Properties properties = new Properties();
+ File file = new File(System.getProperty("java.io.tmpdir")
+ + File.separator + UUID.randomUUID());
+ file.deleteOnExit();
+ properties.setProperty("dataDir", file.getAbsolutePath());
+ properties.setProperty("clientPort", String.valueOf(clientPort));
+
+ QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
+ quorumPeerConfig.parseProperties(properties);
+
+ zkServer = new ZooKeeperServerMain();
+ ServerConfig configuration = new ServerConfig();
+ configuration.readFrom(quorumPeerConfig);
+
+ zkServer.runFromConfig(configuration);
+ } catch (Exception e) {
+ if (errorHandler != null) {
+ errorHandler.handleError(e);
+ } else {
+ logger.error("Exception running embedded ZooKeeper", e);
+ }
+ }
+ }
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java
new file mode 100644
index 00000000000..5166db8f6f1
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/consumer/MultipleProtocolsServiceConsumer.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.consumer;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.spring.api.HelloService;
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+/**
+ * Multiple Protocols Test
+ */
+
+public class MultipleProtocolsServiceConsumer {
+
+ @EnableDubbo
+ @PropertySource({
+ "classpath:/META-INF/multiple-protocols-consumer.properties",
+ "classpath:/META-INF/dubbo-common.properties"
+ })
+ @Configuration
+ static class ConsumerConfiguration {
+
+ @Reference(version = "${hello.service.version}", protocol = "dubbo")
+ private HelloService dubboHelloService;
+
+ @Reference(version = "${hello.service.version}", protocol = "rest")
+ private HelloService restHelloService;
+
+// @Bean
+// public ReferenceBean restReferenceBean(@Value("${hello.service.version}") String version) {
+// ReferenceBean referenceBean = new ReferenceBean();
+// referenceBean.setVersion(version);
+// referenceBean.setProtocol("rest");
+// referenceBean.setInterface(HelloService.class);
+// return referenceBean;
+// }
+
+ }
+
+// @ImportResource("classpath:/META-INF/spring/dubbo-rest-consumer.xml")
+// @Configuration
+// static class ConsumerXMLConfiguration {
+// }
+
+
+ public static void main(String[] args) {
+
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.register(ConsumerConfiguration.class);
+ context.refresh();
+
+ ConsumerConfiguration configuration = context.getBean(ConsumerConfiguration.class);
+ System.out.println(configuration.dubboHelloService.sayHello("mercyblitz"));
+ System.out.println(configuration.restHelloService.sayHello("mercyblitz"));
+
+ context.close();
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java
new file mode 100644
index 00000000000..43a7ced1cfe
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/DefaultHelloService.java
@@ -0,0 +1,30 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.provider;
+
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.config.spring.api.HelloService;
+import com.alibaba.dubbo.rpc.RpcContext;
+
+@Service(version = "${hello.service.version}", protocol = {"dubbo", "rest"})
+public class DefaultHelloService implements HelloService {
+
+ @Override
+ public String sayHello(String name) {
+ return String.format("[%s] Hello , %s", RpcContext.getContext().getUrl(), name);
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java
new file mode 100644
index 00000000000..e55d70acea2
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/multiple/provider/MultipleProtocolsServiceProvider.java
@@ -0,0 +1,50 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.beans.factory.annotation.multiple.provider;
+
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.PropertySource;
+
+import java.io.IOException;
+
+/**
+ * Multiple Protocols Service Provider
+ */
+@EnableDubbo
+@PropertySource({
+ "classpath:/META-INF/multiple-protocols-provider.properties",
+ "classpath:/META-INF/dubbo-common.properties"
+})
+public class MultipleProtocolsServiceProvider {
+
+ public static void main(String[] args) throws IOException {
+// EmbeddedZooKeeper embeddedZooKeeper = new EmbeddedZooKeeper(2181, false);
+// embeddedZooKeeper.start();
+
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.register(MultipleProtocolsServiceProvider.class);
+ context.refresh();
+
+ System.out.println("Enter any key to close the application");
+ System.in.read();
+
+ context.close();
+// embeddedZooKeeper.stop();
+ }
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
index 54d6c972bad..20a1504ea20 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java
@@ -111,5 +111,31 @@ public void test() {
}
+ @Test(expected = UnsupportedOperationException.class)
+ public void testOnException() {
+
+ AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();
+
+ providerContext.register(ProviderConfiguration.class);
+
+ providerContext.refresh();
+
+ AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
+
+ consumerContext.register(ConsumerConfiguration.class);
+
+ consumerContext.refresh();
+
+ ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class);
+
+ // From Child
+ DemoService demoService = child.getDemoServiceFromChild();
+
+ demoService.getBox();
+
+ providerContext.close();
+ consumerContext.close();
+ }
+
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java
index 853df842ba8..30fc54a6708 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrarTest.java
@@ -23,6 +23,11 @@
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static java.util.Arrays.asList;
+
/**
* {@link DubboConfigBindingRegistrar}
*
@@ -55,9 +60,14 @@ public void testRegisterBeanDefinitionsForMultiple() {
context.refresh();
- ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
+ Set expectedBeanNames = new TreeSet(asList("applicationBean1", "applicationBean2", "applicationBean3"));
+ Set actualBeanNames = new TreeSet(asList(context.getBeanNamesForType(ApplicationConfig.class)));
- Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ Assert.assertEquals(expectedBeanNames, actualBeanNames);
+
+ ApplicationConfig applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class);
+
+ Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName());
applicationConfig = context.getBean("applicationBean2", ApplicationConfig.class);
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
index a73dbf2c62a..b871983fb70 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigBindingsRegistrarTest.java
@@ -50,7 +50,7 @@ public void test() {
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class),
- @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class)
+ @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean1", type = ApplicationConfig.class)
})
@PropertySource("META-INF/config.properties")
private static class TestConfig {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java
index ff21bcd0197..5a4222eb741 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java
@@ -84,8 +84,8 @@ public void testMultiple() {
context.refresh();
// application
- ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
- Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ ApplicationConfig applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class);
+ Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName());
ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName());
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java
index d5c41b05bff..15b462e4041 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java
@@ -23,12 +23,18 @@
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
-
+import com.alibaba.dubbo.config.spring.util.ObjectUtils;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static java.util.Arrays.asList;
+
/**
* {@link EnableDubboConfig} Test
*
@@ -47,6 +53,8 @@ public void testSingle() {
ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ Assert.assertArrayEquals(ObjectUtils.of("applicationBean"), context.getBeanNamesForType(ApplicationConfig.class));
+
// module
ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class);
Assert.assertEquals("dubbo-demo-module", moduleConfig.getName());
@@ -82,25 +90,42 @@ public void testMultiple() {
context.register(TestMultipleConfig.class);
context.refresh();
+ Set expectedBeanNames = new TreeSet(asList("applicationBean", "applicationBean1", "applicationBean2", "applicationBean3"));
+ Set actualBeanNames = new TreeSet(asList(context.getBeanNamesForType(ApplicationConfig.class)));
+
+ Assert.assertEquals(expectedBeanNames, actualBeanNames);
+
// application
ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application", applicationConfig.getName());
+ applicationConfig = context.getBean("applicationBean1", ApplicationConfig.class);
+ Assert.assertEquals("dubbo-demo-application1", applicationConfig.getName());
+
ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application2", applicationBean2.getName());
ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class);
Assert.assertEquals("dubbo-demo-application3", applicationBean3.getName());
+
+ Map protocolConfigs = context.getBeansOfType(ProtocolConfig.class);
+
+ for (Map.Entry entry : protocolConfigs.entrySet()) {
+ String beanName = entry.getKey();
+ ProtocolConfig protocol = entry.getValue();
+ Assert.assertEquals(beanName, protocol.getName());
+ }
+
}
- @EnableDubboConfig(multiple = true)
+ @EnableDubboConfig
@PropertySource("META-INF/config.properties")
private static class TestMultipleConfig {
}
- @EnableDubboConfig
+ @EnableDubboConfig(multiple = false)
@PropertySource("META-INF/config.properties")
private static class TestConfig {
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java
index e419632a160..29d8a3cab78 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/EnableDubboTest.java
@@ -24,12 +24,14 @@
import org.junit.Assert;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.springframework.aop.support.AopUtils;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Primary;
-import org.springframework.context.annotation.PropertySource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.*;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
@@ -44,17 +46,21 @@
*
* @since 2.5.8
*/
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {EnableDubboTest.class})
+@TestPropertySource(locations = "classpath:/META-INF/dubbb-provider.properties",
+ properties = "demo.service.version = 2.5.7")
+@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider")
+@ComponentScan(basePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider")
+@EnableTransactionManagement
public class EnableDubboTest {
+ @Autowired
+ private ApplicationContext providerContext;
+
@Test
public void test() {
- AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();
-
- providerContext.register(TestProviderConfiguration.class);
-
- providerContext.refresh();
-
DemoService demoService = providerContext.getBean(DemoService.class);
String value = demoService.sayName("Mercy");
@@ -69,11 +75,7 @@ public void test() {
// Test @Transactional is present or not
Assert.assertNotNull(findAnnotation(beanClass, Transactional.class));
- AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();
-
- consumerContext.register(TestConsumerConfiguration.class);
-
- consumerContext.refresh();
+ AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(TestConsumerConfiguration.class);
TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class);
@@ -128,10 +130,6 @@ public void test() {
// Test multiple binding
Assert.assertEquals("N/A", registryConfig.getAddress());
- providerContext.close();
- consumerContext.close();
-
-
}
@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.config.spring.context.annotation.provider")
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java
index 2641fae8e79..84c451a61fa 100644
--- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java
@@ -29,7 +29,7 @@
* @since 2.5.8
*/
@com.alibaba.dubbo.config.annotation.Service(
- version = "2.5.7",
+ version = "${demo.service.version}",
application = "${demo.service.application}",
protocol = "${demo.service.protocol}",
registry = "${demo.service.registry}"
@@ -45,11 +45,6 @@ public String sayName(String name) {
@Override
public Box getBox() {
- return new Box() {
- @Override
- public String getName() {
- return "MyBox";
- }
- };
+ throw new UnsupportedOperationException("For Purposes!");
}
}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java
new file mode 100644
index 00000000000..c54fa9feb8a
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtilsTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.util;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.annotation.AnnotationConfigUtils;
+import org.springframework.util.ObjectUtils;
+
+/**
+ * {@link AnnotatedBeanDefinitionRegistryUtils} Test
+ *
+ * @see AnnotatedBeanDefinitionRegistryUtils
+ * @since 2.6.6
+ */
+public class AnnotatedBeanDefinitionRegistryUtilsTest {
+
+ private DefaultListableBeanFactory registry = null;
+
+ @Before
+ public void init() {
+ registry = new DefaultListableBeanFactory();
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(registry);
+ }
+
+ @Test
+ public void testRegisterBeans() {
+
+ AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, this.getClass());
+
+ String[] beanNames = registry.getBeanNamesForType(this.getClass());
+
+ Assert.assertEquals(1, beanNames.length);
+
+ beanNames = registry.getBeanNamesForType(AnnotatedBeanDefinitionRegistryUtils.class);
+
+ Assert.assertTrue(ObjectUtils.isEmpty(beanNames));
+
+ AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry);
+
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java
new file mode 100644
index 00000000000..4a17ac1c7b2
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/util/PropertySourcesUtilsTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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 com.alibaba.dubbo.config.spring.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link PropertySourcesUtils} Test
+ *
+ * @author Mercy
+ * @see PropertySourcesUtils
+ * @since 2.6.6
+ */
+public class PropertySourcesUtilsTest {
+
+ @Test
+ public void testGetSubProperties() {
+
+ MutablePropertySources propertySources = new MutablePropertySources();
+
+ Map source = new HashMap();
+ Map source2 = new HashMap();
+
+ MapPropertySource propertySource = new MapPropertySource("propertySource", source);
+ MapPropertySource propertySource2 = new MapPropertySource("propertySource2", source2);
+
+ propertySources.addLast(propertySource);
+ propertySources.addLast(propertySource2);
+
+ Map result = PropertySourcesUtils.getSubProperties(propertySources, "user");
+
+ Assert.assertEquals(Collections.emptyMap(), result);
+
+ source.put("age", "31");
+ source.put("user.name", "Mercy");
+ source.put("user.age", "${age}");
+
+ source2.put("user.name", "mercyblitz");
+ source2.put("user.age", "32");
+
+ Map expected = new HashMap();
+ expected.put("name", "Mercy");
+ expected.put("age", "31");
+
+ result = PropertySourcesUtils.getSubProperties(propertySources, "user");
+
+ Assert.assertEquals(expected, result);
+
+ result = PropertySourcesUtils.getSubProperties(propertySources, "");
+
+ Assert.assertEquals(Collections.emptyMap(), result);
+
+ result = PropertySourcesUtils.getSubProperties(propertySources, "no-exists");
+
+ Assert.assertEquals(Collections.emptyMap(), result);
+
+ }
+
+}
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties
index 6e728ccb208..1063fe68ff1 100644
--- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/config.properties
@@ -14,9 +14,13 @@ dubbo.module.name = dubbo-demo-module
dubbo.registry.address = zookeeper://192.168.99.100:32770
## protocol
+dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 20880
+dubbo.protocols.rest.port=8080
+dubbo.protocols.thrift.port=9090
+
## monitor
dubbo.monitor.address = zookeeper://127.0.0.1:32770
@@ -27,6 +31,6 @@ dubbo.provider.host = 127.0.0.1
dubbo.consumer.client = netty
# multiple Bean definition
-dubbo.applications.applicationBean.name = dubbo-demo-application
+dubbo.applications.applicationBean1.name = dubbo-demo-application1
dubbo.applications.applicationBean2.name = dubbo-demo-application2
dubbo.applications.applicationBean3.name = dubbo-demo-application3
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties
new file mode 100644
index 00000000000..36146a165b7
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-common.properties
@@ -0,0 +1,2 @@
+dubbo.registry.address=zookeeper://127.0.0.1:2181
+hello.service.version=1.0.0
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties
new file mode 100644
index 00000000000..abbe51ce929
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-consumer.properties
@@ -0,0 +1 @@
+dubbo.application.id=provider
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties
new file mode 100644
index 00000000000..98790494336
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/multiple-protocols-provider.properties
@@ -0,0 +1,6 @@
+dubbo.application.id=provider
+dubbo.protocols.dubbo.name=dubbo
+dubbo.protocols.dubbo.port=12345
+dubbo.protocols.rest.name=rest
+dubbo.protocols.rest.port=9090
+dubbo.protocols.rest.server=netty
\ No newline at end of file
diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml
new file mode 100644
index 00000000000..c7db5ff57e6
--- /dev/null
+++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-rest-consumer.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java
index 68ecc0e9efb..d5ae6b8af3b 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryDirectory.java
@@ -78,6 +78,8 @@ public class RegistryDirectory extends AbstractDirectory implements Notify
private volatile URL overrideDirectoryUrl; // Initialization at construction time, assertion not null, and always assign non null value
+ private volatile URL registeredConsumerUrl;
+
/**
* override rules
* Priority: override>-D>consumer>provider
@@ -164,6 +166,16 @@ public void destroy() {
if (isDestroyed()) {
return;
}
+
+ // unregister.
+ try {
+ if (getRegisteredConsumerUrl() != null && registry != null && registry.isAvailable()) {
+ registry.unregister(getRegisteredConsumerUrl());
+ }
+ } catch (Throwable t) {
+ logger.warn("unexpected error when unregister service " + serviceKey + "from registry" + registry.getUrl(), t);
+ }
+
// unsubscribe.
try {
if (getConsumerUrl() != null && registry != null && registry.isAvailable()) {
@@ -612,6 +624,14 @@ public URL getUrl() {
return this.overrideDirectoryUrl;
}
+ public URL getRegisteredConsumerUrl() {
+ return registeredConsumerUrl;
+ }
+
+ public void setRegisteredConsumerUrl(URL registeredConsumerUrl) {
+ this.registeredConsumerUrl = registeredConsumerUrl;
+ }
+
@Override
public boolean isAvailable() {
if (isDestroyed()) {
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java
index e1a59b9dbb2..f8bf2a133bd 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/integration/RegistryProtocol.java
@@ -51,6 +51,9 @@
import static com.alibaba.dubbo.common.Constants.QOS_ENABLE;
import static com.alibaba.dubbo.common.Constants.QOS_PORT;
import static com.alibaba.dubbo.common.Constants.VALIDATION_KEY;
+import static com.alibaba.dubbo.common.Constants.CATEGORY_KEY;
+import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.CHECK_KEY;
/**
* RegistryProtocol
@@ -300,8 +303,9 @@ private Invoker doRefer(Cluster cluster, Registry registry, Class type
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters);
if (!Constants.ANY_VALUE.equals(url.getServiceInterface())
&& url.getParameter(Constants.REGISTER_KEY, true)) {
- registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
- Constants.CHECK_KEY, String.valueOf(false)));
+ URL registeredConsumerUrl = getRegisteredConsumerUrl(subscribeUrl, url);
+ registry.register(registeredConsumerUrl);
+ directory.setRegisteredConsumerUrl(registeredConsumerUrl);
}
directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
@@ -313,6 +317,11 @@ private Invoker doRefer(Cluster cluster, Registry registry, Class type
return invoker;
}
+ public URL getRegisteredConsumerUrl(final URL consumerUrl, URL registryUrl) {
+ return consumerUrl.addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY,
+ CHECK_KEY, String.valueOf(false));
+ }
+
@Override
public void destroy() {
List> exporters = new ArrayList>(bounds.values());
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java
new file mode 100644
index 00000000000..50deb0ab026
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java
@@ -0,0 +1,93 @@
+/*
+ * 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 com.alibaba.dubbo.registry.support;
+
+import java.util.Map;
+
+/**
+ * Dubbo Registration
+ *
+ * @since 2.6.6
+ */
+class DubboRegistration implements Registration {
+
+ private String serviceName;
+
+ private String ip;
+
+ private int port;
+
+ private Map metadata;
+
+ @Override
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ public String getIp() {
+ return ip;
+ }
+
+ public void setIp(String ip) {
+ this.ip = ip;
+ }
+
+ @Override
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ @Override
+ public Map getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(Map metadata) {
+ this.metadata = metadata;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ DubboRegistration that = (DubboRegistration) o;
+
+ if (port != that.port) return false;
+ if (serviceName != null ? !serviceName.equals(that.serviceName) : that.serviceName != null) return false;
+ if (ip != null ? !ip.equals(that.ip) : that.ip != null) return false;
+ return metadata != null ? metadata.equals(that.metadata) : that.metadata == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = serviceName != null ? serviceName.hashCode() : 0;
+ result = 31 * result + (ip != null ? ip.hashCode() : 0);
+ result = 31 * result + port;
+ result = 31 * result + (metadata != null ? metadata.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java
new file mode 100644
index 00000000000..143cc9f4913
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java
@@ -0,0 +1,53 @@
+/*
+ * 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 com.alibaba.dubbo.registry.support;
+
+import java.util.Map;
+
+/**
+ * The Registration
+ *
+ * @since 2.6.6
+ */
+public interface Registration {
+
+ /**
+ * @return The service name
+ */
+ String getServiceName();
+
+ /**
+ * @return The IP address
+ */
+ String getIp();
+
+ /**
+ * @return The service port
+ */
+ int getPort();
+
+ /**
+ * @return The read-only metadata
+ */
+ Map getMetadata();
+
+ @Override
+ boolean equals(Object o);
+
+ @Override
+ int hashCode();
+}
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java
new file mode 100644
index 00000000000..d6b1d8736d3
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java
@@ -0,0 +1,474 @@
+/*
+ * 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 com.alibaba.dubbo.registry.support;
+
+import com.alibaba.dubbo.common.Constants;
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.common.logger.Logger;
+import com.alibaba.dubbo.common.logger.LoggerFactory;
+import com.alibaba.dubbo.common.utils.StringUtils;
+import com.alibaba.dubbo.common.utils.UrlUtils;
+import com.alibaba.dubbo.registry.NotifyListener;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY;
+import static java.lang.Long.getLong;
+import static java.lang.System.getProperty;
+
+/**
+ * {@link FailbackRegistry} extension that is used as the Oriented Service Instance registration, for
+ *
+ * @param The actual type of service instance
+ * @since 2.6.6
+ */
+public abstract class ServiceInstanceRegistry extends FailbackRegistry {
+
+ /**
+ * All supported categories
+ */
+ private static final String[] ALL_SUPPORTED_CATEGORIES = of(
+ PROVIDERS_CATEGORY,
+ CONSUMERS_CATEGORY,
+ ROUTERS_CATEGORY,
+ CONFIGURATORS_CATEGORY
+ );
+
+ private static final int CATEGORY_INDEX = 0;
+
+ private static final int SERVICE_INTERFACE_INDEX = CATEGORY_INDEX + 1;
+
+ private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
+
+ private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1;
+
+ private static final String WILDCARD = "*";
+
+ /**
+ * The separator for service name
+ */
+ private static final String SERVICE_NAME_SEPARATOR = getProperty("dubbo.service.name.separator", ":");
+
+ /**
+ * The interval in second of lookup service names(only for Dubbo-OPS)
+ */
+ private static final long LOOKUP_INTERVAL = getLong("dubbo.service.names.lookup.interval", 30);
+
+ protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+ /**
+ * {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS)
+ */
+ private volatile ScheduledExecutorService serviceNamesScheduler;
+
+ public ServiceInstanceRegistry(URL url) {
+ super(url);
+ }
+
+ @Override
+ protected final void doRegister(URL url) {
+ String serviceName = getServiceName(url);
+ Registration registration = createRegistration(serviceName, url);
+ register(serviceName, toServiceInstance(registration), url);
+ }
+
+ @Override
+ protected final void doUnregister(URL url) {
+ String serviceName = getServiceName(url);
+ Registration registration = createRegistration(serviceName, url);
+ deregister(serviceName, toServiceInstance(registration), url);
+ }
+
+ @Override
+ protected final void doSubscribe(URL url, NotifyListener listener) {
+ Set serviceNames = getServiceNames(url, listener);
+ doSubscribe(url, listener, serviceNames);
+ }
+
+ @Override
+ protected void doUnsubscribe(URL url, NotifyListener listener) {
+ if (isAdminProtocol(url)) {
+ shutdownServiceNamesLookup();
+ }
+ }
+
+ /**
+ * Adapts {@link Registration} to an actual service instance
+ *
+ * @param registration {@link Registration}
+ * @return
+ */
+ protected abstract S toServiceInstance(Registration registration);
+
+ /**
+ * Adapts {@link S} to an {@link Registration}
+ *
+ * @param serviceInstance {@link S}
+ * @return an {@link Registration}
+ */
+ protected abstract Registration toRegistration(S serviceInstance);
+
+ /**
+ * Register a {@link S service instance}
+ *
+ * @param serviceName the service name
+ * @param serviceInstance {@link S service instance}
+ * @param url Dubbo's {@link URL}
+ */
+ protected abstract void register(String serviceName, S serviceInstance, URL url);
+
+ /**
+ * Deregister a {@link DubboRegistration Dubbol registration}
+ *
+ * @param serviceName the service name
+ * @param serviceInstance {@link S service instance}
+ * @param url Dubbo's {@link URL}
+ */
+ protected abstract void deregister(String serviceName, S serviceInstance, URL url);
+
+ private void doSubscribe(final URL url, final NotifyListener listener, final Set serviceNames) {
+ Collection serviceInstances = new LinkedList();
+
+ for (String serviceName : serviceNames) {
+ serviceInstances.addAll(findServiceInstances(serviceName));
+ }
+ notifySubscriber(url, listener, serviceInstances);
+ }
+
+ /**
+ * Notify the Healthy {@link DubboRegistration service instance} to subscriber.
+ *
+ * @param url {@link URL}
+ * @param listener {@link NotifyListener}
+ * @param serviceInstances all {@link S registrations}
+ */
+ private void notifySubscriber(URL url, NotifyListener listener, Collection serviceInstances) {
+ Set healthyServiceInstances = new LinkedHashSet(serviceInstances);
+ // Healthy Instances
+ filterHealthyInstances(healthyServiceInstances);
+ List urls = buildURLs(url, healthyServiceInstances);
+ this.notify(url, listener, urls);
+ }
+
+ private void filterHealthyInstances(Collection serviceInstances) {
+ filter(serviceInstances, new Filter() {
+ @Override
+ public boolean accept(S serviceInstance) {
+ return filterHealthyRegistration(serviceInstance);
+ }
+ });
+ }
+
+ /**
+ * Find the {@link Collection} of {@link S service instances} by the service name
+ *
+ * @param serviceName the service name
+ * @return a {@link Collection} of {@link S service instances}
+ */
+ protected abstract Collection findServiceInstances(String serviceName);
+
+ /**
+ * Filter Healthy the {@link S service instance}
+ *
+ * @param serviceInstance the {@link S service instance}
+ * @return if healthy , return true
+ */
+ protected abstract boolean filterHealthyRegistration(S serviceInstance);
+
+ private void shutdownServiceNamesLookup() {
+ if (serviceNamesScheduler != null) {
+ serviceNamesScheduler.shutdown();
+ }
+ }
+
+ private void scheduleServiceNamesLookup(final URL url,
+ final NotifyListener listener) {
+ if (serviceNamesScheduler == null) {
+ serviceNamesScheduler = Executors.newSingleThreadScheduledExecutor();
+ serviceNamesScheduler.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ Set serviceNames = findAllServiceNames();
+ filter(serviceNames, new Filter() {
+ @Override
+ public boolean accept(String serviceName) {
+ boolean accepted = false;
+ for (String category : ALL_SUPPORTED_CATEGORIES) {
+ String prefix = category + SERVICE_NAME_SEPARATOR;
+ if (serviceName.startsWith(prefix)) {
+ accepted = true;
+ break;
+ }
+ }
+ return accepted;
+ }
+ });
+ doSubscribe(url, listener, serviceNames);
+ }
+ }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
+ }
+ }
+
+ /**
+ * Find all service names
+ *
+ * @return all service names
+ */
+ protected abstract Set findAllServiceNames();
+
+ private List buildURLs(URL consumerURL, Collection serviceInstances) {
+ if (serviceInstances.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List urls = new LinkedList();
+ for (S serviceInstance : serviceInstances) {
+ Registration registration = toRegistration(serviceInstance);
+ URL url = buildURL(registration);
+ if (UrlUtils.isMatch(consumerURL, url)) {
+ urls.add(url);
+ }
+ }
+ return urls;
+ }
+
+ private URL buildURL(Registration registration) {
+ URL url = new URL(registration.getMetadata().get(Constants.PROTOCOL_KEY),
+ registration.getIp(), registration.getPort(),
+ registration.getMetadata());
+ return url;
+ }
+
+ /**
+ * Get the service names for Dubbo OPS
+ *
+ * @param url {@link URL}
+ * @return non-null
+ */
+ private Set getSubscribedServiceNamesForOps(URL url) {
+ Set serviceNames = findAllServiceNames();
+ filterServiceNames(serviceNames, url);
+ return serviceNames;
+ }
+
+ private void filter(Collection collection, Filter filter) {
+ Iterator iterator = collection.iterator();
+ while (iterator.hasNext()) {
+ T data = iterator.next();
+ if (!filter.accept(data)) { // remove if not accept
+ iterator.remove();
+ }
+ }
+ }
+
+ private void filterServiceNames(Set serviceNames, URL url) {
+
+ final String[] categories = getCategories(url);
+
+ final String targetServiceInterface = url.getServiceInterface();
+
+ final String targetVersion = url.getParameter(Constants.VERSION_KEY);
+
+ final String targetGroup = url.getParameter(Constants.GROUP_KEY);
+
+ filter(serviceNames, new Filter() {
+ @Override
+ public boolean accept(String serviceName) {
+ // split service name to segments
+ // (required) segments[0] = category
+ // (required) segments[1] = serviceInterface
+ // (required) segments[2] = version
+ // (optional) segments[3] = group
+ String[] segments = getServiceSegments(serviceName);
+ int length = segments.length;
+ if (length < 4) { // must present 4 segments or more
+ return false;
+ }
+
+ String category = getCategory(segments);
+ if (Arrays.binarySearch(categories, category) > -1) { // no match category
+ return false;
+ }
+
+ String serviceInterface = getServiceInterface(segments);
+ if (!WILDCARD.equals(targetServiceInterface)
+ && !StringUtils.isEquals(targetServiceInterface, serviceInterface)) { // no match interface
+ return false;
+ }
+
+ String version = getServiceVersion(segments);
+ if (!WILDCARD.equals(targetVersion)
+ && !StringUtils.isEquals(targetVersion, version)) { // no match service
+ // version
+ return false;
+ }
+
+ String group = getServiceGroup(segments);
+ if (group != null && !WILDCARD.equals(targetGroup)
+ && !StringUtils.isEquals(targetGroup, group)) { // no match service
+ // group
+ return false;
+ }
+
+ return true;
+ }
+ });
+ }
+
+ protected Registration createRegistration(String serviceName, URL url) {
+ // Append default category if absent
+ String category = url.getParameter(Constants.CATEGORY_KEY,
+ Constants.DEFAULT_CATEGORY);
+ URL newURL = url.addParameter(Constants.CATEGORY_KEY, category);
+ newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol());
+ String ip = url.getHost();
+ int port = url.getPort();
+ DubboRegistration registration = new DubboRegistration();
+ registration.setServiceName(serviceName);
+ registration.setIp(ip);
+ registration.setPort(port);
+ registration.setMetadata(new LinkedHashMap(newURL.getParameters()));
+
+ return registration;
+ }
+
+ /**
+ * Get the categories from {@link URL}
+ *
+ * @param url {@link URL}
+ * @return non-null array
+ */
+ private String[] getCategories(URL url) {
+ return Constants.ANY_VALUE.equals(url.getServiceInterface())
+ ? ALL_SUPPORTED_CATEGORIES
+ : of(Constants.DEFAULT_CATEGORY);
+ }
+
+ /**
+ * A filter
+ */
+ private interface Filter {
+
+ /**
+ * Tests whether or not the specified data should be accepted.
+ *
+ * @param data The data to be tested
+ * @return true
if and only if data
should be accepted
+ */
+ boolean accept(T data);
+
+ }
+
+ /**
+ * Get the subscribed service names from the specified {@link URL url}
+ *
+ * @param url {@link URL}
+ * @param listener {@link NotifyListener}
+ * @return non-null
+ */
+ private Set getServiceNames(URL url, NotifyListener listener) {
+ if (isAdminProtocol(url)) {
+ scheduleServiceNamesLookup(url, listener);
+ return getSubscribedServiceNamesForOps(url);
+ } else {
+ return getServiceNames(url);
+ }
+ }
+
+ private Set getServiceNames(URL url) {
+ String[] categories = getCategories(url);
+ Set serviceNames = new LinkedHashSet(categories.length);
+ for (String category : categories) {
+ final String serviceName = getServiceName(url, category);
+ serviceNames.add(serviceName);
+ }
+ return serviceNames;
+ }
+
+ private boolean isAdminProtocol(URL url) {
+ return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
+ }
+
+ /**
+ * Get the service name
+ *
+ * @param url {@link URL}
+ * @return non-null
+ */
+ public static String getServiceName(URL url) {
+ String category = url.getParameter(Constants.CATEGORY_KEY,
+ Constants.DEFAULT_CATEGORY);
+ return getServiceName(url, category);
+ }
+
+ private static String getServiceName(URL url, String category) {
+ StringBuilder serviceNameBuilder = new StringBuilder(category);
+ appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
+ appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
+ appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
+ return serviceNameBuilder.toString();
+ }
+
+ private static void appendIfPresent(StringBuilder target, URL url,
+ String parameterName) {
+ String parameterValue = url.getParameter(parameterName);
+ appendIfPresent(target, parameterValue);
+ }
+
+ public static String[] getServiceSegments(String serviceName) {
+ return serviceName.split(SERVICE_NAME_SEPARATOR);
+ }
+
+ public static String getCategory(String[] segments) {
+ return segments[CATEGORY_INDEX];
+ }
+
+ public static String getServiceInterface(String[] segments) {
+ return segments[SERVICE_INTERFACE_INDEX];
+ }
+
+ public static String getServiceVersion(String[] segments) {
+ return segments[SERVICE_VERSION_INDEX];
+ }
+
+ public static String getServiceGroup(String[] segments) {
+ return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null;
+ }
+
+ private static T[] of(T... values) {
+ return values;
+ }
+
+ private static void appendIfPresent(StringBuilder target, String parameterValue) {
+ if (StringUtils.isNotEmpty(parameterValue)) {
+ target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
+ }
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml
new file mode 100644
index 00000000000..53b7e72a597
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/pom.xml
@@ -0,0 +1,160 @@
+
+
+
+
+ dubbo-registry
+ com.alibaba
+ 2.6.6-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ dubbo-registry-nacos
+
+
+ 0.6.2
+
+
+
+
+
+ com.alibaba
+ dubbo-registry-api
+ ${project.version}
+ true
+
+
+
+ com.alibaba
+ dubbo-common
+ ${project.version}
+ true
+
+
+
+ com.alibaba.nacos
+ nacos-client
+ ${nacos.version}
+ true
+
+
+
+
+ com.alibaba
+ dubbo-config-api
+ ${project.version}
+ test
+
+
+
+ com.alibaba
+ dubbo-serialization-hessian2
+ ${project.version}
+ test
+
+
+
+ com.alibaba
+ dubbo-config-spring
+ ${project.version}
+ test
+
+
+
+ com.alibaba
+ dubbo-rpc-dubbo
+ ${project.version}
+ test
+
+
+
+ com.alibaba
+ dubbo-remoting-netty4
+ ${project.version}
+ test
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+ test
+
+
+
+
+ com.alibaba
+ dubbo-rpc-rest
+ ${project.version}
+ test
+
+
+
+ org.jboss.resteasy
+ resteasy-jaxrs
+ test
+
+
+
+ org.jboss.resteasy
+ resteasy-client
+ test
+
+
+
+ org.jboss.resteasy
+ resteasy-netty4
+ test
+
+
+
+ javax.validation
+ validation-api
+ test
+
+
+
+ org.jboss.resteasy
+ resteasy-jackson-provider
+ test
+
+
+
+ org.jboss.resteasy
+ resteasy-jaxb-provider
+ test
+
+
+
+ org.springframework
+ spring-test
+ test
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+
+
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java
new file mode 100644
index 00000000000..621e7b44bcc
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistry.java
@@ -0,0 +1,198 @@
+/*
+ * 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 com.alibaba.dubbo.registry.nacos;
+
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.registry.Registry;
+import com.alibaba.dubbo.registry.support.Registration;
+import com.alibaba.dubbo.registry.support.ServiceInstanceRegistry;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import com.alibaba.nacos.api.naming.listener.EventListener;
+import com.alibaba.nacos.api.naming.pojo.Instance;
+import com.alibaba.nacos.api.naming.pojo.ListView;
+
+import java.util.Collection;
+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;
+
+/**
+ * Nacos {@link Registry}
+ *
+ * @since 2.6.6
+ */
+public class NacosRegistry extends ServiceInstanceRegistry {
+
+ /**
+ * The pagination size of query for Nacos service names(only for Dubbo-OPS)
+ */
+ private static final int PAGINATION_SIZE = Integer.getInteger("nacos.service.names.pagination.size", 100);
+
+ private final NamingService namingService;
+
+ private final ConcurrentMap nacosListeners;
+
+ public NacosRegistry(URL url, NamingService namingService) {
+ super(url);
+ this.namingService = namingService;
+ this.nacosListeners = new ConcurrentHashMap();
+ }
+
+
+ @Override
+ protected Instance toServiceInstance(Registration registration) {
+ Instance instance = new Instance();
+ instance.setServiceName(registration.getServiceName());
+ instance.setIp(registration.getIp());
+ instance.setPort(registration.getPort());
+ instance.setMetadata(registration.getMetadata());
+ return instance;
+ }
+
+ @Override
+ protected Registration toRegistration(final Instance serviceInstance) {
+ return new Registration() {
+
+ @Override
+ public String getServiceName() {
+ return serviceInstance.getServiceName();
+ }
+
+ @Override
+ public String getIp() {
+ return serviceInstance.getIp();
+ }
+
+ @Override
+ public int getPort() {
+ return serviceInstance.getPort();
+ }
+
+ @Override
+ public Map getMetadata() {
+ return serviceInstance.getMetadata();
+ }
+ };
+ }
+
+ @Override
+ protected void register(final String serviceName, final Instance serviceInstance, URL url) {
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+ namingService.registerInstance(serviceName, serviceInstance);
+ }
+ });
+ }
+
+ @Override
+ protected void deregister(final String serviceName, final Instance serviceInstance, URL url) {
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+ namingService.deregisterInstance(serviceName, serviceInstance.getIp(), serviceInstance.getPort());
+ }
+ });
+ }
+
+ @Override
+ protected Collection findServiceInstances(final String serviceName) {
+ final Collection instances = new LinkedList();
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+ instances.addAll(namingService.getAllInstances(serviceName));
+ }
+ });
+ return instances;
+ }
+
+ @Override
+ protected boolean filterHealthyRegistration(Instance serviceInstance) {
+ return serviceInstance.isEnabled();
+ }
+
+ @Override
+ protected Set findAllServiceNames() {
+ final Set serviceNames = new LinkedHashSet();
+
+ execute(new NamingServiceCallback() {
+ @Override
+ public void callback(NamingService namingService) throws NacosException {
+
+ int pageIndex = 1;
+ ListView listView = namingService.getServicesOfServer(pageIndex, PAGINATION_SIZE);
+ // First page data
+ List firstPageData = listView.getData();
+ // Append first page into list
+ serviceNames.addAll(firstPageData);
+ // the total count
+ int count = listView.getCount();
+ // the number of pages
+ int pageNumbers = count / PAGINATION_SIZE;
+ int remainder = count % PAGINATION_SIZE;
+ // remain
+ if (remainder > 0) {
+ pageNumbers += 1;
+ }
+ // If more than 1 page
+ while (pageIndex < pageNumbers) {
+ listView = namingService.getServicesOfServer(++pageIndex, PAGINATION_SIZE);
+ serviceNames.addAll(listView.getData());
+ }
+
+ }
+ });
+
+ return serviceNames;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return "UP".equals(namingService.getServerStatus());
+ }
+
+ private void execute(NamingServiceCallback callback) {
+ try {
+ callback.callback(namingService);
+ } catch (NacosException e) {
+ if (logger.isErrorEnabled()) {
+ logger.error(e.getErrMsg(), e);
+ }
+ }
+ }
+
+ /**
+ * {@link NamingService} Callback
+ */
+ interface NamingServiceCallback {
+
+ /**
+ * Callback
+ *
+ * @param namingService {@link NamingService}
+ * @throws NacosException
+ */
+ void callback(NamingService namingService) throws NacosException;
+
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java
new file mode 100644
index 00000000000..56de76076d4
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactory.java
@@ -0,0 +1,108 @@
+/*
+ * 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 com.alibaba.dubbo.registry.nacos;
+
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.registry.Registry;
+import com.alibaba.dubbo.registry.RegistryFactory;
+import com.alibaba.dubbo.registry.support.AbstractRegistryFactory;
+import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import com.alibaba.nacos.client.naming.utils.StringUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+import static com.alibaba.dubbo.common.Constants.BACKUP_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
+import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
+import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
+import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
+import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
+import static com.alibaba.nacos.client.naming.utils.UtilAndComs.NACOS_NAMING_LOG_NAME;
+
+/**
+ * Nacos {@link RegistryFactory}
+ *
+ * @since 2.6.6
+ */
+public class NacosRegistryFactory extends AbstractRegistryFactory {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ protected Registry createRegistry(URL url) {
+ return new NacosRegistry(url, buildNamingService(url));
+ }
+
+ private NamingService buildNamingService(URL url) {
+ Properties nacosProperties = buildNacosProperties(url);
+ NamingService namingService = null;
+ try {
+ namingService = NacosFactory.createNamingService(nacosProperties);
+ } catch (NacosException e) {
+ if (logger.isErrorEnabled()) {
+ logger.error(e.getErrMsg(), e);
+ }
+ throw new IllegalStateException(e);
+ }
+ return namingService;
+ }
+
+ private Properties buildNacosProperties(URL url) {
+ Properties properties = new Properties();
+ setServerAddr(url, properties);
+ setProperties(url, properties);
+ return properties;
+ }
+
+ private void setServerAddr(URL url, Properties properties) {
+ StringBuilder serverAddrBuilder =
+ new StringBuilder(url.getHost()) // Host
+ .append(":")
+ .append(url.getPort()); // Port
+
+ // Append backup parameter as other servers
+ String backup = url.getParameter(BACKUP_KEY);
+ if (backup != null) {
+ serverAddrBuilder.append(",").append(backup);
+ }
+
+ String serverAddr = serverAddrBuilder.toString();
+ properties.put(SERVER_ADDR, serverAddr);
+ }
+
+ private void setProperties(URL url, Properties properties) {
+ putPropertyIfAbsent(url, properties, NAMESPACE);
+ putPropertyIfAbsent(url, properties, NACOS_NAMING_LOG_NAME);
+ putPropertyIfAbsent(url, properties, ENDPOINT);
+ putPropertyIfAbsent(url, properties, NAMESPACE);
+ putPropertyIfAbsent(url, properties, ACCESS_KEY);
+ putPropertyIfAbsent(url, properties, SECRET_KEY);
+ putPropertyIfAbsent(url, properties, CLUSTER_NAME);
+ }
+
+ private void putPropertyIfAbsent(URL url, Properties properties, String propertyName) {
+ String propertyValue = url.getParameter(propertyName);
+ if (StringUtils.isNotEmpty(propertyValue)) {
+ properties.setProperty(propertyName, propertyValue);
+ }
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
new file mode 100644
index 00000000000..370cd4abdcf
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
@@ -0,0 +1 @@
+nacos=com.alibaba.dubbo.registry.nacos.NacosRegistryFactory
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java
new file mode 100644
index 00000000000..c61dcb5127a
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java
@@ -0,0 +1,59 @@
+/*
+ * 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 com.alibaba.dubbo.demo.consumer;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.PropertySource;
+
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@link DemoService} consumer demo
+ */
+@EnableDubbo
+@PropertySource(value = "classpath:/consumer-config.properties")
+public class DemoServiceConsumerBootstrap {
+
+ @Reference(version = "${demo.service.version}")
+ private DemoService demoService;
+
+ @Reference(version = "${demo.service.version}", protocol = "rest")
+ private DemoService restDemoService;
+
+ @PostConstruct
+ public void init() throws InterruptedException {
+ for (int j = 0; j < 10; j++) {
+ System.out.println(demoService.sayName("小马哥(mercyblitz)"));
+ System.out.println(restDemoService.sayName("小马哥(mercyblitz)"));
+ }
+ Thread.sleep(TimeUnit.SECONDS.toMillis(5));
+ }
+
+ public static void main(String[] args) throws IOException {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.register(DemoServiceConsumerBootstrap.class);
+ context.refresh();
+ System.in.read();
+ context.close();
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
new file mode 100644
index 00000000000..65b7befb7a6
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.alibaba.dubbo.demo.consumer;
+
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.io.IOException;
+
+/**
+ * {@link DemoService} consumer demo XML bootstrap
+ */
+public class DemoServiceConsumerXmlBootstrap {
+
+ public static void main(String[] args) throws IOException {
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
+ 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)"));
+ }
+ System.in.read();
+ context.close();
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java
new file mode 100644
index 00000000000..f9cd79742db
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderBootstrap.java
@@ -0,0 +1,41 @@
+/*
+ * 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 com.alibaba.dubbo.demo.provider;
+
+import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.PropertySource;
+
+import java.io.IOException;
+
+/**
+ * {@link DemoService} provider demo
+ */
+@EnableDubbo(scanBasePackages = "com.alibaba.dubbo.demo.service")
+@PropertySource(value = "classpath:/provider-config.properties")
+public class DemoServiceProviderBootstrap {
+
+ public static void main(String[] args) throws IOException {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.register(DemoServiceProviderBootstrap.class);
+ context.refresh();
+ System.out.println("DemoService provider is starting...");
+ System.in.read();
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java
new file mode 100644
index 00000000000..964adbcb5cf
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java
@@ -0,0 +1,37 @@
+/*
+ * 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 com.alibaba.dubbo.demo.provider;
+
+import com.alibaba.dubbo.demo.service.DemoService;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.io.IOException;
+
+/**
+ * {@link DemoService} provider demo XML bootstrap
+ */
+public class DemoServiceProviderXmlBootstrap {
+
+ public static void main(String[] args) throws IOException {
+ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
+ context.setConfigLocation("/META-INF/spring/dubbo-provider-context.xml");
+ context.refresh();
+ System.out.println("DemoService provider (XML) is starting...");
+ System.in.read();
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java
new file mode 100644
index 00000000000..0ff9ada86f7
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DefaultService.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.alibaba.dubbo.demo.service;
+
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.rpc.RpcContext;
+
+import org.springframework.beans.factory.annotation.Value;
+
+
+/**
+ * Default {@link DemoService}
+ *
+ * @since 2.6.5
+ */
+@Service(version = "${demo.service.version}")
+public class DefaultService implements DemoService {
+
+ @Value("${demo.service.name}")
+ private String serviceName;
+
+ public String sayName(String name) {
+ RpcContext rpcContext = RpcContext.getContext();
+ return String.format("Service [name :%s , protocol: %s , port : %d] %s(\"%s\") : Hello,%s",
+ serviceName,
+ rpcContext.getUrl().getProtocol(),
+ rpcContext.getLocalPort(),
+ rpcContext.getMethodName(),
+ name,
+ name);
+ }
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java
new file mode 100644
index 00000000000..381540e1266
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/demo/service/DemoService.java
@@ -0,0 +1,34 @@
+/*
+ * 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 com.alibaba.dubbo.demo.service;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+/**
+ * DemoService
+ *
+ * @since 2.6.5
+ */
+@Path("/demo-service")
+public interface DemoService {
+
+ @GET
+ String sayName(@QueryParam("name") String name);
+
+}
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java
new file mode 100644
index 00000000000..8f7a1525050
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryFactoryTest.java
@@ -0,0 +1,25 @@
+/*
+ * 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 com.alibaba.dubbo.registry.nacos;
+
+/**
+ * {@link NacosRegistryFactory} Test
+ *
+ * @since 2.6.5
+ */
+public class NacosRegistryFactoryTest {
+}
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java
new file mode 100644
index 00000000000..3ff055b6554
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/com/alibaba/dubbo/registry/nacos/NacosRegistryTest.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.dubbo.registry.nacos;
+
+/**
+ * {@link NacosRegistry} Test
+ *
+ * @since 2.6.5
+ */
+public class NacosRegistryTest {
+
+ // Test case Dubbo OPS :
+ // URL : admin://30.5.124.12?category=providers,consumers,routers,configurators&check=false&classifier=*&enabled=*&group=*&interface=*&version=*
+ public void testDoSubscribeForDubboOps() {
+
+ }
+
+}
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
new file mode 100644
index 00000000000..0d47053d0d4
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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
new file mode 100644
index 00000000000..acf08a50370
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties b/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties
new file mode 100644
index 00000000000..d32e6e8a64e
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/consumer-config.properties
@@ -0,0 +1,6 @@
+## Dubbo Application info
+dubbo.application.name=dubbo-consumer-demo
+## Nacos registry address
+dubbo.registry.address=nacos://127.0.0.1:8848
+# @Reference version
+demo.service.version=1.0.0
\ No newline at end of file
diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties
new file mode 100644
index 00000000000..e2dd335b0ed
--- /dev/null
+++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/provider-config.properties
@@ -0,0 +1,14 @@
+## Dubbo Application info
+dubbo.application.name=dubbo-provider-demo
+## Nacos registry address
+dubbo.registry.protocol=nacos
+dubbo.registry.address=127.0.0.1:8848
+## Exports multiple protocols
+### Dubbo Protocol using random port
+dubbo.protocols.dubbo.port=-1
+### REST protocol
+dubbo.protocols.rest.port=9090
+dubbo.protocols.rest.server=netty
+# Provider @Service info
+demo.service.version=1.0.0
+demo.service.name=demoService
\ No newline at end of file
diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml
index b268a88d785..fe3a7f86a14 100644
--- a/dubbo-registry/pom.xml
+++ b/dubbo-registry/pom.xml
@@ -34,5 +34,6 @@
dubbo-registry-multicast
dubbo-registry-zookeeper
dubbo-registry-redis
+ dubbo-registry-nacos