From ea8a826fc16800431d7425f2ef6b2947f2c11fc7 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 7 Feb 2024 13:09:51 +0800 Subject: [PATCH 01/29] begin 1.14.0. --- CHANGELOG.md | 20 -------------------- changes/changes-1.13.0.md | 22 ++++++++++++++++++++++ pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 2 +- 4 files changed, 24 insertions(+), 22 deletions(-) create mode 100644 changes/changes-1.13.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6525f5b02..671ece8fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,2 @@ # Change Log --- - -- [feat: fix the logging problem open at #1189](https://github.com/Tencent/spring-cloud-tencent/pull/1197) -- [fix:the polaris config relation non-daemon thread should stop when application fails to start.](https://github.com/Tencent/spring-cloud-tencent/pull/1110) -- [Refactoring:remove invalid @AutoConfigureAfter and @AutoConfigureBefore from discovery client automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1118) -- [fix:fix feign url bug when using sleuth.](https://github.com/Tencent/spring-cloud-tencent/pull/1119) -- [refactor:optimize the order and condition matching of service registration automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1133) -- [feat:support service contract reporting.](https://github.com/Tencent/spring-cloud-tencent/pull/1135) -- [feat: support log path configuration parameters.](https://github.com/Tencent/spring-cloud-tencent/pull/1143) -- [feat:add swagger exposure filters.](https://github.com/Tencent/spring-cloud-tencent/pull/1144) -- [feat:add swagger report switch.](https://github.com/Tencent/spring-cloud-tencent/pull/1147) -- [fix: dynamic routing using cookies.](https://github.com/Tencent/spring-cloud-tencent/pull/1152) -- [fix:fix retry loadbalancer not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1157) -- [fix:fix header validation when using Chinese char.](https://github.com/Tencent/spring-cloud-tencent/pull/1167) -- [feat: add circuit breaker actuator.](https://github.com/Tencent/spring-cloud-tencent/pull/1172) -- [feat: add metadata transfer for http header via spring.cloud.tencent.metadata.headers.](https://github.com/Tencent/spring-cloud-tencent/pull/1174) -- [fix:remove bcprov-jdk15on dependency.](https://github.com/Tencent/spring-cloud-tencent/pull/1178) -- [feat:support configuration encryption.](https://github.com/Tencent/spring-cloud-tencent/pull/1182) -- [feat:optimize examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1186) -- [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) -- [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) diff --git a/changes/changes-1.13.0.md b/changes/changes-1.13.0.md new file mode 100644 index 000000000..6525f5b02 --- /dev/null +++ b/changes/changes-1.13.0.md @@ -0,0 +1,22 @@ +# Change Log +--- + +- [feat: fix the logging problem open at #1189](https://github.com/Tencent/spring-cloud-tencent/pull/1197) +- [fix:the polaris config relation non-daemon thread should stop when application fails to start.](https://github.com/Tencent/spring-cloud-tencent/pull/1110) +- [Refactoring:remove invalid @AutoConfigureAfter and @AutoConfigureBefore from discovery client automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1118) +- [fix:fix feign url bug when using sleuth.](https://github.com/Tencent/spring-cloud-tencent/pull/1119) +- [refactor:optimize the order and condition matching of service registration automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1133) +- [feat:support service contract reporting.](https://github.com/Tencent/spring-cloud-tencent/pull/1135) +- [feat: support log path configuration parameters.](https://github.com/Tencent/spring-cloud-tencent/pull/1143) +- [feat:add swagger exposure filters.](https://github.com/Tencent/spring-cloud-tencent/pull/1144) +- [feat:add swagger report switch.](https://github.com/Tencent/spring-cloud-tencent/pull/1147) +- [fix: dynamic routing using cookies.](https://github.com/Tencent/spring-cloud-tencent/pull/1152) +- [fix:fix retry loadbalancer not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1157) +- [fix:fix header validation when using Chinese char.](https://github.com/Tencent/spring-cloud-tencent/pull/1167) +- [feat: add circuit breaker actuator.](https://github.com/Tencent/spring-cloud-tencent/pull/1172) +- [feat: add metadata transfer for http header via spring.cloud.tencent.metadata.headers.](https://github.com/Tencent/spring-cloud-tencent/pull/1174) +- [fix:remove bcprov-jdk15on dependency.](https://github.com/Tencent/spring-cloud-tencent/pull/1178) +- [feat:support configuration encryption.](https://github.com/Tencent/spring-cloud-tencent/pull/1182) +- [feat:optimize examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1186) +- [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) +- [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) diff --git a/pom.xml b/pom.xml index b91ab8fca..110bbbf43 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.13.0-Hoxton.SR12 + 1.14.0-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 15d28d129..d398b8b87 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.13.0-Hoxton.SR12 + 1.14.0-Hoxton.SR12-SNAPSHOT 1.15.0 From 3f5eda54ffa07db38172264727429d35f5332c3a Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Sun, 18 Feb 2024 11:04:09 +0800 Subject: [PATCH 02/29] docs:update github configuration. --- .github/PULL_REQUEST_TEMPLATE.md | 3 ++- .github/workflows/codecov.yml | 2 ++ .github/workflows/license-checker.yml | 2 ++ .github/workflows/snapshot.yml | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a56dd0d4b..236851ebe 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,6 +26,7 @@ fixes # ## Checklist (Optional) -- [ ] Will pull request to branch of 2020.0. +- [ ] Will pull request to branch of 2023.0. - [ ] Will pull request to branch of 2022.0. +- [ ] Will pull request to branch of 2020.0. - [ ] Will pull request to branch of hoxton. diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 011787bdb..343fa995e 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -3,6 +3,7 @@ name: Codecov on: push: branches: + - 2023.0 - 2022.0 - 2021.0 - 2020.0 @@ -10,6 +11,7 @@ on: - greenwich pull_request: branches: + - 2023.0 - 2022.0 - 2021.0 - 2020.0 diff --git a/.github/workflows/license-checker.yml b/.github/workflows/license-checker.yml index e5e639135..9d01eb4a8 100644 --- a/.github/workflows/license-checker.yml +++ b/.github/workflows/license-checker.yml @@ -3,6 +3,7 @@ name: License checker on: push: branches: + - 2023.0 - 2022.0 - 2021.0 - 2020.0 @@ -10,6 +11,7 @@ on: - greenwich pull_request: branches: + - 2023.0 - 2022.0 - 2021.0 - 2020.0 diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 1809ba7c6..622c086a9 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -3,6 +3,7 @@ name: Snapshot on: push: branches: + - 2023.0 - 2022.0 - 2021.0 - 2020.0 From aca2982657cbe546aed36d4920bac97de9686e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=81=E5=8C=A0=E5=90=9B?= Date: Wed, 21 Feb 2024 10:58:01 +0800 Subject: [PATCH 03/29] fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. --- changes/changes-1.13.0.md | 1 + .../PolarisLoadBalancerAutoConfiguration.java | 30 ++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/changes/changes-1.13.0.md b/changes/changes-1.13.0.md index 6525f5b02..168274ddc 100644 --- a/changes/changes-1.13.0.md +++ b/changes/changes-1.13.0.md @@ -20,3 +20,4 @@ - [feat:optimize examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1186) - [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) +- fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java index 1a6578449..019c60cc4 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.util.CollectionUtils; /** * Auto-configuration Ribbon for Polaris. @@ -55,23 +56,38 @@ public class PolarisLoadBalancerAutoConfiguration { } @Bean - public RestTemplateCustomizer restTemplateCustomizer( + public RestTemplateCustomizer polarisRestTemplateCustomizer( @Autowired(required = false) RetryLoadBalancerInterceptor retryLoadBalancerInterceptor, @Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List list = new ArrayList<>(restTemplate.getInterceptors()); // LoadBalancerInterceptor must invoke before EnhancedRestTemplateInterceptor - if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) { - int addIndex = list.size(); + int addIndex = list.size(); + if (CollectionUtils.containsInstance(list, retryLoadBalancerInterceptor) || CollectionUtils.containsInstance(list, loadBalancerInterceptor)) { + ClientHttpRequestInterceptor enhancedRestTemplateInterceptor = null; for (int i = 0; i < list.size(); i++) { if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { + enhancedRestTemplateInterceptor = list.get(i); addIndex = i; } } - list.add(addIndex, - retryLoadBalancerInterceptor != null - ? retryLoadBalancerInterceptor - : loadBalancerInterceptor); + if (enhancedRestTemplateInterceptor != null) { + list.remove(addIndex); + list.add(enhancedRestTemplateInterceptor); + } + } + else { + if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { + addIndex = i; + } + } + list.add(addIndex, + retryLoadBalancerInterceptor != null + ? retryLoadBalancerInterceptor + : loadBalancerInterceptor); + } } restTemplate.setInterceptors(list); }; 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 04/29] 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 671ece8fb..3363c658c 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 ce7acf08b..2d12ba7fd 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 633f069b4..be2a37055 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 f8580ee19..e34d79f56 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 b718e88e9..2e250e3d8 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 8a06ec039..0cb2681a4 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 d398b8b87..31f15fab4 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 bc2f153b9..0258ceeea 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 000000000..d02a34704 --- /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 000000000..1fb6ccb2d --- /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 000000000..05cd23f6d --- /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 000000000..7bcc5df85 --- /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 000000000..f5049df76 --- /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 000000000..3f2960883 --- /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 000000000..5d104704f --- /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 000000000..dd047cabc --- /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 000000000..48a31c1cd --- /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 000000000..fee2a497c --- /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 000000000..42dba5525 --- /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 000000000..02e6f4087 --- /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 000000000..6a1255391 --- /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 000000000..1c8e09f91 --- /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 e28a60770..143b6fbb7 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 e5d05b6a3..e176b723d 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(); + }); + } } From d0851bbc7b2602669d70de8a215390f86ae36597 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 13 Mar 2024 20:15:05 +0800 Subject: [PATCH 05/29] docs:update README. --- README-zh.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README-zh.md b/README-zh.md index 3552f2e40..5f7f9c3d1 100644 --- a/README-zh.md +++ b/README-zh.md @@ -61,7 +61,7 @@ Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要 > 注意: > -> 支持Spring Cloud 版本:2022.0、2021.0、2020.0、Hoxton。 +> 支持Spring Cloud 版本:2023.0, 2022.0、2021.0、2020.0、Hoxton。 > > Spring Cloud Tencent > 的版本列表可以查看 diff --git a/README.md b/README.md index 37fc6fe58..0ec14dc27 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ dependencies. > Notice: > -> Support Spring Cloud 2022.0, 2021.0, 2020.0, Hoxton. +> Support Spring Cloud 2023.0, 2022.0, 2021.0, 2020.0, Hoxton. > > The version list of Spring Cloud Tencent can be found > in From 4c7a9c8288ad7bae54d5ae9f2728a00b99f9ab13 Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:18:51 +0800 Subject: [PATCH 06/29] feat: PolarisServiceRegistry#deregister support idempotency. (#1243) --- CHANGELOG.md | 3 ++- .../polaris/registry/PolarisServiceRegistry.java | 6 +++--- .../plugin/lossless/LosslessRegistryAspect.java | 12 +----------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3363c658c..bf85b0ebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Change Log --- -- [feat: support lossless register and deregister](https://github.com/Tencent/spring-cloud-tencent/issues/977) +- [feat: support lossless register and deregister at #977](https://github.com/Tencent/spring-cloud-tencent/pull/1242) +- [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) \ No newline at end of file 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 2d12ba7fd..d61034089 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 @@ -175,7 +175,7 @@ public class PolarisServiceRegistry implements ServiceRegistry Date: Sat, 16 Mar 2024 20:20:30 +0800 Subject: [PATCH 07/29] fix: lossless plugin log support ns (#1244) Co-authored-by: shedfreewu --- .../pom.xml | 9 +++- .../lossless/LosslessRegistryAspect.java | 9 +++- .../SpringCloudLosslessActionProvider.java | 12 +++-- .../config/LosslessAutoConfiguration.java | 40 +++++++++++++- .../transfomer/DiscoveryNamespaceGetter.java | 28 ++++++++++ .../NacosDiscoveryNamespaceGetter.java | 47 +++++++++++++++++ .../PolarisDiscoveryNamespaceGetter.java | 38 ++++++++++++++ .../lossless/LosslessConfigModifierTest.java | 2 + .../lossless/LosslessRegistryAspectTest.java | 52 +++++++++++++++++++ 9 files changed, 228 insertions(+), 9 deletions(-) create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java 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 index d02a34704..c1a4712a5 100644 --- 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 @@ -55,7 +55,14 @@ com.tencent.cloud spring-cloud-starter-tencent-polaris-discovery - test + true + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + 2.2.9.RELEASE + true 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 index 248067616..e0126d458 100644 --- 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 @@ -18,6 +18,7 @@ package com.tencent.cloud.plugin.lossless; import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.pojo.BaseInstance; import org.aspectj.lang.ProceedingJoinPoint; @@ -44,12 +45,16 @@ public class LosslessRegistryAspect { private PolarisSDKContextManager polarisSDKContextManager; + private DiscoveryNamespaceGetter discoveryNamespaceGetter; + public LosslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager) { + LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager, + DiscoveryNamespaceGetter discoveryNamespaceGetter) { this.serviceRegistry = serviceRegistry; this.registration = registration; this.losslessProperties = losslessProperties; this.polarisSDKContextManager = polarisSDKContextManager; + this.discoveryNamespaceGetter = discoveryNamespaceGetter; } @Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(..))") @@ -66,7 +71,7 @@ public class LosslessRegistryAspect { public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { // web started, get port from registration - BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration); + BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, discoveryNamespaceGetter); Runnable registerAction = () -> executeJoinPoint(joinPoint); 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 index 05cd23f6d..511721a5f 100644 --- 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 @@ -22,6 +22,7 @@ import java.util.Map; import com.tencent.cloud.common.util.OkHttpUtil; import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter; import com.tencent.polaris.api.plugin.lossless.InstanceProperties; import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider; import com.tencent.polaris.api.pojo.BaseInstance; @@ -88,13 +89,16 @@ public class SpringCloudLosslessActionProvider implements LosslessActionProvider losslessProperties.getHealthCheckPath(), headers); } - public static BaseInstance getBaseInstance(Registration registration) { - return getBaseInstance(registration, registration.getPort()); + public static BaseInstance getBaseInstance(Registration registration, DiscoveryNamespaceGetter namespaceGetter) { + return getBaseInstance(registration, registration.getPort(), namespaceGetter); } - public static BaseInstance getBaseInstance(Registration registration, Integer port) { - // for common spring cloud registration, not set namespace + public static BaseInstance getBaseInstance(Registration registration, Integer port, + DiscoveryNamespaceGetter namespaceGetter) { DefaultBaseInstance baseInstance = new DefaultBaseInstance(); + if (namespaceGetter != null) { + baseInstance.setNamespace(namespaceGetter.getNamespace()); + } baseInstance.setService(registration.getServiceId()); // before web start, port in registration not init baseInstance.setPort(port); 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 index 7bcc5df85..5bab83f9f 100644 --- 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 @@ -18,10 +18,20 @@ package com.tencent.cloud.plugin.lossless.config; +import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.tencent.cloud.plugin.lossless.LosslessRegistryAspect; +import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter; +import com.tencent.cloud.plugin.lossless.transfomer.NacosDiscoveryNamespaceGetter; +import com.tencent.cloud.plugin.lossless.transfomer.PolarisDiscoveryNamespaceGetter; +import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.discovery.ConditionalOnPolarisDiscoveryEnabled; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; @@ -42,7 +52,33 @@ public class LosslessAutoConfiguration { @Bean @ConditionalOnMissingBean public LosslessRegistryAspect losslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager) { - return new LosslessRegistryAspect(serviceRegistry, registration, losslessProperties, polarisSDKContextManager); + LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager, + @Autowired(required = false) DiscoveryNamespaceGetter discoveryNamespaceGetter) { + return new LosslessRegistryAspect(serviceRegistry, registration, losslessProperties, polarisSDKContextManager, discoveryNamespaceGetter); + } + + @ConditionalOnClass(name = "com.alibaba.cloud.nacos.NacosDiscoveryProperties") + static class Nacos { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnNacosDiscoveryEnabled + @ConditionalOnBean(NacosDiscoveryProperties.class) + public NacosDiscoveryNamespaceGetter nacosDiscoveryNamespaceGetter( + NacosDiscoveryProperties nacosDiscoveryProperties) { + return new NacosDiscoveryNamespaceGetter(nacosDiscoveryProperties); + } + } + + @ConditionalOnClass(name = "com.tencent.cloud.polaris.PolarisDiscoveryProperties") + static class Polaris { + @Bean + @ConditionalOnMissingBean + @ConditionalOnPolarisDiscoveryEnabled + @ConditionalOnBean(PolarisDiscoveryProperties.class) + public PolarisDiscoveryNamespaceGetter polarisDiscoveryNamespaceGetter( + PolarisDiscoveryProperties polarisDiscoveryProperties) { + return new PolarisDiscoveryNamespaceGetter(polarisDiscoveryProperties); + } } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java new file mode 100644 index 000000000..d23a67d0b --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java @@ -0,0 +1,28 @@ +/* + * 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.transfomer; + +/** + * Interface for discovery namespace getter. + * + * @author Shedfree Wu + */ +public interface DiscoveryNamespaceGetter { + + String getNamespace(); +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java new file mode 100644 index 000000000..6d0b605c2 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java @@ -0,0 +1,47 @@ +/* + * 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.transfomer; + +import java.lang.reflect.Method; +import java.util.Properties; + +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.nacos.client.naming.utils.InitUtils; + +import org.springframework.util.ReflectionUtils; + +/** + * Discovery namespace getter for Nacos. + * + * @author Shedfree Wu + */ +public class NacosDiscoveryNamespaceGetter implements DiscoveryNamespaceGetter { + private String namespace; + + public NacosDiscoveryNamespaceGetter(NacosDiscoveryProperties nacosDiscoveryProperties) { + // getNacosProperties is private in low version of spring-cloud-starter-alibaba-nacos-discovery + Method method = ReflectionUtils.findMethod(NacosDiscoveryProperties.class, "getNacosProperties"); + method.setAccessible(true); + this.namespace = InitUtils.initNamespaceForNaming( + (Properties) ReflectionUtils.invokeMethod(method, nacosDiscoveryProperties)); + } + + public String getNamespace() { + return namespace; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java new file mode 100644 index 000000000..51126897b --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java @@ -0,0 +1,38 @@ +/* + * 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.transfomer; + +import com.tencent.cloud.polaris.PolarisDiscoveryProperties; + +/** + * Discovery namespace getter for Polaris. + * + * @author Shedfree Wu + */ +public class PolarisDiscoveryNamespaceGetter implements DiscoveryNamespaceGetter { + + private String namespace; + + public PolarisDiscoveryNamespaceGetter(PolarisDiscoveryProperties polarisDiscoveryProperties) { + this.namespace = polarisDiscoveryProperties.getNamespace(); + } + + public String getNamespace() { + return namespace; + } +} 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 index 42dba5525..0b0d847ff 100644 --- 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 @@ -38,6 +38,7 @@ public class LosslessConfigModifierTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.port=20000") @@ -48,6 +49,7 @@ public class LosslessConfigModifierTest { .withPropertyValues("spring.cloud.gateway.enabled=false"); private final ApplicationContextRunner disabledContextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.enabled=false") .withPropertyValues("spring.application.name=test") 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 index 6a1255391..7339044ce 100644 --- 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 @@ -19,15 +19,22 @@ package com.tencent.cloud.plugin.lossless; import java.util.Collections; +import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration; +import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration; +import com.alibaba.cloud.nacos.registry.NacosRegistration; +import com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration; +import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration; 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.plugin.lossless.transfomer.DiscoveryNamespaceGetter; 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.BaseInstance; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.test.mock.discovery.NamingServer; import org.junit.jupiter.api.AfterAll; @@ -39,7 +46,10 @@ 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.AutoServiceRegistrationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationUtils; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.commons.util.UtilAutoConfiguration; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; @@ -72,6 +82,7 @@ public class LosslessRegistryAspectTest { PolarisPropertiesConfiguration.class, PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) @@ -91,6 +102,7 @@ public class LosslessRegistryAspectTest { PolarisPropertiesConfiguration.class, PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=1000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/test") .withPropertyValues("spring.cloud.polaris.lossless.port=28082") @@ -102,6 +114,31 @@ public class LosslessRegistryAspectTest { .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); + private final WebApplicationContextRunner nacosContextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + AutoServiceRegistrationProperties.class, + UtilAutoConfiguration.class, + UtilIPv6AutoConfiguration.class, + NacosDiscoveryAutoConfiguration.class, + NacosServiceAutoConfiguration.class, + NacosServiceRegistryAutoConfiguration.class, + LosslessAutoConfiguration.class, + LosslessPropertiesBootstrapConfiguration.class, + PolarisContextAutoConfiguration.class) + ) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=true") + .withPropertyValues("spring.cloud.nacos.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.enabled=false") + .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.token=xxxxxx"); + @BeforeAll static void beforeAll() throws Exception { namingServer = NamingServer.startNamingServer(10081); @@ -181,6 +218,21 @@ public class LosslessRegistryAspectTest { }); } + @Test + public void testNaocsRegister() { + this.nacosContextRunner.run(context -> { + + DiscoveryNamespaceGetter discoveryNamespaceGetter = context.getBean(DiscoveryNamespaceGetter.class); + Registration registration = context.getBean(Registration.class); + + assertThat(registration instanceof NacosRegistration).isTrue(); + assertThat(discoveryNamespaceGetter.getNamespace()).isEqualTo(NAMESPACE_TEST); + + BaseInstance baseInstance = SpringCloudLosslessActionProvider.getBaseInstance(registration, discoveryNamespaceGetter); + assertThat(baseInstance.getNamespace()).isEqualTo(NAMESPACE_TEST); + }); + } + @Configuration @EnableAutoConfiguration From c54875bea40010bfe862179c468969b64d2a8c66 Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Sat, 16 Mar 2024 22:30:40 +0800 Subject: [PATCH 08/29] release 1.14.0-rc1 and avoid potential port conflict in unit tests. (#1245) Co-authored-by: shedfreewu --- pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 4 ++-- .../cloud/plugin/lossless/LosslessRegistryAspectTest.java | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 110bbbf43..49e6e8c34 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.14.0-Hoxton.SR12-SNAPSHOT + 1.14.0-Hoxton.SR12-RC1 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 31f15fab4..c39c84639 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,10 +70,10 @@ - 1.14.0-Hoxton.SR12-SNAPSHOT + 1.14.0-Hoxton.SR12-RC1 - 1.15.2-SNAPSHOT + 1.15.2 32.0.1-jre 1.2.13 3.0.0 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 index 7339044ce..db43f84a7 100644 --- 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 @@ -72,6 +72,8 @@ public class LosslessRegistryAspectTest { private static int LOSSLESS_PORT_1 = 28083; + private static int NACOS_LOSSLESS_PORT = 28093; + private static NamingServer namingServer; private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() @@ -131,7 +133,7 @@ public class LosslessRegistryAspectTest { .withPropertyValues("spring.cloud.polaris.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") - .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) + .withPropertyValues("spring.cloud.polaris.lossless.port=" + NACOS_LOSSLESS_PORT) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + APPLICATION_PORT) .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) From 9f0a2825a331a50ebb65b69e56c7003f00f1a093 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:50:13 +0800 Subject: [PATCH 09/29] =?UTF-8?q?feat:=20SCT=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=83=BD=E5=8A=9B=E4=B8=8Epolaris-java?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E7=AE=A1=E7=90=86=E8=83=BD=E5=8A=9B?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=B8=8B=E6=B2=89=E5=8F=8A=E6=95=B4=E5=90=88?= =?UTF-8?q?=20(#1249)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring-cloud-tencent-commons/pom.xml | 4 + .../common/metadata/MetadataContext.java | 181 +++++++++++++----- .../metadata/MetadataContextHolder.java | 89 ++++----- spring-cloud-tencent-dependencies/pom.xml | 2 +- 4 files changed, 186 insertions(+), 90 deletions(-) diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml index b0ace1045..970a5bf97 100644 --- a/spring-cloud-tencent-commons/pom.xml +++ b/spring-cloud-tencent-commons/pom.xml @@ -24,6 +24,10 @@ com.tencent.polaris polaris-model + + com.tencent.polaris + polaris-metadata + diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java index 8fcd89855..b1cfaad89 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java @@ -21,22 +21,25 @@ package com.tencent.cloud.common.metadata; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Optional; +import java.util.function.BiConsumer; +import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.DiscoveryUtil; -import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataMapValue; +import com.tencent.polaris.metadata.core.MetadataObjectValue; +import com.tencent.polaris.metadata.core.MetadataStringValue; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.MetadataValue; +import com.tencent.polaris.metadata.core.TransitiveType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; -/** - * Metadata Context. - * - * @author Haotian Zhang - */ -public class MetadataContext { +public class MetadataContext extends com.tencent.polaris.metadata.core.manager.MetadataContext { /** * transitive context. @@ -63,6 +66,11 @@ public class MetadataContext { */ public static final String FRAGMENT_RAW_TRANSHEADERS_KV = "trans-headers-kv"; + /** + * the key of the header(key-value) list needed to be store as loadbalance data. + */ + public static final String FRAGMENT_LB_METADATA = "load-balance-metadata"; + private static final Logger LOG = LoggerFactory.getLogger(MetadataContext.class); /** * Namespace of local instance. @@ -108,22 +116,70 @@ public class MetadataContext { LOCAL_SERVICE = serviceName; } - private final Map> fragmentContexts; + public MetadataContext() { + super(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX); + } - private final Map loadbalancerMetadata; + private Map getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + Map values = new HashMap<>(); + metadataContainer.iterateMetadataValues(new BiConsumer() { + @Override + public void accept(String s, MetadataValue metadataValue) { + if (metadataValue instanceof MetadataStringValue) { + MetadataStringValue metadataStringValue = (MetadataStringValue) metadataValue; + if (metadataStringValue.getTransitiveType() == transitiveType) { + values.put(s, metadataStringValue.getStringValue()); + } + } + } + }); + return values; + } + private void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream, Map values) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + for (Map.Entry entry : values.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), transitiveType); + } + } - public MetadataContext() { - this.fragmentContexts = new ConcurrentHashMap<>(); - this.loadbalancerMetadata = new ConcurrentHashMap<>(); + private Map getMapMetadataAsMap(MetadataType metadataType, String mapKey, TransitiveType transitiveType, boolean downstream) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + Map values = new HashMap<>(); + MetadataValue metadataValue = metadataContainer.getMetadataValue(mapKey); + if (!(metadataValue instanceof MetadataMapValue)) { + return values; + } + MetadataMapValue metadataMapValue = (MetadataMapValue) metadataValue; + metadataMapValue.iterateMapValues(new BiConsumer() { + @Override + public void accept(String s, MetadataValue metadataValue) { + if (metadataValue instanceof MetadataStringValue) { + MetadataStringValue metadataStringValue = (MetadataStringValue) metadataValue; + if (metadataStringValue.getTransitiveType() == transitiveType) { + values.put(s, metadataStringValue.getStringValue()); + } + } + } + }); + return values; + } + + private void putMapMetadataAsMap(MetadataType metadataType, String mapKey, + TransitiveType transitiveType, boolean downstream, Map values) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + for (Map.Entry entry : values.entrySet()) { + metadataContainer.putMetadataMapValue(mapKey, entry.getKey(), entry.getValue(), transitiveType); + } } public Map getDisposableMetadata() { - return this.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + return getFragmentContext(FRAGMENT_DISPOSABLE); } public Map getTransitiveMetadata() { - return this.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + return getFragmentContext(FRAGMENT_TRANSITIVE); } public Map getCustomMetadata() { @@ -140,51 +196,76 @@ public class MetadataContext { } public Map getTransHeaders() { - return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS); + return this.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS); } public Map getTransHeadersKV() { - return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV); + return getFragmentContext(FRAGMENT_RAW_TRANSHEADERS_KV); } public Map getLoadbalancerMetadata() { - return this.loadbalancerMetadata; + MetadataContainer metadataContainer = getMetadataContainer(MetadataType.APPLICATION, false); + MetadataValue metadataValue = metadataContainer.getMetadataValue(FRAGMENT_LB_METADATA); + Map values = new HashMap<>(); + if (metadataValue instanceof MetadataMapValue) { + MetadataMapValue metadataMapValue = (MetadataMapValue) metadataValue; + metadataMapValue.iterateMapValues(new BiConsumer() { + @Override + public void accept(String s, MetadataValue metadataValue) { + if (metadataValue instanceof MetadataObjectValue) { + Optional objectValue = ((MetadataObjectValue) metadataValue).getObjectValue(); + objectValue.ifPresent(o -> values.put(s, o)); + } + } + }); + } + return values; + } + + public void setLoadbalancer(String key, Object value) { + MetadataContainer metadataContainer = getMetadataContainer(MetadataType.APPLICATION, false); + metadataContainer.putMetadataMapObjectValue(FRAGMENT_LB_METADATA, key, value); } public void setTransitiveMetadata(Map transitiveMetadata) { - this.putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); + putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); } public void setDisposableMetadata(Map disposableMetadata) { - this.putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); + putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); } public void setUpstreamDisposableMetadata(Map upstreamDisposableMetadata) { - this.putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); + putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); } public void setTransHeadersKV(String key, String value) { - this.putContext(FRAGMENT_RAW_TRANSHEADERS_KV, key, value); + putContext(FRAGMENT_RAW_TRANSHEADERS_KV, key, value); } public void setTransHeaders(String key, String value) { - this.putContext(FRAGMENT_RAW_TRANSHEADERS, key, value); - } - - public void setLoadbalancer(String key, Object value) { - this.loadbalancerMetadata.put(key, value); + putContext(FRAGMENT_RAW_TRANSHEADERS, key, value); } public Map getFragmentContext(String fragment) { - Map fragmentContext = fragmentContexts.get(fragment); - if (fragmentContext == null) { - return Collections.emptyMap(); + switch (fragment) { + case FRAGMENT_TRANSITIVE: + return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.PASS_THROUGH, false); + case FRAGMENT_DISPOSABLE: + return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false); + case FRAGMENT_UPSTREAM_DISPOSABLE: + return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true); + case FRAGMENT_RAW_TRANSHEADERS: + return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false); + case FRAGMENT_RAW_TRANSHEADERS_KV: + return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.PASS_THROUGH, false); + default: + return getMapMetadataAsMap(MetadataType.CUSTOM, fragment, TransitiveType.NONE, false); } - return Collections.unmodifiableMap(fragmentContext); } public String getContext(String fragment, String key) { - Map fragmentContext = fragmentContexts.get(fragment); + Map fragmentContext = getFragmentContext(fragment); if (fragmentContext == null) { return null; } @@ -192,22 +273,32 @@ public class MetadataContext { } public void putContext(String fragment, String key, String value) { - Map fragmentContext = fragmentContexts.get(fragment); - if (fragmentContext == null) { - fragmentContext = new ConcurrentHashMap<>(); - fragmentContexts.put(fragment, fragmentContext); - } - fragmentContext.put(key, value); + Map values = new HashMap<>(); + values.put(key, value); + putFragmentContext(fragment, values); } public void putFragmentContext(String fragment, Map context) { - fragmentContexts.put(fragment, context); + switch (fragment) { + case FRAGMENT_TRANSITIVE: + putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.PASS_THROUGH, false, context); + break; + case FRAGMENT_DISPOSABLE: + putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false, context); + break; + case FRAGMENT_UPSTREAM_DISPOSABLE: + putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true, context); + break; + case FRAGMENT_RAW_TRANSHEADERS: + putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false, context); + break; + case FRAGMENT_RAW_TRANSHEADERS_KV: + putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.PASS_THROUGH, false, context); + break; + default: + putMapMetadataAsMap(MetadataType.CUSTOM, fragment, TransitiveType.NONE, false, context); + break; + } } - @Override - public String toString() { - return "MetadataContext{" + - "fragmentContexts=" + JacksonUtils.serialize2Json(fragmentContexts) + - '}'; - } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index 4251b8d3d..90e59921b 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -24,6 +24,9 @@ import java.util.Optional; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -38,8 +41,6 @@ import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_UPSTREA */ public final class MetadataContextHolder { - private static final ThreadLocal METADATA_CONTEXT = new InheritableThreadLocal<>(); - private static MetadataLocalProperties metadataLocalProperties; private static StaticMetadataManager staticMetadataManager; @@ -47,39 +48,42 @@ public final class MetadataContextHolder { private MetadataContextHolder() { } - /** - * Get metadata context. Create if not existing. - * @return METADATA_CONTEXT - */ public static MetadataContext get() { - if (METADATA_CONTEXT.get() != null) { - return METADATA_CONTEXT.get(); - } + return (MetadataContext) com.tencent.polaris.metadata.core.manager.MetadataContextHolder.getOrCreate( + MetadataContextHolder::createMetadataManager); + } + private static MetadataContext createMetadataManager() { + MetadataContext metadataManager = new MetadataContext(); if (metadataLocalProperties == null) { - metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext().getBean(MetadataLocalProperties.class); + metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext() + .getBean(MetadataLocalProperties.class); } if (staticMetadataManager == null) { - staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext().getBean(StaticMetadataManager.class); + staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() + .getBean(StaticMetadataManager.class); + } + MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); + Map mergedStaticTransitiveMetadata = staticMetadataManager.getMergedStaticTransitiveMetadata(); + for (Map.Entry entry : mergedStaticTransitiveMetadata.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); + } + Map mergedStaticDisposableMetadata = staticMetadataManager.getMergedStaticDisposableMetadata(); + for (Map.Entry entry : mergedStaticDisposableMetadata.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); } - - // init static transitive metadata - MetadataContext metadataContext = new MetadataContext(); - metadataContext.setTransitiveMetadata(staticMetadataManager.getMergedStaticTransitiveMetadata()); - metadataContext.setDisposableMetadata(staticMetadataManager.getMergedStaticDisposableMetadata()); if (StringUtils.hasText(staticMetadataManager.getTransHeader())) { - metadataContext.setTransHeaders(staticMetadataManager.getTransHeader(), ""); + String transHeader = staticMetadataManager.getTransHeader(); + metadataContainer.putMetadataMapValue(MetadataContext.FRAGMENT_RAW_TRANSHEADERS, transHeader, "", TransitiveType.NONE); } - - METADATA_CONTEXT.set(metadataContext); - - return METADATA_CONTEXT.get(); + return metadataManager; } /** * Get disposable metadata value from thread local . - * @param key metadata key . + * + * @param key metadata key . * @param upstream upstream disposable , otherwise will return local static disposable metadata . * @return target disposable metadata value . */ @@ -95,6 +99,7 @@ public final class MetadataContextHolder { /** * Get all disposable metadata value from thread local . + * * @param upstream upstream disposable , otherwise will return local static disposable metadata . * @return target disposable metadata value . */ @@ -112,44 +117,40 @@ public final class MetadataContextHolder { /** * Set metadata context. + * * @param metadataContext metadata context */ public static void set(MetadataContext metadataContext) { - METADATA_CONTEXT.set(metadataContext); + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.set(metadataContext); } /** * Save metadata map to thread local. + * * @param dynamicTransitiveMetadata custom metadata collection * @param dynamicDisposableMetadata custom disposable metadata connection */ public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata) { - // Init ThreadLocal. - MetadataContextHolder.remove(); - MetadataContext metadataContext = MetadataContextHolder.get(); - - // Save transitive metadata to ThreadLocal. - if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { - Map staticTransitiveMetadata = metadataContext.getTransitiveMetadata(); - Map mergedTransitiveMetadata = new HashMap<>(); - mergedTransitiveMetadata.putAll(staticTransitiveMetadata); - mergedTransitiveMetadata.putAll(dynamicTransitiveMetadata); - metadataContext.setTransitiveMetadata(Collections.unmodifiableMap(mergedTransitiveMetadata)); - } - if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { - Map mergedUpstreamDisposableMetadata = new HashMap<>(dynamicDisposableMetadata); - metadataContext.setUpstreamDisposableMetadata(Collections.unmodifiableMap(mergedUpstreamDisposableMetadata)); - } - - Map staticDisposableMetadata = metadataContext.getFragmentContext(FRAGMENT_DISPOSABLE); - metadataContext.setDisposableMetadata(Collections.unmodifiableMap(staticDisposableMetadata)); - MetadataContextHolder.set(metadataContext); + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(MetadataContextHolder::createMetadataManager, metadataManager -> { + MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); + if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { + for (Map.Entry entry : dynamicTransitiveMetadata.entrySet()) { + metadataContainerUpstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); + } + } + MetadataContainer metadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, true); + if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { + for (Map.Entry entry : dynamicDisposableMetadata.entrySet()) { + metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } + } + }); } /** * Remove metadata context. */ public static void remove() { - METADATA_CONTEXT.remove(); + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.remove(); } } diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index c39c84639..eb47d2011 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.14.0-Hoxton.SR12-RC1 - 1.15.2 + 1.15.3-SNAPSHOT 32.0.1-jre 1.2.13 3.0.0 From 9672fd60b347b287e4774c77c64dd71e9b4da363 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Fri, 22 Mar 2024 10:53:00 +0800 Subject: [PATCH 10/29] Update CHANGELOG. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf85b0ebf..dc61a27f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,5 @@ --- - [feat: support lossless register and deregister at #977](https://github.com/Tencent/spring-cloud-tencent/pull/1242) -- [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) \ No newline at end of file +- [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) +- [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) \ No newline at end of file From d4c8fff31ab0eeca32cd33f2f100bd8e1cac0f8b Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:53:32 +0800 Subject: [PATCH 11/29] feat: support lane router (#1250) --- CHANGELOG.md | 3 +- .../pom.xml | 24 +++ .../MetadataTransferAutoConfiguration.java | 70 +++------ .../DecodeTransferMetadataReactiveFilter.java | 23 +-- .../DecodeTransferMetadataServletFilter.java | 21 +-- ...codeTransferMedataFeignEnhancedPlugin.java | 140 ++++++++++++++++++ .../EncodeTransferMedataFeignInterceptor.java | 102 ------------- ...sferMedataRestTemplateEnhancedPlugin.java} | 63 ++++---- ...ncodeTransferMedataScgEnhancedPlugin.java} | 62 +++++--- ...ransferMedataWebClientEnhancedPlugin.java} | 58 +++++--- ...deTransferMetadataZuulEnhancedPlugin.java} | 67 ++++----- .../provider/ReactiveMetadataProvider.java | 66 +++++++++ .../provider/ServletMetadataProvider.java | 67 +++++++++ ...MetadataTransferAutoConfigurationTest.java | 52 ++----- ...odeTransferMedataFeignInterceptorTest.java | 2 +- ...sferMedataRestTemplateInterceptorTest.java | 50 ++++++- .../EncodeTransferMedataScgFilterTest.java | 134 +++++++++++++---- ...codeTransferMedataWebClientFilterTest.java | 2 +- .../EncodeTransferMetadataZuulFilterTest.java | 35 ++++- .../provider/MetadataProviderTest.java | 135 +++++++++++++++++ .../pom.xml | 4 + .../cloud/common/constant/OrderConstant.java | 19 --- .../metadata/MetadataContextHolder.java | 10 +- .../cloud/common/util/ReflectionUtils.java | 16 ++ .../tencent/cloud/common/util/UrlUtils.java | 78 ++++++++++ .../expresstion/ExpressionLabelUtils.java | 10 +- .../ServletExpressionLabelUtils.java | 8 +- .../SpringWebExpressionLabelUtils.java | 20 ++- .../metadata/MetadataContextHolderTest.java | 2 +- .../cloud/common/util/UrlUtilsTest.java | 68 +++++++++ .../callee/QuickstartCalleeController.java | 22 +++ .../loadbalancer/PolarisLoadBalancer.java | 4 +- .../feign/EnhancedFeignClient.java | 1 + .../plugin/EnhancedPluginContext.java | 10 ++ .../plugin/PluginOrderConstant.java | 14 ++ .../EnhancedRestTemplateInterceptor.java | 1 + .../scg/EnhancedGatewayGlobalFilter.java | 12 +- ...hancedWebClientExchangeFilterFunction.java | 14 +- .../zuul/EnhancedPreZuulFilter.java | 1 + 39 files changed, 1070 insertions(+), 420 deletions(-) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java delete mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataRestTemplateInterceptor.java => EncodeTransferMedataRestTemplateEnhancedPlugin.java} (60%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataScgFilter.java => EncodeTransferMedataScgEnhancedPlugin.java} (58%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataWebClientFilter.java => EncodeTransferMedataWebClientEnhancedPlugin.java} (57%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMetadataZuulFilter.java => EncodeTransferMetadataZuulEnhancedPlugin.java} (56%) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index dc61a27f3..ac7c92ba2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,4 +3,5 @@ - [feat: support lossless register and deregister at #977](https://github.com/Tencent/spring-cloud-tencent/pull/1242) - [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) -- [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) \ No newline at end of file +- [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) +- [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-metadata-transfer/pom.xml b/spring-cloud-starter-tencent-metadata-transfer/pom.xml index ad4714f7a..35b783daa 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/pom.xml +++ b/spring-cloud-starter-tencent-metadata-transfer/pom.xml @@ -19,6 +19,12 @@ com.tencent.cloud spring-cloud-tencent-commons + + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + @@ -56,6 +62,24 @@ spring-cloud-starter-netflix-ribbon test + + + com.tencent.polaris + polaris-test-mock-discovery + test + + + + com.tencent.polaris + polaris-test-common + test + + + + org.mockito + mockito-inline + test + diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index bbb033282..b9b440890 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -18,31 +18,21 @@ package com.tencent.cloud.metadata.config; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.netflix.zuul.ZuulFilter; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataScgFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulFilter; - -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; +import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulEnhancedPlugin; + import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.reactive.function.client.WebClient; import static javax.servlet.DispatcherType.ASYNC; import static javax.servlet.DispatcherType.ERROR; @@ -100,11 +90,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferZuulFilterConfig { @Bean - public ZuulFilter encodeTransferMetadataZuulFilter() { - return new EncodeTransferMetadataZuulFilter(); + public EncodeTransferMetadataZuulEnhancedPlugin encodeTransferMedataZuulEnhancedPlugin() { + return new EncodeTransferMetadataZuulEnhancedPlugin(); } } @@ -114,11 +105,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferScgFilterConfig { @Bean - public GlobalFilter encodeTransferMedataScgFilter() { - return new EncodeTransferMedataScgFilter(); + public EncodeTransferMedataScgEnhancedPlugin encodeTransferMedataScgEnhancedPlugin() { + return new EncodeTransferMedataScgEnhancedPlugin(); } } @@ -127,11 +119,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.Feign") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferFeignInterceptorConfig { @Bean - public EncodeTransferMedataFeignInterceptor encodeTransferMedataFeignInterceptor() { - return new EncodeTransferMedataFeignInterceptor(); + public EncodeTransferMedataFeignEnhancedPlugin encodeTransferMedataFeignEnhancedPlugin() { + return new EncodeTransferMedataFeignEnhancedPlugin(); } } @@ -140,23 +133,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferRestTemplateConfig { - @Autowired(required = false) - private List restTemplates = Collections.emptyList(); - @Bean - public EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor() { - return new EncodeTransferMedataRestTemplateInterceptor(); - } - - @Bean - public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTemplate(EncodeTransferMedataRestTemplateInterceptor interceptor) { - return () -> restTemplates.forEach(restTemplate -> { - List list = new ArrayList<>(restTemplate.getInterceptors()); - list.add(interceptor); - restTemplate.setInterceptors(list); - }); + public EncodeTransferMedataRestTemplateEnhancedPlugin encodeTransferMedataRestTemplateEnhancedPlugin() { + return new EncodeTransferMedataRestTemplateEnhancedPlugin(); } } @@ -165,20 +147,12 @@ public class MetadataTransferAutoConfiguration { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferWebClientConfig { - @Autowired(required = false) - private List webClientBuilder = Collections.emptyList(); - - @Bean - public EncodeTransferMedataWebClientFilter encodeTransferMedataWebClientFilter() { - return new EncodeTransferMedataWebClientFilter(); - } @Bean - public SmartInitializingSingleton addEncodeTransferMetadataFilterForWebClient(EncodeTransferMedataWebClientFilter filter) { - return () -> webClientBuilder.forEach(webClient -> { - webClient.filter(filter); - }); + public EncodeTransferMedataWebClientEnhancedPlugin encodeTransferMedataWebClientEnhancedPlugin() { + return new EncodeTransferMedataWebClientEnhancedPlugin(); } } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java index 4268f6e79..e4fd1a2cb 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -18,8 +18,6 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -27,6 +25,8 @@ import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; @@ -34,12 +34,10 @@ import reactor.core.publisher.Mono; import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -62,19 +60,16 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); - Map internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA); Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); - + ReactiveMetadataProvider metadataProvider = new ReactiveMetadataProvider(serverHttpRequest); + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); // Save to ServerWebExchange. serverWebExchange.getAttributes().put( MetadataConstant.HeaderName.METADATA_CONTEXT, @@ -89,15 +84,7 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); - String customMetadataStr = httpHeaders.getFirst(headerName); - try { - if (StringUtils.hasText(customMetadataStr)) { - customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); - } - } - catch (UnsupportedEncodingException e) { - LOG.error("Runtime system does not support utf-8 coding.", e); - } + String customMetadataStr = UrlUtils.decode(httpHeaders.getFirst(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); return JacksonUtils.deserialize2Map(customMetadataStr); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index e1d26efcc..d74ddcd71 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -19,8 +19,6 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -32,15 +30,15 @@ import javax.servlet.http.HttpServletResponse; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.metadata.provider.ServletMetadataProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.lang.NonNull; -import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -65,11 +63,10 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); + ServletMetadataProvider metadataProvider = new ServletMetadataProvider(httpServletRequest); + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); TransHeadersTransfer.transfer(httpServletRequest); try { @@ -83,15 +80,7 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private Map getInternalMetadata(HttpServletRequest httpServletRequest, String headerName) { // Get custom metadata string from http header. - String customMetadataStr = httpServletRequest.getHeader(headerName); - try { - if (StringUtils.hasText(customMetadataStr)) { - customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); - } - } - catch (UnsupportedEncodingException e) { - LOG.error("Runtime system does not support utf-8 coding.", e); - } + String customMetadataStr = UrlUtils.decode(httpServletRequest.getHeader(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); // create custom metadata. diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java new file mode 100644 index 000000000..ff722edc6 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java @@ -0,0 +1,140 @@ +/* + * 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.metadata.core; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.ReflectionUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; + +import org.springframework.util.CollectionUtils; + +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; + +/** + * Pre EnhancedPlugin for feign to encode transfer metadata. + * + * @author Shedfree Wu + */ +public class EncodeTransferMedataFeignEnhancedPlugin implements EnhancedPlugin { + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; + } + + @Override + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof Request)) { + return; + } + Request request = (Request) context.getOriginRequest(); + + // get metadata of current thread + MetadataContext metadataContext = MetadataContextHolder.get(); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map transHeaders = metadataContext.getTransHeadersKV(); + + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(request, calleeTransitiveHeaders); + + // build custom disposable metadata request header + this.buildMetadataHeader(request, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // process custom metadata + this.buildMetadataHeader(request, customMetadata, CUSTOM_METADATA); + + // set headers that need to be transmitted from the upstream + this.buildTransmittedHeader(request, transHeaders); + } + + private void buildTransmittedHeader(Request request, Map transHeaders) { + if (!CollectionUtils.isEmpty(transHeaders)) { + Map> headers = getModifiableHeaders(request); + transHeaders.entrySet().stream().forEach(entry -> { + headers.remove(entry.getKey()); + headers.put(entry.getKey(), Arrays.asList(entry.getValue())); + }); + } + } + + /** + * Set metadata into the request header for {@link Request} . + * @param request instance of {@link Request} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(Request request, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); + } + } + + + /** + * Set headerMap into the request header for {@link Request} . + * @param request instance of {@link Request} + * @param headerMap header map . + */ + private void buildHeaderMap(Request request, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + Map> headers = getModifiableHeaders(request); + headerMap.forEach((key, value) -> headers.put(key, Arrays.asList(UrlUtils.encode(value)))); + } + } + + /** + * The value obtained directly from the headers method is an unmodifiable map. + * If the Feign client uses the URL, the original headers are unmodifiable. + * @param request feign request + * @return modifiable headers + */ + private Map> getModifiableHeaders(Request request) { + Map> headers; + headers = (Map>) ReflectionUtils.getFieldValue(request, "headers"); + + if (!(headers instanceof LinkedHashMap)) { + headers = new LinkedHashMap<>(headers); + ReflectionUtils.setFieldValue(request, "headers", headers); + } + return headers; + } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java deleted file mode 100644 index edbf5f0bc..000000000 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.metadata.core; - -import java.io.UnsupportedEncodingException; -import java.util.Map; - -import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.util.JacksonUtils; -import feign.RequestInterceptor; -import feign.RequestTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.core.Ordered; -import org.springframework.util.CollectionUtils; -import org.springframework.web.client.RestTemplate; - -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; -import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; -import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static java.net.URLEncoder.encode; - -/** - * Interceptor used for adding the metadata in http headers from context when web client - * is Feign. - * - * @author Haotian Zhang - */ -public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, Ordered { - - private static final Logger LOG = LoggerFactory.getLogger(EncodeTransferMedataFeignInterceptor.class); - - @Override - public int getOrder() { - return OrderConstant.Client.Feign.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; - } - - @Override - public void apply(RequestTemplate requestTemplate) { - // get metadata of current thread - MetadataContext metadataContext = MetadataContextHolder.get(); - Map customMetadata = metadataContext.getCustomMetadata(); - Map disposableMetadata = metadataContext.getDisposableMetadata(); - Map transHeaders = metadataContext.getTransHeadersKV(); - - this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - - // process custom metadata - this.buildMetadataHeader(requestTemplate, customMetadata, CUSTOM_METADATA); - - // set headers that need to be transmitted from the upstream - this.buildTransmittedHeader(requestTemplate, transHeaders); - } - - private void buildTransmittedHeader(RequestTemplate requestTemplate, Map transHeaders) { - if (!CollectionUtils.isEmpty(transHeaders)) { - transHeaders.entrySet().stream().forEach(entry -> { - requestTemplate.removeHeader(entry.getKey()); - requestTemplate.header(entry.getKey(), entry.getValue()); - }); - } - } - - /** - * Set metadata into the request header for {@link RestTemplate} . - * @param requestTemplate instance of {@link RestTemplate} - * @param metadata metadata map . - * @param headerName target metadata http header name . - */ - private void buildMetadataHeader(RequestTemplate requestTemplate, Map metadata, String headerName) { - if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - requestTemplate.removeHeader(headerName); - try { - requestTemplate.header(headerName, encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - LOG.error("Set header failed.", e); - requestTemplate.header(headerName, encodedMetadata); - } - } - } -} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java similarity index 60% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java index cbf4901b3..50e42885b 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java @@ -18,49 +18,53 @@ package com.tencent.cloud.metadata.core; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; -import com.tencent.cloud.common.constant.OrderConstant; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; -import org.springframework.core.Ordered; import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Interceptor used for adding the metadata in http headers from context when web client - * is RestTemplate. + * Pre EnhancedPlugin for rest template to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { - +public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedPlugin { @Override - public int getOrder() { - return OrderConstant.Client.RestTemplate.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes, - @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof HttpRequest)) { + return; + } + HttpRequest httpRequest = (HttpRequest) context.getOriginRequest(); + // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(httpRequest, calleeTransitiveHeaders); // build custom disposable metadata request header this.buildMetadataHeader(httpRequest, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); @@ -70,8 +74,6 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(httpRequest, transHeaders); - - return clientHttpRequestExecution.execute(httpRequest, bytes); } private void buildTransmittedHeader(HttpRequest request, Map transHeaders) { @@ -82,6 +84,12 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe } } + private void buildHeaderMap(HttpRequest request, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> request.getHeaders().set(key, UrlUtils.encode(value))); + } + } + /** * Set metadata into the request header for {@link HttpRequest} . * @@ -91,13 +99,12 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe */ private void buildMetadataHeader(HttpRequest request, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - request.getHeaders().set(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - request.getHeaders().set(headerName, encodedMetadata); - } + buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java similarity index 58% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java index 2eacd21a7..8c996bbf1 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java @@ -18,42 +18,46 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; -import reactor.core.publisher.Mono; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Scg filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for scg to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { - +public class EncodeTransferMedataScgEnhancedPlugin implements EnhancedPlugin { @Override - public int getOrder() { - return OrderConstant.Client.Scg.ENCODE_TRANSFER_METADATA_FILTER_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof ServerWebExchange)) { + return; + } + ServerWebExchange exchange = (ServerWebExchange) context.getOriginRequest(); + // get request builder ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); @@ -66,11 +70,22 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(builder, calleeTransitiveHeaders); + this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - TransHeadersTransfer.transfer(exchange.getRequest()); - return chain.filter(exchange.mutate().request(builder.build()).build()); + + context.setOriginRequest(exchange.mutate().request(builder.build()).build()); + } + + private void buildHeaderMap(ServerHttpRequest.Builder builder, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> builder.header(key, UrlUtils.encode(value))); + } } /** @@ -81,13 +96,12 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { */ private void buildMetadataHeader(ServerHttpRequest.Builder builder, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - builder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - builder.header(headerName, encodedMetadata); - } + buildHeaderMap(builder, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java similarity index 57% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java index 3547add0e..2967a2b4c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java @@ -18,48 +18,61 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; -import reactor.core.publisher.Mono; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.client.ClientRequest; -import org.springframework.web.reactive.function.client.ClientResponse; -import org.springframework.web.reactive.function.client.ExchangeFilterFunction; -import org.springframework.web.reactive.function.client.ExchangeFunction; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * web client filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for web client to encode transfer metadata. * - * @author sean yu + * @author Shedfree Wu */ -public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFunction { +public class EncodeTransferMedataWebClientEnhancedPlugin implements EnhancedPlugin { + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; + } @Override - public Mono filter(ClientRequest clientRequest, ExchangeFunction next) { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof ClientRequest)) { + return; + } + ClientRequest clientRequest = (ClientRequest) context.getOriginRequest(); + MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); ClientRequest.Builder requestBuilder = ClientRequest.from(clientRequest); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(requestBuilder, calleeTransitiveHeaders); + this.buildMetadataHeader(requestBuilder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestBuilder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); this.buildTransmittedHeader(requestBuilder, transHeaders); - ClientRequest request = requestBuilder.build(); - - return next.exchange(request); + context.setOriginRequest(requestBuilder.build()); } private void buildTransmittedHeader(ClientRequest.Builder requestBuilder, Map transHeaders) { @@ -68,6 +81,11 @@ public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFuncti } } + private void buildHeaderMap(ClientRequest.Builder requestBuilder, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> requestBuilder.header(key, UrlUtils.encode(value))); + } + } /** * Set metadata into the request header for {@link ClientRequest} . @@ -77,14 +95,12 @@ public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFuncti */ private void buildMetadataHeader(ClientRequest.Builder requestBuilder, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - requestBuilder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - requestBuilder.header(headerName, encodedMetadata); - } + buildHeaderMap(requestBuilder, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java similarity index 56% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java index 6aa2a1e05..c1957bda7 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java @@ -18,63 +18,65 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; -import com.netflix.zuul.ZuulFilter; +import com.google.common.collect.ImmutableMap; import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; import org.springframework.util.CollectionUtils; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE; /** - * Zuul filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for zuul to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMetadataZuulFilter extends ZuulFilter { - - @Override - public String filterType() { - return ROUTE_TYPE; - } - - @Override - public int filterOrder() { - return OrderConstant.Client.Zuul.ENCODE_TRANSFER_METADATA_FILTER_ORDER; - } - +public class EncodeTransferMetadataZuulEnhancedPlugin implements EnhancedPlugin { @Override - public boolean shouldFilter() { - return true; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public Object run() { - // get request context - RequestContext requestContext = RequestContext.getCurrentContext(); + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof RequestContext)) { + return; + } + RequestContext requestContext = (RequestContext) context.getOriginRequest(); // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(requestContext, calleeTransitiveHeaders); // Rebuild Metadata Header this.buildMetadataHeader(requestContext, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestContext, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); TransHeadersTransfer.transfer(requestContext.getRequest()); - return null; + } + + private void buildHeaderMap(RequestContext context, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> context.addZuulRequestHeader(key, UrlUtils.encode(value))); + } } /** @@ -86,13 +88,12 @@ public class EncodeTransferMetadataZuulFilter extends ZuulFilter { */ private void buildMetadataHeader(RequestContext context, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - context.addZuulRequestHeader(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - context.addZuulRequestHeader(headerName, encodedMetadata); - } + buildHeaderMap(context, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java new file mode 100644 index 000000000..7eb2dc1c7 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java @@ -0,0 +1,66 @@ +/* + * 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.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; + +import org.springframework.http.server.reactive.ServerHttpRequest; + +/** + * MetadataProvider used for Reactive. + * + * @author Shedfree Wu + */ +public class ReactiveMetadataProvider implements MetadataProvider { + + private ServerHttpRequest serverHttpRequest; + + public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest) { + this.serverHttpRequest = serverHttpRequest; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return serverHttpRequest.getMethodValue(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(serverHttpRequest.getPath().toString()); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(serverHttpRequest, mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(serverHttpRequest, mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(serverHttpRequest, mapKey, null)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java new file mode 100644 index 000000000..f06df5e16 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java @@ -0,0 +1,67 @@ +/* + * 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.metadata.provider; + +import javax.servlet.http.HttpServletRequest; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; +import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; + +/** + * MetadataProvider used for Servlet. + * + * @author Shedfree Wu + */ +public class ServletMetadataProvider implements MetadataProvider { + + private HttpServletRequest httpServletRequest; + + public ServletMetadataProvider(HttpServletRequest httpServletRequest) { + this.httpServletRequest = httpServletRequest; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return httpServletRequest.getMethod(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(httpServletRequest.getRequestURI()); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(httpServletRequest.getHeader(mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(ServletExpressionLabelUtils.getCookieValue(httpServletRequest.getCookies(), mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(ExpressionLabelUtils.getQueryValue(httpServletRequest.getQueryString(), mapKey, null)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java index cd23e7615..c61111191 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java @@ -18,25 +18,17 @@ package com.tencent.cloud.metadata.config; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientFilter; +import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; @@ -59,35 +51,10 @@ public class MetadataTransferAutoConfigurationTest { this.applicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); + assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateInterceptor.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); - assertThat(context).hasSingleBean(GlobalFilter.class); - }); - } - - - @Test - public void test2() { - this.applicationContextRunner - .withConfiguration( - AutoConfigurations.of(MetadataTransferAutoConfiguration.class, RestTemplateConfiguration.class)) - .run(context -> { - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); - EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor = context.getBean(EncodeTransferMedataRestTemplateInterceptor.class); - Map restTemplateMap = context.getBeansOfType(RestTemplate.class); - assertThat(restTemplateMap.size()).isEqualTo(2); - for (String beanName : Arrays.asList("restTemplate", "loadBalancedRestTemplate")) { - RestTemplate restTemplate = restTemplateMap.get(beanName); - assertThat(restTemplate).isNotNull(); - List encodeTransferMedataFeignInterceptorList = restTemplate.getInterceptors() - .stream() - .filter(interceptor -> Objects.equals(interceptor, encodeTransferMedataRestTemplateInterceptor)) - .collect(Collectors.toList()); - //EncodeTransferMetadataFeignInterceptor is not added repeatedly - assertThat(encodeTransferMedataFeignInterceptorList.size()).isEqualTo(1); - } }); } @@ -95,16 +62,15 @@ public class MetadataTransferAutoConfigurationTest { * Reactive web application. */ @Test - public void test3() { + public void test2() { this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); - assertThat(context).hasSingleBean(GlobalFilter.class); - assertThat(context).hasSingleBean(EncodeTransferMedataWebClientFilter.class); + assertThat(context).hasSingleBean(EncodeTransferMedataWebClientEnhancedPlugin.class); }); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java index df3e883f1..e34f4e9ae 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java @@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; /** - * Test for {@link EncodeTransferMedataFeignInterceptor}. + * Test for {@link EncodeTransferMedataFeignEnhancedPlugin}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java index 275784bbb..b0ce9217c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -17,8 +17,14 @@ package com.tencent.cloud.metadata.core; +import java.net.URI; +import java.util.Arrays; +import java.util.Map; + import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,6 +32,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -39,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataRestTemplateInterceptor}. + * Test for {@link EncodeTransferMedataRestTemplateEnhancedPlugin}. * * @author Haotian Zhang */ @@ -72,7 +79,13 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { @Bean public RestTemplate restTemplate() { - return new RestTemplate(); + + EncodeTransferMedataRestTemplateEnhancedPlugin plugin = new EncodeTransferMedataRestTemplateEnhancedPlugin(); + EnhancedRestTemplateInterceptor interceptor = new EnhancedRestTemplateInterceptor( + new DefaultEnhancedPluginRunner(Arrays.asList(plugin), new MockRegistration(), null)); + RestTemplate template = new RestTemplate(); + template.setInterceptors(Arrays.asList(interceptor)); + return template; } @RequestMapping("/test") @@ -80,4 +93,37 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } } + + static class MockRegistration implements Registration { + + @Override + public String getServiceId() { + return "test"; + } + + @Override + public String getHost() { + return "localhost"; + } + + @Override + public int getPort() { + return 0; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public Map getMetadata() { + return null; + } + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java index 97f55f731..cbc1116bc 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java @@ -18,59 +18,129 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Map; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; +import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter; +import org.assertj.core.util.Maps; +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.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.route.Route; import org.springframework.context.ApplicationContext; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.server.ServerWebExchange; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; +import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; /** - * @author quan + * Test for {@link EncodeTransferMedataScgEnhancedPlugin}. + * @author quan, Shedfree Wu */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = RANDOM_PORT, classes = EncodeTransferMedataScgFilterTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) +@ExtendWith(MockitoExtension.class) public class EncodeTransferMedataScgFilterTest { - @Autowired - private ApplicationContext applicationContext; - + private static MockedStatic mockedApplicationContextAwareUtils; + @Mock + Registration registration; @Mock - private GatewayFilterChain chain; + GatewayFilterChain chain; - @Test - public void testTransitiveMetadataFromApplicationConfig() throws UnsupportedEncodingException { - EncodeTransferMedataScgFilter filter = applicationContext.getBean(EncodeTransferMedataScgFilter.class); - MockServerHttpRequest.BaseBuilder builder = MockServerHttpRequest.get(""); - MockServerWebExchange exchange = MockServerWebExchange.from(builder); - filter.filter(exchange, chain); - String metadataStr = exchange.getRequest().getHeaders().getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA); - String decode = URLDecoder.decode(metadataStr, UTF_8); - Map transitiveMap = JacksonUtils.deserialize2Map(decode); - assertThat(transitiveMap.size()).isEqualTo(1); - assertThat(transitiveMap.get("b")).isEqualTo("2"); + @BeforeAll + static void beforeAll() { + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + ApplicationContext applicationContext = mock(ApplicationContext.class); + MetadataLocalProperties metadataLocalProperties = mock(MetadataLocalProperties.class); + StaticMetadataManager staticMetadataManager = mock(StaticMetadataManager.class); + doReturn(metadataLocalProperties).when(applicationContext).getBean(MetadataLocalProperties.class); + doReturn(staticMetadataManager).when(applicationContext).getBean(StaticMetadataManager.class); + mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext) + .thenReturn(applicationContext); + } + + @AfterAll + static void afterAll() { + mockedApplicationContextAwareUtils.close(); } - @SpringBootApplication - protected static class TestApplication { + @BeforeEach + void setUp() { + MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST; + MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER; + } + + @Test + public void testRun() throws URISyntaxException { + + Route route = mock(Route.class); + URI uri = new URI("http://TEST/"); + doReturn(uri).when(route).getUri(); + + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Maps.newHashMap("t-key", "t-value")); + metadataContext.setDisposableMetadata(Maps.newHashMap("d-key", "d-value")); + + MockServerHttpRequest mockServerHttpRequest = MockServerHttpRequest.get("/test").build(); + + EncodeTransferMedataScgEnhancedPlugin plugin = new EncodeTransferMedataScgEnhancedPlugin(); + plugin.getOrder(); + EnhancedGatewayGlobalFilter filter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(Arrays.asList(plugin), registration, null)); + filter.getOrder(); + + MockServerWebExchange mockServerWebExchange = MockServerWebExchange.builder(mockServerHttpRequest).build(); + mockServerWebExchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route); + mockServerWebExchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("http://0.0.0.0/")); + mockServerWebExchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT, metadataContext); + doReturn(Mono.empty()).when(chain).filter(any()); + + + filter.filter(mockServerWebExchange, chain).block(); + + + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + // capture the result exchange + Mockito.verify(chain).filter(captor.capture()); + ServerWebExchange filteredExchange = captor.getValue(); + + assertThat(filteredExchange.getRequest().getHeaders().get(CUSTOM_METADATA)).isNotNull(); + assertThat(filteredExchange.getRequest().getHeaders().get(CUSTOM_DISPOSABLE_METADATA)).isNotNull(); + + // test metadataContext init in EnhancedPlugin + mockServerWebExchange.getAttributes().remove(MetadataConstant.HeaderName.METADATA_CONTEXT); + assertThatCode(() -> filter.filter(mockServerWebExchange, chain).block()).doesNotThrowAnyException(); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java index 85c8b2d35..fe7c30d27 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java @@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataWebClientFilter}. + * Test for {@link EncodeTransferMedataWebClientEnhancedPlugin}. * * @author sean yu */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java index 56895ee25..1c72c5d5a 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java @@ -23,9 +23,13 @@ import java.net.URLDecoder; import java.util.Map; import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.MetadataConstant; +import com.netflix.zuul.exception.ZuulException; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.rpc.enhancement.zuul.EnhancedPreZuulFilter; import org.assertj.core.api.Assertions; +import org.assertj.core.util.Maps; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -38,12 +42,16 @@ import org.springframework.mock.web.MockMultipartHttpServletRequest; import org.springframework.test.context.junit.jupiter.SpringExtension; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY; /** - * Test for {@link EncodeTransferMetadataZuulFilter}. + * Test for {@link EncodeTransferMetadataZuulEnhancedPlugin}. * - * @author quan + * @author quan, Shedfree Wu */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = RANDOM_PORT, @@ -64,17 +72,30 @@ public class EncodeTransferMetadataZuulFilterTest { } @Test - public void multiplePartNamesWithMultipleParts() throws UnsupportedEncodingException { - EncodeTransferMetadataZuulFilter filter = applicationContext.getBean(EncodeTransferMetadataZuulFilter.class); + public void testRun() throws ZuulException, UnsupportedEncodingException { + EnhancedPreZuulFilter filter = applicationContext.getBean(EnhancedPreZuulFilter.class); + RequestContext context = RequestContext.getCurrentContext(); + context.set(SERVICE_ID_KEY, "test-service"); + + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Maps.newHashMap("t-key", "t-value")); + metadataContext.setDisposableMetadata(Maps.newHashMap("d-key", "d-value")); filter.run(); + final RequestContext ctx = RequestContext.getCurrentContext(); Map zuulRequestHeaders = ctx.getZuulRequestHeaders(); - String metadata = zuulRequestHeaders.get(MetadataConstant.HeaderName.CUSTOM_METADATA.toLowerCase()); + // convert header to lower case in com.netflix.zuul.context.RequestContext.addZuulRequestHeader + assertThat(zuulRequestHeaders.get(CUSTOM_METADATA.toLowerCase())).isNotNull(); + assertThat(zuulRequestHeaders.get(CUSTOM_DISPOSABLE_METADATA.toLowerCase())).isNotNull(); + + String metadata = zuulRequestHeaders.get(CUSTOM_METADATA.toLowerCase()); + Assertions.assertThat(metadata).isNotNull(); String decode = URLDecoder.decode(metadata, UTF_8); Map transitiveMap = JacksonUtils.deserialize2Map(decode); - Assertions.assertThat(transitiveMap.size()).isEqualTo(1); + // expect {"b":"2","t-key":"t-value"} + Assertions.assertThat(transitiveMap.size()).isEqualTo(2); Assertions.assertThat(transitiveMap.get("b")).isEqualTo("2"); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java new file mode 100644 index 000000000..ff7aedc5d --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java @@ -0,0 +1,135 @@ +/* + * 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.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import org.junit.Test; + +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpMethod; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.MockCookie; +import org.springframework.mock.web.MockHttpServletRequest; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link ReactiveMetadataProvider} and {@link ServletMetadataProvider}. + * + * @author quan, Shedfree Wu + */ +public class MetadataProviderTest { + + private static final String notExistKey = "empty"; + + @Test + public void testReactiveMetadataProvider() { + String headerKey1 = "header1"; + String headerKey2 = "header2"; + String headerValue1 = "value1"; + String headerValue2 = "value2/test"; + String queryKey1 = "qk1"; + String queryKey2 = "qk2"; + String queryValue1 = "qv1"; + String queryValue2 = "qv2/test"; + String cookieKey1 = "ck1"; + String cookieKey2 = "ck2"; + String cookieValue1 = "cv1"; + String cookieValue2 = "cv2/test"; + String path = "/echo/test"; + MockServerHttpRequest request = MockServerHttpRequest.get(path) + .header(headerKey1, headerValue1) + .header(headerKey2, UrlUtils.encode(headerValue2)) + .queryParam(queryKey1, queryValue1) + .queryParam(queryKey2, UrlUtils.encode(queryValue2)) + .cookie(new HttpCookie(cookieKey1, cookieValue1)) + .cookie(new HttpCookie(cookieKey2, UrlUtils.encode(cookieValue2))) + .build(); + + ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); + // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); + + request = MockServerHttpRequest.get("/echo/" + UrlUtils.decode("a@b")).build(); + reactiveMetadataProvider = new ReactiveMetadataProvider(request); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); + } + + @Test + public void testServletMetadataProvider() { + String headerKey1 = "header1"; + String headerKey2 = "header2"; + String headerValue1 = "value1"; + String headerValue2 = "value2/test"; + String queryKey1 = "qk1"; + String queryKey2 = "qk2"; + String queryValue1 = "qv1"; + String queryValue2 = "qv2/test"; + String cookieKey1 = "ck1"; + String cookieKey2 = "ck2"; + String cookieValue1 = "cv1"; + String cookieValue2 = "cv2/test"; + String path = "/echo/test"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(headerKey1, headerValue1); + request.addHeader(headerKey2, UrlUtils.encode(headerValue2)); + request.setCookies(new MockCookie(cookieKey1, cookieValue1), new MockCookie(cookieKey2, UrlUtils.encode(cookieValue2))); + request.setMethod(HttpMethod.GET.name()); + request.setRequestURI(path); + request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2)); + + ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); + // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); + assertThat(servletMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); + + request.setRequestURI("/echo/" + UrlUtils.decode("a@b")); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 56ac0fe50..98ab742b0 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -48,6 +48,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-lane + 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 be2a37055..2ad9dbb2a 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 @@ -36,10 +36,6 @@ public class OrderConstant { * Order constant for Feign. */ public static class Feign { - /** - * Order of encode transfer metadata interceptor. - */ - public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; /** * Order of encode router label interceptor. @@ -51,10 +47,6 @@ public class OrderConstant { * Order constant for RestTemplate. */ public static class RestTemplate { - /** - * Order of encode transfer metadata interceptor. - */ - public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; /** * Order of encode router label interceptor. @@ -67,12 +59,6 @@ public class OrderConstant { */ public static class Scg { - /** - * Order of encode transfer metadata filter. - * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. - */ - public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = 10150 + 1; - /** * Order of enhanced filter. * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. @@ -85,11 +71,6 @@ public class OrderConstant { */ public static class Zuul { - /** - * Order of encode transfer metadata filter. - */ - public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = RIBBON_ROUTING_FILTER_ORDER - 1; - /** * Order of enhanced ROUTE filter. */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index 90e59921b..37329ea6a 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -24,7 +24,9 @@ import java.util.Optional; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; import com.tencent.polaris.metadata.core.MetadataType; import com.tencent.polaris.metadata.core.TransitiveType; @@ -129,8 +131,10 @@ public final class MetadataContextHolder { * * @param dynamicTransitiveMetadata custom metadata collection * @param dynamicDisposableMetadata custom disposable metadata connection + * @param callerMetadataProvider caller metadata provider */ - public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata) { + public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata, + MetadataProvider callerMetadataProvider) { com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(MetadataContextHolder::createMetadataManager, metadataManager -> { MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { @@ -144,6 +148,10 @@ public final class MetadataContextHolder { metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); } } + if (callerMetadataProvider != null) { + MessageMetadataContainer callerMessageContainer = metadataManager.getMetadataContainer(MetadataType.MESSAGE, true); + callerMessageContainer.setMetadataProvider(callerMetadataProvider); + } }); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java index b9f75b94a..d822b1943 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java @@ -68,4 +68,20 @@ public final class ReflectionUtils extends org.springframework.util.ReflectionUt } return null; } + + public static void setFieldValue(Object instance, String fieldName, Object value) { + Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName); + if (field == null) { + return; + } + + field.setAccessible(true); + + try { + setField(field, instance, value); + } + finally { + field.setAccessible(false); + } + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java new file mode 100644 index 000000000..6190f33c4 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java @@ -0,0 +1,78 @@ +/* + * 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.common.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.util.StringUtils; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +/** + * Utils for URLDecoder/URLEncoder. + * + * @author Shedfree Wu + */ +public final class UrlUtils { + + private static final Logger LOG = LoggerFactory.getLogger(UrlUtils.class); + + private UrlUtils() { + } + + public static String decode(String s) { + return decode(s, UTF_8); + } + + public static String decode(String s, String enc) { + if (!StringUtils.hasText(s)) { + return s; + } + try { + return URLDecoder.decode(s, enc); + } + catch (UnsupportedEncodingException e) { + LOG.warn("Runtime system does not support {} coding. s:{}, msg:{}", enc, s, e.getMessage()); + // return original string + return s; + } + } + + public static String encode(String s) { + return encode(s, UTF_8); + } + + public static String encode(String s, String enc) { + if (!StringUtils.hasText(s)) { + return s; + } + try { + return URLEncoder.encode(s, enc); + } + catch (UnsupportedEncodingException e) { + LOG.warn("Runtime system does not support {} coding. s:{}, msg:{}", enc, s, e.getMessage()); + // return original string + return s; + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java index c7029deff..9c5e73b9d 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java @@ -138,12 +138,16 @@ public final class ExpressionLabelUtils { } public static String getQueryValue(String queryString, String queryKey) { + return getQueryValue(queryString, queryKey, StringUtils.EMPTY); + } + + public static String getQueryValue(String queryString, String queryKey, String defaultValue) { if (StringUtils.isBlank(queryString)) { - return StringUtils.EMPTY; + return defaultValue; } String[] queries = StringUtils.split(queryString, "&"); if (queries == null || queries.length == 0) { - return StringUtils.EMPTY; + return defaultValue; } for (String query : queries) { String[] queryKV = StringUtils.split(query, "="); @@ -151,7 +155,7 @@ public final class ExpressionLabelUtils { return queryKV[1]; } } - return StringUtils.EMPTY; + return defaultValue; } public static String getFirstValue(Map> valueMaps, String key) { diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java index a054c8f65..45ad670b0 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java @@ -83,14 +83,18 @@ public final class ServletExpressionLabelUtils { } public static String getCookieValue(Cookie[] cookies, String key) { + return getCookieValue(cookies, key, StringUtils.EMPTY); + } + + public static String getCookieValue(Cookie[] cookies, String key, String defaultValue) { if (cookies == null || cookies.length == 0) { - return StringUtils.EMPTY; + return defaultValue; } for (Cookie cookie : cookies) { if (StringUtils.equals(cookie.getName(), key)) { return cookie.getValue(); } } - return StringUtils.EMPTY; + return defaultValue; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java index b8b1a59ad..476aeeecf 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java @@ -129,29 +129,41 @@ public final class SpringWebExpressionLabelUtils { } public static String getHeaderValue(ServerHttpRequest request, String key) { + return getHeaderValue(request, key, StringUtils.EMPTY); + } + + public static String getHeaderValue(ServerHttpRequest request, String key, String defaultValue) { String value = request.getHeaders().getFirst(key); if (value == null) { - return StringUtils.EMPTY; + return defaultValue; } return value; } public static String getQueryValue(ServerHttpRequest request, String key) { + return getQueryValue(request, key, StringUtils.EMPTY); + } + + public static String getQueryValue(ServerHttpRequest request, String key, String defaultValue) { MultiValueMap queries = request.getQueryParams(); if (CollectionUtils.isEmpty(queries)) { - return StringUtils.EMPTY; + return defaultValue; } String value = queries.getFirst(key); if (value == null) { - return StringUtils.EMPTY; + return defaultValue; } return value; } public static String getCookieValue(ServerHttpRequest request, String key) { + return getCookieValue(request, key, StringUtils.EMPTY); + } + + public static String getCookieValue(ServerHttpRequest request, String key, String defaultValue) { HttpCookie cookie = request.getCookies().getFirst(key); if (cookie == null) { - return StringUtils.EMPTY; + return defaultValue; } return cookie.getValue(); } diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java index cc992ce19..c2cd05b8d 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java @@ -63,7 +63,7 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - MetadataContextHolder.init(customMetadata, new HashMap<>()); + MetadataContextHolder.init(customMetadata, new HashMap<>(), null); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getTransitiveMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java new file mode 100644 index 000000000..3d77d047c --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java @@ -0,0 +1,68 @@ +/* + * 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.common.util; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Utils for {@link UrlUtils}. + * + * @author Shedfree Wu + */ +public class UrlUtilsTest { + + @Test + public void testEncodeDecode1() { + String expectEncodeValue = "a%2Fb"; + String origin = "a/b"; + String encode1 = UrlUtils.encode(origin); + assertThat(expectEncodeValue).isEqualTo(encode1); + // encode twice is different + String encode2 = UrlUtils.encode(encode1); + assertThat(encode1).isNotEqualTo(encode2); + // test decode + assertThat(origin).isEqualTo(UrlUtils.decode(encode1)); + } + + @Test + public void testEncodeDecode2() { + + String origin = null; + String encode1 = UrlUtils.encode(origin); + assertThat(encode1).isNull(); + + origin = ""; + encode1 = UrlUtils.encode(origin); + assertThat(encode1).isEqualTo(origin); + } + + @Test + public void testError() { + String origin = "a/b"; + String encode = UrlUtils.encode(origin, "error-enc"); + assertThat(encode).isEqualTo(origin); + + encode = "a%2Fb"; + String decode = UrlUtils.decode(encode, "error-enc"); + assertThat(decode).isEqualTo(encode); + } + +} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 072255d85..ce586e97a 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -28,6 +28,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -80,6 +82,26 @@ public class QuickstartCalleeController { return String.format("Quickstart [%s] Service [%s:%s] is called. datasource = [%s].", appName, ip, port, dataSourceProperties); } + /** + * Mock post save value. + * @return true + */ + @PostMapping("/saveValue") + public Boolean saveValue(@RequestParam int value) { + LOG.info("Quickstart [{}] Service [{}:{}] is called. Mock save value = [{}].", appName, ip, port, value); + return true; + } + + /** + * Get path echo of callee. + * @return information of callee + */ + @GetMapping("/path/echo/{param}") + public String pathEcho(@PathVariable String param) { + LOG.info("Quickstart [{}] Service [{}:{}] is called. param = [{}].", appName, ip, port, param); + return String.format("Quickstart [%s] Service [%s:%s] is called. datasource = [%s].", appName, ip, port, param); + } + /** * Get metadata in HTTP header. * diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java index 07335adf5..d9b138343 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java @@ -76,8 +76,8 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { @Override public List getReachableServers() { - // Get servers first from the thread context - if (!CollectionUtils.isEmpty(THREAD_CACHE_SERVERS.get())) { + // Get servers first from the thread context. When routers filter all instances, getReachableServersWithoutCache function cannot be executed. + if (THREAD_CACHE_SERVERS.get() != null) { return THREAD_CACHE_SERVERS.get(); } return getReachableServersWithoutCache(); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java index f50e5df59..ec0e23970 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java @@ -67,6 +67,7 @@ public class EnhancedFeignClient implements Client { .url(url) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); DefaultServiceInstance serviceInstance = new DefaultServiceInstance(request.requestTemplate().feignTarget() diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java index 7eb14ae89..e9ef0cc67 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java @@ -36,6 +36,8 @@ public class EnhancedPluginContext { private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedPluginContext.class); + private Object originRequest; + private EnhancedRequestContext request; private EnhancedResponseContext response; @@ -51,6 +53,14 @@ public class EnhancedPluginContext { */ private ServiceInstance targetServiceInstance; + public Object getOriginRequest() { + return originRequest; + } + + public void setOriginRequest(Object originRequest) { + this.originRequest = originRequest; + } + public EnhancedRequestContext getRequest() { return request; } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java index 6677dac0a..eff88f13a 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java @@ -44,5 +44,19 @@ public class PluginOrderConstant { * {@link com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter}. */ public static final int CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 2; + + /** + * order for + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataZuulEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin}. + */ + public static final int CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java index c50cbb907..6241ac598 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java @@ -58,6 +58,7 @@ public class EnhancedRestTemplateInterceptor implements ClientHttpRequestInterce .url(request.getURI()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); enhancedPluginContext.setTargetServiceInstance((ServiceInstance) MetadataContextHolder.get() diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java index f42aff2bb..7b65f2e81 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java @@ -51,19 +51,21 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered { } @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + public Mono filter(ServerWebExchange originExchange, GatewayFilterChain chain) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() - .httpHeaders(exchange.getRequest().getHeaders()) - .httpMethod(exchange.getRequest().getMethod()) - .url(exchange.getRequest().getURI()) + .httpHeaders(originExchange.getRequest().getHeaders()) + .httpMethod(originExchange.getRequest().getMethod()) + .url(originExchange.getRequest().getURI()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(originExchange); // Run pre enhanced plugins. pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext); - + // Exchange may be changed in plugin + ServerWebExchange exchange = (ServerWebExchange) enhancedPluginContext.getOriginRequest(); long startTime = System.currentTimeMillis(); return chain.filter(exchange) .doOnSubscribe(v -> { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java index 673cac3da..a215cfe8a 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java @@ -46,23 +46,25 @@ public class EnhancedWebClientExchangeFilterFunction implements ExchangeFilterFu } @Override - public Mono filter(ClientRequest request, ExchangeFunction next) { + public Mono filter(ClientRequest originRequest, ExchangeFunction next) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() - .httpHeaders(request.headers()) - .httpMethod(request.method()) - .url(request.url()) + .httpHeaders(originRequest.headers()) + .httpMethod(originRequest.method()) + .url(originRequest.url()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(originRequest); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); enhancedPluginContext.setTargetServiceInstance((ServiceInstance) MetadataContextHolder.get() - .getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE), request.url()); + .getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE), originRequest.url()); // Run post enhanced plugins. pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext); - + // request may be changed by plugin + ClientRequest request = (ClientRequest) enhancedPluginContext.getOriginRequest(); long startTime = System.currentTimeMillis(); return next.exchange(request) .doOnSuccess(response -> { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java index 1254209c7..094f24f79 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java @@ -99,6 +99,7 @@ public class EnhancedPreZuulFilter extends ZuulFilter { .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(context); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); // Run pre enhanced plugins. From 27b96bb7bb1385c7687b57f0e5f7de901fe7f6b4 Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Thu, 28 Mar 2024 15:27:30 +0800 Subject: [PATCH 12/29] fix: router-lane rule support caller ip (#1253) --- CHANGELOG.md | 3 ++- .../config/MetadataTransferAutoConfiguration.java | 9 +++++---- .../core/DecodeTransferMetadataReactiveFilter.java | 9 ++++++++- .../core/DecodeTransferMetadataServletFilter.java | 9 ++++++++- .../metadata/provider/ReactiveMetadataProvider.java | 7 ++++++- .../metadata/provider/ServletMetadataProvider.java | 7 ++++++- .../config/MetadataTransferAutoConfigurationTest.java | 3 ++- .../core/DecodeTransferMetadataReactiveFilterTest.java | 3 ++- .../cloud/metadata/provider/MetadataProviderTest.java | 10 +++++++--- .../cloud/common/metadata/MetadataContextHolder.java | 9 ++++++--- 10 files changed, 52 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac7c92ba2..0526fb27e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,4 +4,5 @@ - [feat: support lossless register and deregister at #977](https://github.com/Tencent/spring-cloud-tencent/pull/1242) - [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) - [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) -- [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) \ No newline at end of file +- [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) +- [feat: lane router rule support caller ip](https://github.com/Tencent/spring-cloud-tencent/pull/1253) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index b9b440890..ea8a33189 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -26,6 +26,7 @@ import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedP import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulEnhancedPlugin; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -66,8 +67,8 @@ public class MetadataTransferAutoConfiguration { } @Bean - public DecodeTransferMetadataServletFilter metadataServletFilter() { - return new DecodeTransferMetadataServletFilter(); + public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextProperties polarisContextProperties) { + return new DecodeTransferMetadataServletFilter(polarisContextProperties); } } @@ -79,8 +80,8 @@ public class MetadataTransferAutoConfiguration { protected static class MetadataReactiveFilterConfig { @Bean - public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() { - return new DecodeTransferMetadataReactiveFilter(); + public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisContextProperties polarisContextProperties) { + return new DecodeTransferMetadataReactiveFilter(polarisContextProperties); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java index e4fd1a2cb..44a8e881b 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -27,6 +27,7 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; @@ -49,8 +50,14 @@ import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUST */ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered { + private PolarisContextProperties polarisContextProperties; + private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class); + public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) { + this.polarisContextProperties = polarisContextProperties; + } + @Override public int getOrder() { return OrderConstant.Server.Reactive.DECODE_TRANSFER_METADATA_FILTER_ORDER; @@ -68,7 +75,7 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered mergedTransitiveMetadata.putAll(customTransitiveMetadata); Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - ReactiveMetadataProvider metadataProvider = new ReactiveMetadataProvider(serverHttpRequest); + ReactiveMetadataProvider metadataProvider = new ReactiveMetadataProvider(serverHttpRequest, polarisContextProperties.getLocalIpAddress()); MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); // Save to ServerWebExchange. serverWebExchange.getAttributes().put( diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index d74ddcd71..44865dcd3 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -32,6 +32,7 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.metadata.provider.ServletMetadataProvider; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,6 +54,12 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); + private PolarisContextProperties polarisContextProperties; + + public DecodeTransferMetadataServletFilter(PolarisContextProperties polarisContextProperties) { + this.polarisContextProperties = polarisContextProperties; + } + @Override protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) @@ -65,7 +72,7 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { mergedTransitiveMetadata.putAll(customTransitiveMetadata); Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - ServletMetadataProvider metadataProvider = new ServletMetadataProvider(httpServletRequest); + ServletMetadataProvider metadataProvider = new ServletMetadataProvider(httpServletRequest, polarisContextProperties.getLocalIpAddress()); MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); TransHeadersTransfer.transfer(httpServletRequest); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java index 7eb2dc1c7..70aee3cf8 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java @@ -34,8 +34,11 @@ public class ReactiveMetadataProvider implements MetadataProvider { private ServerHttpRequest serverHttpRequest; - public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest) { + private String callerIp; + + public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest, String callerIp) { this.serverHttpRequest = serverHttpRequest; + this.callerIp = callerIp; } @Override @@ -45,6 +48,8 @@ public class ReactiveMetadataProvider implements MetadataProvider { return serverHttpRequest.getMethodValue(); case MessageMetadataContainer.LABEL_KEY_PATH: return UrlUtils.decode(serverHttpRequest.getPath().toString()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return callerIp; default: return null; } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java index f06df5e16..e34eccc3b 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java @@ -35,8 +35,11 @@ public class ServletMetadataProvider implements MetadataProvider { private HttpServletRequest httpServletRequest; - public ServletMetadataProvider(HttpServletRequest httpServletRequest) { + private String callerIp; + + public ServletMetadataProvider(HttpServletRequest httpServletRequest, String callerIp) { this.httpServletRequest = httpServletRequest; + this.callerIp = callerIp; } @Override @@ -46,6 +49,8 @@ public class ServletMetadataProvider implements MetadataProvider { return httpServletRequest.getMethod(); case MessageMetadataContainer.LABEL_KEY_PATH: return UrlUtils.decode(httpServletRequest.getRequestURI()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return callerIp; default: return null; } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java index c61111191..4da4dc8d3 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java @@ -21,6 +21,7 @@ package com.tencent.cloud.metadata.config; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -63,7 +64,7 @@ public class MetadataTransferAutoConfigurationTest { */ @Test public void test2() { - this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) + this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class, PolarisContextProperties.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java index bbee696c9..ff27c0c4d 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java @@ -20,6 +20,7 @@ package com.tencent.cloud.metadata.core; import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -54,7 +55,7 @@ public class DecodeTransferMetadataReactiveFilterTest { @BeforeEach public void setUp() { - this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(); + this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(new PolarisContextProperties()); } @Test diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java index ff7aedc5d..add6928d5 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java @@ -54,6 +54,7 @@ public class MetadataProviderTest { String cookieValue1 = "cv1"; String cookieValue2 = "cv2/test"; String path = "/echo/test"; + String callerIp = "localhost"; MockServerHttpRequest request = MockServerHttpRequest.get(path) .header(headerKey1, headerValue1) .header(headerKey2, UrlUtils.encode(headerValue2)) @@ -63,7 +64,7 @@ public class MetadataProviderTest { .cookie(new HttpCookie(cookieKey2, UrlUtils.encode(cookieValue2))) .build(); - ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request); + ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist @@ -80,10 +81,11 @@ public class MetadataProviderTest { assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); request = MockServerHttpRequest.get("/echo/" + UrlUtils.decode("a@b")).build(); - reactiveMetadataProvider = new ReactiveMetadataProvider(request); + reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp); assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); } @@ -102,6 +104,7 @@ public class MetadataProviderTest { String cookieValue1 = "cv1"; String cookieValue2 = "cv2/test"; String path = "/echo/test"; + String callerIp = "localhost"; MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader(headerKey1, headerValue1); request.addHeader(headerKey2, UrlUtils.encode(headerValue2)); @@ -110,7 +113,7 @@ public class MetadataProviderTest { request.setRequestURI(path); request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2)); - ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request); + ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request, callerIp); assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist @@ -127,6 +130,7 @@ public class MetadataProviderTest { assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp); assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); request.setRequestURI("/echo/" + UrlUtils.decode("a@b")); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index 37329ea6a..71e1b7754 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -47,12 +47,15 @@ public final class MetadataContextHolder { private static StaticMetadataManager staticMetadataManager; + static { + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.setInitializer(MetadataContextHolder::createMetadataManager); + } + private MetadataContextHolder() { } public static MetadataContext get() { - return (MetadataContext) com.tencent.polaris.metadata.core.manager.MetadataContextHolder.getOrCreate( - MetadataContextHolder::createMetadataManager); + return (MetadataContext) com.tencent.polaris.metadata.core.manager.MetadataContextHolder.getOrCreate(); } private static MetadataContext createMetadataManager() { @@ -135,7 +138,7 @@ public final class MetadataContextHolder { */ public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata, MetadataProvider callerMetadataProvider) { - com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(MetadataContextHolder::createMetadataManager, metadataManager -> { + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> { MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { for (Map.Entry entry : dynamicTransitiveMetadata.entrySet()) { From 64ac291f4b058d3a6d15968521f24ad7e89353d2 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 2 Apr 2024 14:39:42 +0800 Subject: [PATCH 13/29] feat:add polaris ThreadLocal plugin. (#1255) --- CHANGELOG.md | 3 +- pom.xml | 2 +- spring-cloud-tencent-commons/pom.xml | 5 ++ spring-cloud-tencent-coverage/pom.xml | 5 ++ spring-cloud-tencent-dependencies/pom.xml | 8 ++- spring-cloud-tencent-plugin-starters/pom.xml | 1 + .../pom.xml | 35 +++++++++++ .../threadlocal/TaskExecutorWrapper.java | 45 ++++++++++++++ .../threadlocal/TaskExecutorWrapperTest.java | 62 +++++++++++++++++++ 9 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0526fb27e..c1070584a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,4 +5,5 @@ - [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) - [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) - [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) -- [feat: lane router rule support caller ip](https://github.com/Tencent/spring-cloud-tencent/pull/1253) \ No newline at end of file +- [feat: lane router rule support caller ip](https://github.com/Tencent/spring-cloud-tencent/pull/1253) +- [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) \ No newline at end of file diff --git a/pom.xml b/pom.xml index 49e6e8c34..110bbbf43 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.14.0-Hoxton.SR12-RC1 + 1.14.0-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml index 970a5bf97..d2c5477a1 100644 --- a/spring-cloud-tencent-commons/pom.xml +++ b/spring-cloud-tencent-commons/pom.xml @@ -30,6 +30,11 @@ + + com.tencent.cloud + spring-cloud-starter-tencent-threadlocal-plugin + + org.springframework.boot spring-boot-autoconfigure diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 0cb2681a4..716f69b78 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -93,6 +93,11 @@ com.tencent.cloud spring-cloud-tencent-lossless-plugin + + + com.tencent.cloud + spring-cloud-starter-tencent-threadlocal-plugin + diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index eb47d2011..0a0926af7 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.14.0-Hoxton.SR12-RC1 + 1.14.0-Hoxton.SR12-SNAPSHOT 1.15.3-SNAPSHOT @@ -199,6 +199,12 @@ ${revision} + + com.tencent.cloud + spring-cloud-starter-tencent-threadlocal-plugin + ${revision} + + com.google.guava diff --git a/spring-cloud-tencent-plugin-starters/pom.xml b/spring-cloud-tencent-plugin-starters/pom.xml index 0258ceeea..5debf6360 100644 --- a/spring-cloud-tencent-plugin-starters/pom.xml +++ b/spring-cloud-tencent-plugin-starters/pom.xml @@ -19,6 +19,7 @@ spring-cloud-tencent-gateway-plugin spring-cloud-starter-tencent-discovery-adapter-plugin spring-cloud-tencent-lossless-plugin + spring-cloud-starter-tencent-threadlocal-plugin diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml new file mode 100644 index 000000000..91975c141 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml @@ -0,0 +1,35 @@ + + + + spring-cloud-tencent-plugin-starters + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + spring-cloud-starter-tencent-threadlocal-plugin + Spring Cloud Starter Tencent ThreadLocal plugin + + + + + com.tencent.polaris + polaris-threadlocal + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java new file mode 100644 index 000000000..f2f9dc1c4 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java @@ -0,0 +1,45 @@ +/* + * 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.threadlocal; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import com.tencent.polaris.threadlocal.cross.RunnableWrapper; + +import org.springframework.core.task.TaskExecutor; + +public class TaskExecutorWrapper implements TaskExecutor { + + private final TaskExecutor taskExecutor; + + private final Supplier contextGetter; + + private final Consumer contextSetter; + + public TaskExecutorWrapper(TaskExecutor taskExecutor, Supplier contextGetter, Consumer contextSetter) { + this.taskExecutor = taskExecutor; + this.contextGetter = contextGetter; + this.contextSetter = contextSetter; + } + + @Override + public void execute(Runnable command) { + taskExecutor.execute(new RunnableWrapper<>(command, contextGetter, contextSetter)); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java new file mode 100644 index 000000000..b56215f96 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java @@ -0,0 +1,62 @@ +/* + * 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.threadlocal; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Test; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; + +/** + * Test for {@link TaskExecutorWrapper}. + * + * @author Haotian Zhang + */ +public class TaskExecutorWrapperTest { + + private static final ThreadLocal TEST_THREAD_LOCAL = new ThreadLocal<>(); + + private static final String TEST = "TEST"; + + @Test + public void testExecute() { + TEST_THREAD_LOCAL.set(TEST); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.initialize(); + AtomicReference result = new AtomicReference<>(false); + CountDownLatch latch = new CountDownLatch(1); + TaskExecutorWrapper taskExecutorWrapper = new TaskExecutorWrapper<>( + executor, TEST_THREAD_LOCAL::get, TEST_THREAD_LOCAL::set); + taskExecutorWrapper.execute(() -> { + result.set(TEST.equals(TEST_THREAD_LOCAL.get())); + latch.countDown(); + }); + try { + latch.await(); + assertThat(result.get()).isTrue(); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + } +} From e3c825f02a52d2a74d4a1ca06cb52d6e40d84add Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 3 Apr 2024 09:14:12 +0800 Subject: [PATCH 14/29] release 1.14.0-Hoxton.SR12-RC2. --- pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 110bbbf43..ff792acb8 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.14.0-Hoxton.SR12-SNAPSHOT + 1.14.0-Hoxton.SR12-RC2 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 0a0926af7..157cc42fa 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,10 +70,10 @@ - 1.14.0-Hoxton.SR12-SNAPSHOT + 1.14.0-Hoxton.SR12-RC2 - 1.15.3-SNAPSHOT + 1.15.3 32.0.1-jre 1.2.13 3.0.0 From 96162d16911f35de83f0e80e856c59268bd74306 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 8 Apr 2024 19:05:49 +0800 Subject: [PATCH 15/29] feat:upgrade jackson version. (#1257) --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CHANGELOG.md | 3 +- pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 41 ++++++++++------------- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 236851ebe..f04cb49c3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -14,7 +14,7 @@ Other... Please describe: ## Adding the issue link (#xxx) if possible. ## Note diff --git a/CHANGELOG.md b/CHANGELOG.md index c1070584a..aa0568c38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,4 +6,5 @@ - [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) - [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) - [feat: lane router rule support caller ip](https://github.com/Tencent/spring-cloud-tencent/pull/1253) -- [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) \ No newline at end of file +- [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) +- [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257) diff --git a/pom.xml b/pom.xml index ff792acb8..110bbbf43 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.14.0-Hoxton.SR12-RC2 + 1.14.0-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 157cc42fa..1e5b3d619 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,10 +70,13 @@ - 1.14.0-Hoxton.SR12-RC2 + + 1.14.0-Hoxton.SR12-SNAPSHOT - + 1.15.3 + + 32.0.1-jre 1.2.13 3.0.0 @@ -94,13 +97,14 @@ - polaris-dependencies - com.tencent.polaris - ${polaris.version} + com.fasterxml.jackson + jackson-bom + ${jackson.version} pom import + com.tencent.cloud spring-cloud-tencent-commons @@ -131,7 +135,6 @@ ${revision} - com.tencent.cloud spring-cloud-starter-tencent-polaris-ratelimit @@ -238,24 +241,6 @@ ${logback.version} - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - io.springfox springfox-boot-starter @@ -307,6 +292,14 @@ test + + + polaris-dependencies + com.tencent.polaris + ${polaris.version} + pom + import + From f1fcc1991e73f3c462cd8f251ccd0b0cba2057ff Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Mon, 22 Apr 2024 16:24:01 +0800 Subject: [PATCH 16/29] fix:fix NullPointerException when properties contain kv with null value. --- changes/changes-1.13.0.md | 1 + .../config/listener/PolarisConfigListenerContext.java | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/changes/changes-1.13.0.md b/changes/changes-1.13.0.md index 168274ddc..29813ebfe 100644 --- a/changes/changes-1.13.0.md +++ b/changes/changes-1.13.0.md @@ -21,3 +21,4 @@ - [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) - fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. +- fix:fix NullPointerException when properties contain kv with null value. diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java index 0c2df3149..85bd2ab42 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java @@ -118,6 +118,11 @@ public final class PolarisConfigListenerContext { * @param ret origin properties map */ static void initialize(Map ret) { + for (Map.Entry entry : ret.entrySet()) { + if (entry.getValue() == null) { + ret.put(entry.getKey(), ""); + } + } properties.putAll(ret); } @@ -144,6 +149,9 @@ public final class PolarisConfigListenerContext { ret.keySet().parallelStream().forEach(key -> { Object oldValue = properties.getIfPresent(key); Object newValue = ret.get(key); + if (newValue == null) { + newValue = ""; + } if (oldValue != null) { if (!newValue.equals(oldValue)) { properties.put(key, newValue); From 7ad631d32d943122c8300f4345b2b4f61415369f Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Fri, 26 Apr 2024 12:48:06 +0800 Subject: [PATCH 17/29] fix:fix wrong report when using Zuul with instance not found exception. (#1283) --- CHANGELOG.md | 1 + .../reporter/SuccessPolarisReporter.java | 7 +++ .../zuul/EnhancedErrorZuulFilter.java | 57 +++++++++++++------ 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa0568c38..d0f43caaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,3 +8,4 @@ - [feat: lane router rule support caller ip](https://github.com/Tencent/spring-cloud-tencent/pull/1253) - [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) - [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257) +- [fix:fix wrong report when using Zuul with instance not found exception.](https://github.com/Tencent/spring-cloud-tencent/pull/1283) diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/reporter/SuccessPolarisReporter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/reporter/SuccessPolarisReporter.java index d4c7d6a1e..96d37fe13 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/reporter/SuccessPolarisReporter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/reporter/SuccessPolarisReporter.java @@ -71,6 +71,13 @@ public class SuccessPolarisReporter implements EnhancedPlugin { return; } + if (context.getThrowable() != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Success report with throwable. Don't report. {}", context, context.getThrowable()); + } + return; + } + EnhancedRequestContext request = context.getRequest(); EnhancedResponseContext response = context.getResponse(); ServiceInstance callerServiceInstance = Optional.ofNullable(context.getLocalServiceInstance()).orElse(new DefaultServiceInstance()); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedErrorZuulFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedErrorZuulFilter.java index ed981432f..d858261de 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedErrorZuulFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedErrorZuulFilter.java @@ -20,6 +20,7 @@ package com.tencent.cloud.rpc.enhancement.zuul; import java.util.ArrayList; import java.util.Collection; +import com.netflix.client.ClientException; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; @@ -30,6 +31,7 @@ import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; +import org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException; import org.springframework.core.env.Environment; import org.springframework.http.HttpHeaders; import org.springframework.util.StringUtils; @@ -86,26 +88,45 @@ public class EnhancedErrorZuulFilter extends ZuulFilter { Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME); Throwable throwable = context.getThrowable(); if (throwable != null && startTimeMilliObject != null && startTimeMilliObject instanceof Long) { - HttpHeaders responseHeaders = new HttpHeaders(); - Collection names = context.getResponse().getHeaderNames(); - for (String name : names) { - responseHeaders.put(name, new ArrayList<>(context.getResponse().getHeaders(name))); + if (checkNoInstanceException(throwable)) { + enhancedPluginContext.setThrowable(throwable); + } + else { + HttpHeaders responseHeaders = new HttpHeaders(); + Collection names = context.getResponse().getHeaderNames(); + for (String name : names) { + responseHeaders.put(name, new ArrayList<>(context.getResponse().getHeaders(name))); + } + EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder() + .httpStatus(context.getResponse().getStatus()) + .httpHeaders(responseHeaders) + .build(); + enhancedPluginContext.setResponse(enhancedResponseContext); + Long startTimeMilli = (Long) startTimeMilliObject; + enhancedPluginContext.setDelay(System.currentTimeMillis() - startTimeMilli); + enhancedPluginContext.setThrowable(throwable); + + // Run post enhanced plugins. + pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext); + + // Run finally enhanced plugins. + pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext); } - EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder() - .httpStatus(context.getResponse().getStatus()) - .httpHeaders(responseHeaders) - .build(); - enhancedPluginContext.setResponse(enhancedResponseContext); - Long startTimeMilli = (Long) startTimeMilliObject; - enhancedPluginContext.setDelay(System.currentTimeMillis() - startTimeMilli); - enhancedPluginContext.setThrowable(throwable); - - // Run post enhanced plugins. - pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext); - - // Run finally enhanced plugins. - pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext); } return null; } + + protected boolean checkNoInstanceException(Throwable throwable) { + if (throwable.getCause() instanceof ZuulRuntimeException) { + Throwable cause = null; + if (throwable.getCause().getCause() != null) { + cause = throwable.getCause().getCause().getCause(); + } + if (cause instanceof ClientException && StringUtils.hasText(cause.getMessage()) && + cause.getMessage().contains("Load balancer does not have available server for client")) { + return true; + } + } + return false; + } } From b6863b755d5e204eb3101e9244b629e4cd8f39d6 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Thu, 9 May 2024 18:11:36 +0800 Subject: [PATCH 18/29] feat: merge lane router and lossless features from 2023 (#1288) * feat: add lane router and lossless features from 2023 * Update CHANGELOG.md * fix: change application.yml to bootstrap.yml --- CHANGELOG.md | 1 + spring-cloud-tencent-dependencies/pom.xml | 2 +- .../lossless-callee-service/pom.xml | 63 ++++++++++ .../callee/LosslessCalleeController.java | 95 +++++++++++++++ .../callee/LosslessCalleeService.java | 29 +++++ .../src/main/resources/bootstrap.yml | 36 ++++++ .../lossless-nacos-callee-service/pom.xml | 69 +++++++++++ .../callee/LosslessNacosCalleeController.java | 95 +++++++++++++++ .../callee/LosslessNacosCalleeService.java | 23 ++-- .../src/main/resources/bootstrap.yml | 20 +++ .../lossless-example/pom.xml | 18 +++ .../pom.xml | 24 ++++ .../pom.xml | 70 +++++++++++ .../cloud/lane/callee/CustomMetadata.java | 47 ++++++++ .../callee/LaneRouterCalleeApplication.java | 29 +++++ .../callee/LaneRouterCalleeController.java | 91 ++++++++++++++ .../src/main/resources/bootstrap.yml | 36 ++++++ .../pom.xml | 75 ++++++++++++ .../cloud/lane/caller/CustomMetadata.java | 47 ++++++++ .../lane/caller/LaneRouterCalleeService.java | 41 +++++++ .../caller/LaneRouterCallerApplication.java | 57 +++++++++ .../caller/LaneRouterCallerController.java | 114 ++++++++++++++++++ .../src/main/resources/bootstrap.yml | 42 +++++++ .../router-grayrelease-lane-gateway/pom.xml | 48 ++++++++ .../gateway/LaneRouterGatewayApplication.java | 29 +++++ .../src/main/resources/bootstrap.yml | 39 ++++++ spring-cloud-tencent-examples/pom.xml | 2 + ...acosDiscoveryAdapterAutoConfiguration.java | 13 +- .../transformer/NacosInstanceTransformer.java | 27 +++-- .../NacosRegistrationTransformer.java | 49 ++++++++ ...DiscoveryAdapterAutoConfigurationTest.java | 2 + .../config/NacosInstanceTransformerTest.java | 21 ++-- .../pom.xml | 7 -- .../lossless/LosslessRegistryAspect.java | 20 +-- .../SpringCloudLosslessActionProvider.java | 19 +-- .../config/LosslessAutoConfiguration.java | 46 ++----- .../NacosDiscoveryNamespaceGetter.java | 47 -------- .../lossless/LosslessRegistryAspectTest.java | 53 -------- .../RpcEnhancementAutoConfiguration.java | 18 +++ .../transformer/InstanceTransformer.java | 53 ++++++++ .../PolarisInstanceTransformer.java | 44 +++++++ .../PolarisRegistrationTransformer.java | 15 ++- .../transformer/RegistrationTransformer.java | 58 +++++++++ 43 files changed, 1520 insertions(+), 214 deletions(-) create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java rename spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java => spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java (59%) create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/lossless-example/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java delete mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java rename spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java => spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java (78%) create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d0f43caaa..f925d3b3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,4 @@ - [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) - [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257) - [fix:fix wrong report when using Zuul with instance not found exception.](https://github.com/Tencent/spring-cloud-tencent/pull/1283) +- [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) \ No newline at end of file diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 1e5b3d619..a13e2f395 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -74,7 +74,7 @@ 1.14.0-Hoxton.SR12-SNAPSHOT - 1.15.3 + 1.15.5-SNAPSHOT 32.0.1-jre diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml new file mode 100644 index 000000000..367271702 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + + lossless-example + com.tencent.cloud + ${revision} + ../pom.xml + + lossless-callee-service + Spring Cloud Starter Tencent Lossless Callee Service Example + + + + com.tencent.cloud + spring-cloud-starter-tencent-all + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java new file mode 100644 index 000000000..ec7347c91 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java @@ -0,0 +1,95 @@ +/* + * 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.lossless.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +@RestController +@RequestMapping("/lossless/callee") +public class LosslessCalleeController { + + private static final Logger LOG = LoggerFactory.getLogger(LosslessCalleeController.class); + + @Value("${lossless.healthy.delay.second:0}") + private int healthyDelay; + + private final AtomicBoolean calledHealthyEndpoint = new AtomicBoolean(false); + + private final AtomicInteger healthy = new AtomicInteger(0); + + @GetMapping("/health") + public ResponseEntity health() { + if (healthy.get() == 1) { + return new ResponseEntity<>("OK", HttpStatus.OK); + } + else { + if (calledHealthyEndpoint.compareAndSet(false, true)) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + if (healthyDelay > 0) { + try { + Thread.sleep(healthyDelay * 1000L); + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + healthy.set(1); + } + }); + thread.start(); + } + return new ResponseEntity<>("NOK", HttpStatus.SERVICE_UNAVAILABLE); + } + } + + /** + * Get metadata in HTTP query. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, UTF_8)); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return metadataStr; + } + +} diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java new file mode 100644 index 000000000..542653ba0 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.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 com.tencent.cloud.lossless.callee; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LosslessCalleeService { + public static void main(String[] args) { + SpringApplication.run(LosslessCalleeService.class, args); + } +} diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..4e8c2a8ce --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml @@ -0,0 +1,36 @@ +server: + port: 48090 +spring: + application: + name: LosslessCalleeService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + contract: + exposure: true + report: + enabled: true + stat: + enabled: true + port: 28084 + lossless: + enabled: true + port: 28084 + #healthCheckPath: /actuator/health + #healthCheckInterval: 5000 +lossless: + healthy: + delay: + second: 20 +management: + endpoints: + web: + exposure: + include: + - polaris-discovery + - health \ No newline at end of file diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml new file mode 100644 index 000000000..72f7ed345 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + lossless-example + com.tencent.cloud + ${revision} + ../pom.xml + + com.tencent.polaris + lossless-nacos-callee-service + Spring Cloud Starter Tencent Lossless Nacos Callee Service Example + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + 2.2.10-RC2 + + + + com.tencent.cloud + spring-cloud-starter-tencent-discovery-adapter-plugin + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java new file mode 100644 index 000000000..ea96f64b3 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java @@ -0,0 +1,95 @@ +/* + * 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.lossless.nacos.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +@RestController +@RequestMapping("/lossless/nacos/callee") +public class LosslessNacosCalleeController { + + private static final Logger LOG = LoggerFactory.getLogger(LosslessNacosCalleeController.class); + + @Value("${lossless.healthy.delay.second:0}") + private int healthyDelay; + + private final AtomicBoolean calledHealthyEndpoint = new AtomicBoolean(false); + + private final AtomicInteger healthy = new AtomicInteger(0); + + @GetMapping("/health") + public ResponseEntity health() { + if (healthy.get() == 1) { + return new ResponseEntity<>("OK", HttpStatus.OK); + } + else { + if (calledHealthyEndpoint.compareAndSet(false, true)) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + if (healthyDelay > 0) { + try { + Thread.sleep(healthyDelay * 1000L); + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + healthy.set(1); + } + }); + thread.start(); + } + return new ResponseEntity<>("NOK", HttpStatus.SERVICE_UNAVAILABLE); + } + } + + /** + * Get metadata in HTTP query. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, UTF_8)); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return metadataStr; + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java similarity index 59% rename from spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java rename to spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java index 51126897b..a2d29436a 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/PolarisDiscoveryNamespaceGetter.java +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java @@ -13,26 +13,19 @@ * 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.transfomer; +package com.tencent.cloud.lossless.nacos.callee; -import com.tencent.cloud.polaris.PolarisDiscoveryProperties; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; -/** - * Discovery namespace getter for Polaris. - * - * @author Shedfree Wu - */ -public class PolarisDiscoveryNamespaceGetter implements DiscoveryNamespaceGetter { +@SpringBootApplication +public class LosslessNacosCalleeService { - private String namespace; - - public PolarisDiscoveryNamespaceGetter(PolarisDiscoveryProperties polarisDiscoveryProperties) { - this.namespace = polarisDiscoveryProperties.getNamespace(); + public static void main(String[] args) { + SpringApplication.run(LosslessNacosCalleeService.class, args); } - public String getNamespace() { - return namespace; - } } diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..a621c8c49 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml @@ -0,0 +1,20 @@ +server: + port: 48091 +spring: + application: + name: LosslessNacosCalleeService + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + enabled: true + polaris: + lossless: + enabled: true + port: 28085 + healthCheckPath: /actuator/health + healthCheckInterval: 5000 +lossless: + healthy: + delay: + second: 20 \ No newline at end of file diff --git a/spring-cloud-tencent-examples/lossless-example/pom.xml b/spring-cloud-tencent-examples/lossless-example/pom.xml new file mode 100644 index 000000000..02d46dabd --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/pom.xml @@ -0,0 +1,18 @@ + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + + lossless-callee-service + lossless-nacos-callee-service + + 4.0.0 + + lossless-example + pom + Spring Cloud Starter Tencent Lossless Example + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml new file mode 100644 index 000000000..6f602207d --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml @@ -0,0 +1,24 @@ + + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + + router-grayrelease-lane-gateway + router-grayrelease-lane-caller-service + router-grayrelease-lane-callee-service + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + + pom + Spring Cloud Tencent Polaris Router Lane Example + Example of Spring Cloud Tencent Polaris Router Lane + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml new file mode 100644 index 000000000..3431f03d0 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + ${revision} + ../pom.xml + + + route-grayrelease-lane-callee-service + + + + spring-cloud-starter-tencent-polaris-discovery + com.tencent.cloud + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java new file mode 100644 index 000000000..ba623274e --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java @@ -0,0 +1,47 @@ +/* + * 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.lane.callee; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.spi.InstanceMetadataProvider; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Custom metadata for instance. + * + * @author Haotian Zhang + */ +@Component +public class CustomMetadata implements InstanceMetadataProvider { + + @Value("${service.lane:base}") + private String lane; + + @Override + public Map getMetadata() { + Map metadata = new HashMap<>(); + if (!"base".equals(lane)) { + metadata.put("lane", lane); + } + return metadata; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java new file mode 100644 index 000000000..5ffabdd2c --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.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 com.tencent.cloud.lane.callee; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LaneRouterCalleeApplication { + + public static void main(String[] args) { + SpringApplication.run(LaneRouterCalleeApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java new file mode 100644 index 000000000..d10859db7 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java @@ -0,0 +1,91 @@ +/* + * 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.lane.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +@RestController +@RequestMapping("/lane/callee") +public class LaneRouterCalleeController { + + private static final Logger LOG = LoggerFactory.getLogger(LaneRouterCalleeController.class); + + @Value("${server.port:0}") + private int port; + + @Value("${spring.cloud.client.ip-address:127.0.0.1}") + private String ip; + + @Value("${appName:${spring.application.name}}") + private String appName; + + @Value("${service.lane:base}") + private String lane; + + /** + * Get sum of two value. + * @param value1 value 1 + * @param value2 value 2 + * @return sum + */ + @GetMapping("/sum") + public String sum(@RequestParam int value1, @RequestParam int value2) { + LOG.info("Lane [{}] Callee Service [{} - {}:{}] is called and sum is [{}].", lane, appName, ip, port, value1 + value2); + return String.format("Lane [%s] Callee Service [%s - %s:%s] is called and sum is [%s].", lane, appName, ip, port, value1 + value2); + } + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/info") + public String info() { + LOG.info("Lane [{}] Service [{} - {}:{}] is called.", lane, appName, ip, port); + return String.format("Lane [%s] Service [%s - %s:%s] is called.", lane, appName, ip, port); + } + + /** + * Get metadata in HTTP header. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, UTF_8)); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return String.format("Lane [%s]: %s", lane, metadataStr); + } + +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..29d9d9c96 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/bootstrap.yml @@ -0,0 +1,36 @@ +server: + port: 48093 +spring: + application: + name: LaneCalleeService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + contract: + exposure: true + report: + enabled: true + stat: + enabled: true + port: 28083 + # pushgateway: + # enabled: true + # address: 127.0.0.1:9091 + config: + address: grpc://9.134.5.52:8093 + auto-refresh: true + groups: + - name: ${spring.application.name} + files: [ "config/callee.properties" ] +management: + endpoints: + web: + exposure: + include: + - polaris-discovery + - polaris-config \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml new file mode 100644 index 000000000..f1a48d81b --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + ${revision} + ../pom.xml + + + route-grayrelease-lane-caller-service + + + + spring-cloud-starter-tencent-polaris-discovery + com.tencent.cloud + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java new file mode 100644 index 000000000..51939912e --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java @@ -0,0 +1,47 @@ +/* + * 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.lane.caller; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.spi.InstanceMetadataProvider; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * Custom metadata for instance. + * + * @author Haotian Zhang + */ +@Component +public class CustomMetadata implements InstanceMetadataProvider { + + @Value("${service.lane:base}") + private String lane; + + @Override + public Map getMetadata() { + Map metadata = new HashMap<>(); + if (!"base".equals(lane)) { + metadata.put("lane", lane); + } + return metadata; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java new file mode 100644 index 000000000..b057f4ffe --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java @@ -0,0 +1,41 @@ +/* + * 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.lane.caller; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Quickstart callee feign client. + * + * @author Haotian Zhang + */ +@FeignClient("LaneCalleeService") +public interface LaneRouterCalleeService { + + /** + * Get sum of two value. + * + * @param value1 value 1 + * @param value2 value 2 + * @return sum + */ + @GetMapping("/lane/callee/sum") + String sum(@RequestParam("value1") int value1, @RequestParam("value2") int value2); +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java new file mode 100644 index 000000000..6b387c7b1 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java @@ -0,0 +1,57 @@ +/* + * 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.lane.caller; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@SpringBootApplication +@EnableFeignClients +public class LaneRouterCallerApplication { + + public static void main(String[] args) { + SpringApplication.run(LaneRouterCallerApplication.class, args); + } + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Bean + @LoadBalanced + public RestTemplate defaultRestTemplate() { + DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService"); + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(uriBuilderFactory); + return restTemplate; + } + + @LoadBalanced + @Bean + WebClient.Builder webClientBuilder() { + return WebClient.builder().baseUrl("http://QuickstartCalleeService"); + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java new file mode 100644 index 000000000..90f990dbc --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java @@ -0,0 +1,114 @@ +/* + * 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.lane.caller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; + +@RestController +@RequestMapping("/lane/caller") +public class LaneRouterCallerController { + + private static final Logger LOG = LoggerFactory.getLogger(LaneRouterCallerController.class); + + @Value("${server.port:0}") + private int port; + + @Value("${spring.cloud.client.ip-address:127.0.0.1}") + private String ip; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private LaneRouterCalleeService quickstartCalleeService; + + @Autowired + private WebClient.Builder webClientBuilder; + + @Value("${service.lane:base}") + private String lane; + + @Value("${appName:${spring.application.name}}") + private String appName; + + /** + * Get sum of two value. + * @param value1 value 1 + * @param value2 value 2 + * @return sum + */ + @GetMapping("/feign") + public String feign(@RequestParam int value1, @RequestParam int value2) { + String value = quickstartCalleeService.sum(value1, value2); + return String.format("Lane [%s] Caller Service [%s - %s:%s] -> %s", lane, appName, ip, port, value); + } + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/rest") + public String rest() { + String value = restTemplate.getForObject("http://LaneCalleeService/lane/callee/info", String.class); + return String.format("Lane [%s] Caller Service [%s - %s:%s] -> %s", lane, appName, ip, port, value); + } + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/webclient") + public Mono webclient() { + return webClientBuilder + .build() + .get() + .uri("/quickstart/callee/echo") + .retrieve() + .bodyToMono(String.class); + } + + /** + * Get information of caller. + * @return information of caller + */ + @GetMapping("/info") + public String info() { + LOG.info("Lane {} Service [{} - {}:{}] is called.", lane, appName, ip, port); + return String.format("Lane [%s] Service [%s - %s:%s] is called.", lane, appName, ip, port); + } + + /** + * health check. + * @return health check info + */ + @GetMapping("/healthCheck") + public String healthCheck() { + return "ok"; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..259358d55 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/bootstrap.yml @@ -0,0 +1,42 @@ +server: + port: 48092 +spring: + application: + name: LaneCallerService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + heartbeat: + enabled: true + health-check-url: /lane/caller/healthCheck + contract: + exposure: true + report: + enabled: true + circuitbreaker: + enabled: true + stat: + enabled: true + port: 28082 + # pushgateway: + # enabled: true + # address: 127.0.0.1:9091 + tencent: + rpc-enhancement: + enabled: true + reporter: + enabled: true + ignore-internal-server-error: true + series: server_error + statuses: gateway_timeout, bad_gateway, service_unavailable +management: + endpoints: + web: + exposure: + include: + - polaris-discovery \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml new file mode 100644 index 000000000..efd0edff1 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + ${revision} + ../pom.xml + + + router-grayrelease-lane-gateway + + + + spring-cloud-starter-tencent-polaris-discovery + com.tencent.cloud + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java new file mode 100644 index 000000000..338dd7b01 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.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 com.tencent.cloud.polaris.router.lane.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LaneRouterGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(LaneRouterGatewayApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..1c02136d0 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,39 @@ +server: + port: 48090 +spring: + application: + name: LaneRouterGatewayService + config: + import: optional:polaris + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + contract: + exposure: true + report: + enabled: true + stat: + enabled: true + port: 28081 + gateway: + discovery: + locator: + enabled: true + 'predicates[0]': + name: Path + args: + patterns: '''/'' + serviceId + ''/**''' + 'filters[0]': + name: RewritePath + args: + regexp: '''/'' + serviceId + ''/(?.*)''' + replacement: '''/$\{remaining}''' + routes: + - id: LaneRouterCallerService + uri: lb://LaneCallerService + predicates: + - Path=/LaneCallerService/** + filters: + - StripPrefix=1 diff --git a/spring-cloud-tencent-examples/pom.xml b/spring-cloud-tencent-examples/pom.xml index c7e0c5a94..df75f878b 100644 --- a/spring-cloud-tencent-examples/pom.xml +++ b/spring-cloud-tencent-examples/pom.xml @@ -21,6 +21,8 @@ polaris-router-grayrelease-example polaris-router-featureenv-example quickstart-example + lossless-example + polaris-router-grayrelease-lane-example diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java index d1332926b..4f82638ad 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java @@ -19,8 +19,10 @@ package com.tencent.cloud.plugin.discovery.adapter.config; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; +import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosRegistrationTransformer; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerAutoConfiguration; -import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -41,9 +43,16 @@ public class NacosDiscoveryAdapterAutoConfiguration { @Bean @ConditionalOnMissingBean - @ConditionalOnClass(name = "com.alibaba.cloud.nacos.ribbon.NacosServer") + @ConditionalOnClass(name = "com.alibaba.cloud.nacos.NacosServiceInstance") public InstanceTransformer instanceTransformer() { return new NacosInstanceTransformer(); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(name = "com.alibaba.cloud.nacos.registry.NacosRegistration") + public RegistrationTransformer registrationTransformer() { + return new NacosRegistrationTransformer(); + } + } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java index db1047296..dbcc1c8bc 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java @@ -18,10 +18,11 @@ package com.tencent.cloud.plugin.discovery.adapter.transformer; -import com.alibaba.cloud.nacos.ribbon.NacosServer; -import com.netflix.loadbalancer.Server; -import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; import com.tencent.polaris.api.pojo.DefaultInstance; +import org.apache.commons.lang.StringUtils; + +import org.springframework.cloud.client.ServiceInstance; /** * NacosInstanceTransformer. @@ -31,12 +32,20 @@ import com.tencent.polaris.api.pojo.DefaultInstance; public class NacosInstanceTransformer implements InstanceTransformer { @Override - public void transformCustom(DefaultInstance instance, Server server) { - if ("com.alibaba.cloud.nacos.ribbon.NacosServer".equals(server.getClass().getName())) { - NacosServer nacosServer = (NacosServer) server; - instance.setWeight((int) (nacosServer.getInstance().getWeight() * 100)); - instance.setHealthy(nacosServer.getInstance().isHealthy()); - instance.setMetadata(nacosServer.getMetadata()); + public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) { + if ("com.alibaba.cloud.nacos.NacosServiceInstance".equals(serviceInstance.getClass().getName())) { + String nacosWeight = serviceInstance.getMetadata().get("nacos.weight"); + instance.setWeight( + StringUtils.isBlank(nacosWeight) ? 100 : (int) Double.parseDouble(nacosWeight) * 100 + ); + String nacosHealthy = serviceInstance.getMetadata().get("nacos.healthy"); + instance.setHealthy( + !StringUtils.isBlank(nacosHealthy) && Boolean.parseBoolean(nacosHealthy) + ); + String nacosInstanceId = serviceInstance.getMetadata().get("nacos.instanceId"); + instance.setId(nacosInstanceId); + } } + } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java new file mode 100644 index 000000000..d82558d27 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java @@ -0,0 +1,49 @@ +/* + * 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.discovery.adapter.transformer; + +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.cloud.nacos.registry.NacosRegistration; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.cloud.client.serviceregistry.Registration; + +public class NacosRegistrationTransformer implements RegistrationTransformer { + + @Override + public String getRegistry() { + return "nacos"; + } + + @Override + public void transformCustom(DefaultInstance instance, Registration registration) { + if (registration instanceof NacosRegistration) { + NacosRegistration nacosRegistration = (NacosRegistration) registration; + NacosDiscoveryProperties nacosDiscoveryProperties = nacosRegistration.getNacosDiscoveryProperties(); + String namespace = nacosDiscoveryProperties.getNamespace(); + if (StringUtils.isBlank(namespace)) { + namespace = "default"; + } + instance.setNamespace(namespace); + } + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfigurationTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfigurationTest.java index 8689cb2f0..b2338053e 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfigurationTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfigurationTest.java @@ -19,6 +19,7 @@ package com.tencent.cloud.plugin.discovery.adapter.config; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -44,6 +45,7 @@ public class NacosDiscoveryAdapterAutoConfigurationTest { public void testDefaultInitialization() { this.contextRunner.run(context -> { assertThat(context).hasSingleBean(NacosInstanceTransformer.class); + assertThat(context).doesNotHaveBean(PolarisInstanceTransformer.class); }); } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java index 00dd8be77..8320d6d90 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java @@ -18,10 +18,12 @@ package com.tencent.cloud.plugin.discovery.adapter.config; -import com.alibaba.cloud.nacos.ribbon.NacosServer; +import java.util.HashMap; + +import com.alibaba.cloud.nacos.NacosServiceInstance; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; -import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -51,14 +53,13 @@ public class NacosInstanceTransformerTest { @Test public void test() { NacosInstanceTransformer nacosInstanceTransformer = new NacosInstanceTransformer(); - - com.alibaba.nacos.api.naming.pojo.Instance nacosInstance = new com.alibaba.nacos.api.naming.pojo.Instance(); - nacosInstance.setHealthy(true); - NacosServer nacosServer = new NacosServer(nacosInstance); - - - DefaultInstance instance = new DefaultInstance(); - nacosInstanceTransformer.transformCustom(instance, nacosServer); + NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); + nacosServiceInstance.setMetadata(new HashMap() {{ + put("nacos.weight", "0.01"); + put("nacos.healthy", "true"); + put("nacos.instanceId", "xxx"); + }}); + Instance instance = nacosInstanceTransformer.transform(nacosServiceInstance); assertThat(instance.isHealthy()).isEqualTo(true); } 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 index c1a4712a5..59a313be9 100644 --- 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 @@ -58,13 +58,6 @@ true - - com.alibaba.cloud - spring-cloud-starter-alibaba-nacos-discovery - 2.2.9.RELEASE - true - - com.tencent.polaris polaris-test-mock-discovery 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 index e0126d458..c9af94576 100644 --- 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 @@ -18,8 +18,9 @@ package com.tencent.cloud.plugin.lossless; import com.tencent.cloud.plugin.lossless.config.LosslessProperties; -import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import com.tencent.polaris.api.pojo.BaseInstance; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -37,7 +38,7 @@ import org.springframework.cloud.client.serviceregistry.ServiceRegistry; @Aspect public class LosslessRegistryAspect { - private ServiceRegistry serviceRegistry; + private ServiceRegistry serviceRegistry; private Registration registration; @@ -45,16 +46,19 @@ public class LosslessRegistryAspect { private PolarisSDKContextManager polarisSDKContextManager; - private DiscoveryNamespaceGetter discoveryNamespaceGetter; + private RegistrationTransformer registrationTransformer; - public LosslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager, - DiscoveryNamespaceGetter discoveryNamespaceGetter) { + private PolarisContextProperties properties; + + public LosslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, + PolarisContextProperties properties, LosslessProperties losslessProperties, + PolarisSDKContextManager polarisSDKContextManager, RegistrationTransformer registrationTransformer) { this.serviceRegistry = serviceRegistry; this.registration = registration; this.losslessProperties = losslessProperties; this.polarisSDKContextManager = polarisSDKContextManager; - this.discoveryNamespaceGetter = discoveryNamespaceGetter; + this.registrationTransformer = registrationTransformer; + this.properties = properties; } @Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(..))") @@ -71,7 +75,7 @@ public class LosslessRegistryAspect { public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { // web started, get port from registration - BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, discoveryNamespaceGetter); + BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, registrationTransformer); Runnable registerAction = () -> executeJoinPoint(joinPoint); 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 index 511721a5f..a97df5960 100644 --- 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 @@ -22,11 +22,10 @@ import java.util.Map; import com.tencent.cloud.common.util.OkHttpUtil; import com.tencent.cloud.plugin.lossless.config.LosslessProperties; -import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; 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; @@ -89,20 +88,8 @@ public class SpringCloudLosslessActionProvider implements LosslessActionProvider losslessProperties.getHealthCheckPath(), headers); } - public static BaseInstance getBaseInstance(Registration registration, DiscoveryNamespaceGetter namespaceGetter) { - return getBaseInstance(registration, registration.getPort(), namespaceGetter); + public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { + return registrationTransformer.transform(registration); } - public static BaseInstance getBaseInstance(Registration registration, Integer port, - DiscoveryNamespaceGetter namespaceGetter) { - DefaultBaseInstance baseInstance = new DefaultBaseInstance(); - if (namespaceGetter != null) { - baseInstance.setNamespace(namespaceGetter.getNamespace()); - } - 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 index 5bab83f9f..8b2cffe49 100644 --- 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 @@ -18,20 +18,12 @@ package com.tencent.cloud.plugin.lossless.config; -import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; -import com.alibaba.cloud.nacos.NacosDiscoveryProperties; import com.tencent.cloud.plugin.lossless.LosslessRegistryAspect; -import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter; -import com.tencent.cloud.plugin.lossless.transfomer.NacosDiscoveryNamespaceGetter; -import com.tencent.cloud.plugin.lossless.transfomer.PolarisDiscoveryNamespaceGetter; -import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.polaris.discovery.ConditionalOnPolarisDiscoveryEnabled; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; @@ -51,34 +43,12 @@ public class LosslessAutoConfiguration { @Bean @ConditionalOnMissingBean - public LosslessRegistryAspect losslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager, - @Autowired(required = false) DiscoveryNamespaceGetter discoveryNamespaceGetter) { - return new LosslessRegistryAspect(serviceRegistry, registration, losslessProperties, polarisSDKContextManager, discoveryNamespaceGetter); + public LosslessRegistryAspect losslessRegistryAspect( + ServiceRegistry serviceRegistry, Registration registration, PolarisContextProperties properties, + LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager, + RegistrationTransformer registrationTransformer) { + return new LosslessRegistryAspect(serviceRegistry, registration, properties, losslessProperties, + polarisSDKContextManager, registrationTransformer); } - @ConditionalOnClass(name = "com.alibaba.cloud.nacos.NacosDiscoveryProperties") - static class Nacos { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnNacosDiscoveryEnabled - @ConditionalOnBean(NacosDiscoveryProperties.class) - public NacosDiscoveryNamespaceGetter nacosDiscoveryNamespaceGetter( - NacosDiscoveryProperties nacosDiscoveryProperties) { - return new NacosDiscoveryNamespaceGetter(nacosDiscoveryProperties); - } - } - - @ConditionalOnClass(name = "com.tencent.cloud.polaris.PolarisDiscoveryProperties") - static class Polaris { - @Bean - @ConditionalOnMissingBean - @ConditionalOnPolarisDiscoveryEnabled - @ConditionalOnBean(PolarisDiscoveryProperties.class) - public PolarisDiscoveryNamespaceGetter polarisDiscoveryNamespaceGetter( - PolarisDiscoveryProperties polarisDiscoveryProperties) { - return new PolarisDiscoveryNamespaceGetter(polarisDiscoveryProperties); - } - } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java deleted file mode 100644 index 6d0b605c2..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/NacosDiscoveryNamespaceGetter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.transfomer; - -import java.lang.reflect.Method; -import java.util.Properties; - -import com.alibaba.cloud.nacos.NacosDiscoveryProperties; -import com.alibaba.nacos.client.naming.utils.InitUtils; - -import org.springframework.util.ReflectionUtils; - -/** - * Discovery namespace getter for Nacos. - * - * @author Shedfree Wu - */ -public class NacosDiscoveryNamespaceGetter implements DiscoveryNamespaceGetter { - private String namespace; - - public NacosDiscoveryNamespaceGetter(NacosDiscoveryProperties nacosDiscoveryProperties) { - // getNacosProperties is private in low version of spring-cloud-starter-alibaba-nacos-discovery - Method method = ReflectionUtils.findMethod(NacosDiscoveryProperties.class, "getNacosProperties"); - method.setAccessible(true); - this.namespace = InitUtils.initNamespaceForNaming( - (Properties) ReflectionUtils.invokeMethod(method, nacosDiscoveryProperties)); - } - - public String getNamespace() { - return namespace; - } -} 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 index db43f84a7..45f656529 100644 --- 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 @@ -19,22 +19,15 @@ package com.tencent.cloud.plugin.lossless; import java.util.Collections; -import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration; -import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration; -import com.alibaba.cloud.nacos.registry.NacosRegistration; -import com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration; -import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration; 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.plugin.lossless.transfomer.DiscoveryNamespaceGetter; 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.BaseInstance; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.test.mock.discovery.NamingServer; import org.junit.jupiter.api.AfterAll; @@ -46,10 +39,7 @@ 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.AutoServiceRegistrationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationUtils; -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.commons.util.UtilAutoConfiguration; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; @@ -72,8 +62,6 @@ public class LosslessRegistryAspectTest { private static int LOSSLESS_PORT_1 = 28083; - private static int NACOS_LOSSLESS_PORT = 28093; - private static NamingServer namingServer; private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() @@ -116,31 +104,6 @@ public class LosslessRegistryAspectTest { .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); - private final WebApplicationContextRunner nacosContextRunner = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - AutoServiceRegistrationProperties.class, - UtilAutoConfiguration.class, - UtilIPv6AutoConfiguration.class, - NacosDiscoveryAutoConfiguration.class, - NacosServiceAutoConfiguration.class, - NacosServiceRegistryAutoConfiguration.class, - LosslessAutoConfiguration.class, - LosslessPropertiesBootstrapConfiguration.class, - PolarisContextAutoConfiguration.class) - ) - .withPropertyValues("spring.cloud.nacos.discovery.enabled=true") - .withPropertyValues("spring.cloud.nacos.discovery.namespace=" + NAMESPACE_TEST) - .withPropertyValues("spring.cloud.polaris.discovery.enabled=false") - .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") - .withPropertyValues("spring.cloud.polaris.lossless.port=" + NACOS_LOSSLESS_PORT) - .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.token=xxxxxx"); - @BeforeAll static void beforeAll() throws Exception { namingServer = NamingServer.startNamingServer(10081); @@ -220,22 +183,6 @@ public class LosslessRegistryAspectTest { }); } - @Test - public void testNaocsRegister() { - this.nacosContextRunner.run(context -> { - - DiscoveryNamespaceGetter discoveryNamespaceGetter = context.getBean(DiscoveryNamespaceGetter.class); - Registration registration = context.getBean(Registration.class); - - assertThat(registration instanceof NacosRegistration).isTrue(); - assertThat(discoveryNamespaceGetter.getNamespace()).isEqualTo(NAMESPACE_TEST); - - BaseInstance baseInstance = SpringCloudLosslessActionProvider.getBaseInstance(registration, discoveryNamespaceGetter); - assertThat(baseInstance.getNamespace()).isEqualTo(NAMESPACE_TEST); - }); - } - - @Configuration @EnableAutoConfiguration static class PolarisPropertiesConfiguration { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java index 102f931c6..ea0825a44 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java @@ -35,6 +35,10 @@ import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter; import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer; import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter; +import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisRegistrationTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import com.tencent.cloud.rpc.enhancement.webclient.EnhancedWebClientExchangeFilterFunction; import com.tencent.cloud.rpc.enhancement.webclient.PolarisLoadBalancerClientRequestTransformer; import com.tencent.cloud.rpc.enhancement.webclient.RibbonLoadBalancerClientAspect; @@ -84,6 +88,20 @@ import static javax.servlet.DispatcherType.REQUEST; @AutoConfigureAfter(PolarisContextAutoConfiguration.class) public class RpcEnhancementAutoConfiguration { + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(name = "com.tencent.cloud.common.pojo.PolarisServiceInstance") + public InstanceTransformer instanceTransformer() { + return new PolarisInstanceTransformer(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(name = "com.tencent.cloud.polaris.registry.PolarisRegistration") + public RegistrationTransformer registrationTransformer() { + return new PolarisRegistrationTransformer(); + } + @Bean @Lazy public EnhancedPluginRunner enhancedFeignPluginRunner( diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java new file mode 100644 index 000000000..13c19dfb0 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java @@ -0,0 +1,53 @@ +/* + * 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.rpc.enhancement.transformer; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; + +import org.springframework.cloud.client.ServiceInstance; + +/** + * InstanceTransformer. + * + * @author sean yu + */ +public interface InstanceTransformer { + + default Instance transform(ServiceInstance serviceInstance) { + DefaultInstance instance = new DefaultInstance(); + transformDefault(instance, serviceInstance); + transformCustom(instance, serviceInstance); + return instance; + } + + default void transformDefault(DefaultInstance instance, ServiceInstance serviceInstance) { + instance.setNamespace(MetadataContext.LOCAL_NAMESPACE); + instance.setService(serviceInstance.getServiceId()); + instance.setProtocol(serviceInstance.getScheme()); + instance.setId(serviceInstance.getInstanceId()); + instance.setHost(serviceInstance.getHost()); + instance.setPort(serviceInstance.getPort()); + instance.setMetadata(serviceInstance.getMetadata()); + } + + void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance); + +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java new file mode 100644 index 000000000..a44ef3a56 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java @@ -0,0 +1,44 @@ +/* + * 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.rpc.enhancement.transformer; + +import com.tencent.cloud.common.pojo.PolarisServiceInstance; +import com.tencent.polaris.api.pojo.DefaultInstance; + +import org.springframework.cloud.client.ServiceInstance; + +/** + * PolarisInstanceTransformer. + * + * @author sean yu + */ +public class PolarisInstanceTransformer implements InstanceTransformer { + + @Override + public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) { + if (serviceInstance instanceof PolarisServiceInstance) { + PolarisServiceInstance polarisServiceInstance = (PolarisServiceInstance) serviceInstance; + instance.setRegion(polarisServiceInstance.getPolarisInstance().getRegion()); + instance.setZone(polarisServiceInstance.getPolarisInstance().getZone()); + instance.setCampus(polarisServiceInstance.getPolarisInstance().getCampus()); + instance.setWeight(polarisServiceInstance.getPolarisInstance().getWeight()); + } + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java similarity index 78% rename from spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java index d23a67d0b..20df4f183 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/transfomer/DiscoveryNamespaceGetter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java @@ -13,16 +13,15 @@ * 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.transfomer; +package com.tencent.cloud.rpc.enhancement.transformer; -/** - * Interface for discovery namespace getter. - * - * @author Shedfree Wu - */ -public interface DiscoveryNamespaceGetter { +public class PolarisRegistrationTransformer implements RegistrationTransformer { - String getNamespace(); + @Override + public String getRegistry() { + return "polaris"; + } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java new file mode 100644 index 000000000..7996ebd78 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java @@ -0,0 +1,58 @@ +/* + * 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.rpc.enhancement.transformer; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; + +import org.springframework.cloud.client.serviceregistry.Registration; + + +/** + * RegistrationTransformer extensions to adapt 3rd registration to polaris instance. + * + * @author andrew shan + */ +public interface RegistrationTransformer { + + String getRegistry(); + + default Instance transform(Registration registration) { + DefaultInstance instance = new DefaultInstance(); + transformDefault(instance, registration); + transformCustom(instance, registration); + return instance; + } + + default void transformDefault(DefaultInstance instance, Registration registration) { + instance.setRegistry(getRegistry()); + instance.setNamespace(MetadataContext.LOCAL_NAMESPACE); + instance.setService(registration.getServiceId()); + instance.setProtocol(registration.getScheme()); + instance.setId(registration.getInstanceId()); + instance.setHost(registration.getHost()); + instance.setPort(registration.getPort()); + instance.setMetadata(registration.getMetadata()); + } + + default void transformCustom(DefaultInstance instance, Registration registration) { + + } +} From ca0b8ba98285ad7a9564052d4f0c93ee43dbfa43 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Fri, 10 May 2024 14:32:21 +0800 Subject: [PATCH 19/29] fix: fix npe when add circuitbreak module without feign.hystrix.enable=true (#1292) --- CHANGELOG.md | 3 +- ...sFeignCircuitBreakerInvocationHandler.java | 59 ++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f925d3b3f..48d92ae6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,4 +9,5 @@ - [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) - [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257) - [fix:fix wrong report when using Zuul with instance not found exception.](https://github.com/Tencent/spring-cloud-tencent/pull/1283) -- [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) \ No newline at end of file +- [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) +- [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java index b8419a29c..0379c9977 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java @@ -113,36 +113,41 @@ public class PolarisFeignCircuitBreakerInvocationHandler implements InvocationHa else if ("toString".equals(method.getName())) { return toString(); } - - String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method); - CircuitBreaker circuitBreaker = factory.create(circuitName); Supplier supplier = asSupplier(method, args); - Function fallbackFunction; - if (this.nullableFallbackFactory != null) { - fallbackFunction = throwable -> { - Object fallback = this.nullableFallbackFactory.create(throwable); - try { - return this.fallbackMethodMap.get(method).invoke(fallback, args); - } - catch (Exception exception) { - unwrapAndRethrow(exception); - } - return null; - }; + if (circuitBreakerNameResolver != null) { + String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method); + CircuitBreaker circuitBreaker = factory.create(circuitName); + + Function fallbackFunction; + if (this.nullableFallbackFactory != null) { + fallbackFunction = throwable -> { + Object fallback = this.nullableFallbackFactory.create(throwable); + try { + return this.fallbackMethodMap.get(method).invoke(fallback, args); + } + catch (Exception exception) { + unwrapAndRethrow(exception); + } + return null; + }; + } + else { + fallbackFunction = throwable -> { + PolarisCircuitBreakerFallbackFactory.DefaultFallback fallback = + (PolarisCircuitBreakerFallbackFactory.DefaultFallback) new PolarisCircuitBreakerFallbackFactory(this.decoder).create(throwable); + return fallback.fallback(method); + }; + } + try { + return circuitBreaker.run(supplier, fallbackFunction); + } + catch (FallbackWrapperException e) { + // unwrap And Rethrow + throw e.getCause(); + } } else { - fallbackFunction = throwable -> { - PolarisCircuitBreakerFallbackFactory.DefaultFallback fallback = - (PolarisCircuitBreakerFallbackFactory.DefaultFallback) new PolarisCircuitBreakerFallbackFactory(this.decoder).create(throwable); - return fallback.fallback(method); - }; - } - try { - return circuitBreaker.run(supplier, fallbackFunction); - } - catch (FallbackWrapperException e) { - // unwrap And Rethrow - throw e.getCause(); + return supplier.get(); } } From 8309602d969fa315ccc58763eab5e427f57c894b Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Wed, 15 May 2024 14:52:40 +0800 Subject: [PATCH 20/29] fix:add warn log to ApplicationContextAwareUtils. (#1295) --- CHANGELOG.md | 3 ++- .../util/ApplicationContextAwareUtils.java | 26 +++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48d92ae6d..dc4dbb81d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,4 +10,5 @@ - [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257) - [fix:fix wrong report when using Zuul with instance not found exception.](https://github.com/Tencent/spring-cloud-tencent/pull/1283) - [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) -- [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) \ No newline at end of file +- [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) +- [fix:fix ApplicationContextAwareUtils NPE bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1295) diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java index 98a6a4341..60421b02c 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java @@ -17,6 +17,10 @@ package com.tencent.cloud.common.util; +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -29,6 +33,8 @@ import org.springframework.lang.NonNull; */ public class ApplicationContextAwareUtils implements ApplicationContextAware { + private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationContextAwareUtils.class); + private static ApplicationContext applicationContext; /** @@ -50,7 +56,15 @@ public class ApplicationContextAwareUtils implements ApplicationContextAware { * @return property value */ public static String getProperties(String key) { - return applicationContext.getEnvironment().getProperty(key); + if (applicationContext != null) { + return applicationContext.getEnvironment().getProperty(key); + } + LOGGER.warn("applicationContext is null, try to get property from System.getenv or System.getProperty"); + String property = System.getenv(key); + if (StringUtils.isBlank(property)) { + property = System.getProperty(key); + } + return property; } /** @@ -60,6 +74,14 @@ public class ApplicationContextAwareUtils implements ApplicationContextAware { * @return property value */ public static String getProperties(String key, String defaultValue) { - return applicationContext.getEnvironment().getProperty(key, defaultValue); + if (applicationContext != null) { + return applicationContext.getEnvironment().getProperty(key, defaultValue); + } + LOGGER.warn("applicationContext is null, try to get property from System.getenv or System.getProperty"); + String property = System.getenv(key); + if (StringUtils.isBlank(property)) { + property = System.getProperty(key, defaultValue); + } + return property; } } From 556635386af580e902e699bd6c4a56254c8ebc4c Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Wed, 15 May 2024 16:36:51 +0800 Subject: [PATCH 21/29] feat: support spring.cloud.polaris.router.nearby-router.matchLevel to config nearyby level (#1298) --- .../polaris/router/RouterConfigModifier.java | 60 +++++++++++++++++ .../RouterBootstrapAutoConfiguration.java | 36 ++++++++++ ...RouterConfigModifierAutoConfiguration.java | 47 +++++++++++++ .../PolarisNearByRouterProperties.java | 11 +++ ...itional-spring-configuration-metadata.json | 6 ++ .../main/resources/META-INF/spring.factories | 2 + .../RouterBootstrapAutoConfigurationTest.java | 67 +++++++++++++++++++ .../PolarisNearByRouterPropertiesTest.java | 2 +- 8 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java new file mode 100644 index 000000000..4d30dab48 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java @@ -0,0 +1,60 @@ +/* + * 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.polaris.router; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; +import com.tencent.polaris.api.plugin.route.LocationLevel; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.router.nearby.NearbyRouterConfig; +import org.apache.commons.lang.StringUtils; + +/** + * RouterConfigModifier. + * + * @author sean yu + */ +public class RouterConfigModifier implements PolarisConfigModifier { + + private final PolarisNearByRouterProperties polarisNearByRouterProperties; + + public RouterConfigModifier(PolarisNearByRouterProperties polarisNearByRouterProperties) { + this.polarisNearByRouterProperties = polarisNearByRouterProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + if (StringUtils.isNotBlank(polarisNearByRouterProperties.getMatchLevel())) { + LocationLevel locationLevel = LocationLevel.valueOf(polarisNearByRouterProperties.getMatchLevel()); + NearbyRouterConfig nearbyRouterConfig = configuration.getConsumer().getServiceRouter().getPluginConfig( + ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, NearbyRouterConfig.class); + nearbyRouterConfig.setMatchLevel(locationLevel); + configuration.getConsumer().getServiceRouter() + .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, nearbyRouterConfig); + } + + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.ROUTER_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfiguration.java new file mode 100644 index 000000000..2d02b2a28 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfiguration.java @@ -0,0 +1,36 @@ +/* + * 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.polaris.router.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * RouterBootstrapAutoConfiguration. + * + * @author sean yu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(RouterConfigModifierAutoConfiguration.class) +public class RouterBootstrapAutoConfiguration { + + +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java new file mode 100644 index 000000000..e1de4a37f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java @@ -0,0 +1,47 @@ +/* + * 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.polaris.router.config; + +import com.tencent.cloud.polaris.router.RouterConfigModifier; +import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * RouterConfigModifierAutoConfiguration. + * + * @author sean yu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisRouterEnabled +@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class}) +public class RouterConfigModifierAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public RouterConfigModifier routerConfigModifier(PolarisNearByRouterProperties polarisNearByRouterProperties) { + return new RouterConfigModifier(polarisNearByRouterProperties); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java index 3cd69ca12..1c6a76a60 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java @@ -30,6 +30,8 @@ public class PolarisNearByRouterProperties { private boolean enabled = true; + private String matchLevel; + public boolean isEnabled() { return enabled; } @@ -38,10 +40,19 @@ public class PolarisNearByRouterProperties { this.enabled = enabled; } + public String getMatchLevel() { + return matchLevel; + } + + public void setMatchLevel(String matchLevel) { + this.matchLevel = matchLevel; + } + @Override public String toString() { return "PolarisNearByRouterProperties{" + "enabled=" + enabled + + ", matchLevel='" + matchLevel + '\'' + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 0c935af6e..631bd8e42 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -12,6 +12,12 @@ "defaultValue": true, "description": "the switch for near by router." }, + { + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", + "type": "java.lang.String", + "defaultValue": "zone", + "description": "the match level for nearby router, options can be region/zone/campus." + }, { "name": "spring.cloud.polaris.router.rule-router.enabled", "type": "java.lang.Boolean", diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories index 75f7939ca..db8b9bec4 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories @@ -2,3 +2,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.router.config.RouterAutoConfiguration,\ com.tencent.cloud.polaris.router.config.FeignAutoConfiguration,\ com.tencent.cloud.polaris.router.endpoint.PolarisRouterEndpointAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.polaris.router.config.RouterBootstrapAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java new file mode 100644 index 000000000..f10d9ada4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java @@ -0,0 +1,67 @@ +/* + * 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.polaris.router.config; + +import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.polaris.router.RouterConfigModifier; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import com.tencent.polaris.api.config.Configuration; +import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; +import com.tencent.polaris.factory.ConfigAPIFactory; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.router.nearby.NearbyRouterConfig; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * RouterBootstrapAutoConfigurationTest. + * + * @author sean yu + */ +public class RouterBootstrapAutoConfigurationTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PolarisContextAutoConfiguration.class, + PolarisNearByRouterProperties.class, + RpcEnhancementAutoConfiguration.class, + RouterBootstrapAutoConfiguration.class)) + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.router.nearby-router.matchLevel=campus") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + + @Test + public void testDefaultInitialization() { + this.contextRunner.run(context -> { + assertThat(context).hasSingleBean(RouterConfigModifier.class); + RouterConfigModifier routerConfigModifier = (RouterConfigModifier) context.getBean("routerConfigModifier"); + Configuration configuration = ConfigAPIFactory.defaultConfig(); + routerConfigModifier.modify((ConfigurationImpl) configuration); + NearbyRouterConfig nearbyRouterConfig = configuration.getConsumer().getServiceRouter().getPluginConfig( + ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, NearbyRouterConfig.class); + Assertions.assertEquals("campus", nearbyRouterConfig.getMatchLevel().name()); + }); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java index 572b6f92b..379fbf7e9 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java @@ -49,6 +49,6 @@ public class PolarisNearByRouterPropertiesTest { @Test public void testToString() { assertThat(properties.toString()) - .isEqualTo("PolarisNearByRouterProperties{enabled=true}"); + .isEqualTo("PolarisNearByRouterProperties{enabled=true, matchLevel='null'}"); } } From e1849e27abbc75b40a377bbda7058749a7de0e82 Mon Sep 17 00:00:00 2001 From: fredrikliu <139424001+fredrikliu@users.noreply.github.com> Date: Thu, 16 May 2024 16:31:42 +0800 Subject: [PATCH 22/29] fix:fix the ratelimit bug for hoxton (#1301) * add getActiveRuleName * add change log --------- Co-authored-by: fredrikliu --- CHANGELOG.md | 1 + .../polaris/ratelimit/filter/QuotaCheckReactiveFilter.java | 4 ++-- .../polaris/ratelimit/filter/QuotaCheckServletFilter.java | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc4dbb81d..f0e57d5b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,3 +12,4 @@ - [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) - [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) - [fix:fix ApplicationContextAwareUtils NPE bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1295) +- [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java index f7ce8d21b..f6bf04706 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java @@ -128,12 +128,12 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( - quotaResponse.getActiveRule().getName().getValue(), UTF_8); + quotaResponse.getActiveRuleName(), UTF_8); response.getHeaders().add(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName); } catch (UnsupportedEncodingException e) { LOG.error("Cannot encode {} for header internal-callee-activerule.", - quotaResponse.getActiveRule().getName().getValue(), e); + quotaResponse.getActiveRuleName(), e); } } return response.writeWith(Mono.just(dataBuffer)); diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java index 2f4a56eac..7266e5b54 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java @@ -121,12 +121,12 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( - quotaResponse.getActiveRule().getName().getValue(), UTF_8); + quotaResponse.getActiveRuleName(), UTF_8); response.addHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName); } catch (UnsupportedEncodingException e) { LOG.error("Cannot encode {} for header internal-callee-activerule.", - quotaResponse.getActiveRule().getName().getValue(), e); + quotaResponse.getActiveRuleName(), e); } } return; From 179435805b2769f9d7cc9a600f5bdc90239b4375 Mon Sep 17 00:00:00 2001 From: fredrikliu <139424001+fredrikliu@users.noreply.github.com> Date: Mon, 20 May 2024 15:48:47 +0800 Subject: [PATCH 23/29] release 1.14.0-Hoxton.SR12-RC3 (#1302) Co-authored-by: fredrikliu --- pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 110bbbf43..17c5d73d7 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.14.0-Hoxton.SR12-SNAPSHOT + 1.14.0-Hoxton.SR12-RC3 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index a13e2f395..59894bc37 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -71,10 +71,10 @@ - 1.14.0-Hoxton.SR12-SNAPSHOT + 1.14.0-Hoxton.SR12-RC3 - 1.15.5-SNAPSHOT + 1.15.5 32.0.1-jre From 3962cafecbacc3c18cb547f386e6e4f51decbb82 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Tue, 4 Jun 2024 17:48:13 +0800 Subject: [PATCH 24/29] feat:upgrade jacoco version. (#1306) --- CHANGELOG.md | 3 ++- pom.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e57d5b8..e7fcdabb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,4 +12,5 @@ - [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) - [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) - [fix:fix ApplicationContextAwareUtils NPE bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1295) -- [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) \ No newline at end of file +- [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) +- [feat:upgrade jacoco version.](https://github.com/Tencent/spring-cloud-tencent/pull/1306) \ No newline at end of file diff --git a/pom.xml b/pom.xml index 17c5d73d7..f7ee98e32 100644 --- a/pom.xml +++ b/pom.xml @@ -102,7 +102,7 @@ Hoxton.SR12 - 0.8.8 + 0.8.12 3.2.0 1.2.7 3.0.1 From f354fcf3fb9bdb1f7592951bf93c326f7c162a20 Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Thu, 6 Jun 2024 12:00:31 +0800 Subject: [PATCH 25/29] fix:fix no registry when lossless is disabled. (#1313) --- CHANGELOG.md | 3 ++- .../tencent/cloud/plugin/lossless/LosslessRegistryAspect.java | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7fcdabb2..64b3ad9f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,4 +13,5 @@ - [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) - [fix:fix ApplicationContextAwareUtils NPE bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1295) - [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) -- [feat:upgrade jacoco version.](https://github.com/Tencent/spring-cloud-tencent/pull/1306) \ No newline at end of file +- [feat:upgrade jacoco version.](https://github.com/Tencent/spring-cloud-tencent/pull/1306) +- [fix:fix no registry when lossless is disabled.](https://github.com/Tencent/spring-cloud-tencent/pull/1313) 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 index c9af94576..9dab0f243 100644 --- 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 @@ -73,6 +73,9 @@ public class LosslessRegistryAspect { @Around("registerPointcut()") public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { + if (!losslessProperties.isEnabled()) { + return joinPoint.proceed(); + } // web started, get port from registration BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, registrationTransformer); From 8454f736d8cde71430bdb1b6b951845b4124d3d2 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:13:46 +0800 Subject: [PATCH 26/29] fix: memory not released while using wildcard api call with circuitbreaker enabled (#1335) --- CHANGELOG.md | 1 + spring-cloud-tencent-dependencies/pom.xml | 2 +- .../callee/QuickstartCalleeController.java | 11 +++ .../callee/QuickstartCalleeController.java | 21 +++++ .../CircuitBreakerController.java | 19 +++++ ...CircuitBreakerQuickstartCalleeService.java | 9 +++ ...reakerQuickstartCalleeServiceFallback.java | 5 ++ ...erQuickstartCalleeServiceWithFallback.java | 9 +++ .../lossless/LosslessRegistryAspectTest.java | 2 +- spring-cloud-tencent-polaris-context/pom.xml | 78 +++++++++++++++++++ 10 files changed, 155 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64b3ad9f6..b3e204968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,3 +15,4 @@ - [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) - [feat:upgrade jacoco version.](https://github.com/Tencent/spring-cloud-tencent/pull/1306) - [fix:fix no registry when lossless is disabled.](https://github.com/Tencent/spring-cloud-tencent/pull/1313) +- [fix: memory not released while using wildcard api call with circuitbreaker enabled](https://github.com/Tencent/spring-cloud-tencent/pull/1335) \ No newline at end of file diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 59894bc37..23180a90d 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -74,7 +74,7 @@ 1.14.0-Hoxton.SR12-RC3 - 1.15.5 + 2.0.0.0-SNAPSHOT 32.0.1-jre diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index ce586e97a..a792d5a14 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -128,6 +128,17 @@ public class QuickstartCalleeController { return String.format("Quickstart Callee Service [%s:%s] is called right.", ip, port); } + /** + * Check circuit break. + * + * @return circuit break info + */ + @GetMapping("/circuitBreak/wildcard/{uid}") + public String circuitBreakWildcard(@PathVariable String uid) throws InterruptedException { + LOG.info("Quickstart Callee Service uid {} [{}:{}] is called right.", uid, ip, port); + return String.format("Quickstart Callee Service %s [%s:%s] is called right.", uid, ip, port); + } + @GetMapping("/faultDetect") public String health() { LOG.info("Quickstart Callee Service [{}:{}] is detected right.", ip, port); diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index d4de94f3d..9f923950a 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -119,6 +120,26 @@ public class QuickstartCalleeController { return new ResponseEntity<>(String.format("Quickstart Callee Service [%s:%s] is called right.", ip, port), HttpStatus.OK); } + /** + * Check circuit break. + * + * @return circuit break info + */ + @GetMapping("/circuitBreak/wildcard/{uid}") + public ResponseEntity circuitBreakWildcard(@PathVariable String uid) throws InterruptedException { + if (ifBadGateway) { + LOG.info("Quickstart Callee Service with uid {} [{}:{}] is called wrong.", uid, ip, port); + return new ResponseEntity<>("failed for call quickstart callee service wildcard.", HttpStatus.BAD_GATEWAY); + } + if (ifDelay) { + Thread.sleep(200); + LOG.info("Quickstart Callee Service uid {} [{}:{}] is called slow.", uid, ip, port); + return new ResponseEntity<>(String.format("Quickstart Callee Service [%s:%s] is called slow.", ip, port), HttpStatus.OK); + } + LOG.info("Quickstart Callee Service uid {} [{}:{}] is called right.", uid, ip, port); + return new ResponseEntity<>(String.format("Quickstart Callee Service %s [%s:%s] is called right.", uid, ip, port), HttpStatus.OK); + } + @GetMapping("/setBadGateway") public String setBadGateway(@RequestParam boolean param) { this.ifBadGateway = param; diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java index 4d902aaa2..5b348144b 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java @@ -25,6 +25,7 @@ import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @@ -84,6 +85,24 @@ public class CircuitBreakerController { return circuitBreakerQuickstartCalleeServiceWithFallback.circuitBreak(); } + /** + * Feign circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/feign/fallbackFromPolaris/wildcard/{uid}") + public String circuitBreakFeignFallbackFromPolarisWildcard(@PathVariable String uid) { + return circuitBreakerQuickstartCalleeService.circuitBreakWildcard(uid); + } + + /** + * Feign circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/feign/fallbackFromCode/wildcard/{uid}") + public String circuitBreakFeignFallbackFromCodeWildcard(@PathVariable String uid) { + return circuitBreakerQuickstartCalleeServiceWithFallback.circuitBreakWildcard(uid); + } + /** * RestTemplate circuit breaker. * @return circuit breaker information of callee diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java index 64821b9a9..b96052840 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java @@ -19,6 +19,7 @@ package com.tencent.cloud.quickstart.caller.circuitbreaker; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; /** * Circuit breaker example callee provider. @@ -35,4 +36,12 @@ public interface CircuitBreakerQuickstartCalleeService { */ @GetMapping("/quickstart/callee/circuitBreak") String circuitBreak(); + + /** + * Check circuit break with uid. + * @param uid uid variable + * @return circuit break info + */ + @GetMapping("/quickstart/callee/circuitBreak/wildcard/{uid}") + String circuitBreakWildcard(@PathVariable String uid); } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java index 06a2df366..dbc2b9af8 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java @@ -31,4 +31,9 @@ public class CircuitBreakerQuickstartCalleeServiceFallback implements CircuitBre public String circuitBreak() { return "fallback: trigger the refuse for service callee."; } + + @Override + public String circuitBreakWildcard(String uid) { + return String.format("fallback: trigger the refuse for service callee %s.", uid); + } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java index f71a7650e..fe4a9daf8 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java @@ -19,6 +19,7 @@ package com.tencent.cloud.quickstart.caller.circuitbreaker; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; /** * CircuitBreakerQuickstartCalleeServiceWithFallback. @@ -35,4 +36,12 @@ public interface CircuitBreakerQuickstartCalleeServiceWithFallback { */ @GetMapping("/quickstart/callee/circuitBreak") String circuitBreak(); + + /** + * Check circuit break with uid. + * @param uid uid variable + * @return circuit break info + */ + @GetMapping("/circuitBreak/wildcard/{uid}") + String circuitBreakWildcard(@PathVariable String uid); } 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 index 45f656529..687041540 100644 --- 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 @@ -139,7 +139,7 @@ public class LosslessRegistryAspectTest { assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isFalse(); }).doesNotThrowAnyException(); // delay register after 5s - Thread.sleep(5000); + Thread.sleep(10000); PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); PolarisRegistration registration = context.getBean(PolarisRegistration.class); diff --git a/spring-cloud-tencent-polaris-context/pom.xml b/spring-cloud-tencent-polaris-context/pom.xml index f525ce672..972fe0046 100644 --- a/spring-cloud-tencent-polaris-context/pom.xml +++ b/spring-cloud-tencent-polaris-context/pom.xml @@ -49,6 +49,84 @@ + + com.tencent.polaris + polaris-circuitbreaker-factory + + + com.tencent.polaris + router-rule + + + com.tencent.polaris + router-nearby + + + com.tencent.polaris + router-metadata + + + com.tencent.polaris + circuitbreaker-errrate + + + com.tencent.polaris + circuitbreaker-errcount + + + com.tencent.polaris + circuitbreaker-composite + + + com.tencent.polaris + stat-prometheus + + + com.tencent.polaris + healthchecker-http + + + com.tencent.polaris + healthchecker-tcp + + + com.tencent.polaris + healthchecker-udp + + + + + + com.tencent.polaris + polaris-ratelimit-factory + + + com.tencent.polaris + router-rule + + + com.tencent.polaris + router-nearby + + + com.tencent.polaris + router-metadata + + + com.tencent.polaris + ratelimiter-reject + + + com.tencent.polaris + ratelimiter-unirate + + + com.tencent.polaris + stat-prometheus + + + + com.tencent.polaris polaris-client From a0400ff69fee93f947343029d85e8150550a6086 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Mon, 29 Jul 2024 11:23:05 +0800 Subject: [PATCH 27/29] docs:update codecov.yml. --- .github/workflows/codecov.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 343fa995e..018fce86a 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -33,6 +33,8 @@ jobs: - name: Test with Maven run: mvn clean test -B -U -Psonatype - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: files: ${{ github.workspace }}/target/site/jacoco/jacoco.xml From 873b12ee228a9abcd1f6d142269bc3ef17dc478b Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:11:23 +0800 Subject: [PATCH 28/29] fix: fix npe when feign.hystrix.enabled=false (#1436) --- ...ignIntegrationDisableFeignHystrixTest.java | 56 +++++++++++++++++++ ...risCircuitBreakerFeignIntegrationTest.java | 3 + 2 files changed, 59 insertions(+) create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java new file mode 100644 index 000000000..689eed2e4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java @@ -0,0 +1,56 @@ +/* + * 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.polaris.circuitbreaker.feign; + + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Shedfree Wu + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class, + properties = { + "feign.hystrix.enabled=false", + "spring.cloud.gateway.enabled=false", + "feign.circuitbreaker.enabled=true", + "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, + "spring.cloud.polaris.service=test" + }) +public class PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest { + + @Autowired + private PolarisCircuitBreakerFeignIntegrationTest.EchoService echoService; + + @Test + public void testFeignClient() { + assertThatThrownBy(() -> { + echoService.echo("test"); + }).isInstanceOf(RuntimeException.class).hasMessageContaining("Load balancer does not have available server for client"); + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index a37ccd786..c3bf5e418 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -51,6 +51,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.Customizer; @@ -79,6 +80,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @SpringBootTest(webEnvironment = RANDOM_PORT, classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class, properties = { + "feign.hystrix.enabled=true", "spring.cloud.gateway.enabled=false", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, @@ -244,6 +246,7 @@ public class PolarisCircuitBreakerFeignIntegrationTest { @Bean @Primary @ConditionalOnBean(CircuitBreakerFactory.class) + @ConditionalOnProperty(value = "feign.hystrix.enabled", havingValue = "true") public PolarisFeignCircuitBreakerTargeter polarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { return new PolarisFeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerNameResolver); } From eab382b3710db7f12b76fc31234132afccf175bf Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 30 Oct 2024 15:02:11 +0800 Subject: [PATCH 29/29] refactor:update GitHub Action dependencies. --- .github/workflows/codecov.yml | 4 ++-- .github/workflows/junit_test.yml | 6 +++--- .github/workflows/license-checker.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/snapshot.yml | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 018fce86a..f97516343 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -24,9 +24,9 @@ jobs: steps: - name: Checkout codes - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: 17 diff --git a/.github/workflows/junit_test.yml b/.github/workflows/junit_test.yml index c26f1d8be..0ecdb273b 100644 --- a/.github/workflows/junit_test.yml +++ b/.github/workflows/junit_test.yml @@ -28,14 +28,14 @@ jobs: steps: - name: Checkout codes - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/license-checker.yml b/.github/workflows/license-checker.yml index 9d01eb4a8..77a3333bc 100644 --- a/.github/workflows/license-checker.yml +++ b/.github/workflows/license-checker.yml @@ -22,6 +22,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout codes - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check License Header uses: apache/skywalking-eyes@v0.4.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 49f492d07..602c60148 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,9 +8,9 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 622c086a9..3a9d462a9 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -17,7 +17,7 @@ jobs: IS_SNAPSHOT: ${{ steps.set_output_1.outputs.IS_SNAPSHOT }} steps: - name: Checkout codes - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check deploy type id: set_output_1 run: | @@ -34,9 +34,9 @@ jobs: if: ${{ needs.check-snapshot.outputs.IS_SNAPSHOT == 'true' }} steps: - name: Checkout codes - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin'