From 261ebea29a0165004ba81865759a19707195d714 Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:46:42 +0800 Subject: [PATCH] feat: support lossless register and deregister (#1242) --- CHANGELOG.md | 2 + .../registry/PolarisServiceRegistry.java | 15 +- .../cloud/common/constant/OrderConstant.java | 5 + .../cloud/common}/util/OkHttpUtil.java | 10 +- .../cloud/common}/util/OkHttpUtilTest.java | 12 +- spring-cloud-tencent-coverage/pom.xml | 5 + spring-cloud-tencent-dependencies/pom.xml | 8 +- spring-cloud-tencent-plugin-starters/pom.xml | 1 + .../pom.xml | 75 +++++++ .../lossless/LosslessRegistryAspect.java | 105 ++++++++++ .../SpringCloudLosslessActionProvider.java | 104 ++++++++++ .../config/LosslessAutoConfiguration.java | 48 +++++ .../config/LosslessConfigModifier.java | 59 ++++++ .../lossless/config/LosslessProperties.java | 75 +++++++ .../LosslessPropertiesAutoConfiguration.java | 43 ++++ ...slessPropertiesBootstrapConfiguration.java | 35 ++++ ...itional-spring-configuration-metadata.json | 10 + .../main/resources/META-INF/spring.factories | 4 + .../lossless/LosslessConfigModifierTest.java | 89 ++++++++ .../lossless/LosslessPropertiesTest.java | 40 ++++ .../lossless/LosslessRegistryAspectTest.java | 190 ++++++++++++++++++ .../AutoServiceRegistrationUtils.java | 29 +++ .../context/PolarisSDKContextManager.java | 16 ++ .../PolarisContextAutoConfigurationTest.java | 8 + 24 files changed, 973 insertions(+), 15 deletions(-) rename {spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris => spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common}/util/OkHttpUtil.java (88%) rename {spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris => spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common}/util/OkHttpUtilTest.java (82%) create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 671ece8f..3363c658 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,4 @@ # Change Log --- + +- [feat: support lossless register and deregister](https://github.com/Tencent/spring-cloud-tencent/issues/977) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java index ce7acf08..2d12ba7f 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java @@ -25,10 +25,10 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.util.OkHttpUtil; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.util.OkHttpUtil; import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties; import com.tencent.polaris.api.config.global.StatReporterConfig; import com.tencent.polaris.api.core.ProviderAPI; @@ -237,21 +237,14 @@ public class PolarisServiceRegistry implements ServiceRegistry { try { - String healthCheckEndpoint = polarisDiscoveryProperties.getHealthCheckUrl(); // If the health check passes, the heartbeat will be reported. // If it does not pass, the heartbeat will not be reported. - if (!healthCheckEndpoint.startsWith("/")) { - healthCheckEndpoint = "/" + healthCheckEndpoint; - } - - String healthCheckUrl = String.format("http://%s:%s%s", heartbeatRequest.getHost(), - heartbeatRequest.getPort(), healthCheckEndpoint); - Map headers = new HashMap<>(1); headers.put(HttpHeaders.USER_AGENT, "polaris"); - if (!OkHttpUtil.get(healthCheckUrl, headers)) { + if (!OkHttpUtil.checkUrl(heartbeatRequest.getHost(), heartbeatRequest.getPort(), + polarisDiscoveryProperties.getHealthCheckUrl(), headers)) { LOGGER.error("backend service health check failed. health check endpoint = {}", - healthCheckEndpoint); + polarisDiscoveryProperties.getHealthCheckUrl()); return; } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java index 633f069b..be2a3705 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java @@ -214,6 +214,11 @@ public class OrderConstant { */ public static Integer STAT_REPORTER_ORDER = 1; + /** + * Order of lossless configuration modifier. + */ + public static Integer LOSSLESS_ORDER = 2; + /** * Order of service contract configuration modifier. */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/util/OkHttpUtil.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java similarity index 88% rename from spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/util/OkHttpUtil.java rename to spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java index f8580ee1..e34d79f5 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/util/OkHttpUtil.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.util; +package com.tencent.cloud.common.util; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -87,4 +87,12 @@ public final class OkHttpUtil { } return false; } + + public static boolean checkUrl(String host, Integer port, String endpoint, Map headers) { + if (!endpoint.startsWith("/")) { + endpoint = "/" + endpoint; + } + String checkUrl = String.format("http://%s:%s%s", host, port, endpoint); + return get(checkUrl, headers); + } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/util/OkHttpUtilTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/OkHttpUtilTest.java similarity index 82% rename from spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/util/OkHttpUtilTest.java rename to spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/OkHttpUtilTest.java index b718e88e..2e250e3d 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/util/OkHttpUtilTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/OkHttpUtilTest.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.util; +package com.tencent.cloud.common.util; import org.assertj.core.util.Maps; import org.junit.jupiter.api.Test; @@ -37,7 +37,13 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Haotian Zhang */ @ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = OkHttpUtilTest.TestApplication.class, properties = {"spring.application.name=test", "spring.cloud.polaris.discovery.register=false"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = OkHttpUtilTest.TestApplication.class, + properties = { + "spring.application.name=test", + "spring.cloud.polaris.discovery.register=false", + "spring.cloud.gateway.enabled=false" + }) public class OkHttpUtilTest { @LocalServerPort @@ -46,6 +52,8 @@ public class OkHttpUtilTest { @Test public void testGet() { assertThat(OkHttpUtil.get("http://localhost:" + port + "/test", Maps.newHashMap("key", "value"))).isTrue(); + assertThat(OkHttpUtil.checkUrl("localhost", port, "/test", Maps.newHashMap("key", "value"))).isTrue(); + assertThat(OkHttpUtil.checkUrl("localhost", port, "test", Maps.newHashMap("key", "value"))).isTrue(); assertThat(OkHttpUtil.get("http://localhost:" + port + "/error", Maps.newHashMap("key", "value"))).isFalse(); assertThat(OkHttpUtil.get("http://localhost:55555/error", Maps.newHashMap("key", "value"))).isFalse(); } diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 8a06ec03..0cb2681a 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -88,6 +88,11 @@ com.tencent.cloud spring-cloud-starter-tencent-discovery-adapter-plugin + + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index d398b8b8..31f15fab 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.14.0-Hoxton.SR12-SNAPSHOT - 1.15.0 + 1.15.2-SNAPSHOT 32.0.1-jre 1.2.13 3.0.0 @@ -193,6 +193,12 @@ ${revision} + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + ${revision} + + com.google.guava diff --git a/spring-cloud-tencent-plugin-starters/pom.xml b/spring-cloud-tencent-plugin-starters/pom.xml index bc2f153b..0258ceee 100644 --- a/spring-cloud-tencent-plugin-starters/pom.xml +++ b/spring-cloud-tencent-plugin-starters/pom.xml @@ -18,6 +18,7 @@ spring-cloud-tencent-featureenv-plugin spring-cloud-tencent-gateway-plugin spring-cloud-starter-tencent-discovery-adapter-plugin + spring-cloud-tencent-lossless-plugin diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml new file mode 100644 index 00000000..d02a3470 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml @@ -0,0 +1,75 @@ + + + + spring-cloud-tencent-plugin-starters + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + spring-cloud-tencent-lossless-plugin + Spring Cloud Tencent Lossless Plugin + + + + + com.tencent.cloud + spring-cloud-tencent-polaris-context + + + + com.tencent.cloud + spring-cloud-tencent-commons + + + + com.tencent.polaris + lossless-register + + + + com.tencent.polaris + lossless-deregister + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-web + test + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + test + + + + com.tencent.polaris + polaris-test-mock-discovery + test + + + junit + junit + + + + + + + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java new file mode 100644 index 00000000..1fb6ccb2 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java @@ -0,0 +1,105 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.pojo.BaseInstance; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; + +/** + * Intercept for of register and deregister. + * + * @author Shedfree Wu + */ +@Aspect +public class LosslessRegistryAspect { + + private ServiceRegistry serviceRegistry; + + private Registration registration; + + private LosslessProperties losslessProperties; + + private PolarisSDKContextManager polarisSDKContextManager; + + private final AtomicBoolean doneDeregister = new AtomicBoolean(false); + + + public LosslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, + LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager) { + this.serviceRegistry = serviceRegistry; + this.registration = registration; + this.losslessProperties = losslessProperties; + this.polarisSDKContextManager = polarisSDKContextManager; + } + + @Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(..))") + public void registerPointcut() { + + } + + @Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.deregister(..))") + public void deregisterPointcut() { + + } + + @Around("registerPointcut()") + public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { + + // web started, get port from registration + BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration); + + Runnable registerAction = () -> executeJoinPoint(joinPoint); + + SpringCloudLosslessActionProvider losslessActionProvider = + new SpringCloudLosslessActionProvider(serviceRegistry, registration, losslessProperties, registerAction); + + polarisSDKContextManager.getLosslessAPI().setLosslessActionProvider(instance, losslessActionProvider); + polarisSDKContextManager.getLosslessAPI().losslessRegister(instance); + // return void + return null; + } + + @Around("deregisterPointcut()") + public Object invokeDeregister(ProceedingJoinPoint joinPoint) throws Throwable { + if (doneDeregister.compareAndSet(false, true)) { + return joinPoint.proceed(); + } + else { + return null; + } + } + + public void executeJoinPoint(ProceedingJoinPoint joinPoint) { + try { + joinPoint.proceed(); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java new file mode 100644 index 00000000..05cd23f6 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java @@ -0,0 +1,104 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.util.OkHttpUtil; +import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import com.tencent.polaris.api.plugin.lossless.InstanceProperties; +import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider; +import com.tencent.polaris.api.pojo.BaseInstance; +import com.tencent.polaris.api.pojo.DefaultBaseInstance; +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.http.HttpHeaders; + +/** + * LosslessActionProvider for Spring Cloud. + * + * @author Shedfree Wu + */ +public class SpringCloudLosslessActionProvider implements LosslessActionProvider { + private ServiceRegistry serviceRegistry; + + private LosslessProperties losslessProperties; + + private Runnable originalRegisterAction; + + private Registration registration; + + public SpringCloudLosslessActionProvider(ServiceRegistry serviceRegistry, Registration registration, + LosslessProperties losslessProperties, Runnable originalRegisterAction) { + this.serviceRegistry = serviceRegistry; + this.registration = registration; + this.losslessProperties = losslessProperties; + this.originalRegisterAction = originalRegisterAction; + } + + @Override + public String getName() { + return "spring-cloud"; + } + + @Override + public void doRegister(InstanceProperties instanceProperties) { + // use lambda to do original register + originalRegisterAction.run(); + } + + @Override + public void doDeregister() { + serviceRegistry.deregister(registration); + } + + /** + * Check whether health check is enable. + * @return true: register after passing doHealthCheck, false: register after delayRegisterInterval. + */ + @Override + public boolean isEnableHealthCheck() { + return StringUtils.isNotBlank(losslessProperties.getHealthCheckPath()); + } + + @Override + public boolean doHealthCheck() { + Map headers = new HashMap<>(1); + headers.put(HttpHeaders.USER_AGENT, "polaris"); + + return OkHttpUtil.checkUrl("localhost", registration.getPort(), + losslessProperties.getHealthCheckPath(), headers); + } + + public static BaseInstance getBaseInstance(Registration registration) { + return getBaseInstance(registration, registration.getPort()); + } + + public static BaseInstance getBaseInstance(Registration registration, Integer port) { + // for common spring cloud registration, not set namespace + DefaultBaseInstance baseInstance = new DefaultBaseInstance(); + baseInstance.setService(registration.getServiceId()); + // before web start, port in registration not init + baseInstance.setPort(port); + baseInstance.setHost(registration.getHost()); + return baseInstance; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java new file mode 100644 index 00000000..7bcc5df8 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java @@ -0,0 +1,48 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless.config; + +import com.tencent.cloud.plugin.lossless.LosslessRegistryAspect; +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * Autoconfiguration of lossless. + * + * @author Shedfree Wu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@Import(LosslessPropertiesAutoConfiguration.class) +public class LosslessAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public LosslessRegistryAspect losslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, + LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager) { + return new LosslessRegistryAspect(serviceRegistry, registration, losslessProperties, polarisSDKContextManager); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java new file mode 100644 index 00000000..f5049df7 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless.config; + +import java.util.Objects; + +import com.tencent.cloud.common.constant.OrderConstant.Modifier; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.provider.LosslessConfigImpl; + +/** + * Config modifier for lossless. + * + * @author Shedfree Wu + */ +public class LosslessConfigModifier implements PolarisConfigModifier { + + private final LosslessProperties losslessProperties; + + public LosslessConfigModifier(LosslessProperties losslessProperties) { + this.losslessProperties = losslessProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + if (losslessProperties.isEnabled()) { + LosslessConfigImpl losslessConfig = (LosslessConfigImpl) configuration.getProvider().getLossless(); + losslessConfig.setEnable(true); + losslessConfig.setPort(losslessProperties.getPort()); + if (Objects.nonNull(losslessProperties.getDelayRegisterInterval())) { + losslessConfig.setDelayRegisterInterval(losslessProperties.getDelayRegisterInterval()); + } + if (Objects.nonNull(losslessProperties.getHealthCheckInterval())) { + losslessConfig.setHealthCheckInterval(losslessProperties.getHealthCheckInterval()); + } + } + } + + @Override + public int getOrder() { + return Modifier.LOSSLESS_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java new file mode 100644 index 00000000..3f296088 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java @@ -0,0 +1,75 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("spring.cloud.polaris.lossless") +public class LosslessProperties { + + private boolean enabled = true; + + private int port = 28080; + + private String healthCheckPath; + + private Long delayRegisterInterval; + + private Long healthCheckInterval; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getHealthCheckPath() { + return healthCheckPath; + } + + public void setHealthCheckPath(String healthCheckPath) { + this.healthCheckPath = healthCheckPath; + } + + public Long getDelayRegisterInterval() { + return delayRegisterInterval; + } + + public void setDelayRegisterInterval(Long delayRegisterInterval) { + this.delayRegisterInterval = delayRegisterInterval; + } + + public Long getHealthCheckInterval() { + return healthCheckInterval; + } + + public void setHealthCheckInterval(Long healthCheckInterval) { + this.healthCheckInterval = healthCheckInterval; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java new file mode 100644 index 00000000..5d104704 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless.config; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Autoconfiguration of lossless properties. + * + * @author Shedfree Wu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@EnableConfigurationProperties(LosslessProperties.class) +public class LosslessPropertiesAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public LosslessConfigModifier losslessConfigModifier(LosslessProperties losslessProperties) { + return new LosslessConfigModifier(losslessProperties); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java new file mode 100644 index 00000000..dd047cab --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + + +/** + * BootstrapConfiguration of lossless properties. + * + * @author Shedfree Wu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(LosslessPropertiesAutoConfiguration.class) +public class LosslessPropertiesBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000..48a31c1c --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,10 @@ +{ + "properties": [ + { + "name": "spring.cloud.polaris.lossless.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "the switch for lossless plugin." + } + ] +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..fee2a497 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.plugin.lossless.config.LosslessPropertiesBootstrapConfiguration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.plugin.lossless.config.LosslessAutoConfiguration diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java new file mode 100644 index 00000000..42dba552 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java @@ -0,0 +1,89 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless; + +import com.tencent.cloud.plugin.lossless.config.LosslessConfigModifier; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.config.provider.LosslessConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link LosslessConfigModifier}. + * + * @author Shedfree Wu + */ +public class LosslessConfigModifierTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.port=20000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") + .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=10") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=5") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + private final ApplicationContextRunner disabledContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=false") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + + @BeforeEach + void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + void testModify() { + contextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getProvider().getLossless(); + assertThat(losslessConfig.getHost()).isEqualTo("0.0.0.0"); + assertThat(losslessConfig.getPort()).isEqualTo(20000); + assertThat(losslessConfig.getDelayRegisterInterval()).isEqualTo(10); + assertThat(losslessConfig.getHealthCheckInterval()).isEqualTo(5); + }); + } + + + @Test + void testDisabled() { + disabledContextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getProvider().getLossless(); + assertThat(losslessConfig.isEnable()).isFalse(); + }); + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java new file mode 100644 index 00000000..02e6f408 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless; + +import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link LosslessProperties}. + * + * @author Shedfree Wu + */ +public class LosslessPropertiesTest { + + @Test + void testGetAndSet() { + LosslessProperties polarisStatProperties = new LosslessProperties(); + + // healthCheckPath + polarisStatProperties.setHealthCheckPath("/xxx"); + assertThat(polarisStatProperties.getHealthCheckPath()).isEqualTo("/xxx"); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java new file mode 100644 index 00000000..6a125539 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java @@ -0,0 +1,190 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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.tencent.cloud.plugin.lossless; + +import java.util.Collections; + +import com.tencent.cloud.common.util.OkHttpUtil; +import com.tencent.cloud.plugin.lossless.config.LosslessAutoConfiguration; +import com.tencent.cloud.plugin.lossless.config.LosslessPropertiesBootstrapConfiguration; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration; +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration; +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisServiceRegistry; +import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationUtils; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +/** + * Test for {@link LosslessRegistryAspect}. + * + * @author Shedfree Wu + */ +public class LosslessRegistryAspectTest { + + private static String NAMESPACE_TEST = "Test"; + + private static String SERVICE_PROVIDER = "java_provider_test"; + + private static String HOST = "127.0.0.1"; + + private static int APPLICATION_PORT = 19091; + + private static int LOSSLESS_PORT_1 = 28083; + + private static NamingServer namingServer; + + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + LosslessAutoConfiguration.class, + LosslessPropertiesBootstrapConfiguration.class, + PolarisContextAutoConfiguration.class, + PolarisPropertiesConfiguration.class, + PolarisDiscoveryClientConfiguration.class, + PolarisDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") + .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) + .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) + .withPropertyValues("server.port=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) + .withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") + .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); + + private final WebApplicationContextRunner contextRunner2 = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + LosslessAutoConfiguration.class, + LosslessPropertiesBootstrapConfiguration.class, + PolarisContextAutoConfiguration.class, + PolarisPropertiesConfiguration.class, + PolarisDiscoveryClientConfiguration.class, + PolarisDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=1000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/test") + .withPropertyValues("spring.cloud.polaris.lossless.port=28082") + .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) + .withPropertyValues("server.port=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) + .withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") + .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); + + @BeforeAll + static void beforeAll() throws Exception { + namingServer = NamingServer.startNamingServer(10081); + + // add service + namingServer.getNamingService().addService(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER)); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } + + @BeforeEach + void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + public void testRegister() { + this.contextRunner.run(context -> { + + AbstractAutoServiceRegistration autoServiceRegistration = context.getBean(AbstractAutoServiceRegistration.class); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.register(autoServiceRegistration); + }).doesNotThrowAnyException(); + Thread.sleep(1000); + // before register online status is false + assertThatCode(() -> { + assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isFalse(); + }).doesNotThrowAnyException(); + // delay register after 5s + Thread.sleep(5000); + PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); + PolarisRegistration registration = context.getBean(PolarisRegistration.class); + + assertThatCode(() -> { + assertThat(registry.getStatus(registration)).isEqualTo("DOWN"); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isTrue(); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/offline", Collections.EMPTY_MAP)).isTrue(); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.deRegister(autoServiceRegistration); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + assertThat(registry.getStatus(registration)).isEqualTo("DOWN"); + }).doesNotThrowAnyException(); + }); + } + + @Test + public void testRegister2() { + this.contextRunner2.run(context -> { + + AbstractAutoServiceRegistration autoServiceRegistration = context.getBean(AbstractAutoServiceRegistration.class); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.register(autoServiceRegistration); + }).doesNotThrowAnyException(); + + Thread.sleep(2000); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.deRegister(autoServiceRegistration); + }).doesNotThrowAnyException(); + }); + } + + + @Configuration + @EnableAutoConfiguration + static class PolarisPropertiesConfiguration { + + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java new file mode 100644 index 00000000..1c8e09f9 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java @@ -0,0 +1,29 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.cloud.client.serviceregistry; + +public class AutoServiceRegistrationUtils { + + public static void register(AbstractAutoServiceRegistration autoServiceRegistration) { + autoServiceRegistration.register(); + } + + public static void deRegister(AbstractAutoServiceRegistration autoServiceRegistration) { + autoServiceRegistration.deregister(); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java index e28a6077..143b6fbb 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java @@ -23,6 +23,7 @@ import java.util.Objects; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.api.control.Destroyable; import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.core.LosslessAPI; import com.tencent.polaris.api.core.ProviderAPI; import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.assembly.factory.AssemblyAPIFactory; @@ -55,6 +56,7 @@ public class PolarisSDKContextManager { private volatile static SDKContext sdkContext; private volatile static ProviderAPI providerAPI; private volatile static ConsumerAPI consumerAPI; + private volatile static LosslessAPI losslessAPI; private volatile static RouterAPI routerAPI; private volatile static CircuitBreakAPI circuitBreakAPI; private volatile static LimitAPI limitAPI; @@ -81,6 +83,12 @@ public class PolarisSDKContextManager { providerAPI = null; } + // destroy LosslessAPI + if (Objects.nonNull(losslessAPI)) { + ((AutoCloseable) losslessAPI).close(); + losslessAPI = null; + } + // destroy ConsumerAPI if (Objects.nonNull(consumerAPI)) { ((AutoCloseable) consumerAPI).close(); @@ -135,6 +143,9 @@ public class PolarisSDKContextManager { // init ProviderAPI providerAPI = DiscoveryAPIFactory.createProviderAPIByContext(sdkContext); + // init losslessAPI + losslessAPI = DiscoveryAPIFactory.createLosslessAPIByContext(sdkContext); + // init ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(sdkContext); @@ -183,6 +194,11 @@ public class PolarisSDKContextManager { return providerAPI; } + public LosslessAPI getLosslessAPI() { + init(); + return losslessAPI; + } + public ConsumerAPI getConsumerAPI() { init(); return consumerAPI; diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java index e5d05b6a..e176b723 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java @@ -46,4 +46,12 @@ public class PolarisContextAutoConfigurationTest { assertThat(polarisSDKContextManager).isNotNull(); }); } + + @Test + public void testLosslessAPIProperties() { + contextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + assertThat(polarisSDKContextManager.getLosslessAPI()).isNotNull(); + }); + } }