diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java index 6fca3f2a..c1d23cb1 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java @@ -17,18 +17,21 @@ package com.alibaba.cloud.dubbo.autoconfigure; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; 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.ServiceInstancePreDeregisteredEvent; import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import com.ecwid.consul.v1.agent.model.NewService; import com.netflix.appinfo.InstanceInfo; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.ServiceBean; -import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,6 +45,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; @@ -51,7 +55,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.context.event.ApplicationContextEvent; import org.springframework.context.event.EventListener; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; 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; @@ -106,10 +113,33 @@ public class DubboServiceRegistrationAutoConfiguration { return new RegistryConfig(ADDRESS, PROTOCOL); } + private Map, Set> registrations = new ConcurrentHashMap<>(); + + @Order + @EventListener(ApplicationContextEvent.class) + public void attachDubboMetadataAndRegistAgain(ApplicationContextEvent event) { + registrations.forEach( + (registry, registrations) -> registrations.forEach(registration -> { + attachDubboMetadataServiceMetadata(registration); + registry.register(registration); + })); + } + @EventListener(ServiceInstancePreRegisteredEvent.class) public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) { Registration registration = event.getSource(); - attachDubboMetadataServiceMetadata(registration); + ServiceRegistry registry = event.getRegistry(); + synchronized (registry) { + registrations.putIfAbsent(registry, new HashSet<>()); + registrations.get(registry).add(registration); + } + } + + @EventListener(ServiceInstancePreDeregisteredEvent.class) + public void onServiceInstancePreDeregistered( + ServiceInstancePreDeregisteredEvent event) { + ServiceRegistry registry = event.getRegistry(); + registrations.remove(registry); } private void attachDubboMetadataServiceMetadata(Registration registration) { @@ -132,21 +162,19 @@ public class DubboServiceRegistrationAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean(name = EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME) - @Aspect class EurekaConfiguration implements SmartInitializingSingleton { @Autowired private ObjectProvider> serviceBeans; - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered( - ServiceInstancePreRegisteredEvent event) { - Registration registration = event.getSource(); - EurekaRegistration eurekaRegistration = EurekaRegistration.class - .cast(registration); - InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager() - .getInfo(); - attachDubboMetadataServiceMetadata(instanceInfo.getMetadata()); + @Order(Ordered.LOWEST_PRECEDENCE - 1) + @EventListener(ApplicationContextEvent.class) + public void onServiceInstancePreRegistered(ApplicationContextEvent event) { + registrations.forEach((registry, registrations)-> registrations.forEach(registration -> { + EurekaRegistration eurekaRegistration = (EurekaRegistration) registration; + InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo(); + attachDubboMetadataServiceMetadata(instanceInfo.getMetadata()); + })); } /** @@ -171,21 +199,25 @@ public class DubboServiceRegistrationAutoConfiguration { @AutoConfigureOrder class ConsulConfiguration { - /** - * Handle the pre-registered event of {@link ServiceInstance} for Consul. - * @param event {@link ServiceInstancePreRegisteredEvent} - */ - @EventListener(ServiceInstancePreRegisteredEvent.class) - public void onServiceInstancePreRegistered( - ServiceInstancePreRegisteredEvent event) { - Registration registration = event.getSource(); - Class registrationClass = AopUtils.getTargetClass(registration); - String registrationClassName = registrationClass.getName(); - if (CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME - .equalsIgnoreCase(registrationClassName)) { - ConsulRegistration consulRegistration = (ConsulRegistration) registration; - attachURLsIntoMetadata(consulRegistration); - } + @Order(Ordered.LOWEST_PRECEDENCE - 1) + @EventListener(ApplicationContextEvent.class) + public void attachURLsIntoMetadataBeforeReRegist(ApplicationContextEvent event) { + registrations.entrySet().removeIf(entry -> { + Set registrations = entry.getValue(); + registrations.removeIf(registration -> { + Class registrationClass = AopUtils.getTargetClass(registration); + String registrationClassName = registrationClass.getName(); + return !CONSUL_AUTO_SERVICE_AUTO_REGISTRATION_CLASS_NAME + .equalsIgnoreCase(registrationClassName); + }); + return registrations.isEmpty(); + }); + + registrations.forEach( + (registry, registrations) -> registrations.forEach(registration -> { + ConsulRegistration consulRegistration = (ConsulRegistration) registration; + attachURLsIntoMetadata(consulRegistration); + })); } private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) { diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java index 43e679f5..8cd5c6b7 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/DubboServiceRegistrationEventPublishingAspect.java @@ -16,6 +16,7 @@ package com.alibaba.cloud.dubbo.registry; +import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreDeregisteredEvent; import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent; import com.alibaba.cloud.dubbo.registry.event.ServiceInstanceRegisteredEvent; import org.aspectj.lang.annotation.After; @@ -33,6 +34,7 @@ import org.springframework.context.ApplicationEventPublisherAware; * @author Mercy * @see ServiceInstancePreRegisteredEvent * @see ServiceInstanceRegisteredEvent + * @see ServiceInstancePreDeregisteredEvent */ @Aspect public class DubboServiceRegistrationEventPublishingAspect @@ -41,18 +43,29 @@ public class DubboServiceRegistrationEventPublishingAspect /** * The pointcut expression for {@link ServiceRegistry#register(Registration)}. */ - public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && args(registration)"; + public static final String REGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(*)) && target(registry) && args(registration)"; + + /** + * The pointcut expression for {@link ServiceRegistry#deregister(Registration)}. + */ + public static final String DEREGISTER_POINTCUT_EXPRESSION = "execution(* org.springframework.cloud.client.serviceregistry.ServiceRegistry.deregister(*)) && target(registry) && args(registration)"; private ApplicationEventPublisher applicationEventPublisher; - @Before(REGISTER_POINTCUT_EXPRESSION) - public void beforeRegister(Registration registration) { - applicationEventPublisher - .publishEvent(new ServiceInstancePreRegisteredEvent(registration)); + @Before(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") + public void beforeRegister(ServiceRegistry registry, Registration registration) { + applicationEventPublisher.publishEvent( + new ServiceInstancePreRegisteredEvent(registry, registration)); } - @After(REGISTER_POINTCUT_EXPRESSION) - public void afterRegister(Registration registration) { + @Before(value = DEREGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") + public void beforeDeregister(ServiceRegistry registry, Registration registration) { + applicationEventPublisher.publishEvent( + new ServiceInstancePreDeregisteredEvent(registry, registration)); + } + + @After(value = REGISTER_POINTCUT_EXPRESSION, argNames = "registry, registration") + public void afterRegister(ServiceRegistry registry, Registration registration) { applicationEventPublisher .publishEvent(new ServiceInstanceRegisteredEvent(registration)); } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreDeregisteredEvent.java b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreDeregisteredEvent.java new file mode 100644 index 00000000..5e60be5b --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreDeregisteredEvent.java @@ -0,0 +1,49 @@ +/* + * Copyright 2013-2018 the original author or authors. + * + * Licensed 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 + * + * https://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.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.ApplicationEvent; + +/** + * The + * before-{@link org.springframework.cloud.client.serviceregistry.ServiceRegistry#register(org.springframework.cloud.client.serviceregistry.Registration) + * register} event for {@link org.springframework.cloud.client.ServiceInstance}. + * + * @author Mercy + */ +public class ServiceInstancePreDeregisteredEvent extends ApplicationEvent { + + private final ServiceRegistry registry; + + public ServiceInstancePreDeregisteredEvent(ServiceRegistry registry, + Registration source) { + super(source); + this.registry = registry; + } + + @Override + public Registration getSource() { + return (Registration) super.getSource(); + } + + public ServiceRegistry getRegistry() { + return registry; + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java index 4733fef6..e1b905c0 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-dubbo/src/main/java/com/alibaba/cloud/dubbo/registry/event/ServiceInstancePreRegisteredEvent.java @@ -29,8 +29,12 @@ import org.springframework.context.ApplicationEvent; */ public class ServiceInstancePreRegisteredEvent extends ApplicationEvent { - public ServiceInstancePreRegisteredEvent(Registration source) { + private final ServiceRegistry registry; + + public ServiceInstancePreRegisteredEvent(ServiceRegistry registry, + Registration source) { super(source); + this.registry = registry; } @Override @@ -38,4 +42,8 @@ public class ServiceInstancePreRegisteredEvent extends ApplicationEvent { return (Registration) super.getSource(); } + public ServiceRegistry getRegistry() { + return registry; + } + }