From 7225f63f5655e8752de0ae2b69c5d937ad805bb6 Mon Sep 17 00:00:00 2001 From: mercyblitz Date: Wed, 31 Jul 2019 10:45:40 +0800 Subject: [PATCH] Polish spring-cloud-incubator/spring-cloud-alibaba#623 : Adapter Eureka implementation --- ...ubboServiceDiscoveryAutoConfiguration.java | 134 ++++++++++++++++++ ...oServiceRegistrationAutoConfiguration.java | 30 ++-- ...ionNonWebApplicationAutoConfiguration.java | 12 +- .../registry/AbstractSpringCloudRegistry.java | 70 +++++---- .../dubbo/registry/SpringCloudRegistry.java | 7 +- .../registry/SpringCloudRegistryFactory.java | 10 +- .../event/ServiceInstanceRegisteredEvent.java | 5 +- .../event/ServiceInstancesChangedEvent.java | 59 ++++++++ .../main/resources/META-INF/spring.factories | 3 +- 9 files changed, 261 insertions(+), 69 deletions(-) create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java create mode 100644 spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java new file mode 100644 index 00000000..e8886b04 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceDiscoveryAutoConfiguration.java @@ -0,0 +1,134 @@ +/* + * 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.cloud.dubbo.autoconfigure; + +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; +import com.netflix.discovery.CacheRefreshedEvent; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.cloud.netflix.eureka.CloudEurekaClient; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import java.util.Collection; +import java.util.List; + +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; +import static org.springframework.util.CollectionUtils.isEmpty; +import static org.springframework.util.StringUtils.hasText; + +/** + * Dubbo Service Discovery Auto {@link Configuration} (after {@link DubboServiceRegistrationAutoConfiguration}) + * + * @see DubboServiceRegistrationAutoConfiguration + * @see Configuration + * @see DiscoveryClient + */ +@Configuration +@ConditionalOnClass(name = "org.springframework.cloud.client.discovery.DiscoveryClient") +@ConditionalOnProperty(name = "spring.cloud.discovery.enabled", matchIfMissing = true) +@AutoConfigureAfter(name = { + EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, + ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME +}, value = {DubboServiceRegistrationAutoConfiguration.class}) +public class DubboServiceDiscoveryAutoConfiguration { + + public static final String ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryAutoConfiguration"; + + public static final String CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration"; + + private final DubboServiceMetadataRepository dubboServiceMetadataRepository; + + private final ApplicationEventPublisher applicationEventPublisher; + + private final ObjectProvider discoveryClient; + + public DubboServiceDiscoveryAutoConfiguration(DubboServiceMetadataRepository dubboServiceMetadataRepository, + ApplicationEventPublisher applicationEventPublisher, + ObjectProvider discoveryClient) { + this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; + this.applicationEventPublisher = applicationEventPublisher; + this.discoveryClient = discoveryClient; + } + + + /** + * Dispatch a {@link ServiceInstancesChangedEvent} + * + * @param serviceName the name of service + * @param serviceInstances the {@link ServiceInstance instances} of some service + * @see AbstractSpringCloudRegistry#registerServiceInstancesChangedEventListener(URL, NotifyListener) + */ + protected void dispatchServiceInstancesChangedEvent(String serviceName, Collection serviceInstances) { + if (!hasText(serviceName) || isEmpty(serviceInstances)) { + return; + } + ServiceInstancesChangedEvent event = new ServiceInstancesChangedEvent(serviceName, serviceInstances); + applicationEventPublisher.publishEvent(event); + } + + @Configuration + @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) + class EurekaConfiguration { + + /** + * Dispatch a {@link ServiceInstancesChangedEvent} when the {@link HeartbeatEvent} raised + *

+ * {@link CloudEurekaClient#onCacheRefreshed()} publishes a HeartbeatEvent instead of {@link CacheRefreshedEvent} + * + * @param event the {@link HeartbeatEvent} instance + * @see HeartbeatEvent + * @see CloudEurekaClient#onCacheRefreshed() + * @see CacheRefreshedEvent + */ + @EventListener(HeartbeatEvent.class) + public void onHeartbeatEvent(HeartbeatEvent event) { + discoveryClient.ifAvailable(discoveryClient -> { + dubboServiceMetadataRepository.getSubscribedServices().forEach(serviceName -> { + List serviceInstances = discoveryClient.getInstances(serviceName); + dispatchServiceInstancesChangedEvent(serviceName, serviceInstances); + }); + }); + + } + } + + @Configuration + @ConditionalOnBean(name = ZOOKEEPER_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + class ZookeeperConfiguration { + + } + + @Configuration + @ConditionalOnBean(name = CONSUL_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) + @AutoConfigureOrder + class ConsulConfiguration { + + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index d21e841f..b4331ce8 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -19,6 +19,10 @@ package com.alibaba.cloud.dubbo.autoconfigure; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ServiceBean; +import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import com.ecwid.consul.v1.agent.model.NewService; import com.netflix.appinfo.InstanceInfo; import org.aspectj.lang.annotation.Aspect; @@ -32,10 +36,6 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; @@ -53,8 +53,8 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME; import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS; import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL; import static org.springframework.util.ObjectUtils.isEmpty; @@ -68,24 +68,24 @@ import static org.springframework.util.ObjectUtils.isEmpty; @Import({DubboServiceRegistrationEventPublishingAspect.class}) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @AutoConfigureAfter(name = { - EUREKA_AUTO_CONFIGURATION_CLASS_NAME, - CONSUL_AUTO_CONFIGURATION_CLASS_NAME, + EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME, + CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME, "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" }, value = { DubboMetadataAutoConfiguration.class }) public class DubboServiceRegistrationAutoConfiguration { - public static final String EUREKA_AUTO_CONFIGURATION_CLASS_NAME = + public static final String EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration"; - public static final String CONSUL_AUTO_CONFIGURATION_CLASS_NAME = + public static final String CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration"; - public static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME = + public static final String CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME = "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration"; - public static final String ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME = + public static final String ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME = "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration"; private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class); @@ -108,7 +108,7 @@ public class DubboServiceRegistrationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) @Aspect class EurekaConfiguration implements SmartInitializingSingleton { @@ -138,7 +138,7 @@ public class DubboServiceRegistrationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) @AutoConfigureOrder class ConsulConfiguration { @@ -152,7 +152,7 @@ public class DubboServiceRegistrationAutoConfiguration { Registration registration = event.getSource(); Class registrationClass = AopUtils.getTargetClass(registration); String registrationClassName = registrationClass.getName(); - if (CONSUL_AUTO_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { + if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) { ConsulRegistration consulRegistration = (ConsulRegistration) registration; attachURLsIntoMetadata(consulRegistration); } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java index 6247a520..34d74393 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java @@ -19,6 +19,8 @@ package com.alibaba.cloud.dubbo.autoconfigure; import org.apache.dubbo.common.URL; import org.apache.dubbo.config.spring.ServiceBean; +import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import com.ecwid.consul.v1.agent.model.NewService; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -30,8 +32,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.event.ApplicationStartedEvent; -import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; -import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; @@ -43,8 +43,8 @@ import org.springframework.context.event.EventListener; import java.util.List; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME; -import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; +import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME; /** * Dubbo Service Registration Auto-{@link Configuration} for Non-Web application @@ -117,7 +117,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = ZOOKEEPER_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) class ZookeeperConfiguration implements SmartInitializingSingleton { @Autowired @@ -136,7 +136,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration { } @Configuration - @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME) + @ConditionalOnBean(name = CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME) class ConsulConfiguration { /** diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java index 75c87a92..1be4df3b 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/AbstractSpringCloudRegistry.java @@ -22,6 +22,7 @@ import org.apache.dubbo.registry.RegistryFactory; import org.apache.dubbo.registry.support.FailbackRegistry; import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; import com.alibaba.cloud.dubbo.service.DubboMetadataService; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; import com.alibaba.cloud.dubbo.util.JSONUtils; @@ -29,19 +30,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import static java.util.Collections.emptyList; -import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; @@ -63,8 +65,10 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval"; protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName(); - - private static final Set SCHEDULER_TASKS = new HashSet<>(); + /** + * Caches the IDs of {@link ApplicationListener} + */ + private static final Set registerListeners = new HashSet<>(); protected final Logger logger = LoggerFactory.getLogger(getClass()); @@ -81,22 +85,21 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { private final JSONUtils jsonUtils; - - protected final ScheduledExecutorService servicesLookupScheduler; + private final ConfigurableApplicationContext applicationContext; public AbstractSpringCloudRegistry(URL url, DiscoveryClient discoveryClient, DubboServiceMetadataRepository dubboServiceMetadataRepository, DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, JSONUtils jsonUtils, - ScheduledExecutorService servicesLookupScheduler) { + ConfigurableApplicationContext applicationContext) { super(url); this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L); this.discoveryClient = discoveryClient; this.repository = dubboServiceMetadataRepository; this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy; this.jsonUtils = jsonUtils; - this.servicesLookupScheduler = servicesLookupScheduler; + this.applicationContext = applicationContext; } protected boolean shouldRegister(URL url) { @@ -159,29 +162,45 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { doSubscribeDubboServiceURLs(url, listener); - submitSchedulerTaskIfAbsent(url, listener); + registerServiceInstancesChangedEventListener(url, listener); } - private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) { - String taskId = url.toIdentityString(); - if (SCHEDULER_TASKS.add(taskId)) { - schedule(() -> doSubscribeDubboServiceURLs(url, listener)); + /** + * Register a {@link ApplicationListener listener} for {@link ServiceInstancesChangedEvent} + * + * @param url {@link URL} + * @param listener {@link NotifyListener} + */ + private void registerServiceInstancesChangedEventListener(URL url, NotifyListener listener) { + String listenerId = url.toIdentityString(); + if (registerListeners.add(listenerId)) { + applicationContext.addApplicationListener(new ApplicationListener() { + @Override + public void onApplicationEvent(ServiceInstancesChangedEvent event) { + String serviceName = event.getServiceName(); + subscribeDubboServiceURLs(url, listener, serviceName, s -> event.getServiceInstances()); + } + }); } } - protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { + private void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) { Set subscribedServices = repository.getSubscribedServices(); + // Sync + subscribedServices.forEach(service -> subscribeDubboServiceURLs(url, listener, service, this::getServiceInstances)); + } - subscribedServices.stream() + protected void subscribeDubboServiceURLs(URL url, NotifyListener listener, String serviceName, + Function> serviceInstancesFunction) { + Optional.ofNullable(serviceName) .map(dubboMetadataConfigServiceProxy::getProxy) .filter(Objects::nonNull) - .forEach(dubboMetadataService -> { + .ifPresent(dubboMetadataService -> { List exportedURLs = getExportedURLs(dubboMetadataService, url); List allSubscribedURLs = new LinkedList<>(); for (URL exportedURL : exportedURLs) { - String serviceName = exportedURL.getParameter(APPLICATION_KEY); - List serviceInstances = getServiceInstances(serviceName); + Collection serviceInstances = serviceInstancesFunction.apply(serviceName); String protocol = exportedURL.getProtocol(); List subscribedURLs = new LinkedList<>(); serviceInstances.forEach(serviceInstance -> { @@ -252,7 +271,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { @Override public final void doUnsubscribe(URL url, NotifyListener listener) { if (isAdminURL(url)) { - shutdownServiceNamesLookup(); } } @@ -261,12 +279,6 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { return !discoveryClient.getServices().isEmpty(); } - protected void shutdownServiceNamesLookup() { - if (servicesLookupScheduler != null) { - servicesLookupScheduler.shutdown(); - } - } - protected boolean isAdminURL(URL url) { return ADMIN_PROTOCOL.equals(url.getProtocol()); } @@ -275,8 +287,4 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry { return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); } - protected ScheduledFuture schedule(Runnable runnable) { - return this.servicesLookupScheduler.scheduleAtFixedRate(runnable, servicesLookupInterval, - servicesLookupInterval, TimeUnit.SECONDS); - } } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java index ce09de4e..e7afca62 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistry.java @@ -23,8 +23,7 @@ import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepositor import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; import com.alibaba.cloud.dubbo.util.JSONUtils; import org.springframework.cloud.client.discovery.DiscoveryClient; - -import java.util.concurrent.ScheduledExecutorService; +import org.springframework.context.ConfigurableApplicationContext; /** * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" @@ -39,8 +38,8 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry { DubboServiceMetadataRepository dubboServiceMetadataRepository, DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, JSONUtils jsonUtils, - ScheduledExecutorService servicesLookupScheduler) { - super(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler); + ConfigurableApplicationContext applicationContext) { + super(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, jsonUtils, applicationContext); this.dubboServiceMetadataRepository = dubboServiceMetadataRepository; } diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java index 9cdf099c..64991b30 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/SpringCloudRegistryFactory.java @@ -17,7 +17,6 @@ package com.alibaba.cloud.dubbo.registry; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; @@ -27,10 +26,7 @@ import com.alibaba.cloud.dubbo.util.JSONUtils; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.context.ConfigurableApplicationContext; -import java.util.concurrent.ScheduledExecutorService; - import static java.lang.System.getProperty; -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; /** * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" @@ -50,8 +46,6 @@ public class SpringCloudRegistryFactory implements RegistryFactory { private static ConfigurableApplicationContext applicationContext; - private final ScheduledExecutorService servicesLookupScheduler; - private DiscoveryClient discoveryClient; private DubboServiceMetadataRepository dubboServiceMetadataRepository; @@ -63,8 +57,6 @@ public class SpringCloudRegistryFactory implements RegistryFactory { private volatile boolean initialized = false; public SpringCloudRegistryFactory() { - servicesLookupScheduler = newSingleThreadScheduledExecutor( - new NamedThreadFactory(SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX)); } protected void init() { @@ -81,7 +73,7 @@ public class SpringCloudRegistryFactory implements RegistryFactory { public Registry getRegistry(URL url) { init(); return new SpringCloudRegistry(url, discoveryClient, dubboServiceMetadataRepository, - dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler); + dubboMetadataConfigServiceProxy, jsonUtils, applicationContext); } public static void setApplicationContext(ConfigurableApplicationContext applicationContext) { diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java index 0022cfac..c51e86ab 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstanceRegisteredEvent.java @@ -18,15 +18,14 @@ package com.alibaba.cloud.dubbo.registry.event; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; - -import java.util.EventObject; +import org.springframework.context.ApplicationEvent; /** * The after-{@link ServiceRegistry#register(Registration) register} event for {@link Registration} * * @author Mercy */ -public class ServiceInstanceRegisteredEvent extends EventObject { +public class ServiceInstanceRegisteredEvent extends ApplicationEvent { public ServiceInstanceRegisteredEvent(Registration source) { super(source); diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java new file mode 100644 index 00000000..a3cac681 --- /dev/null +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancesChangedEvent.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.dubbo.registry.event; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.context.ApplicationEvent; + +import java.util.Collection; + +import static java.util.Collections.unmodifiableCollection; + +/** + * An event raised after the {@link ServiceInstance instances} of one service has been changed. + */ +public class ServiceInstancesChangedEvent extends ApplicationEvent { + + private final String serviceName; + + private final Collection serviceInstances; + + /** + * @param serviceName The name of service that was changed + * @param serviceInstances all {@link ServiceInstance service instances} + * @throws IllegalArgumentException if source is null. + */ + public ServiceInstancesChangedEvent(String serviceName, Collection serviceInstances) { + super(serviceName); + this.serviceName = serviceName; + this.serviceInstances = unmodifiableCollection(serviceInstances); + } + + /** + * @return The name of service that was changed + */ + public String getServiceName() { + return serviceName; + } + + /** + * @return all {@link ServiceInstance service instances} + */ + public Collection getServiceInstances() { + return serviceInstances; + } +} diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories index dbaa6c57..5969971e 100644 --- a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories @@ -4,7 +4,8 @@ com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration,\ com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration,\ com.alibaba.cloud.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\ -com.alibaba.cloud.dubbo.autoconfigure.DubboServiceAutoConfiguration +com.alibaba.cloud.dubbo.autoconfigure.DubboServiceAutoConfiguration,\ +com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration=\ com.alibaba.cloud.dubbo.actuate.DubboMetadataEndpointAutoConfiguration