From 8f907d81dff2f265351bb7c2de09575c928e87ba Mon Sep 17 00:00:00 2001 From: lepdou Date: Tue, 26 Apr 2022 22:22:02 +0800 Subject: [PATCH 01/25] polaris-ratelimit-factory include router-metadata for distribute rate limit --- spring-cloud-starter-tencent-polaris-ratelimit/pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml index a313fb962..fe07a8d90 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml +++ b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml @@ -34,10 +34,6 @@ com.tencent.polaris router-nearby - - com.tencent.polaris - router-metadata - com.tencent.polaris router-canary From 43f9ebc4c370645a66351984528cd0f483f2e0ac Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Tue, 26 Apr 2022 23:43:46 +0800 Subject: [PATCH 02/25] release:release 1.4.0-Hoxton.SR9. --- CHANGELOG.md | 1 + pom.xml | 2 +- .../config/MetadataTransferAutoConfigurationTest.java | 2 +- .../intercepter/EncodeTransferMedataFeignInterceptorTest.java | 2 +- .../EncodeTransferMedataRestTemplateInterceptorTest.java | 2 +- .../polaris/circuitbreaker/feign/TestPolarisFeignApp.java | 2 ++ .../java/com/tencent/cloud/polaris/PolarisPropertiesTest.java | 2 +- .../discovery/PolarisDiscoveryAutoConfigurationTest.java | 2 +- .../discovery/PolarisDiscoveryClientConfigurationTest.java | 2 +- .../cloud/polaris/discovery/PolarisDiscoveryClientTest.java | 2 +- .../cloud/polaris/discovery/PolarisServiceDiscoveryTest.java | 2 +- .../PolarisReactiveDiscoveryClientConfigurationTest.java | 2 +- .../reactive/PolarisReactiveDiscoveryClientTest.java | 2 +- .../registry/PolarisServiceRegistryAutoConfigurationTest.java | 2 +- .../cloud/polaris/registry/PolarisServiceRegistryTest.java | 2 +- .../ribbon/PolarisRibbonServerListConfigurationTest.java | 2 +- .../tencent/cloud/polaris/ribbon/PolarisServerListTest.java | 2 +- .../cloud/common/metadata/MetadataContextHolderTest.java | 2 +- .../common/metadata/config/MetadataAutoConfigurationTest.java | 2 +- .../common/metadata/config/MetadataLocalPropertiesTest.java | 2 +- spring-cloud-tencent-dependencies/pom.xml | 4 ++-- .../gateway/example/callee/GatewayCalleeController.java | 4 ++++ .../config/PolarisLoadBalancerAutoConfigurationTest.java | 2 +- src/checkstyle/checkstyle-suppressions.xml | 1 + 24 files changed, 29 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f979111..2784188a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,4 @@ - [Feature: Optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/130) - [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/131) - [feat:refactor loadbalancer module as a basic module for router and circuit breaker.](https://github.com/Tencent/spring-cloud-tencent/pull/136) +- [feat:enable distribute rate limit](https://github.com/Tencent/spring-cloud-tencent/pull/139) \ No newline at end of file diff --git a/pom.xml b/pom.xml index e3346026b..8d2fffd2e 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.0-Hoxton.SR9-SNAPSHOT + 1.4.0-Hoxton.SR9 Hoxton.SR9 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 a3d924158..87968b8b3 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 @@ -29,7 +29,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.gateway.filter.GlobalFilter; /** - * Test for {@link MetadataTransferAutoConfiguration} + * Test for {@link MetadataTransferAutoConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java index 21426f565..cecb5ddbe 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java @@ -46,7 +46,7 @@ import org.springframework.web.bind.annotation.RestController; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; /** - * Test for {@link EncodeTransferMedataFeignInterceptor} + * Test for {@link EncodeTransferMedataFeignInterceptor}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java index 6a7f98b25..6877842ac 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -47,7 +47,7 @@ import org.springframework.web.client.RestTemplate; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataRestTemplateInterceptor} + * Test for {@link EncodeTransferMedataRestTemplateInterceptor}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/TestPolarisFeignApp.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/TestPolarisFeignApp.java index b593392d5..b6dfb10b2 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/TestPolarisFeignApp.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/TestPolarisFeignApp.java @@ -43,6 +43,8 @@ public class TestPolarisFeignApp { /** * Get info of service B. + * + * @return info */ @GetMapping("/example/service/b/info") String info(); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisPropertiesTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisPropertiesTest.java index 518797e2c..a1259704a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisPropertiesTest.java @@ -26,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; /** - * Test for {@link PolarisDiscoveryProperties} + * Test for {@link PolarisDiscoveryProperties}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java index fc6ed91fe..cdad58bc0 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java @@ -38,7 +38,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisDiscoveryAutoConfiguration} + * Test for {@link PolarisDiscoveryAutoConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientConfigurationTest.java index 7a9b78943..022377238 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientConfigurationTest.java @@ -34,7 +34,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisDiscoveryClientConfiguration} + * Test for {@link PolarisDiscoveryClientConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java index baad9d365..e72393161 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java @@ -37,7 +37,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** - * Test for {@link PolarisDiscoveryClient} + * Test for {@link PolarisDiscoveryClient}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscoveryTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscoveryTest.java index 56ff83db7..874d577b1 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscoveryTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscoveryTest.java @@ -41,7 +41,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisServiceDiscovery} + * Test for {@link PolarisServiceDiscovery}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java index 0bbcc6548..527b07e22 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java @@ -35,7 +35,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisReactiveDiscoveryClientConfiguration} + * Test for {@link PolarisReactiveDiscoveryClientConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java index 99aa8f1df..300a94cd9 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java @@ -37,7 +37,7 @@ import static java.util.Collections.singletonList; import static org.mockito.Mockito.when; /** - * Test for {@link PolarisReactiveDiscoveryClient} + * Test for {@link PolarisReactiveDiscoveryClient}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfigurationTest.java index e1645d80c..ede3f0387 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfigurationTest.java @@ -37,7 +37,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisServiceRegistryAutoConfiguration} + * Test for {@link PolarisServiceRegistryAutoConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java index 4371e32ac..f37ed344c 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java @@ -41,7 +41,7 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.when; /** - * Test for {@link PolarisServiceRegistry} + * Test for {@link PolarisServiceRegistry}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisRibbonServerListConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisRibbonServerListConfigurationTest.java index d429da7b4..ae3a1eb79 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisRibbonServerListConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisRibbonServerListConfigurationTest.java @@ -39,7 +39,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisRibbonServerListConfiguration} + * Test for {@link PolarisRibbonServerListConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisServerListTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisServerListTest.java index 9cd01db87..a036ed344 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisServerListTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/ribbon/PolarisServerListTest.java @@ -46,7 +46,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** - * Test for {@link PolarisServerList} + * Test for {@link PolarisServerList}. * * @author Haotian Zhang */ 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 6883ae50d..29d280044 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 @@ -29,7 +29,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** - * Test for {@link MetadataContextHolder} + * Test for {@link MetadataContextHolder}. * * @author Haotian Zhang */ diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java index bcf42ee14..76be75bd4 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java @@ -30,7 +30,7 @@ import org.springframework.boot.test.context.runner.ReactiveWebApplicationContex import org.springframework.boot.test.context.runner.WebApplicationContextRunner; /** - * Test for {@link MetadataAutoConfiguration} + * Test for {@link MetadataAutoConfiguration}. * * @author Haotian Zhang */ diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java index 44128591c..815010ce1 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java @@ -27,7 +27,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; /** - * Test for {@link MetadataLocalProperties} + * Test for {@link MetadataLocalProperties}. * * @author Haotian Zhang */ diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index f9da2e8e0..7d3dd55fd 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,8 +70,8 @@ - 1.4.0-Hoxton.SR9-SNAPSHOT - 1.5.0-SNAPSHOT + 1.4.0-Hoxton.SR9 + 1.5.0 2.0.0 diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java index 77f84f518..40ddeb240 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java @@ -55,6 +55,10 @@ public class GatewayCalleeController { /** * Get metadata in HTTP header. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception */ @RequestMapping("/echo") public String echoHeader( diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfigurationTest.java b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfigurationTest.java index 3e87d5fdd..1c89de2d6 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfigurationTest.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfigurationTest.java @@ -31,7 +31,7 @@ import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisLoadBalancerAutoConfiguration} + * Test for {@link PolarisLoadBalancerAutoConfiguration}. * * @author Haotian Zhang */ diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 5993108df..68f366fb0 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -4,4 +4,5 @@ "https://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> + \ No newline at end of file From 4ec4bca3eceff761607d7dc6f63247c34c858308 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Wed, 27 Apr 2022 00:08:10 +0800 Subject: [PATCH 03/25] feat:use 1.5.1 version of polaris-java. --- 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 8d2fffd2e..d82f65301 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.0-Hoxton.SR9 + 1.4.1-Hoxton.SR9-SNAPSHOT Hoxton.SR9 diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 7d3dd55fd..5fbe01acb 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,8 +70,8 @@ - 1.4.0-Hoxton.SR9 - 1.5.0 + 1.4.1-Hoxton.SR9-SNAPSHOT + 1.5.1 2.0.0 From 4077df90db58e9f1d86ba69dcf85c876b0bd0d9e Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Wed, 27 Apr 2022 10:48:45 +0800 Subject: [PATCH 04/25] release:release 1.4.1-Hoxton.SR9. --- pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d82f65301..6feeda61c 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.1-Hoxton.SR9-SNAPSHOT + 1.4.1-Hoxton.SR9 Hoxton.SR9 diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 5fbe01acb..8e32288d0 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.1-Hoxton.SR9-SNAPSHOT + 1.4.1-Hoxton.SR9 1.5.1 2.0.0 From 0a35bb6aceefd0c9549d636c77927bd65a93ac83 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Sat, 7 May 2022 17:15:06 +0800 Subject: [PATCH 05/25] Update README-zh.md --- README-zh.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-zh.md b/README-zh.md index ff760c7d5..77e2cc475 100644 --- a/README-zh.md +++ b/README-zh.md @@ -12,7 +12,7 @@ ## 介绍 -Spring Cloud Tencent 是腾讯开发和维护的一站式微服务解决方案。 +Spring Cloud Tencent 是腾讯开源的一站式微服务解决方案。 Spring Cloud Tencent 实现了Spring Cloud 标准微服务 SPI,开发者可以基于 Spring Cloud Tencent 快速开发 Spring Cloud 云原生分布式应用。 From 3a4d0bf038e3721554fbdb95fea87ef671110b5c Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Sat, 7 May 2022 17:15:38 +0800 Subject: [PATCH 06/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7b735c3a..9fee461ed 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ English | [简体中文](./README-zh.md) ## Introduction -Spring Cloud Tencent is a one-stop microservice solution developed and maintained by Tencent. +Spring Cloud Tencent is a open source one-stop microservice solution from Tencent. Spring Cloud Tencent implements the Spring Cloud standard microservice SPI, so developers can quickly develop Spring Cloud cloud-native distributed applications based on Spring Cloud Tencent. From e15efda9f4c4264a1c58e86c3f0ea58f84bc69e2 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Wed, 11 May 2022 11:53:54 +0800 Subject: [PATCH 07/25] fix:fix routes of gateway doesn't refresh bug. --- pom.xml | 2 +- .../polaris/DiscoveryConfigModifier.java | 9 +++ .../polaris/PolarisDiscoveryProperties.java | 13 ++++ .../discovery/PolarisDiscoveryHandler.java | 8 +++ .../PolarisServiceChangeListener.java | 62 +++++++++++++++++++ .../registry/PolarisServiceRegistry.java | 10 ++- ...larisServiceRegistryAutoConfiguration.java | 13 ++-- ...itional-spring-configuration-metadata.json | 6 ++ spring-cloud-tencent-dependencies/pom.xml | 2 +- .../src/main/resources/bootstrap.yml | 49 ++++++++++++--- src/checkstyle/checkstyle-suppressions.xml | 1 + 11 files changed, 160 insertions(+), 15 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java diff --git a/pom.xml b/pom.xml index 6feeda61c..1bd9b8b05 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.1-Hoxton.SR9 + 1.4.2-Hoxton.SR9-SNAPSHOT Hoxton.SR9 diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java index a52a6dd4b..67690ef24 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java @@ -24,6 +24,8 @@ import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; +import org.springframework.beans.factory.annotation.Autowired; + /** * Spring Cloud Tencent config Override polaris config. * @@ -31,6 +33,9 @@ import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; */ public class DiscoveryConfigModifier implements PolarisConfigModifier { + @Autowired + private PolarisDiscoveryProperties polarisDiscoveryProperties; + @Override public void modify(ConfigurationImpl configuration) { // Set excludeCircuitBreakInstances to false @@ -41,6 +46,10 @@ public class DiscoveryConfigModifier implements PolarisConfigModifier { // Update modified config to source properties configuration.getConsumer().getServiceRouter() .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig); + + // Set ServiceRefreshInterval + configuration.getConsumer().getLocalCache() + .setServiceListRefreshInterval(polarisDiscoveryProperties.getServiceListRefreshInterval()); } @Override diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java index 37b0ad45f..77483b360 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java @@ -105,6 +105,11 @@ public class PolarisDiscoveryProperties { @Value("${spring.cloud.polaris.discovery.health-check-url:}") private String healthCheckUrl; + /** + * Millis interval of refresh of service info list. Default: 60000. + */ + private Long serviceListRefreshInterval = 60000L; + @Autowired private Environment environment; @@ -218,6 +223,14 @@ public class PolarisDiscoveryProperties { this.healthCheckUrl = healthCheckUrl; } + public Long getServiceListRefreshInterval() { + return serviceListRefreshInterval; + } + + public void setServiceListRefreshInterval(Long serviceListRefreshInterval) { + this.serviceListRefreshInterval = serviceListRefreshInterval; + } + @Override public String toString() { return "PolarisProperties{" + "token='" + token + '\'' + ", namespace='" diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java index 951c99f76..86e829080 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java @@ -33,6 +33,7 @@ import com.tencent.polaris.api.rpc.GetInstancesRequest; import com.tencent.polaris.api.rpc.GetServicesRequest; import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.api.rpc.ServicesResponse; +import com.tencent.polaris.client.api.SDKContext; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +53,9 @@ public class PolarisDiscoveryHandler { @Autowired private ProviderAPI providerAPI; + @Autowired + private SDKContext sdkContext; + @Autowired private ConsumerAPI polarisConsumer; @@ -114,6 +118,10 @@ public class PolarisDiscoveryHandler { return providerAPI; } + public SDKContext getSdkContext() { + return sdkContext; + } + /** * Return all service for given namespace. * @return service list diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java new file mode 100644 index 000000000..d52628f28 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java @@ -0,0 +1,62 @@ +package com.tencent.cloud.polaris.registry; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; +import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; +import com.tencent.polaris.api.pojo.RegistryCacheValue; +import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.client.pojo.ServicesByProto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; + +/** + * Change listener of Polaris service info. + * + * @author Haotian Zhang + */ +public class PolarisServiceChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceChangeListener.class); + + private static final AtomicInteger INDEX = new AtomicInteger(0); + + private ApplicationEventPublisher publisher; + + @Override + public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, + RegistryCacheValue newValue) { + if (newValue.getEventType() != ServiceEventKey.EventType.SERVICE) { + return; + } + if (oldValue instanceof ServicesByProto && newValue instanceof ServicesByProto) { + LOG.debug("receive service={} change event", svcEventKey); + Set oldServiceInfoSet = ((ServicesByProto) oldValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + Set newServiceInfoSet = ((ServicesByProto) newValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + + Sets.SetView addServiceInfoSetView = Sets.difference(newServiceInfoSet, oldServiceInfoSet); + Sets.SetView deleteServiceInfoSetView = Sets.difference(oldServiceInfoSet, newServiceInfoSet); + + if (addServiceInfoSetView.isEmpty() && deleteServiceInfoSetView.isEmpty()) { + return; + } + LOG.info("Service info is update. Add service of {}. Delete service of {}", addServiceInfoSetView, deleteServiceInfoSetView); + + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} 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 83f8967f0..987413ed0 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 @@ -65,9 +65,11 @@ public class PolarisServiceRegistry implements ServiceRegistry { private final ScheduledExecutorService heartbeatExecutor; + private final PolarisServiceChangeListener polarisServiceChangeListener; + public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties) { + MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryHandler = polarisDiscoveryHandler; this.metadataLocalProperties = metadataLocalProperties; @@ -79,6 +81,8 @@ public class PolarisServiceRegistry implements ServiceRegistry { else { this.heartbeatExecutor = null; } + + this.polarisServiceChangeListener = polarisServiceChangeListener; } @Override @@ -116,6 +120,10 @@ public class PolarisServiceRegistry implements ServiceRegistry { // Start the heartbeat thread after the registration is successful. heartbeat(heartbeatRequest); } + + // Register service change listener + polarisDiscoveryHandler.getSdkContext().getExtensions().getLocalRegistry() + .registerResourceListener(polarisServiceChangeListener); } catch (Exception e) { log.error("polaris registry, {} register failed...{},", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index 93e282c8c..fba7be0bd 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -27,6 +27,7 @@ import com.tencent.polaris.client.api.SDKContext; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; @@ -52,11 +53,10 @@ public class PolarisServiceRegistryAutoConfiguration { @Bean public PolarisServiceRegistry polarisServiceRegistry( - PolarisDiscoveryProperties polarisDiscoveryProperties, - PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties) { + PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, + MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { return new PolarisServiceRegistry(polarisDiscoveryProperties, - polarisDiscoveryHandler, metadataLocalProperties); + polarisDiscoveryHandler, metadataLocalProperties, polarisServiceChangeListener); } @Bean @@ -78,4 +78,9 @@ public class PolarisServiceRegistryAutoConfiguration { autoServiceRegistrationProperties, registration); } + @Bean + @ConditionalOnMissingBean + public PolarisServiceChangeListener polarisServiceChangeListener() { + return new PolarisServiceChangeListener(); + } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json index eb160ae93..7743b5f6c 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -59,6 +59,12 @@ "type": "java.lang.Integer", "defaultValue": 100, "description": "the weight of polaris instance , use to load-balance." + }, + { + "name": "spring.cloud.polaris.discovery.service-list-refresh-interval", + "type": "java.lang.Long", + "defaultValue": 60000, + "description": "Millis interval of refresh of service info list. Default: 60000." } ] } diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 8e32288d0..1dc4849f3 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.1-Hoxton.SR9 + 1.4.2-Hoxton.SR9-SNAPSHOT 1.5.1 2.0.0 diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml index b820b2ee6..8acb66cb9 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml @@ -15,19 +15,52 @@ spring: address: grpc://127.0.0.1:8091 namespace: default enabled: true + discovery: + service-list-refresh-interval: 1000 gateway: discovery: locator: enabled: true - lowerCaseServiceId: false - routes: - - id: GatewayCalleeService - uri: lb://GatewayCalleeService - predicates: - - Path=/GatewayCalleeService/** - filters: - - StripPrefix=1 + 'predicates[0]': + name: Path + args: + patterns: '''/'' + serviceId + ''/**''' + 'filters[0]': + name: RewritePath + args: + regexp: '''/'' + serviceId + ''/(?.*)''' + replacement: '''/$\{remaining}''' + 'filters[1]': + name: Retry + args: + retries: 3 + exceptions: + '[0]': '''java.net.ConnectException''' + '[1]': '''java.io.IOException''' + statuses: + '[0]': '''BAD_GATEWAY''' + '[1]': '''SERVICE_UNAVAILABLE''' + series: + '[0]': '''CLIENT_ERROR''' + methods: + '[0]': '''GET''' + '[1]': '''POST''' + '[2]': '''PUT''' + '[3]': '''DELETE''' + backoff: + firstBackoff: '''100ms''' + maxBackoff: '''500ms''' + factor: 2 + basedOnPreviousValue: false +# routes: +# - id: GatewayCalleeService +# uri: lb://GatewayCalleeService +# predicates: +# - Path=/GatewayCalleeService/** +# filters: +# - StripPrefix=1 logging: level: org.springframework.cloud.gateway: info + com.tencent.cloud.polaris: debug diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 68f366fb0..ace6b329d 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -5,4 +5,5 @@ + \ No newline at end of file From 353bf60724859e71ff97549a6a4638ce2282ed45 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Wed, 11 May 2022 11:56:03 +0800 Subject: [PATCH 08/25] docs:update CHANGELOG.md. --- CHANGELOG.md | 6 +----- changes/changes-1.4.0.md | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 changes/changes-1.4.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2784188a0..6a9771825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,4 @@ # Change Log --- -- [Feature: Support custom rate limit reject response info](https://github.com/Tencent/spring-cloud-tencent/pull/128) -- [Feature: Optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/130) -- [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/131) -- [feat:refactor loadbalancer module as a basic module for router and circuit breaker.](https://github.com/Tencent/spring-cloud-tencent/pull/136) -- [feat:enable distribute rate limit](https://github.com/Tencent/spring-cloud-tencent/pull/139) \ No newline at end of file +- [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) \ No newline at end of file diff --git a/changes/changes-1.4.0.md b/changes/changes-1.4.0.md new file mode 100644 index 000000000..2784188a0 --- /dev/null +++ b/changes/changes-1.4.0.md @@ -0,0 +1,8 @@ +# Change Log +--- + +- [Feature: Support custom rate limit reject response info](https://github.com/Tencent/spring-cloud-tencent/pull/128) +- [Feature: Optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/130) +- [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/131) +- [feat:refactor loadbalancer module as a basic module for router and circuit breaker.](https://github.com/Tencent/spring-cloud-tencent/pull/136) +- [feat:enable distribute rate limit](https://github.com/Tencent/spring-cloud-tencent/pull/139) \ No newline at end of file From f22f32aca675bdb8b86723ea78a532f7937f01f2 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 11 May 2022 14:06:46 +0800 Subject: [PATCH 09/25] fix:fix routes of gateway doesn't refresh bug. (#158) * fix:fix routes of gateway doesn't refresh bug. * docs:update CHANGELOG.md. --- CHANGELOG.md | 6 +- changes/changes-1.4.0.md | 8 +++ pom.xml | 2 +- .../polaris/DiscoveryConfigModifier.java | 9 +++ .../polaris/PolarisDiscoveryProperties.java | 13 ++++ .../discovery/PolarisDiscoveryHandler.java | 8 +++ .../PolarisServiceChangeListener.java | 62 +++++++++++++++++++ .../registry/PolarisServiceRegistry.java | 10 ++- ...larisServiceRegistryAutoConfiguration.java | 13 ++-- ...itional-spring-configuration-metadata.json | 6 ++ spring-cloud-tencent-dependencies/pom.xml | 2 +- .../src/main/resources/bootstrap.yml | 49 ++++++++++++--- src/checkstyle/checkstyle-suppressions.xml | 1 + 13 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 changes/changes-1.4.0.md create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2784188a0..6a9771825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,4 @@ # Change Log --- -- [Feature: Support custom rate limit reject response info](https://github.com/Tencent/spring-cloud-tencent/pull/128) -- [Feature: Optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/130) -- [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/131) -- [feat:refactor loadbalancer module as a basic module for router and circuit breaker.](https://github.com/Tencent/spring-cloud-tencent/pull/136) -- [feat:enable distribute rate limit](https://github.com/Tencent/spring-cloud-tencent/pull/139) \ No newline at end of file +- [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) \ No newline at end of file diff --git a/changes/changes-1.4.0.md b/changes/changes-1.4.0.md new file mode 100644 index 000000000..2784188a0 --- /dev/null +++ b/changes/changes-1.4.0.md @@ -0,0 +1,8 @@ +# Change Log +--- + +- [Feature: Support custom rate limit reject response info](https://github.com/Tencent/spring-cloud-tencent/pull/128) +- [Feature: Optimize config server address](https://github.com/Tencent/spring-cloud-tencent/pull/130) +- [Feature: Remove spring-javaformat-maven-plugin](https://github.com/Tencent/spring-cloud-tencent/pull/131) +- [feat:refactor loadbalancer module as a basic module for router and circuit breaker.](https://github.com/Tencent/spring-cloud-tencent/pull/136) +- [feat:enable distribute rate limit](https://github.com/Tencent/spring-cloud-tencent/pull/139) \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6feeda61c..1bd9b8b05 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.1-Hoxton.SR9 + 1.4.2-Hoxton.SR9-SNAPSHOT Hoxton.SR9 diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java index a52a6dd4b..67690ef24 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java @@ -24,6 +24,8 @@ import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; +import org.springframework.beans.factory.annotation.Autowired; + /** * Spring Cloud Tencent config Override polaris config. * @@ -31,6 +33,9 @@ import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; */ public class DiscoveryConfigModifier implements PolarisConfigModifier { + @Autowired + private PolarisDiscoveryProperties polarisDiscoveryProperties; + @Override public void modify(ConfigurationImpl configuration) { // Set excludeCircuitBreakInstances to false @@ -41,6 +46,10 @@ public class DiscoveryConfigModifier implements PolarisConfigModifier { // Update modified config to source properties configuration.getConsumer().getServiceRouter() .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig); + + // Set ServiceRefreshInterval + configuration.getConsumer().getLocalCache() + .setServiceListRefreshInterval(polarisDiscoveryProperties.getServiceListRefreshInterval()); } @Override diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java index 37b0ad45f..77483b360 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java @@ -105,6 +105,11 @@ public class PolarisDiscoveryProperties { @Value("${spring.cloud.polaris.discovery.health-check-url:}") private String healthCheckUrl; + /** + * Millis interval of refresh of service info list. Default: 60000. + */ + private Long serviceListRefreshInterval = 60000L; + @Autowired private Environment environment; @@ -218,6 +223,14 @@ public class PolarisDiscoveryProperties { this.healthCheckUrl = healthCheckUrl; } + public Long getServiceListRefreshInterval() { + return serviceListRefreshInterval; + } + + public void setServiceListRefreshInterval(Long serviceListRefreshInterval) { + this.serviceListRefreshInterval = serviceListRefreshInterval; + } + @Override public String toString() { return "PolarisProperties{" + "token='" + token + '\'' + ", namespace='" diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java index 951c99f76..86e829080 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java @@ -33,6 +33,7 @@ import com.tencent.polaris.api.rpc.GetInstancesRequest; import com.tencent.polaris.api.rpc.GetServicesRequest; import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.api.rpc.ServicesResponse; +import com.tencent.polaris.client.api.SDKContext; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -52,6 +53,9 @@ public class PolarisDiscoveryHandler { @Autowired private ProviderAPI providerAPI; + @Autowired + private SDKContext sdkContext; + @Autowired private ConsumerAPI polarisConsumer; @@ -114,6 +118,10 @@ public class PolarisDiscoveryHandler { return providerAPI; } + public SDKContext getSdkContext() { + return sdkContext; + } + /** * Return all service for given namespace. * @return service list diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java new file mode 100644 index 000000000..d52628f28 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java @@ -0,0 +1,62 @@ +package com.tencent.cloud.polaris.registry; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; +import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; +import com.tencent.polaris.api.pojo.RegistryCacheValue; +import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.client.pojo.ServicesByProto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; + +/** + * Change listener of Polaris service info. + * + * @author Haotian Zhang + */ +public class PolarisServiceChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceChangeListener.class); + + private static final AtomicInteger INDEX = new AtomicInteger(0); + + private ApplicationEventPublisher publisher; + + @Override + public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, + RegistryCacheValue newValue) { + if (newValue.getEventType() != ServiceEventKey.EventType.SERVICE) { + return; + } + if (oldValue instanceof ServicesByProto && newValue instanceof ServicesByProto) { + LOG.debug("receive service={} change event", svcEventKey); + Set oldServiceInfoSet = ((ServicesByProto) oldValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + Set newServiceInfoSet = ((ServicesByProto) newValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + + Sets.SetView addServiceInfoSetView = Sets.difference(newServiceInfoSet, oldServiceInfoSet); + Sets.SetView deleteServiceInfoSetView = Sets.difference(oldServiceInfoSet, newServiceInfoSet); + + if (addServiceInfoSetView.isEmpty() && deleteServiceInfoSetView.isEmpty()) { + return; + } + LOG.info("Service info is update. Add service of {}. Delete service of {}", addServiceInfoSetView, deleteServiceInfoSetView); + + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} 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 83f8967f0..987413ed0 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 @@ -65,9 +65,11 @@ public class PolarisServiceRegistry implements ServiceRegistry { private final ScheduledExecutorService heartbeatExecutor; + private final PolarisServiceChangeListener polarisServiceChangeListener; + public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties) { + MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryHandler = polarisDiscoveryHandler; this.metadataLocalProperties = metadataLocalProperties; @@ -79,6 +81,8 @@ public class PolarisServiceRegistry implements ServiceRegistry { else { this.heartbeatExecutor = null; } + + this.polarisServiceChangeListener = polarisServiceChangeListener; } @Override @@ -116,6 +120,10 @@ public class PolarisServiceRegistry implements ServiceRegistry { // Start the heartbeat thread after the registration is successful. heartbeat(heartbeatRequest); } + + // Register service change listener + polarisDiscoveryHandler.getSdkContext().getExtensions().getLocalRegistry() + .registerResourceListener(polarisServiceChangeListener); } catch (Exception e) { log.error("polaris registry, {} register failed...{},", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index 93e282c8c..fba7be0bd 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -27,6 +27,7 @@ import com.tencent.polaris.client.api.SDKContext; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; @@ -52,11 +53,10 @@ public class PolarisServiceRegistryAutoConfiguration { @Bean public PolarisServiceRegistry polarisServiceRegistry( - PolarisDiscoveryProperties polarisDiscoveryProperties, - PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties) { + PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, + MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { return new PolarisServiceRegistry(polarisDiscoveryProperties, - polarisDiscoveryHandler, metadataLocalProperties); + polarisDiscoveryHandler, metadataLocalProperties, polarisServiceChangeListener); } @Bean @@ -78,4 +78,9 @@ public class PolarisServiceRegistryAutoConfiguration { autoServiceRegistrationProperties, registration); } + @Bean + @ConditionalOnMissingBean + public PolarisServiceChangeListener polarisServiceChangeListener() { + return new PolarisServiceChangeListener(); + } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json index eb160ae93..7743b5f6c 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -59,6 +59,12 @@ "type": "java.lang.Integer", "defaultValue": 100, "description": "the weight of polaris instance , use to load-balance." + }, + { + "name": "spring.cloud.polaris.discovery.service-list-refresh-interval", + "type": "java.lang.Long", + "defaultValue": 60000, + "description": "Millis interval of refresh of service info list. Default: 60000." } ] } diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 8e32288d0..1dc4849f3 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.1-Hoxton.SR9 + 1.4.2-Hoxton.SR9-SNAPSHOT 1.5.1 2.0.0 diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml index b820b2ee6..8acb66cb9 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml @@ -15,19 +15,52 @@ spring: address: grpc://127.0.0.1:8091 namespace: default enabled: true + discovery: + service-list-refresh-interval: 1000 gateway: discovery: locator: enabled: true - lowerCaseServiceId: false - routes: - - id: GatewayCalleeService - uri: lb://GatewayCalleeService - predicates: - - Path=/GatewayCalleeService/** - filters: - - StripPrefix=1 + 'predicates[0]': + name: Path + args: + patterns: '''/'' + serviceId + ''/**''' + 'filters[0]': + name: RewritePath + args: + regexp: '''/'' + serviceId + ''/(?.*)''' + replacement: '''/$\{remaining}''' + 'filters[1]': + name: Retry + args: + retries: 3 + exceptions: + '[0]': '''java.net.ConnectException''' + '[1]': '''java.io.IOException''' + statuses: + '[0]': '''BAD_GATEWAY''' + '[1]': '''SERVICE_UNAVAILABLE''' + series: + '[0]': '''CLIENT_ERROR''' + methods: + '[0]': '''GET''' + '[1]': '''POST''' + '[2]': '''PUT''' + '[3]': '''DELETE''' + backoff: + firstBackoff: '''100ms''' + maxBackoff: '''500ms''' + factor: 2 + basedOnPreviousValue: false +# routes: +# - id: GatewayCalleeService +# uri: lb://GatewayCalleeService +# predicates: +# - Path=/GatewayCalleeService/** +# filters: +# - StripPrefix=1 logging: level: org.springframework.cloud.gateway: info + com.tencent.cloud.polaris: debug diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index 68f366fb0..ace6b329d 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -5,4 +5,5 @@ + \ No newline at end of file From 34c95ca61ac01773dded16539428d1566152d067 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Wed, 11 May 2022 11:53:54 +0800 Subject: [PATCH 10/25] feat:use 1.5.2-SNAPSHOT version of polaris-java. --- spring-cloud-tencent-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 1dc4849f3..20a0e4577 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -71,7 +71,7 @@ 1.4.2-Hoxton.SR9-SNAPSHOT - 1.5.1 + 1.5.2-SNAPSHOT 2.0.0 From c27ef60a1b125c58d3701808df713b08a3398106 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Thu, 12 May 2022 11:48:05 +0800 Subject: [PATCH 11/25] fix:Turn off automatic injection of Polars rule. --- CHANGELOG.md | 3 ++- .../PolarisRibbonClientConfiguration.java | 24 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9771825..28499dd51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Change Log --- -- [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) \ No newline at end of file +- [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) +- [fix:Turn off automatic injection of Polars rule.](https://github.com/Tencent/spring-cloud-tencent/pull/152) \ No newline at end of file diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java index 3e84ed57f..3436a9ecb 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java @@ -24,8 +24,6 @@ import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; -import com.tencent.cloud.polaris.loadbalancer.rule.PolarisLoadBalanceRule; -import com.tencent.cloud.polaris.loadbalancer.rule.PolarisWeightedRandomRule; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.router.api.core.RouterAPI; @@ -41,17 +39,17 @@ import org.springframework.context.annotation.Configuration; @Configuration public class PolarisRibbonClientConfiguration { - @Bean - @ConditionalOnMissingBean - public IRule polarisRibbonRule( - PolarisLoadBalancerProperties polarisLoadBalancerProperties) { - switch (PolarisLoadBalanceRule - .fromStrategy(polarisLoadBalancerProperties.getStrategy())) { - case WEIGHTED_RANDOM_RULE: - default: - return new PolarisWeightedRandomRule(); - } - } +// @Bean +// @ConditionalOnMissingBean +// public IRule polarisRibbonRule( +// PolarisLoadBalancerProperties polarisLoadBalancerProperties) { +// switch (PolarisLoadBalanceRule +// .fromStrategy(polarisLoadBalancerProperties.getStrategy())) { +// case WEIGHTED_RANDOM_RULE: +// default: +// return new PolarisWeightedRandomRule(); +// } +// } @Bean @ConditionalOnMissingBean From ae73c89baf615b05819170afa20dc7b4b515c267 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Thu, 12 May 2022 17:23:39 +0800 Subject: [PATCH 12/25] feat:optimize code. --- .../cloud/polaris/registry/PolarisServiceRegistry.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 987413ed0..f12b50d9a 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 @@ -34,14 +34,13 @@ import com.tencent.polaris.api.rpc.InstanceHeartbeatRequest; import com.tencent.polaris.api.rpc.InstanceRegisterRequest; import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.client.util.NamedThreadFactory; -import org.apache.logging.log4j.util.Strings; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.util.StringUtils; import static org.springframework.util.ReflectionUtils.rethrowRuntimeException; @@ -207,7 +206,7 @@ public class PolarisServiceRegistry implements ServiceRegistry { // first. // If the health check passes, the heartbeat will be reported. // If it does not pass, the heartbeat will not be reported. - if (Strings.isNotEmpty(healthCheckEndpoint)) { + if (!StringUtils.isNotBlank(healthCheckEndpoint)) { if (!healthCheckEndpoint.startsWith("/")) { healthCheckEndpoint = "/" + healthCheckEndpoint; } From 3303d995d23ce8469db082f40d06595d7d27354c Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Thu, 12 May 2022 17:34:00 +0800 Subject: [PATCH 13/25] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28499dd51..af06c3331 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,4 @@ --- - [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) -- [fix:Turn off automatic injection of Polars rule.](https://github.com/Tencent/spring-cloud-tencent/pull/152) \ No newline at end of file +- [fix:Turn off automatic injection of Polars rule.](https://github.com/Tencent/spring-cloud-tencent/pull/162) From 247e15a84e6b8f4a62c7f278e2b07b295de3ab9b Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Thu, 12 May 2022 19:49:53 +0800 Subject: [PATCH 14/25] feat:release 1.4.2-Hoxton.SR9. --- 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 1bd9b8b05..fd263d077 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.2-Hoxton.SR9-SNAPSHOT + 1.4.2-Hoxton.SR9 Hoxton.SR9 diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 20a0e4577..b74474252 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,8 +70,8 @@ - 1.4.2-Hoxton.SR9-SNAPSHOT - 1.5.2-SNAPSHOT + 1.4.2-Hoxton.SR9 + 1.5.2 2.0.0 From 266ee13bd2a488a43da0e1337aff748e0db3b448 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Fri, 13 May 2022 20:44:21 +0800 Subject: [PATCH 15/25] fix:fix wrong context data storage. --- CHANGELOG.md | 3 +- changes/changes-1.4.2.md | 5 ++ pom.xml | 2 +- .../DecodeTransferMetadataReactiveFilter.java | 2 +- .../DecodeTransferMetadataServletFilter.java | 2 +- ...odeTransferMedataFeignInterceptorTest.java | 7 +- ...sferMedataRestTemplateInterceptorTest.java | 7 +- .../feign/PolarisFeignClient.java | 27 ++++--- .../discovery/PolarisDiscoveryHandler.java | 4 -- .../polaris/registry/PolarisRegistration.java | 4 +- .../registry/PolarisServiceRegistry.java | 2 +- .../common/constant/MetadataConstant.java | 22 ------ .../common/metadata/MetadataContext.java | 35 ++-------- .../metadata/MetadataContextHolder.java | 7 +- .../config/MetadataAutoConfiguration.java | 31 -------- .../gateway/MetadataFirstScgFilter.java | 22 ------ .../gateway/MetadataFirstZuulFilter.java | 70 ------------------- .../feign/MetadataFirstFeignInterceptor.java | 55 --------------- .../metadata/MetadataContextHolderTest.java | 3 +- .../config/MetadataAutoConfigurationTest.java | 44 ++---------- spring-cloud-tencent-dependencies/pom.xml | 2 +- .../loadbalancer/PolarisLoadBalancer.java | 15 ++-- 22 files changed, 47 insertions(+), 324 deletions(-) create mode 100644 changes/changes-1.4.2.md delete mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstZuulFilter.java delete mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/interceptor/feign/MetadataFirstFeignInterceptor.java diff --git a/CHANGELOG.md b/CHANGELOG.md index af06c3331..85c31fadf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,4 @@ # Change Log --- -- [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) -- [fix:Turn off automatic injection of Polars rule.](https://github.com/Tencent/spring-cloud-tencent/pull/162) +- [fix:fix wrong context data storage.](https://github.com/Tencent/spring-cloud-tencent/pull/170) diff --git a/changes/changes-1.4.2.md b/changes/changes-1.4.2.md new file mode 100644 index 000000000..af06c3331 --- /dev/null +++ b/changes/changes-1.4.2.md @@ -0,0 +1,5 @@ +# Change Log +--- + +- [fix:fix routes of gateway doesn't refresh bug.](https://github.com/Tencent/spring-cloud-tencent/pull/158) +- [fix:Turn off automatic injection of Polars rule.](https://github.com/Tencent/spring-cloud-tencent/pull/162) diff --git a/pom.xml b/pom.xml index fd263d077..6713a41d4 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.2-Hoxton.SR9 + 1.4.3-Hoxton.SR9-SNAPSHOT Hoxton.SR9 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 aac449fac..2dea4fd66 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 @@ -75,7 +75,7 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered Map upstreamCustomMetadataMap = JacksonUtils .deserialize2Map(customMetadataStr); - MetadataContextHolder.init(upstreamCustomMetadataMap, null); + MetadataContextHolder.init(upstreamCustomMetadataMap); // 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 da1261f65..23934edec 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 @@ -72,7 +72,7 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { .deserialize2Map(customMetadataStr); try { - MetadataContextHolder.init(upstreamCustomMetadataMap, null); + MetadataContextHolder.init(upstreamCustomMetadataMap); filterChain.doFilter(httpServletRequest, httpServletResponse); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java index cecb5ddbe..d71e93a64 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java @@ -24,7 +24,6 @@ import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; -import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; import feign.RequestInterceptor; import feign.RequestTemplate; @@ -67,7 +66,7 @@ public class EncodeTransferMedataFeignInterceptorTest { public void test1() { String metadata = testFeign.test(); Assertions.assertThat(metadata) - .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}{}"); + .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}"); Assertions.assertThat(metadataLocalProperties.getContent().get("a")) .isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")) @@ -92,9 +91,7 @@ public class EncodeTransferMedataFeignInterceptorTest { public String test( @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr) throws UnsupportedEncodingException { - String systemMetadataStr = JacksonUtils - .serialize2Json(MetadataContextHolder.get().getAllSystemMetadata()); - return URLDecoder.decode(customMetadataStr, "UTF-8") + systemMetadataStr; + return URLDecoder.decode(customMetadataStr, "UTF-8"); } @FeignClient(name = "test-feign", url = "http://localhost:8081") diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java index 6877842ac..733539df4 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -24,7 +24,6 @@ import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; -import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; import org.assertj.core.api.Assertions; import org.junit.Test; @@ -77,7 +76,7 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { httpEntity, String.class) .getBody(); Assertions.assertThat(metadata) - .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}{}"); + .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}"); Assertions.assertThat(metadataLocalProperties.getContent().get("a")) .isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")) @@ -106,9 +105,7 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { public String test( @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr) throws UnsupportedEncodingException { - String systemMetadataStr = JacksonUtils - .serialize2Json(MetadataContextHolder.get().getAllSystemMetadata()); - return URLDecoder.decode(customMetadataStr, "UTF-8") + systemMetadataStr; + return URLDecoder.decode(customMetadataStr, "UTF-8"); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java index bb061b3b7..0996f0b21 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java @@ -20,9 +20,7 @@ package com.tencent.cloud.polaris.circuitbreaker.feign; import java.io.IOException; import java.net.URI; -import com.tencent.cloud.common.constant.MetadataConstant.SystemMetadataKey; import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.RetStatus; import com.tencent.polaris.api.pojo.ServiceKey; @@ -32,6 +30,8 @@ import feign.Request; import feign.Request.Options; import feign.Response; import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import static feign.Util.checkNotNull; @@ -42,6 +42,9 @@ import static feign.Util.checkNotNull; */ public class PolarisFeignClient implements Client { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisFeignClient.class); + private final Client delegate; private final ConsumerAPI consumerAPI; @@ -64,6 +67,7 @@ public class PolarisFeignClient implements Client { } catch (IOException origin) { resultRequest.setRetStatus(RetStatus.RetFail); + throw origin; } finally { @@ -74,24 +78,17 @@ public class PolarisFeignClient implements Client { private ServiceCallResult createServiceCallResult(final Request request) { ServiceCallResult resultRequest = new ServiceCallResult(); - MetadataContext metadataContext = MetadataContextHolder.get(); - String namespace = metadataContext - .getSystemMetadata(SystemMetadataKey.PEER_NAMESPACE); - resultRequest.setNamespace(namespace); - String serviceName = metadataContext - .getSystemMetadata(SystemMetadataKey.PEER_SERVICE); + resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE); + String serviceName = request.requestTemplate().feignTarget().name(); resultRequest.setService(serviceName); - String method = metadataContext.getSystemMetadata(SystemMetadataKey.PEER_PATH); - resultRequest.setMethod(method); + URI uri = URI.create(request.url()); + resultRequest.setMethod(uri.getPath()); resultRequest.setRetStatus(RetStatus.RetSuccess); String sourceNamespace = MetadataContext.LOCAL_NAMESPACE; String sourceService = MetadataContext.LOCAL_SERVICE; - if (StringUtils.isNotBlank(sourceNamespace) - && StringUtils.isNotBlank(sourceService)) { - resultRequest - .setCallerService(new ServiceKey(sourceNamespace, sourceService)); + if (StringUtils.isNotBlank(sourceNamespace) && StringUtils.isNotBlank(sourceService)) { + resultRequest.setCallerService(new ServiceKey(sourceNamespace, sourceService)); } - URI uri = URI.create(request.url()); resultRequest.setHost(uri.getHost()); resultRequest.setPort(uri.getPort()); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java index 86e829080..e71eb1fcd 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java @@ -20,7 +20,6 @@ package com.tencent.cloud.polaris.discovery; import java.util.Map; -import com.tencent.cloud.common.constant.MetadataConstant.SystemMetadataKey; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; @@ -70,9 +69,6 @@ public class PolarisDiscoveryHandler { GetInstancesRequest getInstancesRequest = new GetInstancesRequest(); getInstancesRequest.setNamespace(namespace); getInstancesRequest.setService(service); - String method = MetadataContextHolder.get() - .getSystemMetadata(SystemMetadataKey.PEER_PATH); - getInstancesRequest.setMethod(method); String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; Map allTransitiveCustomMetadata = MetadataContextHolder.get() diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java index 9ca6b9e08..ed8baacc9 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java @@ -19,9 +19,9 @@ package com.tencent.cloud.polaris.registry; import java.net.URI; +import java.util.Collections; import java.util.Map; -import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.polaris.client.api.SDKContext; @@ -84,7 +84,7 @@ public class PolarisRegistration implements Registration, ServiceInstance { @Override public Map getMetadata() { - return MetadataContextHolder.get().getAllSystemMetadata(); + return Collections.emptyMap(); } public PolarisDiscoveryProperties getPolarisProperties() { 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 f12b50d9a..6b171c1de 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 @@ -206,7 +206,7 @@ public class PolarisServiceRegistry implements ServiceRegistry { // first. // If the health check passes, the heartbeat will be reported. // If it does not pass, the heartbeat will not be reported. - if (!StringUtils.isNotBlank(healthCheckEndpoint)) { + if (StringUtils.isNotBlank(healthCheckEndpoint)) { if (!healthCheckEndpoint.startsWith("/")) { healthCheckEndpoint = "/" + healthCheckEndpoint; } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java index ce498126b..d45c71568 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java @@ -26,28 +26,6 @@ import org.springframework.core.Ordered; */ public final class MetadataConstant { - /** - * System metadata key. - */ - public static class SystemMetadataKey { - - /** - * Peer namespace. - */ - public static String PEER_NAMESPACE = "PEER_NAMESPACE"; - - /** - * Peer service. - */ - public static String PEER_SERVICE = "PEER_SERVICE"; - - /** - * Peer path. - */ - public static String PEER_PATH = "PEER_PATH"; - - } - /** * Order of filter, interceptor, ... */ 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 6f06e811b..584465ff9 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 @@ -44,16 +44,6 @@ public class MetadataContext { */ public static String LOCAL_SERVICE; - /** - * Transitive custom metadata content. - */ - private final Map transitiveCustomMetadata; - - /** - * System metadata content. - */ - private final Map systemMetadata; - static { String namespace = ApplicationContextAwareUtils .getProperties("spring.cloud.polaris.namespace"); @@ -73,9 +63,13 @@ public class MetadataContext { LOCAL_SERVICE = serviceName; } + /** + * Transitive custom metadata content. + */ + private final Map transitiveCustomMetadata; + public MetadataContext() { this.transitiveCustomMetadata = new ConcurrentHashMap<>(); - this.systemMetadata = new ConcurrentHashMap<>(); } public Map getAllTransitiveCustomMetadata() { @@ -94,27 +88,10 @@ public class MetadataContext { this.transitiveCustomMetadata.putAll(customMetadata); } - public Map getAllSystemMetadata() { - return Collections.unmodifiableMap(this.systemMetadata); - } - - public String getSystemMetadata(String key) { - return this.systemMetadata.get(key); - } - - public void putSystemMetadata(String key, String value) { - this.systemMetadata.put(key, value); - } - - public void putAllSystemMetadata(Map systemMetadata) { - this.systemMetadata.putAll(systemMetadata); - } - @Override public String toString() { return "MetadataContext{" + "transitiveCustomMetadata=" - + JacksonUtils.serialize2Json(transitiveCustomMetadata) - + ", systemMetadata=" + JacksonUtils.serialize2Json(systemMetadata) + '}'; + + JacksonUtils.serialize2Json(transitiveCustomMetadata) + '}'; } } 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 b8811f8a5..3ec3eb7fc 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 @@ -92,10 +92,8 @@ public final class MetadataContextHolder { /** * Save metadata map to thread local. * @param customMetadataMap custom metadata collection - * @param systemMetadataMap system metadata collection */ - public static void init(Map customMetadataMap, - Map systemMetadataMap) { + public static void init(Map customMetadataMap) { // Init ThreadLocal. MetadataContextHolder.remove(); MetadataContext metadataContext = MetadataContextHolder.get(); @@ -104,9 +102,6 @@ public final class MetadataContextHolder { if (!CollectionUtils.isEmpty(customMetadataMap)) { metadataContext.putAllTransitiveCustomMetadata(customMetadataMap); } - if (!CollectionUtils.isEmpty(systemMetadataMap)) { - metadataContext.putAllSystemMetadata(systemMetadataMap); - } MetadataContextHolder.set(metadataContext); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java index b0e85c4ae..6188c61ae 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java @@ -18,10 +18,7 @@ package com.tencent.cloud.common.metadata.config; -import com.netflix.zuul.ZuulFilter; import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter; -import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstZuulFilter; -import com.tencent.cloud.common.metadata.interceptor.feign.MetadataFirstFeignInterceptor; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -45,34 +42,6 @@ public class MetadataAutoConfiguration { return new MetadataLocalProperties(); } - /** - * Create when Feign exists. - */ - @Configuration - @ConditionalOnClass(name = "feign.Feign") - static class MetadataFeignInterceptorConfig { - - @Bean - public MetadataFirstFeignInterceptor metadataFirstFeignInterceptor() { - return new MetadataFirstFeignInterceptor(); - } - - } - - /** - * Create when gateway application is Zuul. - */ - @Configuration - @ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet") - static class MetadataZuulFilterConfig { - - @Bean - public ZuulFilter metadataFirstZuulFilter() { - return new MetadataFirstZuulFilter(); - } - - } - /** * Create when gateway application is SCG. */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstScgFilter.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstScgFilter.java index 21c6c4d54..a79ba5323 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstScgFilter.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstScgFilter.java @@ -25,12 +25,10 @@ import reactor.core.publisher.Mono; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.cloud.gateway.route.Route; import org.springframework.core.Ordered; import org.springframework.web.server.ServerWebExchange; import static org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER; -import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; /** * Scg output first filter used for setting peer info in context. @@ -51,9 +49,6 @@ public class MetadataFirstScgFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - // get request context - Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); - // get metadata of current thread MetadataContext metadataContext = exchange .getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT); @@ -61,23 +56,6 @@ public class MetadataFirstScgFilter implements GlobalFilter, Ordered { metadataContext = MetadataContextHolder.get(); } - // TODO The peer namespace is temporarily the same as the local namespace - metadataContext.putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_NAMESPACE, - MetadataContext.LOCAL_NAMESPACE); - if (route != null) { - metadataContext.putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_SERVICE, - route.getUri().getAuthority()); - } - else { - metadataContext.putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_SERVICE, - exchange.getRequest().getURI().getAuthority()); - } - metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH, - exchange.getRequest().getURI().getPath()); - exchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT, metadataContext); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstZuulFilter.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstZuulFilter.java deleted file mode 100644 index acb2acc87..000000000 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/filter/gateway/MetadataFirstZuulFilter.java +++ /dev/null @@ -1,70 +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.common.metadata.filter.gateway; - -import com.netflix.zuul.ZuulFilter; -import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; - -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.REQUEST_URI_KEY; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY; - -/** - * Zuul output first filter used for setting peer info in context. - * - * @author Haotian Zhang - */ -public class MetadataFirstZuulFilter extends ZuulFilter { - - @Override - public String filterType() { - return PRE_TYPE; - } - - @Override - public int filterOrder() { - return PRE_DECORATION_FILTER_ORDER + 1; - } - - @Override - public boolean shouldFilter() { - return true; - } - - @Override - public Object run() { - // get request context - RequestContext requestContext = RequestContext.getCurrentContext(); - - // TODO The peer namespace is temporarily the same as the local namespace - MetadataContextHolder.get().putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_NAMESPACE, - MetadataContext.LOCAL_NAMESPACE); - MetadataContextHolder.get().putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_SERVICE, - (String) requestContext.get(SERVICE_ID_KEY)); - MetadataContextHolder.get().putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_PATH, - (String) requestContext.get(REQUEST_URI_KEY)); - return null; - } - -} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/interceptor/feign/MetadataFirstFeignInterceptor.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/interceptor/feign/MetadataFirstFeignInterceptor.java deleted file mode 100644 index 18f5390ab..000000000 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/interceptor/feign/MetadataFirstFeignInterceptor.java +++ /dev/null @@ -1,55 +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.common.metadata.interceptor.feign; - -import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import feign.RequestInterceptor; -import feign.RequestTemplate; - -import org.springframework.core.Ordered; - -/** - * Interceptor used for setting peer info in context. - * - * @author Haotian Zhang - */ -public class MetadataFirstFeignInterceptor implements RequestInterceptor, Ordered { - - @Override - public int getOrder() { - return MetadataConstant.OrderConstant.METADATA_FIRST_FEIGN_INTERCEPTOR_ORDER; - } - - @Override - public void apply(RequestTemplate requestTemplate) { - // get metadata of current thread - MetadataContext metadataContext = MetadataContextHolder.get(); - - // TODO The peer namespace is temporarily the same as the local namespace - metadataContext.putSystemMetadata( - MetadataConstant.SystemMetadataKey.PEER_NAMESPACE, - MetadataContext.LOCAL_NAMESPACE); - metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE, - requestTemplate.feignTarget().name()); - metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH, - requestTemplate.path()); - } - -} 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 29d280044..0fbcf36ab 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 @@ -58,8 +58,7 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - Map systemMetadata = new HashMap<>(); - MetadataContextHolder.init(customMetadata, systemMetadata); + MetadataContextHolder.init(customMetadata); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getAllTransitiveCustomMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java index 76be75bd4..fb19efb18 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfigurationTest.java @@ -19,8 +19,6 @@ package com.tencent.cloud.common.metadata.config; import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter; -import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstZuulFilter; -import com.tencent.cloud.common.metadata.interceptor.feign.MetadataFirstFeignInterceptor; import org.assertj.core.api.Assertions; import org.junit.Test; @@ -50,20 +48,10 @@ public class MetadataAutoConfigurationTest { this.applicationContextRunner .withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class)) .run(context -> { - Assertions.assertThat(context) - .hasSingleBean(MetadataLocalProperties.class); - Assertions.assertThat(context).hasSingleBean( - MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstFeignInterceptor.class); - Assertions.assertThat(context).hasSingleBean( - MetadataAutoConfiguration.MetadataZuulFilterConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstZuulFilter.class); + Assertions.assertThat(context).hasSingleBean(MetadataLocalProperties.class); Assertions.assertThat(context).hasSingleBean( MetadataAutoConfiguration.MetadataScgFilterConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstScgFilter.class); + Assertions.assertThat(context).hasSingleBean(MetadataFirstScgFilter.class); }); } @@ -75,20 +63,10 @@ public class MetadataAutoConfigurationTest { this.webApplicationContextRunner .withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class)) .run(context -> { - Assertions.assertThat(context) - .hasSingleBean(MetadataLocalProperties.class); - Assertions.assertThat(context).hasSingleBean( - MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstFeignInterceptor.class); - Assertions.assertThat(context).hasSingleBean( - MetadataAutoConfiguration.MetadataZuulFilterConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstZuulFilter.class); + Assertions.assertThat(context).hasSingleBean(MetadataLocalProperties.class); Assertions.assertThat(context).hasSingleBean( MetadataAutoConfiguration.MetadataScgFilterConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstScgFilter.class); + Assertions.assertThat(context).hasSingleBean(MetadataFirstScgFilter.class); }); } @@ -100,20 +78,10 @@ public class MetadataAutoConfigurationTest { this.reactiveWebApplicationContextRunner .withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class)) .run(context -> { - Assertions.assertThat(context) - .hasSingleBean(MetadataLocalProperties.class); - Assertions.assertThat(context).hasSingleBean( - MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstFeignInterceptor.class); - Assertions.assertThat(context).hasSingleBean( - MetadataAutoConfiguration.MetadataZuulFilterConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstZuulFilter.class); + Assertions.assertThat(context).hasSingleBean(MetadataLocalProperties.class); Assertions.assertThat(context).hasSingleBean( MetadataAutoConfiguration.MetadataScgFilterConfig.class); - Assertions.assertThat(context) - .hasSingleBean(MetadataFirstScgFilter.class); + Assertions.assertThat(context).hasSingleBean(MetadataFirstScgFilter.class); }); } diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index b74474252..f67e0d517 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.2-Hoxton.SR9 + 1.4.3-Hoxton.SR9-SNAPSHOT 1.5.2 2.0.0 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 37ae60526..b9e0de6f1 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 @@ -30,7 +30,6 @@ import com.netflix.loadbalancer.PollingServerListUpdater; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.tencent.cloud.common.constant.ContextConstant; -import com.tencent.cloud.common.constant.MetadataConstant.SystemMetadataKey; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.pojo.PolarisServer; @@ -89,9 +88,6 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { String srcService = MetadataContext.LOCAL_SERVICE; Map transitiveCustomMetadata = MetadataContextHolder.get() .getAllTransitiveCustomMetadata(); - String method = MetadataContextHolder.get() - .getSystemMetadata(SystemMetadataKey.PEER_PATH); - processRoutersRequest.setMethod(method); if (StringUtils.isNotBlank(srcNamespace) && StringUtils.isNotBlank(srcService)) { ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setNamespace(srcNamespace); @@ -111,14 +107,11 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { } private ServiceInstances getPolarisDiscoveryServiceInstances() { - String serviceName = MetadataContextHolder.get().getSystemMetadata(SystemMetadataKey.PEER_SERVICE); - if (StringUtils.isBlank(serviceName)) { - List allServers = super.getAllServers(); - if (CollectionUtils.isEmpty(allServers)) { - return null; - } - serviceName = ((PolarisServer) super.getAllServers().get(0)).getServiceInstances().getService(); + List allServers = super.getAllServers(); + if (CollectionUtils.isEmpty(allServers)) { + return null; } + String serviceName = ((PolarisServer) super.getAllServers().get(0)).getServiceInstances().getService(); return getAllInstances(MetadataContext.LOCAL_NAMESPACE, serviceName).toServiceInstances(); } From 900acc4421ea62f89ce8ec4551aa9e6790805cd8 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Tue, 17 May 2022 10:36:07 +0800 Subject: [PATCH 16/25] fix:fix route not refreshing bug when first instance of one service up. --- CHANGELOG.md | 1 + .../PolarisDiscoveryAutoConfiguration.java | 5 +- ...sRefreshApplicationReadyEventListener.java | 70 ++++++++++++++++ .../refresh/PolarisRefreshConfiguration.java | 32 ++++++++ .../PolarisServiceStatusChangeListener.java | 80 +++++++++++++++++++ .../PolarisServiceChangeListener.java | 62 -------------- .../registry/PolarisServiceRegistry.java | 10 +-- ...larisServiceRegistryAutoConfiguration.java | 12 +-- .../loadbalancer/PolarisLoadBalancer.java | 23 +----- 9 files changed, 193 insertions(+), 102 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java delete mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c31fadf..c8e3ed71d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,4 @@ --- - [fix:fix wrong context data storage.](https://github.com/Tencent/spring-cloud-tencent/pull/170) +- [fix:fix route not refreshing bug when first instance of one service up.](https://github.com/Tencent/spring-cloud-tencent/pull/174) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java index 139f72508..cc8000f44 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java @@ -19,6 +19,7 @@ package com.tencent.cloud.polaris.discovery; import com.tencent.cloud.polaris.discovery.reactive.PolarisReactiveDiscoveryClientConfiguration; +import com.tencent.cloud.polaris.discovery.refresh.PolarisRefreshConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -32,8 +33,8 @@ import org.springframework.context.annotation.Import; */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisDiscoveryEnabled -@Import({ PolarisDiscoveryClientConfiguration.class, - PolarisReactiveDiscoveryClientConfiguration.class }) +@Import({PolarisDiscoveryClientConfiguration.class, + PolarisReactiveDiscoveryClientConfiguration.class, PolarisRefreshConfiguration.class}) public class PolarisDiscoveryAutoConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java new file mode 100644 index 000000000..831573893 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java @@ -0,0 +1,70 @@ +package com.tencent.cloud.polaris.discovery.refresh; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; +import com.tencent.polaris.client.util.NamedThreadFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.ApplicationListener; + +import static com.tencent.cloud.polaris.discovery.refresh.PolarisServiceStatusChangeListener.INDEX; + +/** + * Begin refresh when application is ready. + * + * @author Haotian Zhang + */ +public class PolarisRefreshApplicationReadyEventListener implements ApplicationListener, ApplicationEventPublisherAware { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisRefreshConfiguration.class); + private static final int DELAY = 60; + private final PolarisDiscoveryHandler polarisDiscoveryHandler; + private final PolarisServiceStatusChangeListener polarisServiceStatusChangeListener; + private final ScheduledExecutorService refreshExecutor; + private ApplicationEventPublisher publisher; + + public PolarisRefreshApplicationReadyEventListener(PolarisDiscoveryHandler polarisDiscoveryHandler, PolarisServiceStatusChangeListener polarisServiceStatusChangeListener) { + this.polarisDiscoveryHandler = polarisDiscoveryHandler; + this.polarisServiceStatusChangeListener = polarisServiceStatusChangeListener; + this.refreshExecutor = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("polaris-service-refresh")); + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + // Register service change listener. + polarisDiscoveryHandler.getSdkContext().getExtensions().getLocalRegistry() + .registerResourceListener(polarisServiceStatusChangeListener); + + // Begin scheduled refresh thread. + refresh(); + } + + /** + * Start the refresh thread. + */ + public void refresh() { + refreshExecutor.scheduleWithFixedDelay(() -> { + try { + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + catch (Exception e) { + LOG.error("refresh polaris service error.", e); + } + }, DELAY, DELAY, TimeUnit.SECONDS); + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java new file mode 100644 index 000000000..fe723bda7 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java @@ -0,0 +1,32 @@ +package com.tencent.cloud.polaris.discovery.refresh; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Configuration for listening the change of service status. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +public class PolarisRefreshConfiguration { + + @Bean + @ConditionalOnMissingBean + public PolarisServiceStatusChangeListener polarisServiceChangeListener() { + return new PolarisServiceStatusChangeListener(); + } + + @Bean + @ConditionalOnMissingBean + public PolarisRefreshApplicationReadyEventListener polarisServiceStatusApplicationReadyEventListener( + PolarisDiscoveryHandler polarisDiscoveryHandler, + PolarisServiceStatusChangeListener polarisServiceStatusChangeListener) { + return new PolarisRefreshApplicationReadyEventListener(polarisDiscoveryHandler, polarisServiceStatusChangeListener); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java new file mode 100644 index 000000000..ccbc32e61 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java @@ -0,0 +1,80 @@ +package com.tencent.cloud.polaris.discovery.refresh; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; +import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; +import com.tencent.polaris.api.pojo.RegistryCacheValue; +import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.client.pojo.ServiceInstancesByProto; +import com.tencent.polaris.client.pojo.ServicesByProto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.util.CollectionUtils; + +/** + * Change listener of Polaris service info. When service info is created or deleted, or, instance of service is from 0 to + * + * @author Haotian Zhang + */ +public class PolarisServiceStatusChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { + + /** + * Index of service info status. + */ + public static final AtomicLong INDEX = new AtomicLong(0); + + private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceStatusChangeListener.class); + + private ApplicationEventPublisher publisher; + + @Override + public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, + RegistryCacheValue newValue) { + if (newValue.getEventType() == ServiceEventKey.EventType.SERVICE) { + if (oldValue instanceof ServicesByProto && newValue instanceof ServicesByProto) { + LOG.debug("receive service={} change event", svcEventKey); + Set oldServiceInfoSet = ((ServicesByProto) oldValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + Set newServiceInfoSet = ((ServicesByProto) newValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + + Sets.SetView addServiceInfoSetView = Sets.difference(newServiceInfoSet, oldServiceInfoSet); + Sets.SetView deleteServiceInfoSetView = Sets.difference(oldServiceInfoSet, newServiceInfoSet); + + if (addServiceInfoSetView.isEmpty() && deleteServiceInfoSetView.isEmpty()) { + return; + } + LOG.info("Service status is update. Add service of {}. Delete service of {}", addServiceInfoSetView, deleteServiceInfoSetView); + + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + } + else if (newValue.getEventType() == ServiceEventKey.EventType.INSTANCE) { + if (oldValue instanceof ServiceInstancesByProto && newValue instanceof ServiceInstancesByProto) { + LOG.debug("receive service instances={} change event", svcEventKey); + ServiceInstancesByProto oldIns = (ServiceInstancesByProto) oldValue; + ServiceInstancesByProto newIns = (ServiceInstancesByProto) newValue; + if ((CollectionUtils.isEmpty(oldIns.getInstances()) && !CollectionUtils.isEmpty(newIns.getInstances())) || + (!CollectionUtils.isEmpty(oldIns.getInstances()) && CollectionUtils.isEmpty(newIns.getInstances()))) { + LOG.info("Service status of {} is update.", newIns.getService()); + + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + } + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java deleted file mode 100644 index d52628f28..000000000 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.tencent.cloud.polaris.registry; - -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import com.google.common.collect.Sets; -import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; -import com.tencent.polaris.api.pojo.RegistryCacheValue; -import com.tencent.polaris.api.pojo.ServiceEventKey; -import com.tencent.polaris.client.pojo.ServicesByProto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.client.discovery.event.HeartbeatEvent; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; - -/** - * Change listener of Polaris service info. - * - * @author Haotian Zhang - */ -public class PolarisServiceChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { - - private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceChangeListener.class); - - private static final AtomicInteger INDEX = new AtomicInteger(0); - - private ApplicationEventPublisher publisher; - - @Override - public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, - RegistryCacheValue newValue) { - if (newValue.getEventType() != ServiceEventKey.EventType.SERVICE) { - return; - } - if (oldValue instanceof ServicesByProto && newValue instanceof ServicesByProto) { - LOG.debug("receive service={} change event", svcEventKey); - Set oldServiceInfoSet = ((ServicesByProto) oldValue).getServices().stream() - .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); - Set newServiceInfoSet = ((ServicesByProto) newValue).getServices().stream() - .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); - - Sets.SetView addServiceInfoSetView = Sets.difference(newServiceInfoSet, oldServiceInfoSet); - Sets.SetView deleteServiceInfoSetView = Sets.difference(oldServiceInfoSet, newServiceInfoSet); - - if (addServiceInfoSetView.isEmpty() && deleteServiceInfoSetView.isEmpty()) { - return; - } - LOG.info("Service info is update. Add service of {}. Delete service of {}", addServiceInfoSetView, deleteServiceInfoSetView); - - // Trigger reload of gateway route cache. - this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); - } - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.publisher = applicationEventPublisher; - } -} 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 6b171c1de..0d39c7262 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 @@ -64,11 +64,9 @@ public class PolarisServiceRegistry implements ServiceRegistry { private final ScheduledExecutorService heartbeatExecutor; - private final PolarisServiceChangeListener polarisServiceChangeListener; - public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { + MetadataLocalProperties metadataLocalProperties) { this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryHandler = polarisDiscoveryHandler; this.metadataLocalProperties = metadataLocalProperties; @@ -80,8 +78,6 @@ public class PolarisServiceRegistry implements ServiceRegistry { else { this.heartbeatExecutor = null; } - - this.polarisServiceChangeListener = polarisServiceChangeListener; } @Override @@ -119,10 +115,6 @@ public class PolarisServiceRegistry implements ServiceRegistry { // Start the heartbeat thread after the registration is successful. heartbeat(heartbeatRequest); } - - // Register service change listener - polarisDiscoveryHandler.getSdkContext().getExtensions().getLocalRegistry() - .registerResourceListener(polarisServiceChangeListener); } catch (Exception e) { log.error("polaris registry, {} register failed...{},", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index fba7be0bd..68f338c5d 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -27,7 +27,6 @@ import com.tencent.polaris.client.api.SDKContext; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; @@ -54,9 +53,8 @@ public class PolarisServiceRegistryAutoConfiguration { @Bean public PolarisServiceRegistry polarisServiceRegistry( PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { - return new PolarisServiceRegistry(polarisDiscoveryProperties, - polarisDiscoveryHandler, metadataLocalProperties, polarisServiceChangeListener); + MetadataLocalProperties metadataLocalProperties) { + return new PolarisServiceRegistry(polarisDiscoveryProperties, polarisDiscoveryHandler, metadataLocalProperties); } @Bean @@ -77,10 +75,4 @@ public class PolarisServiceRegistryAutoConfiguration { return new PolarisAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); } - - @Bean - @ConditionalOnMissingBean - public PolarisServiceChangeListener polarisServiceChangeListener() { - return new PolarisServiceChangeListener(); - } } 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 b9e0de6f1..574a42610 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 @@ -107,12 +107,7 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { } private ServiceInstances getPolarisDiscoveryServiceInstances() { - List allServers = super.getAllServers(); - if (CollectionUtils.isEmpty(allServers)) { - return null; - } - String serviceName = ((PolarisServer) super.getAllServers().get(0)).getServiceInstances().getService(); - return getAllInstances(MetadataContext.LOCAL_NAMESPACE, serviceName).toServiceInstances(); + return getAllInstances(MetadataContext.LOCAL_NAMESPACE, name).toServiceInstances(); } private ServiceInstances getExtendDiscoveryServiceInstances() { @@ -121,26 +116,16 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { return null; } ServiceInstances serviceInstances; - String serviceName; - // notice the difference between different service registries - if (StringUtils.isNotBlank( - allServers.get(0).getMetaInfo().getServiceIdForDiscovery())) { - serviceName = allServers.get(0).getMetaInfo().getServiceIdForDiscovery(); - } - else { - serviceName = allServers.get(0).getMetaInfo().getAppName(); - } - if (StringUtils.isBlank(serviceName)) { + if (StringUtils.isBlank(name)) { throw new IllegalStateException( "PolarisLoadBalancer only Server with AppName or ServiceIdForDiscovery attribute"); } - ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, - serviceName); + ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, name); List instances = new ArrayList<>(8); for (Server server : allServers) { DefaultInstance instance = new DefaultInstance(); instance.setNamespace(MetadataContext.LOCAL_NAMESPACE); - instance.setService(serviceName); + instance.setService(name); instance.setHealthy(server.isAlive()); instance.setProtocol(server.getScheme()); instance.setId(server.getId()); From 4fe8602c7476d8666f2b02f7542ea4b255096d17 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Tue, 17 May 2022 11:07:35 +0800 Subject: [PATCH 17/25] fix:fix route not refreshing bug when first instance of one service up. (#174) --- CHANGELOG.md | 1 + .../PolarisDiscoveryAutoConfiguration.java | 5 +- ...sRefreshApplicationReadyEventListener.java | 70 ++++++++++++++++ .../refresh/PolarisRefreshConfiguration.java | 32 ++++++++ .../PolarisServiceStatusChangeListener.java | 80 +++++++++++++++++++ .../PolarisServiceChangeListener.java | 62 -------------- .../registry/PolarisServiceRegistry.java | 10 +-- ...larisServiceRegistryAutoConfiguration.java | 12 +-- .../loadbalancer/PolarisLoadBalancer.java | 23 +----- 9 files changed, 193 insertions(+), 102 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java delete mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c31fadf..c8e3ed71d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,4 @@ --- - [fix:fix wrong context data storage.](https://github.com/Tencent/spring-cloud-tencent/pull/170) +- [fix:fix route not refreshing bug when first instance of one service up.](https://github.com/Tencent/spring-cloud-tencent/pull/174) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java index 139f72508..cc8000f44 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfiguration.java @@ -19,6 +19,7 @@ package com.tencent.cloud.polaris.discovery; import com.tencent.cloud.polaris.discovery.reactive.PolarisReactiveDiscoveryClientConfiguration; +import com.tencent.cloud.polaris.discovery.refresh.PolarisRefreshConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -32,8 +33,8 @@ import org.springframework.context.annotation.Import; */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisDiscoveryEnabled -@Import({ PolarisDiscoveryClientConfiguration.class, - PolarisReactiveDiscoveryClientConfiguration.class }) +@Import({PolarisDiscoveryClientConfiguration.class, + PolarisReactiveDiscoveryClientConfiguration.class, PolarisRefreshConfiguration.class}) public class PolarisDiscoveryAutoConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java new file mode 100644 index 000000000..831573893 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java @@ -0,0 +1,70 @@ +package com.tencent.cloud.polaris.discovery.refresh; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; +import com.tencent.polaris.client.util.NamedThreadFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.ApplicationListener; + +import static com.tencent.cloud.polaris.discovery.refresh.PolarisServiceStatusChangeListener.INDEX; + +/** + * Begin refresh when application is ready. + * + * @author Haotian Zhang + */ +public class PolarisRefreshApplicationReadyEventListener implements ApplicationListener, ApplicationEventPublisherAware { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisRefreshConfiguration.class); + private static final int DELAY = 60; + private final PolarisDiscoveryHandler polarisDiscoveryHandler; + private final PolarisServiceStatusChangeListener polarisServiceStatusChangeListener; + private final ScheduledExecutorService refreshExecutor; + private ApplicationEventPublisher publisher; + + public PolarisRefreshApplicationReadyEventListener(PolarisDiscoveryHandler polarisDiscoveryHandler, PolarisServiceStatusChangeListener polarisServiceStatusChangeListener) { + this.polarisDiscoveryHandler = polarisDiscoveryHandler; + this.polarisServiceStatusChangeListener = polarisServiceStatusChangeListener; + this.refreshExecutor = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("polaris-service-refresh")); + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + // Register service change listener. + polarisDiscoveryHandler.getSdkContext().getExtensions().getLocalRegistry() + .registerResourceListener(polarisServiceStatusChangeListener); + + // Begin scheduled refresh thread. + refresh(); + } + + /** + * Start the refresh thread. + */ + public void refresh() { + refreshExecutor.scheduleWithFixedDelay(() -> { + try { + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + catch (Exception e) { + LOG.error("refresh polaris service error.", e); + } + }, DELAY, DELAY, TimeUnit.SECONDS); + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java new file mode 100644 index 000000000..fe723bda7 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java @@ -0,0 +1,32 @@ +package com.tencent.cloud.polaris.discovery.refresh; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Configuration for listening the change of service status. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +public class PolarisRefreshConfiguration { + + @Bean + @ConditionalOnMissingBean + public PolarisServiceStatusChangeListener polarisServiceChangeListener() { + return new PolarisServiceStatusChangeListener(); + } + + @Bean + @ConditionalOnMissingBean + public PolarisRefreshApplicationReadyEventListener polarisServiceStatusApplicationReadyEventListener( + PolarisDiscoveryHandler polarisDiscoveryHandler, + PolarisServiceStatusChangeListener polarisServiceStatusChangeListener) { + return new PolarisRefreshApplicationReadyEventListener(polarisDiscoveryHandler, polarisServiceStatusChangeListener); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java new file mode 100644 index 000000000..ccbc32e61 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java @@ -0,0 +1,80 @@ +package com.tencent.cloud.polaris.discovery.refresh; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; +import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; +import com.tencent.polaris.api.pojo.RegistryCacheValue; +import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.client.pojo.ServiceInstancesByProto; +import com.tencent.polaris.client.pojo.ServicesByProto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.discovery.event.HeartbeatEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.util.CollectionUtils; + +/** + * Change listener of Polaris service info. When service info is created or deleted, or, instance of service is from 0 to + * + * @author Haotian Zhang + */ +public class PolarisServiceStatusChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { + + /** + * Index of service info status. + */ + public static final AtomicLong INDEX = new AtomicLong(0); + + private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceStatusChangeListener.class); + + private ApplicationEventPublisher publisher; + + @Override + public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, + RegistryCacheValue newValue) { + if (newValue.getEventType() == ServiceEventKey.EventType.SERVICE) { + if (oldValue instanceof ServicesByProto && newValue instanceof ServicesByProto) { + LOG.debug("receive service={} change event", svcEventKey); + Set oldServiceInfoSet = ((ServicesByProto) oldValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + Set newServiceInfoSet = ((ServicesByProto) newValue).getServices().stream() + .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); + + Sets.SetView addServiceInfoSetView = Sets.difference(newServiceInfoSet, oldServiceInfoSet); + Sets.SetView deleteServiceInfoSetView = Sets.difference(oldServiceInfoSet, newServiceInfoSet); + + if (addServiceInfoSetView.isEmpty() && deleteServiceInfoSetView.isEmpty()) { + return; + } + LOG.info("Service status is update. Add service of {}. Delete service of {}", addServiceInfoSetView, deleteServiceInfoSetView); + + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + } + else if (newValue.getEventType() == ServiceEventKey.EventType.INSTANCE) { + if (oldValue instanceof ServiceInstancesByProto && newValue instanceof ServiceInstancesByProto) { + LOG.debug("receive service instances={} change event", svcEventKey); + ServiceInstancesByProto oldIns = (ServiceInstancesByProto) oldValue; + ServiceInstancesByProto newIns = (ServiceInstancesByProto) newValue; + if ((CollectionUtils.isEmpty(oldIns.getInstances()) && !CollectionUtils.isEmpty(newIns.getInstances())) || + (!CollectionUtils.isEmpty(oldIns.getInstances()) && CollectionUtils.isEmpty(newIns.getInstances()))) { + LOG.info("Service status of {} is update.", newIns.getService()); + + // Trigger reload of gateway route cache. + this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); + } + } + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.publisher = applicationEventPublisher; + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java deleted file mode 100644 index d52628f28..000000000 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceChangeListener.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.tencent.cloud.polaris.registry; - -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import com.google.common.collect.Sets; -import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; -import com.tencent.polaris.api.pojo.RegistryCacheValue; -import com.tencent.polaris.api.pojo.ServiceEventKey; -import com.tencent.polaris.client.pojo.ServicesByProto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.cloud.client.discovery.event.HeartbeatEvent; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; - -/** - * Change listener of Polaris service info. - * - * @author Haotian Zhang - */ -public class PolarisServiceChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { - - private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceChangeListener.class); - - private static final AtomicInteger INDEX = new AtomicInteger(0); - - private ApplicationEventPublisher publisher; - - @Override - public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, - RegistryCacheValue newValue) { - if (newValue.getEventType() != ServiceEventKey.EventType.SERVICE) { - return; - } - if (oldValue instanceof ServicesByProto && newValue instanceof ServicesByProto) { - LOG.debug("receive service={} change event", svcEventKey); - Set oldServiceInfoSet = ((ServicesByProto) oldValue).getServices().stream() - .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); - Set newServiceInfoSet = ((ServicesByProto) newValue).getServices().stream() - .map(i -> i.getNamespace() + "::" + i.getService()).collect(Collectors.toSet()); - - Sets.SetView addServiceInfoSetView = Sets.difference(newServiceInfoSet, oldServiceInfoSet); - Sets.SetView deleteServiceInfoSetView = Sets.difference(oldServiceInfoSet, newServiceInfoSet); - - if (addServiceInfoSetView.isEmpty() && deleteServiceInfoSetView.isEmpty()) { - return; - } - LOG.info("Service info is update. Add service of {}. Delete service of {}", addServiceInfoSetView, deleteServiceInfoSetView); - - // Trigger reload of gateway route cache. - this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); - } - } - - @Override - public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { - this.publisher = applicationEventPublisher; - } -} 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 6b171c1de..0d39c7262 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 @@ -64,11 +64,9 @@ public class PolarisServiceRegistry implements ServiceRegistry { private final ScheduledExecutorService heartbeatExecutor; - private final PolarisServiceChangeListener polarisServiceChangeListener; - public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { + MetadataLocalProperties metadataLocalProperties) { this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryHandler = polarisDiscoveryHandler; this.metadataLocalProperties = metadataLocalProperties; @@ -80,8 +78,6 @@ public class PolarisServiceRegistry implements ServiceRegistry { else { this.heartbeatExecutor = null; } - - this.polarisServiceChangeListener = polarisServiceChangeListener; } @Override @@ -119,10 +115,6 @@ public class PolarisServiceRegistry implements ServiceRegistry { // Start the heartbeat thread after the registration is successful. heartbeat(heartbeatRequest); } - - // Register service change listener - polarisDiscoveryHandler.getSdkContext().getExtensions().getLocalRegistry() - .registerResourceListener(polarisServiceChangeListener); } catch (Exception e) { log.error("polaris registry, {} register failed...{},", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index fba7be0bd..68f338c5d 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -27,7 +27,6 @@ import com.tencent.polaris.client.api.SDKContext; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; @@ -54,9 +53,8 @@ public class PolarisServiceRegistryAutoConfiguration { @Bean public PolarisServiceRegistry polarisServiceRegistry( PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, - MetadataLocalProperties metadataLocalProperties, PolarisServiceChangeListener polarisServiceChangeListener) { - return new PolarisServiceRegistry(polarisDiscoveryProperties, - polarisDiscoveryHandler, metadataLocalProperties, polarisServiceChangeListener); + MetadataLocalProperties metadataLocalProperties) { + return new PolarisServiceRegistry(polarisDiscoveryProperties, polarisDiscoveryHandler, metadataLocalProperties); } @Bean @@ -77,10 +75,4 @@ public class PolarisServiceRegistryAutoConfiguration { return new PolarisAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); } - - @Bean - @ConditionalOnMissingBean - public PolarisServiceChangeListener polarisServiceChangeListener() { - return new PolarisServiceChangeListener(); - } } 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 b9e0de6f1..574a42610 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 @@ -107,12 +107,7 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { } private ServiceInstances getPolarisDiscoveryServiceInstances() { - List allServers = super.getAllServers(); - if (CollectionUtils.isEmpty(allServers)) { - return null; - } - String serviceName = ((PolarisServer) super.getAllServers().get(0)).getServiceInstances().getService(); - return getAllInstances(MetadataContext.LOCAL_NAMESPACE, serviceName).toServiceInstances(); + return getAllInstances(MetadataContext.LOCAL_NAMESPACE, name).toServiceInstances(); } private ServiceInstances getExtendDiscoveryServiceInstances() { @@ -121,26 +116,16 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { return null; } ServiceInstances serviceInstances; - String serviceName; - // notice the difference between different service registries - if (StringUtils.isNotBlank( - allServers.get(0).getMetaInfo().getServiceIdForDiscovery())) { - serviceName = allServers.get(0).getMetaInfo().getServiceIdForDiscovery(); - } - else { - serviceName = allServers.get(0).getMetaInfo().getAppName(); - } - if (StringUtils.isBlank(serviceName)) { + if (StringUtils.isBlank(name)) { throw new IllegalStateException( "PolarisLoadBalancer only Server with AppName or ServiceIdForDiscovery attribute"); } - ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, - serviceName); + ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, name); List instances = new ArrayList<>(8); for (Server server : allServers) { DefaultInstance instance = new DefaultInstance(); instance.setNamespace(MetadataContext.LOCAL_NAMESPACE); - instance.setService(serviceName); + instance.setService(name); instance.setHealthy(server.isAlive()); instance.setProtocol(server.getScheme()); instance.setId(server.getId()); From b59b80a686cc5375a095569e52af7684e0ec9ffc Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Tue, 17 May 2022 11:22:35 +0800 Subject: [PATCH 18/25] release:release 1.4.3-Hoxton.SR9. --- pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6713a41d4..4fe6ab52f 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.3-Hoxton.SR9-SNAPSHOT + 1.4.3-Hoxton.SR9 Hoxton.SR9 diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index f67e0d517..2c5ed21f9 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.3-Hoxton.SR9-SNAPSHOT + 1.4.3-Hoxton.SR9 1.5.2 2.0.0 From 734be5032f9648351bc641a5af753f726ed66240 Mon Sep 17 00:00:00 2001 From: SkyeBeFreeman <928016560@qq.com> Date: Tue, 17 May 2022 20:59:05 +0800 Subject: [PATCH 19/25] fix:fix wrong isAliveFlag config when creating new PolarisServer. --- CHANGELOG.md | 3 +-- changes/changes-1.4.3.md | 5 +++++ pom.xml | 2 +- .../java/com/tencent/cloud/common/pojo/PolarisServer.java | 1 + spring-cloud-tencent-dependencies/pom.xml | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 changes/changes-1.4.3.md diff --git a/CHANGELOG.md b/CHANGELOG.md index c8e3ed71d..1aa0ff740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,4 @@ # Change Log --- -- [fix:fix wrong context data storage.](https://github.com/Tencent/spring-cloud-tencent/pull/170) -- [fix:fix route not refreshing bug when first instance of one service up.](https://github.com/Tencent/spring-cloud-tencent/pull/174) +- [fix:fix wrong isAliveFlag config when creating new PolarisServer.](https://github.com/Tencent/spring-cloud-tencent/pull/179) diff --git a/changes/changes-1.4.3.md b/changes/changes-1.4.3.md new file mode 100644 index 000000000..c8e3ed71d --- /dev/null +++ b/changes/changes-1.4.3.md @@ -0,0 +1,5 @@ +# Change Log +--- + +- [fix:fix wrong context data storage.](https://github.com/Tencent/spring-cloud-tencent/pull/170) +- [fix:fix route not refreshing bug when first instance of one service up.](https://github.com/Tencent/spring-cloud-tencent/pull/174) diff --git a/pom.xml b/pom.xml index 4fe6ab52f..d531541f5 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.3-Hoxton.SR9 + 1.4.4-Hoxton.SR9 Hoxton.SR9 diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServer.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServer.java index be55ed31e..fa458f5c3 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServer.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServer.java @@ -48,6 +48,7 @@ public class PolarisServer extends Server { } this.serviceInstances = serviceInstances; this.instance = instance; + this.setAlive(true); this.metaInfo = new MetaInfo() { @Override public String getAppName() { diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 2c5ed21f9..205ff1186 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.3-Hoxton.SR9 + 1.4.4-Hoxton.SR9 1.5.2 2.0.0 From 4fc6aca5b11e12bb9d03e75a996fc45f08738470 Mon Sep 17 00:00:00 2001 From: lepdou Date: Wed, 18 May 2022 20:52:25 +0800 Subject: [PATCH 20/25] support router by request label --- CHANGELOG.md | 2 +- .../EncodeTransferMedataFeignInterceptor.java | 7 +- ...TransferMedataRestTemplateInterceptor.java | 6 +- .../core/EncodeTransferMedataScgFilter.java | 3 +- .../EncodeTransferMetadataZuulFilter.java | 3 +- ...odeTransferMedataFeignInterceptorTest.java | 15 +- ...sferMedataRestTemplateInterceptorTest.java | 7 +- .../feign/PolarisFeignClient.java | 1 + .../discovery/PolarisDiscoveryHandler.java | 4 +- .../pom.xml | 6 + .../PolarisLoadBalancerCompositeRule.java | 184 ++++++++++++++++++ .../polaris/router/PolarisRouterContext.java | 53 +++++ ...package-info.java => RouterConstants.java} | 15 +- .../polaris/router/SimpleLoadBalancer.java | 63 ++++++ .../router/config/FeignConfiguration.java | 44 +++++ .../router/config/RibbonConfiguration.java | 43 ++++ .../config/RouterAutoConfiguration.java | 61 ++++++ ...olarisCachingSpringLoadBalanceFactory.java | 72 +++++++ .../feign/PolarisFeignLoadBalancer.java | 68 +++++++ .../router/feign/RouterLabelInterceptor.java | 88 +++++++++ .../PolarisLoadBalancerBeanPostProcessor.java | 60 ++++++ .../PolarisLoadBalancerInterceptor.java | 120 ++++++++++++ .../router/spi/RouterLabelResolver.java | 48 +++++ .../main/resources/META-INF/spring.factories | 2 + .../common/metadata/MetadataContext.java | 50 +++-- .../metadata/MetadataContextHolder.java | 5 +- .../metadata/MetadataContextHolderTest.java | 7 +- .../polaris-config-example/README-zh.md | 2 +- .../example/RouterCalleeController.java | 9 +- .../cloud/polaris/router/example/User.java | 45 ++--- .../example/RouterCalleeController.java | 10 +- .../cloud/polaris/router/example/User.java | 53 +++++ .../router-caller-service/pom.xml | 6 + .../example/CustomRouterLabelResolver.java | 60 ++++++ .../router/example/RouterCalleeService.java | 8 +- .../example/RouterCallerController.java | 18 +- .../cloud/polaris/router/example/User.java | 45 +++++ .../src/main/resources/bootstrap.yml | 4 + .../loadbalancer/LoadBalancerUtils.java | 58 ++++++ .../loadbalancer/PolarisLoadBalancer.java | 51 ++--- ...ndomRule.java => PolarisWeightedRule.java} | 59 ++---- .../PolarisLoadBalancerAutoConfiguration.java | 8 +- .../config/PolarisLoadBalancerProperties.java | 2 +- .../PolarisRibbonClientConfiguration.java | 20 +- 44 files changed, 1301 insertions(+), 194 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/{package-info.java => RouterConstants.java} (80%) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactory.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories rename spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisLoadBalanceRule.java => spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/User.java (55%) create mode 100644 spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/User.java create mode 100644 spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java create mode 100644 spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/User.java create mode 100644 spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/LoadBalancerUtils.java rename spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/{rule/PolarisWeightedRandomRule.java => PolarisWeightedRule.java} (53%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa0ff740..55ca6aa41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ # Change Log --- -- [fix:fix wrong isAliveFlag config when creating new PolarisServer.](https://github.com/Tencent/spring-cloud-tencent/pull/179) +- [fix:Router support request label.](https://github.com/Tencent/spring-cloud-tencent/pull/165) 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 index 711d5b947..2e6e78d24 100644 --- 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 @@ -65,14 +65,13 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, Map headerMetadataMap = JacksonUtils .deserialize2Map(headerMetadataStr); for (String key : headerMetadataMap.keySet()) { - metadataContext.putTransitiveCustomMetadata(key, - headerMetadataMap.get(key)); + metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key)); } } } - Map customMetadata = metadataContext - .getAllTransitiveCustomMetadata(); + Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + if (!CollectionUtils.isEmpty(customMetadata)) { String metadataStr = JacksonUtils.serialize2Json(customMetadata); requestTemplate.removeHeader(CUSTOM_METADATA); 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/EncodeTransferMedataRestTemplateInterceptor.java index 47709ba6c..c97ddb9d8 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/EncodeTransferMedataRestTemplateInterceptor.java @@ -63,12 +63,10 @@ public class EncodeTransferMedataRestTemplateInterceptor Map headerMetadataMap = JacksonUtils .deserialize2Map(metadataStr); for (String key : headerMetadataMap.keySet()) { - metadataContext.putTransitiveCustomMetadata(key, - headerMetadataMap.get(key)); + metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key)); } } - Map customMetadata = metadataContext - .getAllTransitiveCustomMetadata(); + Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); if (!CollectionUtils.isEmpty(customMetadata)) { metadataStr = JacksonUtils.serialize2Json(customMetadata); try { 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/EncodeTransferMedataScgFilter.java index 6c5937bce..200a83743 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/EncodeTransferMedataScgFilter.java @@ -65,8 +65,7 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { if (metadataContext == null) { metadataContext = MetadataContextHolder.get(); } - Map customMetadata = metadataContext - .getAllTransitiveCustomMetadata(); + Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); if (!CollectionUtils.isEmpty(customMetadata)) { String metadataStr = JacksonUtils.serialize2Json(customMetadata); try { 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/EncodeTransferMetadataZuulFilter.java index 3fac6f6d7..cf192e955 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/EncodeTransferMetadataZuulFilter.java @@ -65,8 +65,7 @@ public class EncodeTransferMetadataZuulFilter extends ZuulFilter { MetadataContext metadataContext = MetadataContextHolder.get(); // add new metadata and cover old - Map customMetadata = metadataContext - .getAllTransitiveCustomMetadata(); + Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); if (!CollectionUtils.isEmpty(customMetadata)) { String metadataStr = JacksonUtils.serialize2Json(customMetadata); try { diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java index d71e93a64..7d7811420 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java @@ -22,6 +22,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; +import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; @@ -52,8 +53,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = DEFINED_PORT, classes = EncodeTransferMedataFeignInterceptorTest.TestApplication.class, - properties = { "server.port=8081", - "spring.config.location = classpath:application-test.yml" }) + properties = {"server.port=8081", + "spring.config.location = classpath:application-test.yml"}) public class EncodeTransferMedataFeignInterceptorTest { @Autowired @@ -72,13 +73,13 @@ public class EncodeTransferMedataFeignInterceptorTest { Assertions.assertThat(metadataLocalProperties.getContent().get("b")) .isEqualTo("2"); Assertions - .assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("a")) + .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a")) .isEqualTo("11"); Assertions - .assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("b")) + .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b")) .isEqualTo("22"); Assertions - .assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("c")) + .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c")) .isEqualTo("33"); } @@ -98,8 +99,8 @@ public class EncodeTransferMedataFeignInterceptorTest { public interface TestFeign { @RequestMapping(value = "/test", - headers = { MetadataConstant.HeaderName.CUSTOM_METADATA - + "={\"a\":\"11" + "\",\"b\":\"22\",\"c\":\"33\"}" }) + headers = {MetadataConstant.HeaderName.CUSTOM_METADATA + + "={\"a\":\"11" + "\",\"b\":\"22\",\"c\":\"33\"}"}) String test(); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java index 733539df4..26f1bc395 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -22,6 +22,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; +import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; @@ -82,13 +83,13 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { Assertions.assertThat(metadataLocalProperties.getContent().get("b")) .isEqualTo("2"); Assertions - .assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("a")) + .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a")) .isEqualTo("11"); Assertions - .assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("b")) + .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b")) .isEqualTo("22"); Assertions - .assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("c")) + .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c")) .isEqualTo("33"); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java index 0996f0b21..54ab9a53e 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java @@ -13,6 +13,7 @@ * 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; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java index e71eb1fcd..bd64f463b 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryHandler.java @@ -71,8 +71,8 @@ public class PolarisDiscoveryHandler { getInstancesRequest.setService(service); String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; - Map allTransitiveCustomMetadata = MetadataContextHolder.get() - .getAllTransitiveCustomMetadata(); + Map allTransitiveCustomMetadata = MetadataContextHolder.get(). + getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); if (StringUtils.isNotBlank(localNamespace) || StringUtils.isNotBlank(localService) || null != allTransitiveCustomMetadata) { ServiceInfo sourceService = new ServiceInfo(); diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index d623da7b1..94a69d9bc 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -27,6 +27,12 @@ router-rule + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java new file mode 100644 index 000000000..d270f766c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java @@ -0,0 +1,184 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractLoadBalancerRule; +import com.netflix.loadbalancer.AvailabilityFilteringRule; +import com.netflix.loadbalancer.BestAvailableRule; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.RandomRule; +import com.netflix.loadbalancer.RetryRule; +import com.netflix.loadbalancer.RoundRobinRule; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.WeightedResponseTimeRule; +import com.netflix.loadbalancer.ZoneAvoidanceRule; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.pojo.PolarisServer; +import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; +import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRule; +import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; +import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.pojo.ServiceInfo; +import com.tencent.polaris.api.pojo.ServiceInstances; +import com.tencent.polaris.router.api.core.RouterAPI; +import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; +import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse; +import org.apache.commons.lang.StringUtils; + +import org.springframework.util.CollectionUtils; + +/** + * + * Service routing entrance. + * + * Rule routing needs to rely on request parameters for server filtering, + * and {@link com.netflix.loadbalancer.ServerListFilter#getFilteredListOfServers(List)} + * The interface cannot obtain the context object of the request granularity, + * so the routing capability cannot be achieved through ServerListFilter. + * + * And {@link com.netflix.loadbalancer.IRule#choose(Object)} provides the ability to pass in context parameters, + * so routing capabilities are implemented through IRule. + * + * @author Haotian Zhang, lepdou + */ +public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule { + + private final static String STRATEGY_RANDOM = "random"; + private final static String STRATEGY_ROUND_ROBIN = "roundRobin"; + private final static String STRATEGY_WEIGHT = "polarisWeighted"; + private final static String STRATEGY_RETRY = "retry"; + private final static String STRATEGY_RESPONSE_TIME_WEIGHTED = "responseTimeWeighted"; + private final static String STRATEGY_BEST_AVAILABLE = "bestAvailable"; + private final static String STRATEGY_ZONE_AVOIDANCE = "zoneAvoidance"; + private final static String STRATEGY_AVAILABILITY_FILTERING = "availabilityFilteringRule"; + + private final PolarisLoadBalancerProperties loadBalancerProperties; + private final RouterAPI routerAPI; + + private final AbstractLoadBalancerRule delegateRule; + + public PolarisLoadBalancerCompositeRule(RouterAPI routerAPI, PolarisLoadBalancerProperties polarisLoadBalancerProperties, + IClientConfig iClientConfig) { + this.routerAPI = routerAPI; + this.loadBalancerProperties = polarisLoadBalancerProperties; + + delegateRule = getRule(); + delegateRule.initWithNiwsConfig(iClientConfig); + } + + @Override + public void initWithNiwsConfig(IClientConfig clientConfig) { + } + + @Override + public Server choose(Object key) { + // 1. get all servers + List allServers = getLoadBalancer().getReachableServers(); + if (CollectionUtils.isEmpty(allServers)) { + return null; + } + + // 2. filter by router + List serversAfterRouter = doRouter(allServers, key); + + // 3. filter by load balance. + // A LoadBalancer needs to be regenerated for each request, + // because the list of servers may be different after filtered by router + ILoadBalancer loadBalancer = new SimpleLoadBalancer(); + loadBalancer.addServers(serversAfterRouter); + delegateRule.setLoadBalancer(loadBalancer); + + return delegateRule.choose(key); + } + + private List doRouter(List allServers, Object key) { + ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(allServers); + + // filter instance by routers + ProcessRoutersRequest processRoutersRequest = buildProcessRoutersRequest(serviceInstances, key); + + ProcessRoutersResponse processRoutersResponse = routerAPI.processRouters(processRoutersRequest); + + List filteredInstances = new ArrayList<>(); + ServiceInstances filteredServiceInstances = processRoutersResponse.getServiceInstances(); + for (Instance instance : filteredServiceInstances.getInstances()) { + filteredInstances.add(new PolarisServer(serviceInstances, instance)); + } + return filteredInstances; + } + + private ProcessRoutersRequest buildProcessRoutersRequest(ServiceInstances serviceInstances, Object key) { + ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest(); + processRoutersRequest.setDstInstances(serviceInstances); + + Map routerMetadata; + if (key instanceof PolarisRouterContext) { + routerMetadata = ((PolarisRouterContext) key).getLabels(); + } + else { + routerMetadata = Collections.emptyMap(); + } + + String srcNamespace = MetadataContext.LOCAL_NAMESPACE; + String srcService = MetadataContext.LOCAL_SERVICE; + + if (StringUtils.isNotBlank(srcNamespace) && StringUtils.isNotBlank(srcService)) { + ServiceInfo serviceInfo = new ServiceInfo(); + serviceInfo.setNamespace(srcNamespace); + serviceInfo.setService(srcService); + serviceInfo.setMetadata(routerMetadata); + processRoutersRequest.setSourceService(serviceInfo); + } + + return processRoutersRequest; + } + + public AbstractLoadBalancerRule getRule() { + String loadBalanceStrategy = loadBalancerProperties.getStrategy(); + if (org.springframework.util.StringUtils.isEmpty(loadBalanceStrategy)) { + return new RoundRobinRule(); + } + + switch (loadBalanceStrategy) { + case STRATEGY_RANDOM: + return new RandomRule(); + case STRATEGY_WEIGHT: + return new PolarisWeightedRule(routerAPI); + case STRATEGY_RETRY: + return new RetryRule(); + case STRATEGY_RESPONSE_TIME_WEIGHTED: + return new WeightedResponseTimeRule(); + case STRATEGY_BEST_AVAILABLE: + return new BestAvailableRule(); + case STRATEGY_ROUND_ROBIN: + return new RoundRobinRule(); + case STRATEGY_AVAILABILITY_FILTERING: + return new AvailabilityFilteringRule(); + case STRATEGY_ZONE_AVOIDANCE: + default: + return new ZoneAvoidanceRule(); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java new file mode 100644 index 000000000..2ed7e727e --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.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.polaris.router; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.util.CollectionUtils; + +/** + * the context for router. + * + *@author lepdou 2022-05-17 + */ +public class PolarisRouterContext { + + private Map labels; + + public Map getLabels() { + if (CollectionUtils.isEmpty(labels)) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(labels); + } + + public void setLabels(Map labels) { + this.labels = labels; + } + + public void putLabel(String key, String value) { + if (labels == null) { + labels = new HashMap<>(); + } + labels.put(key, value); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/package-info.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java similarity index 80% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/package-info.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java index 3eb18e376..77266cc02 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/package-info.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConstants.java @@ -13,11 +13,20 @@ * 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; + /** - * Package info of router. + * Router constants. * - * @author Haotian Zhang + *@author lepdou 2022-05-17 */ -package com.tencent.cloud.polaris.router; +public class RouterConstants { + + /** + * the header of router label. + */ + public static final String ROUTER_LABEL_HEADER = "router-label"; +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java new file mode 100644 index 000000000..c8ab04c3c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/SimpleLoadBalancer.java @@ -0,0 +1,63 @@ +/* + * 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 java.util.List; + +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.Server; + +/** + * Simple load balancer only for getting and setting servers. + * + *@author lepdou 2022-05-17 + */ +public class SimpleLoadBalancer implements ILoadBalancer { + private List servers; + + @Override + public void addServers(List newServers) { + this.servers = newServers; + } + + @Override + public Server chooseServer(Object key) { + return null; + } + + @Override + public void markServerDown(Server server) { + + } + + @Override + public List getServerList(boolean availableOnly) { + return servers; + } + + @Override + public List getReachableServers() { + return servers; + } + + @Override + public List getAllServers() { + return servers; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.java new file mode 100644 index 000000000..d5d22444e --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.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.polaris.router.config; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ILoadBalancer; +import com.tencent.cloud.polaris.router.feign.PolarisFeignLoadBalancer; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * configuration for feign component. + * + *@author lepdou 2022-05-16 + */ +@Configuration +public class FeignConfiguration { + + @Bean + @ConditionalOnMissingBean + public PolarisFeignLoadBalancer polarisFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, + ServerIntrospector serverIntrospector) { + return new PolarisFeignLoadBalancer(lb, clientConfig, serverIntrospector); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java new file mode 100644 index 000000000..d139bf7b3 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.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.polaris.router.config; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.IRule; +import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; +import com.tencent.cloud.polaris.router.PolarisLoadBalancerCompositeRule; +import com.tencent.polaris.router.api.core.RouterAPI; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Auto configuration for ribbon components. + * @author lepdou 2022-05-17 + */ +@Configuration +public class RibbonConfiguration { + + @Bean + public IRule polarisLoadBalancerCompositeRule(RouterAPI routerAPI, + PolarisLoadBalancerProperties polarisLoadBalancerProperties, + IClientConfig iClientConfig) { + return new PolarisLoadBalancerCompositeRule(routerAPI, polarisLoadBalancerProperties, iClientConfig); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java new file mode 100644 index 000000000..950638406 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java @@ -0,0 +1,61 @@ +/* + * 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.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; +import com.tencent.cloud.polaris.router.feign.RouterLabelInterceptor; +import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerBeanPostProcessor; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; + +import org.springframework.cloud.netflix.ribbon.RibbonClients; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.lang.Nullable; + +import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; + +/** + * router module auto configuration. + * + *@author lepdou 2022-05-11 + */ +@Configuration +@RibbonClients(defaultConfiguration = {FeignConfiguration.class, RibbonConfiguration.class}) +public class RouterAutoConfiguration { + + @Bean + public RouterLabelInterceptor routerLabelInterceptor(@Nullable RouterLabelResolver resolver, + MetadataLocalProperties metadataLocalProperties) { + return new RouterLabelInterceptor(resolver, metadataLocalProperties); + } + + @Bean + public PolarisCachingSpringLoadBalanceFactory polarisCachingSpringLoadBalanceFactory(SpringClientFactory factory) { + return new PolarisCachingSpringLoadBalanceFactory(factory); + } + + @Bean + @Order(HIGHEST_PRECEDENCE) + public PolarisLoadBalancerBeanPostProcessor polarisLoadBalancerBeanPostProcessor() { + return new PolarisLoadBalancerBeanPostProcessor(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactory.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactory.java new file mode 100644 index 000000000..2c15ce790 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisCachingSpringLoadBalanceFactory.java @@ -0,0 +1,72 @@ +/* + * 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.feign; + +import java.util.Map; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ILoadBalancer; + +import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory; +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory; +import org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer; +import org.springframework.util.ConcurrentReferenceHashMap; + +/** + * Extends CachingSpringLoadBalancerFactory to be able to create PolarisFeignLoadBalance. + * + *@author lepdou 2022-05-16 + */ +public class PolarisCachingSpringLoadBalanceFactory extends CachingSpringLoadBalancerFactory { + + private final Map cache = new ConcurrentReferenceHashMap<>(); + + public PolarisCachingSpringLoadBalanceFactory(SpringClientFactory factory) { + super(factory); + } + + public PolarisCachingSpringLoadBalanceFactory(SpringClientFactory factory, + LoadBalancedRetryFactory loadBalancedRetryPolicyFactory) { + super(factory, loadBalancedRetryPolicyFactory); + } + + @Override + public FeignLoadBalancer create(String clientName) { + FeignLoadBalancer client = this.cache.get(clientName); + if (client != null) { + return client; + } + + IClientConfig config = this.factory.getClientConfig(clientName); + ILoadBalancer lb = this.factory.getLoadBalancer(clientName); + ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class); + + FeignLoadBalancer loadBalancer = new PolarisFeignLoadBalancer(lb, config, serverIntrospector); + + //There is a concurrency problem here. + //When the concurrency is high, it may cause a service to create multiple FeignLoadBalancers. + //But there is no concurrency control in CachingSpringLoadBalancerFactory, + //so no locks will be added here for the time being + cache.putIfAbsent(clientName, loadBalancer); + + return loadBalancer; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java new file mode 100644 index 000000000..d9ac98b04 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.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.polaris.router.feign; + +import java.util.Collection; +import java.util.Map; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ILoadBalancer; +import com.netflix.loadbalancer.reactive.LoadBalancerCommand; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.RouterConstants; + +import org.springframework.cloud.netflix.ribbon.ServerIntrospector; +import org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer; +import org.springframework.util.CollectionUtils; + +/** + * In order to pass router context for {@link com.tencent.cloud.polaris.router.PolarisLoadBalancerCompositeRule}. + * + *@author lepdou 2022-05-16 + */ +public class PolarisFeignLoadBalancer extends FeignLoadBalancer { + + public PolarisFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) { + super(lb, clientConfig, serverIntrospector); + } + + @Override + protected void customizeLoadBalancerCommandBuilder(RibbonRequest request, IClientConfig config, + LoadBalancerCommand.Builder builder) { + Map> headers = request.getRequest().headers(); + Collection labelHeaderValues = headers.get(RouterConstants.ROUTER_LABEL_HEADER); + + if (CollectionUtils.isEmpty(labelHeaderValues)) { + builder.withServerLocator(null); + return; + } + + PolarisRouterContext routerContext = new PolarisRouterContext(); + + labelHeaderValues.forEach(labelHeaderValue -> { + Map labels = JacksonUtils.deserialize2Map(labelHeaderValue); + if (!CollectionUtils.isEmpty(labels)) { + routerContext.setLabels(labels); + } + }); + + builder.withServerLocator(routerContext); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java new file mode 100644 index 000000000..47d4cc1fe --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java @@ -0,0 +1,88 @@ +/* + * 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.feign; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.router.RouterConstants; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import feign.RequestInterceptor; +import feign.RequestTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.core.Ordered; +import org.springframework.util.CollectionUtils; + +/** + * Resolver labels from request. + * + *@author lepdou 2022-05-12 + */ +public class RouterLabelInterceptor implements RequestInterceptor, Ordered { + private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelInterceptor.class); + + private final RouterLabelResolver resolver; + private final MetadataLocalProperties metadataLocalProperties; + + public RouterLabelInterceptor(RouterLabelResolver resolver, + MetadataLocalProperties metadataLocalProperties) { + this.resolver = resolver; + this.metadataLocalProperties = metadataLocalProperties; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public void apply(RequestTemplate requestTemplate) { + Map labels = new HashMap<>(); + + // labels from downstream + Map transitiveLabels = MetadataContextHolder.get() + .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + labels.putAll(transitiveLabels); + + // labels from request + if (resolver != null) { + try { + Map customResolvedLabels = resolver.resolve(requestTemplate); + if (!CollectionUtils.isEmpty(customResolvedLabels)) { + labels.putAll(customResolvedLabels); + } + } + catch (Throwable t) { + LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t); + } + } + + //local service labels + labels.putAll(metadataLocalProperties.getContent()); + + // pass label by header + requestTemplate.header(RouterConstants.ROUTER_LABEL_HEADER, JacksonUtils.serialize2Json(labels)); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java new file mode 100644 index 000000000..bdee51767 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.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.resttemplate; + +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; + +/** + * Replace LoadBalancerInterceptor with PolarisLoadBalancerInterceptor. + * PolarisLoadBalancerInterceptor can pass routing context information. + * + *@author lepdou 2022-05-18 + */ +public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { + + private BeanFactory factory; + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.factory = beanFactory; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof LoadBalancerInterceptor) { + LoadBalancerRequestFactory requestFactory = this.factory.getBean(LoadBalancerRequestFactory.class); + LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class); + RouterLabelResolver routerLabelResolver = this.factory.getBean(RouterLabelResolver.class); + MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class); + + return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory, + routerLabelResolver, metadataLocalProperties); + } + return bean; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java new file mode 100644 index 000000000..53c2a3401 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java @@ -0,0 +1,120 @@ +/* + * 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.resttemplate; + +import java.io.IOException; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; +import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor capabilities. + * Parses the label from the request and puts it into the RouterContext for routing. + * + *@author lepdou 2022-05-18 + */ +public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { + private static final Logger LOGGER = LoggerFactory.getLogger(PolarisLoadBalancerInterceptor.class); + + private final LoadBalancerClient loadBalancer; + private final LoadBalancerRequestFactory requestFactory; + private final RouterLabelResolver resolver; + private final MetadataLocalProperties metadataLocalProperties; + + private final boolean isRibbonLoadBalanceClient; + + public PolarisLoadBalancerInterceptor(LoadBalancerClient loadBalancer, + LoadBalancerRequestFactory requestFactory, + RouterLabelResolver resolver, + MetadataLocalProperties metadataLocalProperties) { + super(loadBalancer, requestFactory); + this.loadBalancer = loadBalancer; + this.requestFactory = requestFactory; + this.resolver = resolver; + this.metadataLocalProperties = metadataLocalProperties; + + this.isRibbonLoadBalanceClient = loadBalancer instanceof RibbonLoadBalancerClient; + } + + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + final URI originalUri = request.getURI(); + String serviceName = originalUri.getHost(); + Assert.state(serviceName != null, + "Request URI does not contain a valid hostname: " + originalUri); + + if (isRibbonLoadBalanceClient) { + PolarisRouterContext routerContext = genRouterContext(request, body); + + return ((RibbonLoadBalancerClient) loadBalancer).execute(serviceName, + this.requestFactory.createRequest(request, body, execution), routerContext); + } + + return this.loadBalancer.execute(serviceName, + this.requestFactory.createRequest(request, body, execution)); + } + + private PolarisRouterContext genRouterContext(HttpRequest request, byte[] body) { + Map labels = new HashMap<>(); + + // labels from downstream + Map transitiveLabels = MetadataContextHolder.get() + .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + labels.putAll(transitiveLabels); + + // labels from request + if (resolver != null) { + try { + Map customResolvedLabels = resolver.resolve(request, body); + if (!CollectionUtils.isEmpty(customResolvedLabels)) { + labels.putAll(customResolvedLabels); + } + } + catch (Throwable t) { + LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t); + } + } + + //local service labels + labels.putAll(metadataLocalProperties.getContent()); + + PolarisRouterContext routerContext = new PolarisRouterContext(); + routerContext.setLabels(labels); + + return routerContext; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java new file mode 100644 index 000000000..8b2f394d5 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.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.polaris.router.spi; + +import java.util.Map; + +import feign.RequestTemplate; + +import org.springframework.http.HttpRequest; + +/** + * The spi for resolving labels from request. + * + * @author lepdou 2022-05-11 + */ +public interface RouterLabelResolver { + + /** + * resolve labels from feign request. + * @param requestTemplate the feign request. + * @return resolved labels + */ + Map resolve(RequestTemplate requestTemplate); + + /** + * resolve labels from rest template request. + * @param request the rest template request. + * @param body the rest template request body. + * @return resolved labels + */ + Map resolve(HttpRequest request, byte[] body); +} 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 new file mode 100644 index 000000000..d33dcea7f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.polaris.router.config.RouterAutoConfiguration 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 584465ff9..f98ea308a 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 @@ -34,6 +34,10 @@ import org.springframework.util.StringUtils; */ public class MetadataContext { + /** + * transitive context. + */ + public static final String FRAGMENT_TRANSITIVE = "transitive"; /** * Namespace of local instance. */ @@ -44,6 +48,9 @@ public class MetadataContext { */ public static String LOCAL_SERVICE; + + private final Map> fragmentContexts; + static { String namespace = ApplicationContextAwareUtils .getProperties("spring.cloud.polaris.namespace"); @@ -63,35 +70,44 @@ public class MetadataContext { LOCAL_SERVICE = serviceName; } - /** - * Transitive custom metadata content. - */ - private final Map transitiveCustomMetadata; - public MetadataContext() { - this.transitiveCustomMetadata = new ConcurrentHashMap<>(); + this.fragmentContexts = new ConcurrentHashMap<>(); } - public Map getAllTransitiveCustomMetadata() { - return Collections.unmodifiableMap(this.transitiveCustomMetadata); + + public Map getFragmentContext(String fragment) { + Map fragmentContext = fragmentContexts.get(fragment); + if (fragmentContext == null) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(fragmentContext); } - public String getTransitiveCustomMetadata(String key) { - return this.transitiveCustomMetadata.get(key); + public String getContext(String fragment, String key) { + Map fragmentContext = fragmentContexts.get(fragment); + if (fragmentContext == null) { + return null; + } + return fragmentContext.get(key); } - public void putTransitiveCustomMetadata(String key, String value) { - this.transitiveCustomMetadata.put(key, value); + 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); } - public void putAllTransitiveCustomMetadata(Map customMetadata) { - this.transitiveCustomMetadata.putAll(customMetadata); + public void putFragmentContext(String fragment, Map context) { + fragmentContexts.put(fragment, context); } @Override public String toString() { - return "MetadataContext{" + "transitiveCustomMetadata=" - + JacksonUtils.serialize2Json(transitiveCustomMetadata) + '}'; + 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 3ec3eb7fc..d12dd79e2 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 @@ -13,6 +13,7 @@ * 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.metadata; @@ -57,7 +58,7 @@ public final class MetadataContextHolder { Map transitiveMetadataMap = getTransitiveMetadataMap( metadataLocalProperties.getContent(), metadataLocalProperties.getTransitive()); - metadataContext.putAllTransitiveCustomMetadata(transitiveMetadataMap); + metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, transitiveMetadataMap); METADATA_CONTEXT.set(metadataContext); } @@ -100,7 +101,7 @@ public final class MetadataContextHolder { // Save to ThreadLocal. if (!CollectionUtils.isEmpty(customMetadataMap)) { - metadataContext.putAllTransitiveCustomMetadata(customMetadataMap); + metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, customMetadataMap); } MetadataContextHolder.set(metadataContext); } 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 0fbcf36ab..39375d753 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 @@ -13,6 +13,7 @@ * 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.metadata; @@ -45,10 +46,10 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "2"); MetadataContext metadataContext = MetadataContextHolder.get(); - metadataContext.putAllTransitiveCustomMetadata(customMetadata); + metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, customMetadata); MetadataContextHolder.set(metadataContext); - customMetadata = MetadataContextHolder.get().getAllTransitiveCustomMetadata(); + customMetadata = MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("2"); @@ -60,7 +61,7 @@ public class MetadataContextHolderTest { customMetadata.put("c", "3"); MetadataContextHolder.init(customMetadata); metadataContext = MetadataContextHolder.get(); - customMetadata = metadataContext.getAllTransitiveCustomMetadata(); + customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("22"); Assertions.assertThat(customMetadata.get("c")).isEqualTo("3"); diff --git a/spring-cloud-tencent-examples/polaris-config-example/README-zh.md b/spring-cloud-tencent-examples/polaris-config-example/README-zh.md index f4c12aec3..f131d319e 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/README-zh.md +++ b/spring-cloud-tencent-examples/polaris-config-example/README-zh.md @@ -13,7 +13,7 @@ spring: polaris: namespace: dev config: - address: grpc://9.134.122.18:8093 # the address of polaris config server + address: grpc://127.0.0.1:8093 # the address of polaris config server auto-refresh: true # auto refresh when config file changed groups: - name: ${spring.application.name} # group name diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java index f02f1887d..925031a7b 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java @@ -22,7 +22,8 @@ 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.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -44,10 +45,10 @@ public class RouterCalleeController { * Get information of callee. * @return information of callee */ - @GetMapping("/info") - public String info() { + @PostMapping("/info") + public String info(String name, @RequestBody User user) { LOG.info("Discovery Service Callee [{}] is called.", port); - return String.format("Discovery Service Callee [%s] is called.", port); + return String.format("Discovery Service Callee [%s] is called. user = %s", port, user); } } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisLoadBalanceRule.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/User.java similarity index 55% rename from spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisLoadBalanceRule.java rename to spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/User.java index 4831e76e6..ff83552db 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisLoadBalanceRule.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service1/src/main/java/com/tencent/cloud/polaris/router/example/User.java @@ -13,40 +13,41 @@ * 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.loadbalancer.rule; - -import java.util.Arrays; +package com.tencent.cloud.polaris.router.example; /** - * Load balance rule. - * - * @author Haotian Zhang + * demo object. + * @author lepdou 2022-05-12 */ -public enum PolarisLoadBalanceRule { +public class User { - /** - * Weighted random load balance rule. - */ - WEIGHTED_RANDOM_RULE("weighted_random"); + private String name; + private int age; - /** - * Load balance strategy. - */ - final String policy; + public String getName() { + return name; + } - PolarisLoadBalanceRule(String strategy) { - this.policy = strategy; + public void setName(String name) { + this.name = name; } - public static PolarisLoadBalanceRule fromStrategy(String strategy) { - return Arrays.stream(values()).filter(t -> t.getPolicy().equals(strategy)) - .findAny().orElse(WEIGHTED_RANDOM_RULE); + public int getAge() { + return age; } - public String getPolicy() { - return policy; + public void setAge(int age) { + this.age = age; } + @Override + public String toString() { + return "User{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } } diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java index f02f1887d..b3e365ab8 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeController.java @@ -22,8 +22,10 @@ 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.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** @@ -44,10 +46,10 @@ public class RouterCalleeController { * Get information of callee. * @return information of callee */ - @GetMapping("/info") - public String info() { + @PostMapping("/info") + public String info(@RequestParam("name") String name, @RequestBody User user) { LOG.info("Discovery Service Callee [{}] is called.", port); - return String.format("Discovery Service Callee [%s] is called.", port); + return String.format("Discovery Service Callee [%s] is called. user = %s", port, user); } } diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/User.java b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/User.java new file mode 100644 index 000000000..ff83552db --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-example/router-callee-service2/src/main/java/com/tencent/cloud/polaris/router/example/User.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.polaris.router.example; + +/** + * demo object. + * @author lepdou 2022-05-12 + */ +public class User { + + private String name; + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "User{" + + "name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/pom.xml b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/pom.xml index 8a1af3407..fbdbf7081 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/pom.xml +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/pom.xml @@ -22,6 +22,12 @@ com.tencent.cloud spring-cloud-starter-tencent-polaris-router + + + com.google.code.gson + gson + 2.9.0 + diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java new file mode 100644 index 000000000..0eb90aa69 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.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.example; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.Gson; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import feign.RequestTemplate; + +import org.springframework.http.HttpRequest; +import org.springframework.stereotype.Component; + +/** + * + * Customize the business tag information obtained from the request + * + *@author lepdou 2022-05-12 + */ +@Component +public class CustomRouterLabelResolver implements RouterLabelResolver { + private final Gson gson = new Gson(); + + @Override + public Map resolve(RequestTemplate requestTemplate) { + Map labels = new HashMap<>(); + + User user = gson.fromJson(new String(requestTemplate.body()), User.class); + + labels.put("user", user.getName()); + + return labels; + } + + @Override + public Map resolve(HttpRequest request, byte[] body) { + Map labels = new HashMap<>(); + User user = gson.fromJson(new String(body), User.class); + + labels.put("user", user.getName()); + return labels; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeService.java b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeService.java index 52439e3e5..7f1f1db39 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeService.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCalleeService.java @@ -19,7 +19,9 @@ package com.tencent.cloud.polaris.router.example; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; /** * Router callee feign client. @@ -29,7 +31,7 @@ import org.springframework.web.bind.annotation.GetMapping; @FeignClient("RouterCalleeService") public interface RouterCalleeService { - @GetMapping("/router/service/callee/info") - String info(); + @PostMapping("/router/service/callee/info") + String info(@RequestParam("name") String name, @RequestBody User user); } diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCallerController.java b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCallerController.java index 13b4ed4b7..866069d24 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCallerController.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/RouterCallerController.java @@ -21,6 +21,7 @@ package com.tencent.cloud.polaris.router.example; import org.springframework.beans.factory.annotation.Autowired; 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; @@ -44,8 +45,11 @@ public class RouterCallerController { * @return info */ @GetMapping("/feign") - public String feign() { - return routerCalleeService.info(); + public String feign(@RequestParam String name) { + User user = new User(); + user.setName(name); + user.setAge(18); + return routerCalleeService.info(name, user); } /** @@ -53,10 +57,12 @@ public class RouterCallerController { * @return information of callee */ @GetMapping("/rest") - public String rest() { - return restTemplate.getForObject( - "http://DiscoveryCalleeService/discovery/service/callee/info", - String.class); + public String rest(@RequestParam String name) { + User user = new User(); + user.setName(name); + user.setAge(18); + return restTemplate.postForObject( + "http://RouterCalleeService/router/service/callee/info?name={name}", user, String.class, name); } /** diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/User.java b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/User.java new file mode 100644 index 000000000..f68c6fff4 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/User.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.polaris.router.example; + +/** + * demo object. + * @author lepdou 2022-05-12 + */ +public class User { + + private String name; + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/resources/bootstrap.yml index ff1b89568..b30d1ff9b 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/resources/bootstrap.yml @@ -4,6 +4,10 @@ spring: application: name: RouterCallerService cloud: + tencent: + metadata: + content: + k1: v1 polaris: address: grpc://127.0.0.1:8091 namespace: default diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/LoadBalancerUtils.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/LoadBalancerUtils.java new file mode 100644 index 000000000..d7295447e --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/LoadBalancerUtils.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.polaris.loadbalancer; + +import java.util.ArrayList; +import java.util.List; + +import com.netflix.loadbalancer.Server; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.pojo.PolarisServer; +import com.tencent.polaris.api.pojo.DefaultServiceInstances; +import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.pojo.ServiceInstances; +import com.tencent.polaris.api.pojo.ServiceKey; + +/** + * load balancer utils. + * + *@author lepdou 2022-05-17 + */ +public class LoadBalancerUtils { + + public static ServiceInstances transferServersToServiceInstances(List servers) { + List instances = new ArrayList<>(servers.size()); + String serviceName = null; + + for (Server server : servers) { + if (server instanceof PolarisServer) { + Instance instance = ((PolarisServer) server).getInstance(); + instances.add(instance); + + if (serviceName == null) { + serviceName = instance.getService(); + } + } + } + + ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceName); + + return new DefaultServiceInstances(serviceKey, instances); + } +} 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 574a42610..2bc371b9d 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 @@ -13,14 +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.polaris.loadbalancer; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedList; import java.util.List; -import java.util.Map; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.DynamicServerListLoadBalancer; @@ -31,21 +32,16 @@ import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.tencent.cloud.common.constant.ContextConstant; import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultServiceInstances; import com.tencent.polaris.api.pojo.Instance; -import com.tencent.polaris.api.pojo.ServiceInfo; import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.api.rpc.GetAllInstancesRequest; +import com.tencent.polaris.api.rpc.GetHealthyInstancesRequest; import com.tencent.polaris.api.rpc.InstancesResponse; -import com.tencent.polaris.router.api.core.RouterAPI; -import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; -import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; @@ -56,16 +52,13 @@ import org.apache.commons.lang.StringUtils; */ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { - private final RouterAPI routerAPI; - - private ConsumerAPI consumerAPI; + private final ConsumerAPI consumerAPI; - private PolarisLoadBalancerProperties polarisLoadBalancerProperties; + private final PolarisLoadBalancerProperties polarisLoadBalancerProperties; public PolarisLoadBalancer(IClientConfig config, IRule rule, IPing ping, ServerList serverList, - RouterAPI routerAPI, ConsumerAPI consumerAPI, PolarisLoadBalancerProperties properties) { + ConsumerAPI consumerAPI, PolarisLoadBalancerProperties properties) { super(config, rule, ping, serverList, null, new PollingServerListUpdater()); - this.routerAPI = routerAPI; this.consumerAPI = consumerAPI; this.polarisLoadBalancerProperties = properties; } @@ -79,31 +72,17 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { else { serviceInstances = getExtendDiscoveryServiceInstances(); } + if (serviceInstances == null || CollectionUtils.isEmpty(serviceInstances.getInstances())) { return Collections.emptyList(); } - ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest(); - processRoutersRequest.setDstInstances(serviceInstances); - String srcNamespace = MetadataContext.LOCAL_NAMESPACE; - String srcService = MetadataContext.LOCAL_SERVICE; - Map transitiveCustomMetadata = MetadataContextHolder.get() - .getAllTransitiveCustomMetadata(); - if (StringUtils.isNotBlank(srcNamespace) && StringUtils.isNotBlank(srcService)) { - ServiceInfo serviceInfo = new ServiceInfo(); - serviceInfo.setNamespace(srcNamespace); - serviceInfo.setService(srcService); - serviceInfo.setMetadata(transitiveCustomMetadata); - processRoutersRequest.setSourceService(serviceInfo); - } - ProcessRoutersResponse processRoutersResponse = routerAPI - .processRouters(processRoutersRequest); - ServiceInstances filteredServiceInstances = processRoutersResponse - .getServiceInstances(); - List filteredInstances = new ArrayList<>(); - for (Instance instance : filteredServiceInstances.getInstances()) { - filteredInstances.add(new PolarisServer(serviceInstances, instance)); + + List servers = new LinkedList<>(); + for (Instance instance : serviceInstances.getInstances()) { + servers.add(new PolarisServer(serviceInstances, instance)); } - return filteredInstances; + + return servers; } private ServiceInstances getPolarisDiscoveryServiceInstances() { @@ -151,10 +130,10 @@ public class PolarisLoadBalancer extends DynamicServerListLoadBalancer { * @return list of instances */ public InstancesResponse getAllInstances(String namespace, String serviceName) { - GetAllInstancesRequest request = new GetAllInstancesRequest(); + GetHealthyInstancesRequest request = new GetHealthyInstancesRequest(); request.setNamespace(namespace); request.setService(serviceName); - return consumerAPI.getAllInstance(request); + return consumerAPI.getHealthyInstancesInstance(request); } } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisWeightedRandomRule.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRule.java similarity index 53% rename from spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisWeightedRandomRule.java rename to spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRule.java index 055f4bab3..124085717 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/rule/PolarisWeightedRandomRule.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRule.java @@ -16,86 +16,57 @@ * */ -package com.tencent.cloud.polaris.loadbalancer.rule; +package com.tencent.cloud.polaris.loadbalancer; -import java.util.ArrayList; import java.util.List; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.Server; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.polaris.api.config.consumer.LoadBalanceConfig; -import com.tencent.polaris.api.pojo.DefaultServiceInstances; import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.ServiceInstances; -import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.router.api.core.RouterAPI; import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest; import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; /** - * Weighted random load balance strategy. + * Polaris weighted load balancer. * - * @author Haotian Zhang + *@author lepdou 2022-05-17 */ -public class PolarisWeightedRandomRule extends AbstractLoadBalancerRule { +public class PolarisWeightedRule extends AbstractLoadBalancerRule { - private static final String POLICY = LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM; + private final RouterAPI routerAPI; - @Autowired - private RouterAPI polarisRouter; + public PolarisWeightedRule(RouterAPI routerAPI) { + this.routerAPI = routerAPI; + } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { - } @Override public Server choose(Object key) { - // 1. filter by router - List serversAfterRouter = getLoadBalancer().getReachableServers(); - if (CollectionUtils.isEmpty(serversAfterRouter)) { + List servers = getLoadBalancer().getReachableServers(); + if (CollectionUtils.isEmpty(servers)) { return null; } - ServiceInstances serviceInstances = transferServersToServiceInstances( - serversAfterRouter); + ServiceInstances serviceInstances = LoadBalancerUtils.transferServersToServiceInstances(servers); - // 2. filter by load balance ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest(); request.setDstInstances(serviceInstances); - request.setLbPolicy(POLICY); - ProcessLoadBalanceResponse processLoadBalanceResponse = polarisRouter - .processLoadBalance(request); - Instance targetInstance = processLoadBalanceResponse.getTargetInstance(); - - return new PolarisServer(serviceInstances, targetInstance); - } + request.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM); - ServiceInstances transferServersToServiceInstances(List servers) { - List instances = new ArrayList<>(servers.size()); - String serviceName = null; + ProcessLoadBalanceResponse processLoadBalanceResponse = routerAPI.processLoadBalance(request); - for (Server server : servers) { - if (server instanceof PolarisServer) { - Instance instance = ((PolarisServer) server).getInstance(); - instances.add(instance); - - if (serviceName == null) { - serviceName = instance.getService(); - } - } - } - - ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, - serviceName); + Instance targetInstance = processLoadBalanceResponse.getTargetInstance(); - return new DefaultServiceInstances(serviceKey, instances); + return new PolarisServer(serviceInstances, targetInstance); } - } 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 0b8b0583c..6774b5487 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 @@ -24,7 +24,6 @@ import com.tencent.polaris.factory.api.RouterAPIFactory; import com.tencent.polaris.router.api.core.RouterAPI; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; @@ -46,15 +45,12 @@ import org.springframework.context.annotation.Configuration; public class PolarisLoadBalancerAutoConfiguration { @Bean - @ConditionalOnMissingBean public PolarisLoadBalancerProperties polarisLoadBalancerProperties() { return new PolarisLoadBalancerProperties(); } - @Bean(name = "polarisRoute") - @ConditionalOnMissingBean - public RouterAPI polarisRouter(SDKContext polarisContext) throws PolarisException { + @Bean + public RouterAPI routerAPI(SDKContext polarisContext) throws PolarisException { return RouterAPIFactory.createRouterAPIByContext(polarisContext); } - } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerProperties.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerProperties.java index 22760e463..9d4d06059 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerProperties.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerProperties.java @@ -37,7 +37,7 @@ public class PolarisLoadBalancerProperties { /** * Load balance strategy. */ - private String strategy = "weightedRandom"; + private String strategy; /** * Type of discovery server. diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java index 3436a9ecb..3fbc2c76d 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java @@ -13,6 +13,7 @@ * 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.loadbalancer.config; @@ -25,9 +26,7 @@ import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerList; import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer; import com.tencent.polaris.api.core.ConsumerAPI; -import com.tencent.polaris.router.api.core.RouterAPI; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -39,25 +38,12 @@ import org.springframework.context.annotation.Configuration; @Configuration public class PolarisRibbonClientConfiguration { -// @Bean -// @ConditionalOnMissingBean -// public IRule polarisRibbonRule( -// PolarisLoadBalancerProperties polarisLoadBalancerProperties) { -// switch (PolarisLoadBalanceRule -// .fromStrategy(polarisLoadBalancerProperties.getStrategy())) { -// case WEIGHTED_RANDOM_RULE: -// default: -// return new PolarisWeightedRandomRule(); -// } -// } - @Bean - @ConditionalOnMissingBean public ILoadBalancer polarisLoadBalancer(IClientConfig iClientConfig, IRule iRule, - IPing iPing, ServerList serverList, RouterAPI polarisRouter, + IPing iPing, ServerList serverList, ConsumerAPI consumerAPI, PolarisLoadBalancerProperties polarisLoadBalancerProperties) { return new PolarisLoadBalancer(iClientConfig, iRule, iPing, serverList, - polarisRouter, consumerAPI, polarisLoadBalancerProperties); + consumerAPI, polarisLoadBalancerProperties); } } From eec74c11c292a1b1009b3369ae5fd9ef0f5cd113 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Thu, 19 May 2022 11:30:28 +0800 Subject: [PATCH 21/25] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9fee461ed..b6226bb07 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,12 @@ For example: - [Project Structure Overview](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) - [Participate in co-construction](https://github.com/Tencent/spring-cloud-tencent/wiki/Contributing) +## Chat Group + +Please scan the QR code to join the chat group. + + + ## License The spring-cloud-tencent is licensed under the BSD 3-Clause License. Copyright and license information can be found in the file [LICENSE](LICENSE) From d549d7e04403ed6620088fecb365de2913f704a6 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Thu, 19 May 2022 11:32:22 +0800 Subject: [PATCH 22/25] Update README-zh.md --- README-zh.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README-zh.md b/README-zh.md index 77e2cc475..2f42d8720 100644 --- a/README-zh.md +++ b/README-zh.md @@ -80,6 +80,13 @@ Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要 - [项目概览](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) - [参与共建](https://github.com/Tencent/spring-cloud-tencent/wiki/Contributing) +## 交流群 + +扫描下面的二维码加入 Spring Cloud Tencent 交流群。 + + + + ## License The spring-cloud-tencent is licensed under the BSD 3-Clause License. Copyright and license information can be found in the file [LICENSE](LICENSE) From c66b68e171954b4f8d4b97fa41fbae03e1d98505 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Thu, 19 May 2022 17:04:40 +0800 Subject: [PATCH 23/25] feat:update to 1.5.0-Hoxton.SR9-SNAPSHOT. (#188) --- CHANGELOG.md | 1 - changes/changes-1.4.4.md | 4 ++++ pom.xml | 2 +- ...arisRefreshApplicationReadyEventListener.java | 16 ++++++++++++++++ .../refresh/PolarisRefreshConfiguration.java | 16 ++++++++++++++++ .../PolarisServiceStatusChangeListener.java | 16 ++++++++++++++++ spring-cloud-tencent-dependencies/pom.xml | 2 +- 7 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 changes/changes-1.4.4.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa0ff740..06c1f8175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,3 @@ # Change Log --- -- [fix:fix wrong isAliveFlag config when creating new PolarisServer.](https://github.com/Tencent/spring-cloud-tencent/pull/179) diff --git a/changes/changes-1.4.4.md b/changes/changes-1.4.4.md new file mode 100644 index 000000000..1aa0ff740 --- /dev/null +++ b/changes/changes-1.4.4.md @@ -0,0 +1,4 @@ +# Change Log +--- + +- [fix:fix wrong isAliveFlag config when creating new PolarisServer.](https://github.com/Tencent/spring-cloud-tencent/pull/179) diff --git a/pom.xml b/pom.xml index d531541f5..b7489edde 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ - 1.4.4-Hoxton.SR9 + 1.5.0-Hoxton.SR9-SNAPSHOT Hoxton.SR9 diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java index 831573893..d80accc57 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshApplicationReadyEventListener.java @@ -1,3 +1,19 @@ +/* + * 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.discovery.refresh; import java.util.concurrent.Executors; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java index fe723bda7..acbe54b7a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisRefreshConfiguration.java @@ -1,3 +1,19 @@ +/* + * 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.discovery.refresh; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java index ccbc32e61..c923295d5 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java @@ -1,3 +1,19 @@ +/* + * 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.discovery.refresh; import java.util.Set; diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 205ff1186..02465fb0a 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.4.4-Hoxton.SR9 + 1.5.0-Hoxton.SR9-SNAPSHOT 1.5.2 2.0.0 From 83338d7b1d8e648a38f6303b0746a50fc2c27295 Mon Sep 17 00:00:00 2001 From: lepdou Date: Thu, 19 May 2022 20:39:06 +0800 Subject: [PATCH 24/25] support parse ratelimit rule expression labels --- CHANGELOG.md | 2 +- changes/changes-1.4.4.md | 4 + .../ratelimit/RateLimitRuleLabelResolver.java | 72 +++++++ .../config/RateLimitConfiguration.java | 17 +- .../filter/QuotaCheckReactiveFilter.java | 73 ++++--- .../filter/QuotaCheckServletFilter.java | 84 +++++--- .../common/util/ExpressionLabelUtils.java | 187 ++++++++++++++++++ .../PolarisContextAutoConfiguration.java | 4 + .../polaris/context/ServiceRuleManager.java | 114 +++++++++++ 9 files changed, 497 insertions(+), 60 deletions(-) create mode 100644 changes/changes-1.4.4.md create mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa0ff740..8954bd05b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ # Change Log --- -- [fix:fix wrong isAliveFlag config when creating new PolarisServer.](https://github.com/Tencent/spring-cloud-tencent/pull/179) +- [Feature: Support parse ratelimit rule expression labels.](https://github.com/Tencent/spring-cloud-tencent/pull/182) diff --git a/changes/changes-1.4.4.md b/changes/changes-1.4.4.md new file mode 100644 index 000000000..1aa0ff740 --- /dev/null +++ b/changes/changes-1.4.4.md @@ -0,0 +1,4 @@ +# Change Log +--- + +- [fix:fix wrong isAliveFlag config when creating new PolarisServer.](https://github.com/Tencent/spring-cloud-tencent/pull/179) diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java new file mode 100644 index 000000000..4c29cb3ad --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java @@ -0,0 +1,72 @@ +/* + * 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.ratelimit; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.polaris.client.pb.ModelProto; +import com.tencent.polaris.client.pb.RateLimitProto; + +import org.springframework.util.CollectionUtils; + +/** + * resolve labels from rate limit rule. + * + *@author lepdou 2022-05-13 + */ +public class RateLimitRuleLabelResolver { + + private final ServiceRuleManager serviceRuleManager; + + public RateLimitRuleLabelResolver(ServiceRuleManager serviceRuleManager) { + this.serviceRuleManager = serviceRuleManager; + } + + public Set getExpressionLabelKeys(String namespace, String service) { + RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service); + if (rateLimitRule == null) { + return Collections.emptySet(); + } + + List rules = rateLimitRule.getRulesList(); + if (CollectionUtils.isEmpty(rules)) { + return Collections.emptySet(); + } + + Set expressionLabels = new HashSet<>(); + for (RateLimitProto.Rule rule : rules) { + Map labels = rule.getLabelsMap(); + if (CollectionUtils.isEmpty(labels)) { + return Collections.emptySet(); + } + for (String key : labels.keySet()) { + if (ExpressionLabelUtils.isExpressionLabel(key)) { + expressionLabels.add(key); + } + } + } + return expressionLabels; + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java index cf4d33a91..bf912674d 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfiguration.java @@ -19,6 +19,8 @@ package com.tencent.cloud.polaris.ratelimit.config; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; @@ -62,6 +64,11 @@ public class RateLimitConfiguration { return LimitAPIFactory.createLimitAPIByContext(polarisContext); } + @Bean + public RateLimitRuleLabelResolver rateLimitRuleLabelService(ServiceRuleManager serviceRuleManager) { + return new RateLimitRuleLabelResolver(serviceRuleManager); + } + /** * Create when web application type is SERVLET. */ @@ -73,9 +80,10 @@ public class RateLimitConfiguration { @ConditionalOnMissingBean public QuotaCheckServletFilter quotaCheckFilter(LimitAPI limitAPI, @Nullable PolarisRateLimiterLabelServletResolver labelResolver, - PolarisRateLimitProperties polarisRateLimitProperties) { + PolarisRateLimitProperties polarisRateLimitProperties, + RateLimitRuleLabelResolver rateLimitRuleLabelResolver) { return new QuotaCheckServletFilter(limitAPI, labelResolver, - polarisRateLimitProperties); + polarisRateLimitProperties, rateLimitRuleLabelResolver); } @Bean @@ -101,9 +109,10 @@ public class RateLimitConfiguration { @Bean public QuotaCheckReactiveFilter quotaCheckReactiveFilter(LimitAPI limitAPI, @Nullable PolarisRateLimiterLabelReactiveResolver labelResolver, - PolarisRateLimitProperties polarisRateLimitProperties) { + PolarisRateLimitProperties polarisRateLimitProperties, + RateLimitRuleLabelResolver rateLimitRuleLabelResolver) { return new QuotaCheckReactiveFilter(limitAPI, labelResolver, - polarisRateLimitProperties); + polarisRateLimitProperties, rateLimitRuleLabelResolver); } } 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 9a0db9a77..d9b8d3389 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 @@ -21,10 +21,14 @@ package com.tencent.cloud.polaris.ratelimit.filter; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.Set; import javax.annotation.PostConstruct; +import com.google.common.collect.Maps; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; @@ -42,7 +46,6 @@ import org.springframework.core.Ordered; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; @@ -52,7 +55,7 @@ import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.LAB /** * Reactive filter to check quota. * - * @author Haotian Zhang + * @author Haotian Zhang, lepdou */ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { @@ -65,14 +68,18 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { private final PolarisRateLimitProperties polarisRateLimitProperties; + private final RateLimitRuleLabelResolver rateLimitRuleLabelResolver; + private String rejectTips; public QuotaCheckReactiveFilter(LimitAPI limitAPI, PolarisRateLimiterLabelReactiveResolver labelResolver, - PolarisRateLimitProperties polarisRateLimitProperties) { + PolarisRateLimitProperties polarisRateLimitProperties, + RateLimitRuleLabelResolver rateLimitRuleLabelResolver) { this.limitAPI = limitAPI; this.labelResolver = labelResolver; this.polarisRateLimitProperties = polarisRateLimitProperties; + this.rateLimitRuleLabelResolver = rateLimitRuleLabelResolver; } @PostConstruct @@ -90,27 +97,7 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; - Map labels = new HashMap<>(); - - // add build in labels - String path = exchange.getRequest().getURI().getPath(); - if (StringUtils.isNotBlank(path)) { - labels.put(LABEL_METHOD, path); - } - - // add custom labels - if (labelResolver != null) { - try { - Map customLabels = labelResolver.resolve(exchange); - if (!CollectionUtils.isEmpty(customLabels)) { - labels.putAll(customLabels); - } - } - catch (Throwable e) { - LOG.error("resolve custom label failed. resolver = {}", - labelResolver.getClass().getName(), e); - } - } + Map labels = getRequestLabels(exchange, localNamespace, localService); try { QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, @@ -134,4 +121,42 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { return chain.filter(exchange); } + private Map getRequestLabels(ServerWebExchange exchange, String localNamespace, String localService) { + Map labels = new HashMap<>(); + + // add build in labels + String path = exchange.getRequest().getURI().getPath(); + if (StringUtils.isNotBlank(path)) { + labels.put(LABEL_METHOD, path); + } + + // add rule expression labels + Map expressionLabels = getRuleExpressionLabels(exchange, localNamespace, localService); + labels.putAll(expressionLabels); + + // add custom labels + Map customResolvedLabels = getCustomResolvedLabels(exchange); + labels.putAll(customResolvedLabels); + + return labels; + } + + private Map getCustomResolvedLabels(ServerWebExchange exchange) { + if (labelResolver != null) { + try { + return labelResolver.resolve(exchange); + } + catch (Throwable e) { + LOG.error("resolve custom label failed. resolver = {}", + labelResolver.getClass().getName(), e); + } + } + return Maps.newHashMap(); + } + + private Map getRuleExpressionLabels(ServerWebExchange exchange, String namespace, String service) { + Set expressionLabels = rateLimitRuleLabelResolver.getExpressionLabelKeys(namespace, service); + return ExpressionLabelUtils.resolve(exchange, expressionLabels); + } + } 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 ae1601093..54a9e545f 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 @@ -19,8 +19,10 @@ package com.tencent.cloud.polaris.ratelimit.filter; import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import javax.annotation.PostConstruct; import javax.servlet.FilterChain; @@ -29,6 +31,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import com.tencent.cloud.polaris.ratelimit.RateLimitRuleLabelResolver; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; @@ -42,7 +46,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; -import org.springframework.util.CollectionUtils; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.LABEL_METHOD; @@ -50,13 +53,12 @@ import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.LAB /** * Servlet filter to check quota. * - * @author Haotian Zhang + * @author Haotian Zhang, lepdou */ @Order(RateLimitConstant.FILTER_ORDER) public class QuotaCheckServletFilter extends OncePerRequestFilter { - private static final Logger LOG = LoggerFactory - .getLogger(QuotaCheckServletFilter.class); + private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class); private final LimitAPI limitAPI; @@ -64,14 +66,18 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { private final PolarisRateLimitProperties polarisRateLimitProperties; + private final RateLimitRuleLabelResolver rateLimitRuleLabelResolver; + private String rejectTips; public QuotaCheckServletFilter(LimitAPI limitAPI, PolarisRateLimiterLabelServletResolver labelResolver, - PolarisRateLimitProperties polarisRateLimitProperties) { + PolarisRateLimitProperties polarisRateLimitProperties, + RateLimitRuleLabelResolver rateLimitRuleLabelResolver) { this.limitAPI = limitAPI; this.labelResolver = labelResolver; this.polarisRateLimitProperties = polarisRateLimitProperties; + this.rateLimitRuleLabelResolver = rateLimitRuleLabelResolver; } @PostConstruct @@ -80,52 +86,68 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { } @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; + Map labels = getRequestLabels(request, localNamespace, localService); + + try { + QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, + localNamespace, localService, 1, labels, null); + + if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { + response.setStatus(polarisRateLimitProperties.getRejectHttpCode()); + response.getWriter().write(rejectTips); + return; + } + + filterChain.doFilter(request, response); + } + catch (Throwable t) { + // An exception occurs in the rate limiting API call, + // which should not affect the call of the business process. + LOG.error("fail to invoke getQuota, service is " + localService, t); + filterChain.doFilter(request, response); + } + } + + private Map getRequestLabels(HttpServletRequest request, String localNamespace, String localService) { Map labels = new HashMap<>(); // add build in labels String path = request.getRequestURI(); - if (StringUtils.isNotBlank(path)) { labels.put(LABEL_METHOD, path); } - // add custom labels + // add rule expression labels + Map expressionLabels = getRuleExpressionLabels(request, localNamespace, localService); + labels.putAll(expressionLabels); + + // add custom resolved labels + Map customLabels = getCustomResolvedLabels(request); + labels.putAll(customLabels); + + return labels; + } + + private Map getCustomResolvedLabels(HttpServletRequest request) { if (labelResolver != null) { try { - Map customLabels = labelResolver.resolve(request); - if (!CollectionUtils.isEmpty(customLabels)) { - labels.putAll(customLabels); - } + return labelResolver.resolve(request); } catch (Throwable e) { LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e); } } - - try { - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, - localNamespace, localService, 1, labels, null); - if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { - response.setStatus(polarisRateLimitProperties.getRejectHttpCode()); - response.getWriter().write(rejectTips); - } - else { - filterChain.doFilter(request, response); - } - } - catch (Throwable t) { - // An exception occurs in the rate limiting API call, - // which should not affect the call of the business process. - LOG.error("fail to invoke getQuota, service is " + localService, t); - filterChain.doFilter(request, response); - } + return Collections.emptyMap(); } + private Map getRuleExpressionLabels(HttpServletRequest request, String namespace, String service) { + Set expressionLabels = rateLimitRuleLabelResolver.getExpressionLabelKeys(namespace, service); + return ExpressionLabelUtils.resolve(request, expressionLabels); + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java new file mode 100644 index 000000000..7e93fdb6a --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java @@ -0,0 +1,187 @@ +/* + * 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.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; + +import org.springframework.http.HttpCookie; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.CollectionUtils; +import org.springframework.util.MultiValueMap; +import org.springframework.web.server.ServerWebExchange; + +/** + * the utils for parse label expression. + * + *@author lepdou 2022-05-13 + */ +public class ExpressionLabelUtils { + + private static final String LABEL_HEADER_PREFIX = "${http.header."; + private static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length(); + private static final String LABEL_QUERY_PREFIX = "${http.query."; + private static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length(); + private static final String LABEL_COOKIE_PREFIX = "${http.cookie."; + private static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length(); + private static final String LABEL_METHOD = "${http.method}"; + private static final String LABEL_URI = "${http.uri}"; + + private static final String LABEL_SUFFIX = "}"; + + public static boolean isExpressionLabel(String labelKey) { + if (StringUtils.isEmpty(labelKey)) { + return false; + } + if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey) || + StringUtils.startsWithIgnoreCase(LABEL_URI, labelKey)) { + return true; + } + return (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX) || + StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX) || + StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) + && StringUtils.endsWith(labelKey, LABEL_SUFFIX); + } + + public static Map resolve(HttpServletRequest request, Set labelKeys) { + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + Map labels = new HashMap<>(); + + for (String labelKey : labelKeys) { + if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { + String headerKey = labelKey.substring(LABEL_HEADER_PREFIX_LEN, labelKey.length() - 1); + labels.put(labelKey, request.getHeader(headerKey)); + } + else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) { + String queryKey = labelKey.substring(LABEL_QUERY_PREFIX_LEN, labelKey.length() - 1); + labels.put(labelKey, getQueryValue(request.getQueryString(), queryKey)); + } + else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) { + String cookieKey = labelKey.substring(LABEL_COOKIE_PREFIX_LEN, labelKey.length() - 1); + labels.put(labelKey, getCookieValue(request.getCookies(), cookieKey)); + } + else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) { + labels.put(labelKey, request.getMethod()); + } + else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) { + labels.put(labelKey, request.getRequestURI()); + } + } + + return labels; + } + + public static Map resolve(ServerWebExchange exchange, Set labelKeys) { + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + Map labels = new HashMap<>(); + + for (String labelKey : labelKeys) { + if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { + String headerKey = labelKey.substring(LABEL_HEADER_PREFIX_LEN, labelKey.length() - 1); + labels.put(labelKey, getHeaderValue(exchange.getRequest(), headerKey)); + } + else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) { + String queryKey = labelKey.substring(LABEL_QUERY_PREFIX_LEN, labelKey.length() - 1); + labels.put(labelKey, getQueryValue(exchange.getRequest(), queryKey)); + } + else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) { + String cookieKey = labelKey.substring(LABEL_COOKIE_PREFIX_LEN, labelKey.length() - 1); + labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey)); + } + else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) { + labels.put(labelKey, exchange.getRequest().getMethodValue()); + } + else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) { + labels.put(labelKey, exchange.getRequest().getURI().getPath()); + } + } + + return labels; + } + + private static String getQueryValue(String queryString, String queryKey) { + if (StringUtils.isBlank(queryString)) { + return StringUtils.EMPTY; + } + String[] queries = StringUtils.split(queryString, "&"); + if (queries == null || queries.length == 0) { + return StringUtils.EMPTY; + } + for (String query : queries) { + String[] queryKV = StringUtils.split(query, "="); + if (queryKV != null && queryKV.length == 2 && StringUtils.equals(queryKV[0], queryKey)) { + return queryKV[1]; + } + } + return StringUtils.EMPTY; + } + + private static String getCookieValue(Cookie[] cookies, String key) { + if (cookies == null || cookies.length == 0) { + return StringUtils.EMPTY; + } + for (Cookie cookie : cookies) { + if (StringUtils.equals(cookie.getName(), key)) { + return cookie.getValue(); + } + } + return StringUtils.EMPTY; + } + + private static String getHeaderValue(ServerHttpRequest request, String key) { + String value = request.getHeaders().getFirst(key); + if (value == null) { + return StringUtils.EMPTY; + } + return value; + } + + private static String getQueryValue(ServerHttpRequest request, String key) { + MultiValueMap queries = request.getQueryParams(); + if (CollectionUtils.isEmpty(queries)) { + return StringUtils.EMPTY; + } + String value = queries.getFirst(key); + if (value == null) { + return StringUtils.EMPTY; + } + return value; + } + + private static String getCookieValue(ServerHttpRequest request, String key) { + HttpCookie cookie = request.getCookies().getFirst(key); + if (cookie == null) { + return StringUtils.EMPTY; + } + return cookie.getValue(); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisContextAutoConfiguration.java index 11e081287..db8424a34 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisContextAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisContextAutoConfiguration.java @@ -47,4 +47,8 @@ public class PolarisContextAutoConfiguration { return new ModifyAddress(); } + @Bean + public ServiceRuleManager serviceRuleManager(SDKContext sdkContext) { + return new ServiceRuleManager(sdkContext); + } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java new file mode 100644 index 000000000..a615c5c80 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.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.polaris.context; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.tencent.polaris.api.pojo.DefaultServiceEventKeysProvider; +import com.tencent.polaris.api.pojo.ServiceEventKey; +import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.api.pojo.ServiceRule; +import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.client.flow.BaseFlow; +import com.tencent.polaris.client.flow.DefaultFlowControlParam; +import com.tencent.polaris.client.flow.FlowControlParam; +import com.tencent.polaris.client.flow.ResourcesResponse; +import com.tencent.polaris.client.pb.RateLimitProto; +import com.tencent.polaris.client.pb.RoutingProto; + +/** + * the manager of service governance rules. for example: rate limit rule, router rules. + * + *@author lepdou 2022-05-13 + */ +public class ServiceRuleManager { + + private final SDKContext sdkContext; + + private final FlowControlParam controlParam; + + public ServiceRuleManager(SDKContext sdkContext) { + this.sdkContext = sdkContext; + controlParam = new DefaultFlowControlParam(); + controlParam.setTimeoutMs(sdkContext.getConfig().getGlobal().getAPI().getTimeout()); + controlParam.setMaxRetry(sdkContext.getConfig().getGlobal().getAPI().getMaxRetryTimes()); + controlParam.setRetryIntervalMs(sdkContext.getConfig().getGlobal().getAPI().getRetryInterval()); + } + + public RateLimitProto.RateLimit getServiceRateLimitRule(String namespace, String service) { + ServiceEventKey serviceEventKey = new ServiceEventKey(new ServiceKey(namespace, service), + ServiceEventKey.EventType.RATE_LIMITING); + + DefaultServiceEventKeysProvider svcKeysProvider = new DefaultServiceEventKeysProvider(); + svcKeysProvider.setSvcEventKey(serviceEventKey); + + ResourcesResponse resourcesResponse = BaseFlow + .syncGetResources(sdkContext.getExtensions(), true, svcKeysProvider, controlParam); + + ServiceRule serviceRule = resourcesResponse.getServiceRule(serviceEventKey); + if (serviceRule != null) { + Object rule = serviceRule.getRule(); + if (rule instanceof RateLimitProto.RateLimit) { + return (RateLimitProto.RateLimit) rule; + } + } + + return null; + } + + public List getServiceRouterRule(String namespace, String sourceService, String dstService) { + Set routerKeys = new HashSet<>(); + + ServiceEventKey dstSvcEventKey = new ServiceEventKey(new ServiceKey(namespace, dstService), + ServiceEventKey.EventType.ROUTING); + routerKeys.add(dstSvcEventKey); + + ServiceEventKey srcSvcEventKey = new ServiceEventKey(new ServiceKey(namespace, sourceService), + ServiceEventKey.EventType.ROUTING); + + DefaultServiceEventKeysProvider svcKeysProvider = new DefaultServiceEventKeysProvider(); + svcKeysProvider.setSvcEventKeys(routerKeys); + + + ResourcesResponse resourcesResponse = BaseFlow + .syncGetResources(sdkContext.getExtensions(), true, svcKeysProvider, controlParam); + + List rules = new ArrayList<>(); + ServiceRule sourceServiceRule = resourcesResponse.getServiceRule(srcSvcEventKey); + if (sourceServiceRule != null) { + Object rule = sourceServiceRule.getRule(); + if (rule instanceof RoutingProto.Routing) { + rules.add((RoutingProto.Routing) rule); + } + } + + ServiceRule dstServiceRule = resourcesResponse.getServiceRule(dstSvcEventKey); + if (dstServiceRule != null) { + Object rule = dstServiceRule.getRule(); + if (rule instanceof RoutingProto.Routing) { + rules.add((RoutingProto.Routing) rule); + } + } + + return rules; + } +} From d72cd884adca884ff6c43bc88c86f73a6c7a1d3d Mon Sep 17 00:00:00 2001 From: lepdou Date: Fri, 20 May 2022 14:43:43 +0800 Subject: [PATCH 25/25] feature: support router expression label --- CHANGELOG.md | 3 +- .../pom.xml | 7 + .../router/RouterRuleLabelResolver.java | 75 ++++++++ .../config/RouterAutoConfiguration.java | 12 +- .../feign/FeignExpressionLabelUtils.java | 81 ++++++++ .../feign/PolarisFeignLoadBalancer.java | 10 +- .../router/feign/RouterLabelInterceptor.java | 39 +++- .../PolarisLoadBalancerBeanPostProcessor.java | 4 +- .../PolarisLoadBalancerInterceptor.java | 37 +++- spring-cloud-tencent-commons/pom.xml | 12 ++ .../common/util/ExpressionLabelUtils.java | 178 +++++++++++++++--- .../polaris/context/ServiceRuleManager.java | 11 +- 12 files changed, 430 insertions(+), 39 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3f17d2d..0fd331294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,4 +3,5 @@ - [Feature: Support parse ratelimit rule expression labels.](https://github.com/Tencent/spring-cloud-tencent/pull/183) -- [fix:Router support request label.](https://github.com/Tencent/spring-cloud-tencent/pull/165) \ No newline at end of file +- [Feature: Router support request label.](https://github.com/Tencent/spring-cloud-tencent/pull/165) +- [Feature: Support router expression label](https://github.com/Tencent/spring-cloud-tencent/pull/190) diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 94a69d9bc..6f0fa315d 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -33,6 +33,13 @@ spring-cloud-starter-openfeign true + + + org.springframework.boot + spring-boot-starter-web + true + + diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.java new file mode 100644 index 000000000..5ab6e549f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolver.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.polaris.router; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.polaris.client.pb.ModelProto; +import com.tencent.polaris.client.pb.RoutingProto; + +import org.springframework.util.CollectionUtils; + +/** + * Resolve label expressions from routing rules. + * @author lepdou 2022-05-19 + */ +public class RouterRuleLabelResolver { + + private final ServiceRuleManager serviceRuleManager; + + public RouterRuleLabelResolver(ServiceRuleManager serviceRuleManager) { + this.serviceRuleManager = serviceRuleManager; + } + + public Set getExpressionLabelKeys(String namespace, String sourceService, String dstService) { + List rules = serviceRuleManager.getServiceRouterRule(namespace, sourceService, dstService); + + if (CollectionUtils.isEmpty(rules)) { + return Collections.emptySet(); + } + + Set expressionLabels = new HashSet<>(); + + for (RoutingProto.Route rule : rules) { + List sources = rule.getSourcesList(); + if (CollectionUtils.isEmpty(sources)) { + continue; + } + for (RoutingProto.Source source : sources) { + Map labels = source.getMetadataMap(); + if (CollectionUtils.isEmpty(labels)) { + continue; + } + for (String labelKey : labels.keySet()) { + if (ExpressionLabelUtils.isExpressionLabel(labelKey)) { + expressionLabels.add(labelKey); + } + } + } + } + + return expressionLabels; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java index 950638406..5065b09b5 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java @@ -19,6 +19,8 @@ package com.tencent.cloud.polaris.router.config; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; import com.tencent.cloud.polaris.router.feign.RouterLabelInterceptor; import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerBeanPostProcessor; @@ -44,8 +46,9 @@ public class RouterAutoConfiguration { @Bean public RouterLabelInterceptor routerLabelInterceptor(@Nullable RouterLabelResolver resolver, - MetadataLocalProperties metadataLocalProperties) { - return new RouterLabelInterceptor(resolver, metadataLocalProperties); + MetadataLocalProperties metadataLocalProperties, + RouterRuleLabelResolver routerRuleLabelResolver) { + return new RouterLabelInterceptor(resolver, metadataLocalProperties, routerRuleLabelResolver); } @Bean @@ -58,4 +61,9 @@ public class RouterAutoConfiguration { public PolarisLoadBalancerBeanPostProcessor polarisLoadBalancerBeanPostProcessor() { return new PolarisLoadBalancerBeanPostProcessor(); } + + @Bean + public RouterRuleLabelResolver routerRuleLabelResolver(ServiceRuleManager serviceRuleManager) { + return new RouterRuleLabelResolver(serviceRuleManager); + } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java new file mode 100644 index 000000000..cf4408d37 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java @@ -0,0 +1,81 @@ +/* + * 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.feign; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import feign.RequestTemplate; +import org.apache.commons.lang.StringUtils; + +import org.springframework.util.CollectionUtils; + +/** + * Resolve rule expression label from feign request. + * @author lepdou 2022-05-20 + */ +public class FeignExpressionLabelUtils { + + public static Map resolve(RequestTemplate request, Set labelKeys) { + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + Map labels = new HashMap<>(); + + for (String labelKey : labelKeys) { + if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_HEADER_PREFIX)) { + String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); + if (StringUtils.isBlank(headerKey)) { + continue; + } + labels.put(labelKey, getHeaderValue(request, headerKey)); + } + else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_QUERY_PREFIX)) { + String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); + if (StringUtils.isBlank(queryKey)) { + continue; + } + labels.put(labelKey, getQueryValue(request, queryKey)); + } + else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_METHOD, labelKey)) { + labels.put(labelKey, request.method()); + } + else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) { + labels.put(labelKey, request.request().url()); + } + } + + return labels; + } + + public static String getHeaderValue(RequestTemplate request, String key) { + Map> headers = request.headers(); + return ExpressionLabelUtils.getFirstValue(headers, key); + + } + + public static String getQueryValue(RequestTemplate request, String key) { + return ExpressionLabelUtils.getFirstValue(request.queries(), key); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java index d9ac98b04..067332dd6 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java @@ -19,11 +19,13 @@ package com.tencent.cloud.polaris.router.feign; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.reactive.LoadBalancerCommand; +import com.tencent.cloud.common.util.ExpressionLabelUtils; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.RouterConstants; @@ -59,7 +61,13 @@ public class PolarisFeignLoadBalancer extends FeignLoadBalancer { labelHeaderValues.forEach(labelHeaderValue -> { Map labels = JacksonUtils.deserialize2Map(labelHeaderValue); if (!CollectionUtils.isEmpty(labels)) { - routerContext.setLabels(labels); + Map unescapeLabels = new HashMap<>(labels.size()); + for (Map.Entry entry : labels.entrySet()) { + String escapedKey = ExpressionLabelUtils.unescape(entry.getKey()); + String escapedValue = ExpressionLabelUtils.unescape(entry.getValue()); + unescapeLabels.put(escapedKey, escapedValue); + } + routerContext.setLabels(unescapeLabels); } }); diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java index 47d4cc1fe..48c3fb667 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelInterceptor.java @@ -18,14 +18,18 @@ package com.tencent.cloud.polaris.router.feign; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ExpressionLabelUtils; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.polaris.router.RouterConstants; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import feign.RequestInterceptor; import feign.RequestTemplate; @@ -45,11 +49,14 @@ public class RouterLabelInterceptor implements RequestInterceptor, Ordered { private final RouterLabelResolver resolver; private final MetadataLocalProperties metadataLocalProperties; + private final RouterRuleLabelResolver routerRuleLabelResolver; public RouterLabelInterceptor(RouterLabelResolver resolver, - MetadataLocalProperties metadataLocalProperties) { + MetadataLocalProperties metadataLocalProperties, + RouterRuleLabelResolver routerRuleLabelResolver) { this.resolver = resolver; this.metadataLocalProperties = metadataLocalProperties; + this.routerRuleLabelResolver = routerRuleLabelResolver; } @Override @@ -79,10 +86,38 @@ public class RouterLabelInterceptor implements RequestInterceptor, Ordered { } } + // labels from rule expression + String peerServiceName = requestTemplate.feignTarget().name(); + Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, peerServiceName); + labels.putAll(ruleExpressionLabels); + + //local service labels labels.putAll(metadataLocalProperties.getContent()); + // Because when the label is placed in RequestTemplate.header, + // RequestTemplate will parse the header according to the regular, which conflicts with the expression. + // Avoid conflicts by escaping. + Map escapeLabels = new HashMap<>(labels.size()); + for (Map.Entry entry : labels.entrySet()) { + String escapedKey = ExpressionLabelUtils.escape(entry.getKey()); + String escapedValue = ExpressionLabelUtils.escape(entry.getValue()); + escapeLabels.put(escapedKey, escapedValue); + } + // pass label by header - requestTemplate.header(RouterConstants.ROUTER_LABEL_HEADER, JacksonUtils.serialize2Json(labels)); + requestTemplate.header(RouterConstants.ROUTER_LABEL_HEADER, JacksonUtils.serialize2Json(escapeLabels)); + } + + private Map getRuleExpressionLabels(RequestTemplate requestTemplate, String peerService) { + Set labelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, + MetadataContext.LOCAL_SERVICE, peerService); + + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + return FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys); } + } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java index bdee51767..6fe192003 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java @@ -19,6 +19,7 @@ package com.tencent.cloud.polaris.router.resttemplate; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import org.springframework.beans.BeansException; @@ -51,9 +52,10 @@ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class); RouterLabelResolver routerLabelResolver = this.factory.getBean(RouterLabelResolver.class); MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class); + RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class); return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory, - routerLabelResolver, metadataLocalProperties); + routerLabelResolver, metadataLocalProperties, routerRuleLabelResolver); } return bean; } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java index 53c2a3401..2e3e691f4 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java @@ -20,13 +20,17 @@ package com.tencent.cloud.polaris.router.resttemplate; import java.io.IOException; import java.net.URI; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ExpressionLabelUtils; import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,18 +58,21 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { private final LoadBalancerRequestFactory requestFactory; private final RouterLabelResolver resolver; private final MetadataLocalProperties metadataLocalProperties; + private final RouterRuleLabelResolver routerRuleLabelResolver; private final boolean isRibbonLoadBalanceClient; public PolarisLoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory, RouterLabelResolver resolver, - MetadataLocalProperties metadataLocalProperties) { + MetadataLocalProperties metadataLocalProperties, + RouterRuleLabelResolver routerRuleLabelResolver) { super(loadBalancer, requestFactory); this.loadBalancer = loadBalancer; this.requestFactory = requestFactory; this.resolver = resolver; this.metadataLocalProperties = metadataLocalProperties; + this.routerRuleLabelResolver = routerRuleLabelResolver; this.isRibbonLoadBalanceClient = loadBalancer instanceof RibbonLoadBalancerClient; } @@ -73,22 +80,22 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI(); - String serviceName = originalUri.getHost(); - Assert.state(serviceName != null, + String peerServiceName = originalUri.getHost(); + Assert.state(peerServiceName != null, "Request URI does not contain a valid hostname: " + originalUri); if (isRibbonLoadBalanceClient) { - PolarisRouterContext routerContext = genRouterContext(request, body); + PolarisRouterContext routerContext = genRouterContext(request, body, peerServiceName); - return ((RibbonLoadBalancerClient) loadBalancer).execute(serviceName, + return ((RibbonLoadBalancerClient) loadBalancer).execute(peerServiceName, this.requestFactory.createRequest(request, body, execution), routerContext); } - return this.loadBalancer.execute(serviceName, + return this.loadBalancer.execute(peerServiceName, this.requestFactory.createRequest(request, body, execution)); } - private PolarisRouterContext genRouterContext(HttpRequest request, byte[] body) { + private PolarisRouterContext genRouterContext(HttpRequest request, byte[] body, String peerServiceName) { Map labels = new HashMap<>(); // labels from downstream @@ -109,6 +116,11 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { } } + Map ruleExpressionLabels = getExpressionLabels(request, peerServiceName); + if (!CollectionUtils.isEmpty(ruleExpressionLabels)) { + labels.putAll(ruleExpressionLabels); + } + //local service labels labels.putAll(metadataLocalProperties.getContent()); @@ -117,4 +129,15 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { return routerContext; } + + private Map getExpressionLabels(HttpRequest request, String peerServiceName) { + Set labelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, + MetadataContext.LOCAL_SERVICE, peerServiceName); + + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + return ExpressionLabelUtils.resolve(request, labelKeys); + } } diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml index b9b853c2e..eae677526 100644 --- a/spring-cloud-tencent-commons/pom.xml +++ b/spring-cloud-tencent-commons/pom.xml @@ -83,6 +83,18 @@ true + + org.springframework.boot + spring-boot-starter-web + true + + + + org.springframework.boot + spring-boot-starter-webflux + true + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java index 7e93fdb6a..26557aa3d 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ExpressionLabelUtils.java @@ -18,6 +18,7 @@ package com.tencent.cloud.common.util; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -29,6 +30,8 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.springframework.http.HttpCookie; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.CollectionUtils; import org.springframework.util.MultiValueMap; @@ -41,16 +44,50 @@ import org.springframework.web.server.ServerWebExchange; */ public class ExpressionLabelUtils { - private static final String LABEL_HEADER_PREFIX = "${http.header."; - private static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length(); - private static final String LABEL_QUERY_PREFIX = "${http.query."; - private static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length(); - private static final String LABEL_COOKIE_PREFIX = "${http.cookie."; - private static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length(); - private static final String LABEL_METHOD = "${http.method}"; - private static final String LABEL_URI = "${http.uri}"; - - private static final String LABEL_SUFFIX = "}"; + /** + * the expression prefix of header label. + */ + public static final String LABEL_HEADER_PREFIX = "${http.header."; + /** + * the length of expression header label prefix. + */ + public static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length(); + /** + * the expression prefix of query. + */ + public static final String LABEL_QUERY_PREFIX = "${http.query."; + /** + * the length of expression query label prefix. + */ + public static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length(); + /** + * the expression prefix of cookie. + */ + public static final String LABEL_COOKIE_PREFIX = "${http.cookie."; + /** + * the length of expression cookie label prefix. + */ + public static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length(); + /** + * the expression of method. + */ + public static final String LABEL_METHOD = "${http.method}"; + /** + * the expression of uri. + */ + public static final String LABEL_URI = "${http.uri}"; + /** + * the prefix of expression. + */ + public static final String LABEL_PREFIX = "${"; + /** + * the suffix of expression. + */ + public static final String LABEL_SUFFIX = "}"; + /** + * the escape prefix of label. + */ + public static final String LABEL_ESCAPE_PREFIX = "$$$$"; public static boolean isExpressionLabel(String labelKey) { if (StringUtils.isEmpty(labelKey)) { @@ -66,6 +103,14 @@ public class ExpressionLabelUtils { && StringUtils.endsWith(labelKey, LABEL_SUFFIX); } + public static String escape(String str) { + return StringUtils.replace(str, LABEL_PREFIX, LABEL_ESCAPE_PREFIX); + } + + public static String unescape(String str) { + return StringUtils.replace(str, LABEL_ESCAPE_PREFIX, LABEL_PREFIX); + } + public static Map resolve(HttpServletRequest request, Set labelKeys) { if (CollectionUtils.isEmpty(labelKeys)) { return Collections.emptyMap(); @@ -75,15 +120,24 @@ public class ExpressionLabelUtils { for (String labelKey : labelKeys) { if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { - String headerKey = labelKey.substring(LABEL_HEADER_PREFIX_LEN, labelKey.length() - 1); + String headerKey = parseHeaderKey(labelKey); + if (StringUtils.isBlank(headerKey)) { + continue; + } labels.put(labelKey, request.getHeader(headerKey)); } else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) { - String queryKey = labelKey.substring(LABEL_QUERY_PREFIX_LEN, labelKey.length() - 1); + String queryKey = parseQueryKey(labelKey); + if (StringUtils.isBlank(queryKey)) { + continue; + } labels.put(labelKey, getQueryValue(request.getQueryString(), queryKey)); } else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) { - String cookieKey = labelKey.substring(LABEL_COOKIE_PREFIX_LEN, labelKey.length() - 1); + String cookieKey = parseCookieKey(labelKey); + if (StringUtils.isBlank(cookieKey)) { + continue; + } labels.put(labelKey, getCookieValue(request.getCookies(), cookieKey)); } else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) { @@ -106,15 +160,24 @@ public class ExpressionLabelUtils { for (String labelKey : labelKeys) { if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { - String headerKey = labelKey.substring(LABEL_HEADER_PREFIX_LEN, labelKey.length() - 1); + String headerKey = parseHeaderKey(labelKey); + if (StringUtils.isBlank(headerKey)) { + continue; + } labels.put(labelKey, getHeaderValue(exchange.getRequest(), headerKey)); } else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) { - String queryKey = labelKey.substring(LABEL_QUERY_PREFIX_LEN, labelKey.length() - 1); + String queryKey = parseQueryKey(labelKey); + if (StringUtils.isBlank(queryKey)) { + continue; + } labels.put(labelKey, getQueryValue(exchange.getRequest(), queryKey)); } else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_COOKIE_PREFIX)) { - String cookieKey = labelKey.substring(LABEL_COOKIE_PREFIX_LEN, labelKey.length() - 1); + String cookieKey = parseCookieKey(labelKey); + if (StringUtils.isBlank(cookieKey)) { + continue; + } labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey)); } else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) { @@ -128,7 +191,52 @@ public class ExpressionLabelUtils { return labels; } - private static String getQueryValue(String queryString, String queryKey) { + public static Map resolve(HttpRequest request, Set labelKeys) { + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + Map labels = new HashMap<>(); + + for (String labelKey : labelKeys) { + if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_HEADER_PREFIX)) { + String headerKey = parseHeaderKey(labelKey); + if (StringUtils.isBlank(headerKey)) { + continue; + } + labels.put(labelKey, getHeaderValue(request, headerKey)); + } + else if (StringUtils.startsWithIgnoreCase(labelKey, LABEL_QUERY_PREFIX)) { + String queryKey = parseQueryKey(labelKey); + if (StringUtils.isBlank(queryKey)) { + continue; + } + labels.put(labelKey, getQueryValue(request, queryKey)); + } + else if (StringUtils.equalsIgnoreCase(LABEL_METHOD, labelKey)) { + labels.put(labelKey, request.getMethodValue()); + } + else if (StringUtils.equalsIgnoreCase(LABEL_URI, labelKey)) { + labels.put(labelKey, request.getURI().getPath()); + } + } + + return labels; + } + + public static String parseHeaderKey(String expression) { + return expression.substring(LABEL_HEADER_PREFIX_LEN, expression.length() - 1); + } + + public static String parseQueryKey(String expression) { + return expression.substring(LABEL_QUERY_PREFIX_LEN, expression.length() - 1); + } + + public static String parseCookieKey(String expression) { + return expression.substring(LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); + } + + public static String getQueryValue(String queryString, String queryKey) { if (StringUtils.isBlank(queryString)) { return StringUtils.EMPTY; } @@ -145,7 +253,7 @@ public class ExpressionLabelUtils { return StringUtils.EMPTY; } - private static String getCookieValue(Cookie[] cookies, String key) { + public static String getCookieValue(Cookie[] cookies, String key) { if (cookies == null || cookies.length == 0) { return StringUtils.EMPTY; } @@ -157,7 +265,7 @@ public class ExpressionLabelUtils { return StringUtils.EMPTY; } - private static String getHeaderValue(ServerHttpRequest request, String key) { + public static String getHeaderValue(ServerHttpRequest request, String key) { String value = request.getHeaders().getFirst(key); if (value == null) { return StringUtils.EMPTY; @@ -165,7 +273,7 @@ public class ExpressionLabelUtils { return value; } - private static String getQueryValue(ServerHttpRequest request, String key) { + public static String getQueryValue(ServerHttpRequest request, String key) { MultiValueMap queries = request.getQueryParams(); if (CollectionUtils.isEmpty(queries)) { return StringUtils.EMPTY; @@ -177,11 +285,39 @@ public class ExpressionLabelUtils { return value; } - private static String getCookieValue(ServerHttpRequest request, String key) { + public static String getCookieValue(ServerHttpRequest request, String key) { HttpCookie cookie = request.getCookies().getFirst(key); if (cookie == null) { return StringUtils.EMPTY; } return cookie.getValue(); } + + public static String getHeaderValue(HttpRequest request, String key) { + HttpHeaders headers = request.getHeaders(); + return headers.getFirst(key); + } + + public static String getQueryValue(HttpRequest request, String key) { + String query = request.getURI().getQuery(); + return getQueryValue(query, key); + } + + public static String getFirstValue(Map> valueMaps, String key) { + if (CollectionUtils.isEmpty(valueMaps)) { + return StringUtils.EMPTY; + } + + Collection values = valueMaps.get(key); + + if (CollectionUtils.isEmpty(values)) { + return StringUtils.EMPTY; + } + + for (String value : values) { + return value; + } + + return StringUtils.EMPTY; + } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java index a615c5c80..8b3fb16d4 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ServiceRuleManager.java @@ -75,7 +75,7 @@ public class ServiceRuleManager { return null; } - public List getServiceRouterRule(String namespace, String sourceService, String dstService) { + public List getServiceRouterRule(String namespace, String sourceService, String dstService) { Set routerKeys = new HashSet<>(); ServiceEventKey dstSvcEventKey = new ServiceEventKey(new ServiceKey(namespace, dstService), @@ -92,20 +92,23 @@ public class ServiceRuleManager { ResourcesResponse resourcesResponse = BaseFlow .syncGetResources(sdkContext.getExtensions(), true, svcKeysProvider, controlParam); - List rules = new ArrayList<>(); + List rules = new ArrayList<>(); + + //get source service outbound rules. ServiceRule sourceServiceRule = resourcesResponse.getServiceRule(srcSvcEventKey); if (sourceServiceRule != null) { Object rule = sourceServiceRule.getRule(); if (rule instanceof RoutingProto.Routing) { - rules.add((RoutingProto.Routing) rule); + rules.addAll(((RoutingProto.Routing) rule).getOutboundsList()); } } + //get peer service inbound rules. ServiceRule dstServiceRule = resourcesResponse.getServiceRule(dstSvcEventKey); if (dstServiceRule != null) { Object rule = dstServiceRule.getRule(); if (rule instanceof RoutingProto.Routing) { - rules.add((RoutingProto.Routing) rule); + rules.addAll(((RoutingProto.Routing) rule).getInboundsList()); } }