diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java new file mode 100644 index 00000000000..610058acd71 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.spring.beans.factory.annotation; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.registry.Registry; + +import org.springframework.core.env.Environment; + +import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL; +import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName; +import static org.springframework.util.StringUtils.arrayToCommaDelimitedString; +import static org.springframework.util.StringUtils.hasText; + +/** + * The Bean Name Builder for the annotations {@link Service} and {@link Reference} + *

+ * The naming rule is consistent with the the implementation {@link Registry} that is based on the service-name aware + * infrastructure, e.g Spring Cloud, Cloud Native and so on. + *

+ * The pattern of bean name : ${category}:${protocol}:${serviceInterface}:${version}:${group}. + *

+ * ${version} and ${group} are optional. + * + * @since 2.6.6 + */ +class AnnotationBeanNameBuilder { + + private static final String SEPARATOR = ":"; + + // Required properties + + private final String category; + + private final String protocol; + + private final String interfaceClassName; + + // Optional properties + + private String version; + + private String group; + + private Environment environment; + + private AnnotationBeanNameBuilder(String category, String protocol, String interfaceClassName) { + this.category = category; + this.protocol = protocol; + this.interfaceClassName = interfaceClassName; + } + + private AnnotationBeanNameBuilder(Service service, Class interfaceClass) { + this(PROVIDERS_CATEGORY, resolveProtocol(service.protocol()), resolveInterfaceName(service, interfaceClass)); + this.group(service.group()); + this.version(service.version()); + } + + private AnnotationBeanNameBuilder(Reference reference, Class interfaceClass) { + this(CONSUMERS_CATEGORY, resolveProtocol(reference.protocol()), resolveInterfaceName(reference, interfaceClass)); + this.group(reference.group()); + this.version(reference.version()); + } + + public static AnnotationBeanNameBuilder create(Service service, Class interfaceClass) { + return new AnnotationBeanNameBuilder(service, interfaceClass); + } + + public static AnnotationBeanNameBuilder create(Reference reference, Class interfaceClass) { + return new AnnotationBeanNameBuilder(reference, interfaceClass); + } + + private static void append(StringBuilder builder, String value) { + if (hasText(value)) { + builder.append(SEPARATOR).append(value); + } + } + + public AnnotationBeanNameBuilder group(String group) { + this.group = group; + return this; + } + + public AnnotationBeanNameBuilder version(String version) { + this.version = version; + return this; + } + + public AnnotationBeanNameBuilder environment(Environment environment) { + this.environment = environment; + return this; + } + + /** + * Resolve the protocol + * + * @param protocols one or more protocols + * @return if protocols == null, it will return + * {@link Constants#DEFAULT_PROTOCOL "dubbo"} as the default protocol + * @see Constants#DEFAULT_PROTOCOL + */ + private static String resolveProtocol(String... protocols) { + String protocol = arrayToCommaDelimitedString(protocols); + return hasText(protocol) ? protocol : DEFAULT_PROTOCOL; + } + + /** + * Build bean name while resolve the placeholders if possible. + * + * @return pattern : ${category}:${protocol}:${serviceInterface}:${version}:${group} + */ + public String build() { + // Append the required properties + StringBuilder beanNameBuilder = new StringBuilder(category); + append(beanNameBuilder, protocol); + append(beanNameBuilder, interfaceClassName); + // Append the optional properties + append(beanNameBuilder, version); + append(beanNameBuilder, group); + String beanName = beanNameBuilder.toString(); + // Resolve placeholders + return environment != null ? environment.resolvePlaceholders(beanName) : beanName; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index e02c1e10cc5..94bf9e800fe 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -188,7 +188,9 @@ protected String buildInjectedObjectCacheKey(Reference reference, Object bean, S private String buildReferencedBeanName(Reference reference, Class injectedType) { - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment()); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType); + + builder.environment(getEnvironment()); return getEnvironment().resolvePlaceholders(builder.build()); } @@ -261,4 +263,4 @@ public void destroy() throws Exception { this.injectedFieldReferenceBeanCache.clear(); this.injectedMethodReferenceBeanCache.clear(); } -} +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java index 22fa70422d5..532026de3d1 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java @@ -18,7 +18,6 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.config.MethodConfig; import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner; @@ -290,8 +289,9 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean */ private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, interfaceClass); + builder.environment(environment); return builder.build(); @@ -316,8 +316,9 @@ private Class resolveServiceInterfaceClass(Class annotatedServiceBeanClass } if (interfaceClass == null) { - - Class[] allInterfaces = annotatedServiceBeanClass.getInterfaces(); + // Find all interfaces from the annotated class + // To resolve an issue : https://github.com/apache/incubator-dubbo/issues/3251 + Class[] allInterfaces = ClassUtils.getAllInterfacesForClass(annotatedServiceBeanClass); if (allInterfaces.length > 0) { interfaceClass = allInterfaces[0]; @@ -435,11 +436,6 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class builder.addPropertyValue("protocols", protocolRuntimeBeanReferences); } - List methodConfigs = MethodConfig.constructMethodConfig(service.methods()); - if (!methodConfigs.isEmpty()) { - builder.addPropertyValue("methods", methodConfigs); - } - return builder.getBeanDefinition(); } @@ -490,4 +486,4 @@ public void setBeanClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } -} +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java deleted file mode 100644 index 6cd712408be..00000000000 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.dubbo.config.spring.beans.factory.annotation; - -import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.config.spring.ReferenceBean; -import org.apache.dubbo.config.spring.ServiceBean; - -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - -import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName; - - -/** - * Dubbo {@link Service @Service} Bean Builder - * - * @see Service - * @see Reference - * @see ServiceBean - * @see ReferenceBean - * @since 2.6.5 - */ -class ServiceBeanNameBuilder { - - private static final String SEPARATOR = ":"; - - private final String interfaceClassName; - - private final Environment environment; - - // Optional - private String version; - - private String group; - - private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) { - this.interfaceClassName = interfaceClassName; - this.environment = environment; - } - - private ServiceBeanNameBuilder(Class interfaceClass, Environment environment) { - this(interfaceClass.getName(), environment); - } - - private ServiceBeanNameBuilder(Service service, Class interfaceClass, Environment environment) { - this(resolveInterfaceName(service, interfaceClass), environment); - this.group(service.group()); - this.version(service.version()); - } - - private ServiceBeanNameBuilder(Reference reference, Class interfaceClass, Environment environment) { - this(resolveInterfaceName(reference, interfaceClass), environment); - this.group(reference.group()); - this.version(reference.version()); - } - - public static ServiceBeanNameBuilder create(Class interfaceClass, Environment environment) { - return new ServiceBeanNameBuilder(interfaceClass, environment); - } - - public static ServiceBeanNameBuilder create(Service service, Class interfaceClass, Environment environment) { - return new ServiceBeanNameBuilder(service, interfaceClass, environment); - } - - public static ServiceBeanNameBuilder create(Reference reference, Class interfaceClass, Environment environment) { - return new ServiceBeanNameBuilder(reference, interfaceClass, environment); - } - - private static void append(StringBuilder builder, String value) { - if (StringUtils.hasText(value)) { - builder.append(SEPARATOR).append(value); - } - } - - public ServiceBeanNameBuilder group(String group) { - this.group = group; - return this; - } - - public ServiceBeanNameBuilder version(String version) { - this.version = version; - return this; - } - - public String build() { - StringBuilder beanNameBuilder = new StringBuilder("ServiceBean"); - // Required - append(beanNameBuilder, interfaceClassName); - // Optional - append(beanNameBuilder, version); - append(beanNameBuilder, group); - // Build - String rawBeanName = beanNameBuilder.toString(); - // Resolve placeholders - return environment.resolvePlaceholders(rawBeanName); - } -} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java similarity index 51% rename from dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java rename to dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java index b3616cd58a3..2e79109ab33 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java @@ -16,29 +16,31 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; - import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.annotation.Service; import org.apache.dubbo.config.spring.api.DemoService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +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 org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.GROUP; +import static org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationBeanNameBuilderTest.VERSION; /** - * {@link ServiceBeanNameBuilder} Test + * {@link AnnotationBeanNameBuilder} Test * - * @see ServiceBeanNameBuilder - * @since 2.6.5 + * @see AnnotationBeanNameBuilder + * @since 2.6.6 */ -@Service(interfaceClass = DemoService.class, group = ServiceBeanNameBuilderTest.GROUP, version = ServiceBeanNameBuilderTest.VERSION, +@Service(interfaceClass = DemoService.class, group = GROUP, version = VERSION, application = "application", module = "module", registry = {"1", "2", "3"}) -public class ServiceBeanNameBuilderTest { +public class AnnotationBeanNameBuilderTest { - @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0", + @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "${dubbo.version}", application = "application", module = "module", registry = {"1", "2", "3"}) static final Class INTERFACE_CLASS = DemoService.class; @@ -46,30 +48,36 @@ public class ServiceBeanNameBuilderTest { static final String VERSION = "1.0.0"; - static final String BEAN_NAME = "ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO"; - - private MockEnvironment environment = new MockEnvironment(); + private MockEnvironment environment; - @Test - public void testRequiredAttributes() { - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment); - Assertions.assertEquals("ServiceBean:org.apache.dubbo.config.spring.api.DemoService", builder.build()); + @Before + public void prepare() { + environment = new MockEnvironment(); + environment.setProperty("dubbo.version", "1.0.0"); } @Test public void testServiceAnnotation() { - Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class); - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment); - Assertions.assertEquals(BEAN_NAME, + Service service = AnnotationUtils.getAnnotation(AnnotationBeanNameBuilderTest.class, Service.class); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, INTERFACE_CLASS); + Assert.assertEquals("providers:dubbo:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", + builder.build()); + + builder.environment(environment); + Assert.assertEquals("providers:dubbo:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", builder.build()); } @Test public void testReferenceAnnotation() { - Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); - ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment); - Assertions.assertEquals(BEAN_NAME, + Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(AnnotationBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); + AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, INTERFACE_CLASS); + Assert.assertEquals("consumers:dubbo:org.apache.dubbo.config.spring.api.DemoService:${dubbo.version}:DUBBO", + builder.build()); + + builder.environment(environment); + Assert.assertEquals("consumers:dubbo:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO", builder.build()); } -} +} \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/pom.xml b/dubbo-registry/dubbo-registry-nacos/pom.xml new file mode 100644 index 00000000000..f64fa021df2 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/pom.xml @@ -0,0 +1,153 @@ + + + + org.apache.dubbo + dubbo-registry + 2.7.1-SNAPSHOT + ../pom.xml + + 4.0.0 + + org.apache.dubbo + dubbo-registry-nacos + ${project.artifactId} + The Nacos registry module of Dubbo project + + + 0.9.0 + + + + + + org.apache.dubbo + dubbo-registry-api + ${project.version} + true + + + + org.apache.dubbo + dubbo-common + ${project.version} + true + + + + com.alibaba.nacos + nacos-client + ${nacos.version} + true + + + + + org.apache.dubbo + dubbo-config-api + ${project.version} + test + + + + org.apache.dubbo + dubbo-serialization-hessian2 + ${project.version} + test + + + + org.apache.dubbo + dubbo-config-spring + ${project.version} + test + + + + org.apache.dubbo + dubbo-rpc-dubbo + ${project.version} + test + + + + org.apache.dubbo + dubbo-remoting-netty4 + ${project.version} + test + + + + ch.qos.logback + logback-classic + test + + + + + org.apache.dubbo + 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 + + + + \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java new file mode 100644 index 00000000000..31ca2a83ca5 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistry.java @@ -0,0 +1,530 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.registry.nacos; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.registry.NotifyListener; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.support.FailbackRegistry; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.listener.Event; +import com.alibaba.nacos.api.naming.listener.EventListener; +import com.alibaba.nacos.api.naming.listener.NamingEvent; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static org.apache.dubbo.common.Constants.ADMIN_PROTOCOL; +import static org.apache.dubbo.common.Constants.CATEGORY_KEY; +import static org.apache.dubbo.common.Constants.CONFIGURATORS_CATEGORY; +import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY; +import static org.apache.dubbo.common.Constants.DEFAULT_CATEGORY; +import static org.apache.dubbo.common.Constants.GROUP_KEY; +import static org.apache.dubbo.common.Constants.INTERFACE_KEY; +import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY; +import static org.apache.dubbo.common.Constants.ROUTERS_CATEGORY; +import static org.apache.dubbo.common.Constants.VERSION_KEY; + +/** + * Nacos {@link Registry} + * + * @see #SERVICE_NAME_SEPARATOR + * @see #PAGINATION_SIZE + * @see #LOOKUP_INTERVAL + * @since 2.6.5 + */ +public class NacosRegistry 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 = 1; + + private static final int SERVICE_VERSION_INDEX = 2; + + private static final int SERVICE_GROUP_INDEX = 3; + + private static final String WILDCARD = "*"; + + /** + * The separator for service name + * + * @revert change a constant to be configurable, it's designed for Windows file name that is compatible with old + * Nacos binary release(< 0.6.1) + */ + private static final String SERVICE_NAME_SEPARATOR = System.getProperty("nacos.service.name.separator", ":"); + + /** + * 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); + + /** + * The interval in second of lookup Nacos service names(only for Dubbo-OPS) + */ + private static final long LOOKUP_INTERVAL = Long.getLong("nacos.service.names.lookup.interval", 30); + + /** + * {@link ScheduledExecutorService} lookup Nacos service names(only for Dubbo-OPS) + */ + private volatile ScheduledExecutorService scheduledExecutorService; + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final NamingService namingService; + + private final ConcurrentMap nacosListeners; + + public NacosRegistry(URL url, NamingService namingService) { + super(url); + this.namingService = namingService; + this.nacosListeners = new ConcurrentHashMap(); + } + + @Override + public boolean isAvailable() { + return "UP".equals(namingService.getServerStatus()); + } + + @Override + public List lookup(final URL url) { + final List urls = new LinkedList(); + execute(new NamingServiceCallback() { + @Override + public void callback(NamingService namingService) throws NacosException { + List serviceNames = getServiceNames(url, null); + for (String serviceName : serviceNames) { + List instances = namingService.getAllInstances(serviceName); + urls.addAll(buildURLs(url, instances)); + } + } + }); + return urls; + } + + @Override + public void doRegister(URL url) { + final String serviceName = getServiceName(url); + final Instance instance = createInstance(url); + execute(new NamingServiceCallback() { + public void callback(NamingService namingService) throws NacosException { + namingService.registerInstance(serviceName, instance); + } + }); + } + + @Override + public void doUnregister(final URL url) { + execute(new NamingServiceCallback() { + public void callback(NamingService namingService) throws NacosException { + String serviceName = getServiceName(url); + Instance instance = createInstance(url); + namingService.deregisterInstance(serviceName, instance.getIp(), instance.getPort()); + } + }); + } + + @Override + public void doSubscribe(final URL url, final NotifyListener listener) { + List serviceNames = getServiceNames(url, listener); + doSubscribe(url, listener, serviceNames); + } + + private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) { + execute(new NamingServiceCallback() { + @Override + public void callback(NamingService namingService) throws NacosException { + for (String serviceName : serviceNames) { + List instances = namingService.getAllInstances(serviceName); + notifySubscriber(url, listener, instances); + subscribeEventListener(serviceName, url, listener); + } + } + }); + } + + @Override + public void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } + } + + private void shutdownServiceNamesLookup() { + if (scheduledExecutorService != null) { + scheduledExecutorService.shutdown(); + } + } + + /** + * Get the service names from the specified {@link URL url} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @return non-null + */ + private List getServiceNames(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + scheduleServiceNamesLookup(url, listener); + return getServiceNamesForOps(url); + } else { + return doGetServiceNames(url); + } + } + + private boolean isAdminProtocol(URL url) { + return ADMIN_PROTOCOL.equals(url.getProtocol()); + } + + private void scheduleServiceNamesLookup(final URL url, final NotifyListener listener) { + if (scheduledExecutorService == null) { + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + scheduledExecutorService.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + List serviceNames = getAllServiceNames(); + filterData(serviceNames, new NacosDataFilter() { + @Override + public boolean accept(String serviceName) { + boolean accepted = false; + for (String category : ALL_SUPPORTED_CATEGORIES) { + String prefix = category + SERVICE_NAME_SEPARATOR; + if (StringUtils.startsWith(serviceName, prefix)) { + accepted = true; + break; + } + } + return accepted; + } + }); + doSubscribe(url, listener, serviceNames); + } + }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS); + } + } + + /** + * Get the service names for Dubbo OPS + * + * @param url {@link URL} + * @return non-null + */ + private List getServiceNamesForOps(URL url) { + List serviceNames = getAllServiceNames(); + filterServiceNames(serviceNames, url); + return serviceNames; + } + + private List getAllServiceNames() { + + final List serviceNames = new LinkedList(); + + 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; + } + + private void filterServiceNames(List serviceNames, URL url) { + + final String[] categories = getCategories(url); + + final String targetServiceInterface = url.getServiceInterface(); + + final String targetVersion = url.getParameter(VERSION_KEY); + + final String targetGroup = url.getParameter(GROUP_KEY); + + filterData(serviceNames, new NacosDataFilter() { + @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 = StringUtils.split(serviceName, SERVICE_NAME_SEPARATOR); + int length = segments.length; + if (length < 3) { // must present 3 segments or more + return false; + } + + String category = segments[CATEGORY_INDEX]; + if (!ArrayUtils.contains(categories, category)) { // no match category + return false; + } + + String serviceInterface = segments[SERVICE_INTERFACE_INDEX]; + if (!WILDCARD.equals(targetServiceInterface) && + !StringUtils.equals(targetServiceInterface, serviceInterface)) { // no match service interface + return false; + } + + String version = segments[SERVICE_VERSION_INDEX]; + if (!WILDCARD.equals(targetVersion) && + !StringUtils.equals(targetVersion, version)) { // no match service version + return false; + } + + String group = length > 3 ? segments[SERVICE_GROUP_INDEX] : null; + if (group != null && !WILDCARD.equals(targetGroup) + && !StringUtils.equals(targetGroup, group)) { // no match service group + return false; + } + + return true; + } + }); + } + + private void filterData(Collection collection, NacosDataFilter filter) { + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + T data = iterator.next(); + if (!filter.accept(data)) { // remove if not accept + iterator.remove(); + } + } + } + + private List doGetServiceNames(URL url) { + String[] categories = getCategories(url); + List serviceNames = new ArrayList(categories.length); + for (String category : categories) { + final String serviceName = getServiceName(url, category); + serviceNames.add(serviceName); + } + return serviceNames; + } + + private List buildURLs(URL consumerURL, Collection instances) { + if (instances.isEmpty()) { + return Collections.emptyList(); + } + List urls = new LinkedList(); + for (Instance instance : instances) { + URL url = buildURL(instance); + if (UrlUtils.isMatch(consumerURL, url)) { + urls.add(url); + } + } + return urls; + } + + private void subscribeEventListener(String serviceName, final URL url, final NotifyListener listener) + throws NacosException { + if (!nacosListeners.containsKey(serviceName)) { + EventListener eventListener = new EventListener() { + public void onEvent(Event event) { + if (event instanceof NamingEvent) { + NamingEvent e = (NamingEvent) event; + notifySubscriber(url, listener, e.getInstances()); + } + } + }; + namingService.subscribe(serviceName, eventListener); + nacosListeners.put(serviceName, eventListener); + } + } + + /** + * Notify the Healthy {@link Instance instances} to subscriber. + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + * @param instances all {@link Instance instances} + */ + private void notifySubscriber(URL url, NotifyListener listener, Collection instances) { + List healthyInstances = new LinkedList(instances); + // Healthy Instances + filterHealthyInstances(healthyInstances); + List urls = buildURLs(url, healthyInstances); + NacosRegistry.this.notify(url, listener, urls); + } + + /** + * 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); + } + + private URL buildURL(Instance instance) { + Map metadata = instance.getMetadata(); + String protocol = metadata.get(Constants.PROTOCOL_KEY); + String path = metadata.get(Constants.PATH_KEY); + URL url = new URL(protocol, + instance.getIp(), + instance.getPort(), + path, + instance.getMetadata()); + return url; + } + + private Instance createInstance(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()); + newURL = newURL.addParameter(Constants.PATH_KEY, url.getPath()); + String ip = url.getHost(); + int port = url.getPort(); + Instance instance = new Instance(); + instance.setIp(ip); + instance.setPort(port); + instance.setMetadata(new HashMap(newURL.getParameters())); + return instance; + } + + private String getServiceName(URL url) { + String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); + return getServiceName(url, category); + } + + private String getServiceName(URL url, String category) { + StringBuilder serviceNameBuilder = new StringBuilder(category); + appendIfPresent(serviceNameBuilder, url, INTERFACE_KEY); + appendIfPresent(serviceNameBuilder, url, VERSION_KEY); + appendIfPresent(serviceNameBuilder, url, GROUP_KEY); + return serviceNameBuilder.toString(); + } + + private void appendIfPresent(StringBuilder target, URL url, String parameterName) { + String parameterValue = url.getParameter(parameterName); + if (!StringUtils.isBlank(parameterValue)) { + target.append(SERVICE_NAME_SEPARATOR).append(parameterValue); + } + } + + private void execute(NamingServiceCallback callback) { + try { + callback.callback(namingService); + } catch (NacosException e) { + if (logger.isErrorEnabled()) { + logger.error(e.getErrMsg(), e); + } + } + } + + private void filterHealthyInstances(Collection instances) { + filterData(instances, new NacosDataFilter() { + @Override + public boolean accept(Instance data) { + return data.isEnabled(); + } + }); + } + + private static T[] of(T... values) { + return values; + } + + + /** + * A filter for Nacos data + * + * @since 2.6.5 + */ + private interface NacosDataFilter { + + /** + * 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); + + } + + /** + * {@link NamingService} Callback + * + * @since 2.6.5 + */ + 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/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/dubbo/registry/nacos/NacosRegistryFactory.java new file mode 100644 index 00000000000..1470c198932 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/java/org/apache/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 org.apache.dubbo.registry.nacos; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.RegistryFactory; +import org.apache.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.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; +import static org.apache.dubbo.common.Constants.BACKUP_KEY; + +/** + * Nacos {@link RegistryFactory} + * + * @since 2.6.5 + */ +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/internal/org.apache.dubbo.registry.RegistryFactory b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory new file mode 100644 index 00000000000..bb754674978 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.registry.RegistryFactory @@ -0,0 +1 @@ +nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerBootstrap.java new file mode 100644 index 00000000000..b411d4a80f0 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.dubbo.demo.consumer; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.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/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/consumer/DemoServiceConsumerXmlBootstrap.java new file mode 100644 index 00000000000..cc25f8c1355 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.dubbo.demo.consumer; + +import org.apache.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/org/apache/dubbo/demo/provider/DemoServiceProviderBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderBootstrap.java new file mode 100644 index 00000000000..c1d2ec4f0f5 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.dubbo.demo.provider; + +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.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 = "org.apache.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/org/apache/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/provider/DemoServiceProviderXmlBootstrap.java new file mode 100644 index 00000000000..0a37f3fabe9 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.dubbo.demo.provider; + +import org.apache.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/org/apache/dubbo/demo/service/DefaultService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DefaultService.java new file mode 100644 index 00000000000..56393ef3961 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.dubbo.demo.service; + +import org.apache.dubbo.config.annotation.Service; +import org.apache.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/org/apache/dubbo/demo/service/DemoService.java b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/dubbo/demo/service/DemoService.java new file mode 100644 index 00000000000..0c808779311 --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/java/org/apache/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 org.apache.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/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..3fa32d77b5f --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-consumer-context.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ 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..36b1267ddbb --- /dev/null +++ b/dubbo-registry/dubbo-registry-nacos/src/test/resources/META-INF/spring/dubbo-provider-context.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + \ 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 33a329bb0fd..ea09685010a 100644 --- a/dubbo-registry/pom.xml +++ b/dubbo-registry/pom.xml @@ -36,5 +36,6 @@ dubbo-registry-redis dubbo-registry-consul dubbo-registry-etcd3 + dubbo-registry-nacos