From 0602974b60e678ffcafb3cb0e1d180905dbcd442 Mon Sep 17 00:00:00 2001 From: ZhangBin Date: Tue, 23 May 2023 15:35:48 +0800 Subject: [PATCH] fix: Nacos integration with SpringBootAdmin.(2021.x) (#3307) --- .../src/main/asciidoc-zh/nacos-discovery.adoc | 1 + .../src/main/asciidoc/nacos-discovery.adoc | 1 + .../NacosDiscoveryClientConfiguration.java | 12 --- .../NacosDiscoveryHeartBeatConfiguration.java | 85 +++++++++++++++++++ ... => NacosDiscoveryHeartBeatPublisher.java} | 34 ++++---- ...itional-spring-configuration-metadata.json | 6 ++ .../main/resources/META-INF/spring.factories | 1 + ...NacosDiscoveryClientConfigurationTest.java | 16 ---- ...osDiscoveryHeartBeatConfigurationTest.java | 72 ++++++++++++++++ 9 files changed, 185 insertions(+), 43 deletions(-) create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfiguration.java rename spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/{GatewayLocatorHeartBeatPublisher.java => NacosDiscoveryHeartBeatPublisher.java} (71%) create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfigurationTest.java diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc index 3baeff2c1..64071ca1f 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc @@ -355,5 +355,6 @@ spring.cloud.nacos.discovery.ip-type=IPv6 |接入点|`spring.cloud.nacos.discovery.endpoint`||地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 |是否集成LoadBalancer|`spring.cloud.loadbalancer.nacos.enabled`|`false`| |是否开启Nacos Watch|`spring.cloud.nacos.discovery.watch.enabled`|`true`|可以设置成false来关闭 watch +|是否开启Nacos Discovery HeartBeat|`spring.cloud.nacos.discovery.heart-beat.enabled`|`false`|可以设置成 true 来开启 heart beat |=== diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc index ba209f02f..89fa6e31a 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/nacos-discovery.adoc @@ -359,5 +359,6 @@ The following shows the other configurations of the starter of Nacos Discovery: |Endpoint|`spring.cloud.nacos.discovery.endpoint`||The domain name of a certain service in a specific region. You can retrieve the server address dynamically with this domain name |Integrate LoadBalancer or not|`spring.cloud.loadbalancer.nacos.enabled`|`false`| |Enable Nacos Watch|`spring.cloud.nacos.discovery.watch.enabled`|`false`|set to true to enable watch +|Enable Nacos Discovery HeartBeat|`spring.cloud.nacos.discovery.heart-beat.enabled`|`false`|set to true to enable heart beat |=== diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfiguration.java index 7001b8e17..be57ab7d1 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfiguration.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfiguration.java @@ -64,16 +64,4 @@ public class NacosDiscoveryClientConfiguration { return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties); } - /** - * Spring Cloud Gateway HeartBeat . - * publish an event every 30 seconds - * see https://github.com/alibaba/spring-cloud-alibaba/issues/2868 - */ - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(value = "spring.cloud.gateway.discovery.locator.enabled", matchIfMissing = false) - public GatewayLocatorHeartBeatPublisher gatewayLocatorHeartBeatPublisher(NacosDiscoveryProperties nacosDiscoveryProperties) { - return new GatewayLocatorHeartBeatPublisher(nacosDiscoveryProperties); - } - } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfiguration.java new file mode 100644 index 000000000..7d2f873c0 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfiguration.java @@ -0,0 +1,85 @@ +/* + * Copyright 2013-2023 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.nacos.discovery; + +import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled; +import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +/** + * @author xiaojing + * @author echooymxq + * @author ruansheng + * @author zhangbin + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnDiscoveryEnabled +@ConditionalOnBlockingDiscoveryEnabled +@ConditionalOnNacosDiscoveryEnabled +@AutoConfigureAfter(value = NacosDiscoveryAutoConfiguration.class, + name = "de.codecentric.boot.admin.server.cloud.config.AdminServerDiscoveryAutoConfiguration") +public class NacosDiscoveryHeartBeatConfiguration { + + /** + * Nacos HeartBeat is no longer enabled by default . + * publish an event every 30 seconds + * see https://github.com/alibaba/spring-cloud-alibaba/issues/2868 + * see https://github.com/alibaba/spring-cloud-alibaba/issues/3258 + */ + @Bean + @ConditionalOnMissingBean + @Conditional(NacosDiscoveryHeartBeatCondition.class) + public NacosDiscoveryHeartBeatPublisher nacosDiscoveryHeartBeatPublisher(NacosDiscoveryProperties nacosDiscoveryProperties) { + return new NacosDiscoveryHeartBeatPublisher(nacosDiscoveryProperties); + } + + private static class NacosDiscoveryHeartBeatCondition extends AnyNestedCondition { + + NacosDiscoveryHeartBeatCondition() { + super(ConfigurationPhase.REGISTER_BEAN); + } + + /** + * Spring Cloud Gateway HeartBeat . + */ + @ConditionalOnProperty(value = "spring.cloud.gateway.discovery.locator.enabled", matchIfMissing = false) + static class GatewayLocatorHeartBeatEnabled { } + + /** + * Spring Boot Admin HeartBeat . + */ + @ConditionalOnBean(type = "de.codecentric.boot.admin.server.cloud.discovery.InstanceDiscoveryListener") + static class SpringBootAdminHeartBeatEnabled { } + + /** + * Nacos HeartBeat . + */ + @ConditionalOnProperty(value = "spring.cloud.nacos.discovery.heart-beat.enabled", matchIfMissing = false) + static class NacosDiscoveryHeartBeatEnabled { } + } + +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/GatewayLocatorHeartBeatPublisher.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatPublisher.java similarity index 71% rename from spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/GatewayLocatorHeartBeatPublisher.java rename to spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatPublisher.java index 39a89cd6b..5fcadc927 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/GatewayLocatorHeartBeatPublisher.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatPublisher.java @@ -16,6 +16,7 @@ package com.alibaba.cloud.nacos.discovery; +import java.time.Duration; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -35,19 +36,19 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; * @author yuhuangbin * @author ruansheng */ -public class GatewayLocatorHeartBeatPublisher implements ApplicationEventPublisherAware, SmartLifecycle { +public class NacosDiscoveryHeartBeatPublisher implements ApplicationEventPublisherAware, SmartLifecycle { - private static final Logger log = LoggerFactory.getLogger(GatewayLocatorHeartBeatPublisher.class); + private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryHeartBeatPublisher.class); private final NacosDiscoveryProperties nacosDiscoveryProperties; private final ThreadPoolTaskScheduler taskScheduler; - private final AtomicLong nacosWatchIndex = new AtomicLong(0); + private final AtomicLong nacosHeartBeatIndex = new AtomicLong(0); private final AtomicBoolean running = new AtomicBoolean(false); private ApplicationEventPublisher publisher; - private ScheduledFuture watchFuture; + private ScheduledFuture heartBeatFuture; - public GatewayLocatorHeartBeatPublisher(NacosDiscoveryProperties nacosDiscoveryProperties) { + public NacosDiscoveryHeartBeatPublisher(NacosDiscoveryProperties nacosDiscoveryProperties) { this.nacosDiscoveryProperties = nacosDiscoveryProperties; this.taskScheduler = getTaskScheduler(); } @@ -61,19 +62,22 @@ public class GatewayLocatorHeartBeatPublisher implements ApplicationEventPublish @Override public void start() { - log.info("Start nacos gateway locator heartBeat task scheduler."); - this.watchFuture = this.taskScheduler.scheduleWithFixedDelay( - this::publishHeartBeat, this.nacosDiscoveryProperties.getWatchDelay()); - + if (this.running.compareAndSet(false, true)) { + log.info("Start nacos heartBeat task scheduler."); + this.heartBeatFuture = this.taskScheduler.scheduleWithFixedDelay( + this::publishHeartBeat, Duration.ofMillis(this.nacosDiscoveryProperties.getWatchDelay())); + } } @Override public void stop() { - if (this.watchFuture != null) { - // shutdown current user-thread, - // then the other daemon-threads will terminate automatic. - this.taskScheduler.shutdown(); - this.watchFuture.cancel(true); + if (this.running.compareAndSet(true, false)) { + if (this.heartBeatFuture != null) { + // shutdown current user-thread, + // then the other daemon-threads will terminate automatic. + this.taskScheduler.shutdown(); + this.heartBeatFuture.cancel(true); + } } } @@ -96,7 +100,7 @@ public class GatewayLocatorHeartBeatPublisher implements ApplicationEventPublish * nacos doesn't support watch now , publish an event every 30 seconds. */ public void publishHeartBeat() { - HeartbeatEvent event = new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement()); + HeartbeatEvent event = new HeartbeatEvent(this, nacosHeartBeatIndex.getAndIncrement()); this.publisher.publishEvent(event); } } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json index fb5ea510f..c1b3711fd 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -47,6 +47,12 @@ "defaultValue": "false", "description": "enable nacos discovery watch or not ." }, + { + "name": "spring.cloud.nacos.discovery.heart-beat.enabled", + "type": "java.lang.Boolean", + "defaultValue": "false", + "description": "enable nacos discovery heart beat or not ." + }, { "name": "spring.cloud.nacos.discovery.username", "type": "java.lang.String", diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories index 728db642e..db5f71df0 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories @@ -3,6 +3,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\ com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\ com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\ + com.alibaba.cloud.nacos.discovery.NacosDiscoveryHeartBeatConfiguration,\ com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\ com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\ com.alibaba.cloud.nacos.loadbalancer.LoadBalancerNacosAutoConfiguration,\ diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfigurationTest.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfigurationTest.java index 384bbdcfa..c3c8b094c 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfigurationTest.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryClientConfigurationTest.java @@ -76,20 +76,4 @@ public class NacosDiscoveryClientConfigurationTest { .run(context -> assertThat(context).hasSingleBean(NacosWatch.class)); } - @Test - public void testDefaultGatewayLocatorHeartBeatPublisher() { - contextRunner.run(context -> - assertThat(context).doesNotHaveBean(GatewayLocatorHeartBeatPublisher.class) - ); - } - - @Test - public void testGatewayLocatorHeartBeatPublisherEnabled() { - contextRunner - .withPropertyValues("spring.cloud.gateway.discovery.locator.enabled=true") - .run(context -> - assertThat(context).hasSingleBean(GatewayLocatorHeartBeatPublisher.class) - ); - } - } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfigurationTest.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfigurationTest.java new file mode 100644 index 000000000..bf1306237 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/test/java/com/alibaba/cloud/nacos/discovery/NacosDiscoveryHeartBeatConfigurationTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013-2023 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.nacos.discovery; + +import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration; +import com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration; +import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.cloud.commons.util.UtilAutoConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author echooymxq + **/ +public class NacosDiscoveryHeartBeatConfigurationTest { + + private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + AutoServiceRegistrationConfiguration.class, + NacosServiceRegistryAutoConfiguration.class, + UtilAutoConfiguration.class, + UtilIPv6AutoConfiguration.class, + NacosServiceAutoConfiguration.class, + NacosDiscoveryAutoConfiguration.class, + NacosDiscoveryClientConfiguration.class, + NacosDiscoveryHeartBeatConfiguration.class, this.getClass())); + + @Test + public void testDefaultNacosDiscoveryHeartBeatPublisher() { + contextRunner.run(context -> + assertThat(context).doesNotHaveBean(NacosDiscoveryHeartBeatPublisher.class) + ); + } + + @Test + public void testNacosDiscoveryHeartBeatPublisherEnabledForGateway() { + contextRunner + .withPropertyValues("spring.cloud.gateway.discovery.locator.enabled=true") + .run(context -> + assertThat(context).hasSingleBean(NacosDiscoveryHeartBeatPublisher.class) + ); + } + + @Test + public void testNacosDiscoveryHeartBeatPublisherEnabledForProperties() { + contextRunner + .withPropertyValues("spring.cloud.nacos.discovery.heart-beat.enabled=true") + .run(context -> + assertThat(context).hasSingleBean(NacosDiscoveryHeartBeatPublisher.class) + ); + } + +}