diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java deleted file mode 100644 index cf72a4a1b93..00000000000 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilder.java +++ /dev/null @@ -1,142 +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 com.alibaba.dubbo.config.spring.beans.factory.annotation; - -import com.alibaba.dubbo.common.Constants; -import com.alibaba.dubbo.config.annotation.Reference; -import com.alibaba.dubbo.config.annotation.Service; -import com.alibaba.dubbo.registry.Registry; - -import org.springframework.core.env.Environment; - -import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; -import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; -import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; -import static com.alibaba.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/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index c7908cd7b66..2033e63ecc2 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -21,7 +21,6 @@ import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent; import com.alibaba.dubbo.config.spring.util.AnnotationUtils; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.context.ApplicationContext; @@ -105,7 +104,7 @@ public Map> getInjectedMetho } @Override - protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, + protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception { String referencedBeanName = buildReferencedBeanName(reference, injectedType); @@ -188,9 +187,7 @@ protected String buildInjectedObjectCacheKey(Reference reference, Object bean, S private String buildReferencedBeanName(Reference reference, Class injectedType) { - AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(reference, injectedType); - - builder.environment(getEnvironment()); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment()); return getEnvironment().resolvePlaceholders(builder.build()); } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java index 457f35567fe..5e961160927 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java @@ -23,7 +23,6 @@ import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.dubbo.config.spring.ServiceBean; import com.alibaba.dubbo.config.spring.context.annotation.DubboClassPathBeanDefinitionScanner; - import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.BeanClassLoaderAware; @@ -291,9 +290,7 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean */ private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { - AnnotationBeanNameBuilder builder = AnnotationBeanNameBuilder.create(service, interfaceClass); - - builder.environment(environment); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); return builder.build(); } @@ -439,7 +436,7 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class Method[] methods = service.methods(); List methodConfigs = MethodConfig.constructMethodConfig(methods); - if(!methodConfigs.isEmpty()){ + if (!methodConfigs.isEmpty()) { builder.addPropertyValue("methods", methodConfigs); } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java index 4a97a24b6d7..8121c0486ee 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java @@ -20,7 +20,6 @@ import com.alibaba.dubbo.config.annotation.Service; import com.alibaba.dubbo.config.spring.ReferenceBean; import com.alibaba.dubbo.config.spring.ServiceBean; - import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @@ -35,9 +34,7 @@ * @see ServiceBean * @see ReferenceBean * @since 2.6.5 - * @deprecated {@link AnnotationBeanNameBuilder} as the replacement */ -@Deprecated class ServiceBeanNameBuilder { private static final String SEPARATOR = ":"; 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 deleted file mode 100644 index 28c53ccd06a..00000000000 --- a/dubbo-config/dubbo-config-spring/src/test/java/com/alibaba/dubbo/config/spring/beans/factory/annotation/AnnotationBeanNameBuilderTest.java +++ /dev/null @@ -1,83 +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 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-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 deleted file mode 100644 index 50deb0ab026..00000000000 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/DubboRegistration.java +++ /dev/null @@ -1,93 +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 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 deleted file mode 100644 index 143cc9f4913..00000000000 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/Registration.java +++ /dev/null @@ -1,53 +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 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 deleted file mode 100644 index dd196040e58..00000000000 --- a/dubbo-registry/dubbo-registry-api/src/main/java/com/alibaba/dubbo/registry/support/ServiceInstanceRegistry.java +++ /dev/null @@ -1,471 +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 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); - append(serviceNameBuilder, url, Constants.INTERFACE_KEY); - append(serviceNameBuilder, url, Constants.VERSION_KEY); - append(serviceNameBuilder, url, Constants.GROUP_KEY); - return serviceNameBuilder.toString(); - } - - private static void append(StringBuilder target, URL url, - String parameterName) { - target.append(SERVICE_NAME_SEPARATOR); - String parameterValue = url.getParameter(parameterName); - if (StringUtils.isNotEmpty(parameterValue)) { - target.append(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; - } -} 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 index 621e7b44bcc..20ce09acbec 100644 --- 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 @@ -16,37 +16,98 @@ */ package com.alibaba.dubbo.registry.nacos; +import com.alibaba.dubbo.common.Constants; import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.common.utils.NetUtils; +import com.alibaba.dubbo.common.utils.UrlUtils; +import com.alibaba.dubbo.registry.NotifyListener; import com.alibaba.dubbo.registry.Registry; -import com.alibaba.dubbo.registry.support.Registration; -import com.alibaba.dubbo.registry.support.ServiceInstanceRegistry; +import com.alibaba.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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashSet; +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.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import 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; /** * Nacos {@link Registry} * - * @since 2.6.6 + * @see #SERVICE_NAME_SEPARATOR + * @see #PAGINATION_SIZE + * @see #LOOKUP_INTERVAL + * @since 2.6.5 */ -public class NacosRegistry extends ServiceInstanceRegistry { +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; @@ -57,83 +118,140 @@ public NacosRegistry(URL url, 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; + public boolean isAvailable() { + return "UP".equals(namingService.getServerStatus()); } @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(); - } - + public List lookup(final URL url) { + final List urls = new LinkedList(); + execute(new NamingServiceCallback() { @Override - public Map getMetadata() { - return serviceInstance.getMetadata(); + 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 - protected void register(final String serviceName, final Instance serviceInstance, URL url) { + protected void doRegister(URL url) { + final String serviceName = getServiceName(url); + final Instance instance = createInstance(url); execute(new NamingServiceCallback() { - @Override public void callback(NamingService namingService) throws NacosException { - namingService.registerInstance(serviceName, serviceInstance); + namingService.registerInstance(serviceName, instance); } }); } - @Override - protected void deregister(final String serviceName, final Instance serviceInstance, URL url) { + protected void doUnregister(final URL url) { execute(new NamingServiceCallback() { - @Override public void callback(NamingService namingService) throws NacosException { - namingService.deregisterInstance(serviceName, serviceInstance.getIp(), serviceInstance.getPort()); + String serviceName = getServiceName(url); + Instance instance = createInstance(url); + namingService.deregisterInstance(serviceName, instance.getIp(), instance.getPort()); } }); } - @Override - protected Collection findServiceInstances(final String serviceName) { - final Collection instances = new LinkedList(); + protected 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 { - instances.addAll(namingService.getAllInstances(serviceName)); + for (String serviceName : serviceNames) { + List instances = namingService.getAllInstances(serviceName); + notifySubscriber(url, listener, instances); + subscribeEventListener(serviceName, url, listener); + } } }); - return instances; } @Override - protected boolean filterHealthyRegistration(Instance serviceInstance) { - return serviceInstance.isEnabled(); + protected void doUnsubscribe(URL url, NotifyListener listener) { + if (isAdminProtocol(url)) { + shutdownServiceNamesLookup(); + } } - @Override - protected Set findAllServiceNames() { - final Set serviceNames = new LinkedHashSet(); + 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 Constants.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 @@ -166,9 +284,177 @@ public void callback(NamingService namingService) throws NacosException { return serviceNames; } - @Override - public boolean isAvailable() { - return "UP".equals(namingService.getServerStatus()); + private void filterServiceNames(List 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); + + 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); + if (logger.isInfoEnabled()) { + logger.info("The URLs[size : {}] are about to be notified from instances : {}", urls.size(), instances); + } + 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) { + URL url = new URL(instance.getMetadata().get(Constants.PROTOCOL_KEY), + instance.getIp(), + instance.getPort(), + 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()); + String ip = NetUtils.getLocalHost(); + int port = newURL.getParameter(Constants.BIND_PORT_KEY, 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(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); + return getServiceName(url, category); + } + + private 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 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) { @@ -181,8 +467,42 @@ private void execute(NamingServiceCallback callback) { } } + 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 {