From 3ddfd85d4f33483fa20631524fdb819e0ddbe26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=81=E5=8C=A0=E5=90=9B?= Date: Wed, 21 Feb 2024 10:58:01 +0800 Subject: [PATCH 01/19] fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. --- CHANGELOG.md | 1 + pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 2 +- .../PolarisLoadBalancerAutoConfiguration.java | 30 ++++++++++++++----- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6525f5b02..168274ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,3 +20,4 @@ - [feat:optimize examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1186) - [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) +- fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. diff --git a/pom.xml b/pom.xml index b91ab8fca..402cf97b3 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.13.0-Hoxton.SR12 + 1.13.1-Hoxton.SR12 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 15d28d129..2cfa7bdfa 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.13.0-Hoxton.SR12 + 1.13.1-Hoxton.SR12 1.15.0 diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java index 1a6578449..019c60cc4 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisLoadBalancerAutoConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.util.CollectionUtils; /** * Auto-configuration Ribbon for Polaris. @@ -55,23 +56,38 @@ public PolarisLoadBalancerProperties polarisLoadBalancerProperties() { } @Bean - public RestTemplateCustomizer restTemplateCustomizer( + public RestTemplateCustomizer polarisRestTemplateCustomizer( @Autowired(required = false) RetryLoadBalancerInterceptor retryLoadBalancerInterceptor, @Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) { return restTemplate -> { List list = new ArrayList<>(restTemplate.getInterceptors()); // LoadBalancerInterceptor must invoke before EnhancedRestTemplateInterceptor - if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) { - int addIndex = list.size(); + int addIndex = list.size(); + if (CollectionUtils.containsInstance(list, retryLoadBalancerInterceptor) || CollectionUtils.containsInstance(list, loadBalancerInterceptor)) { + ClientHttpRequestInterceptor enhancedRestTemplateInterceptor = null; for (int i = 0; i < list.size(); i++) { if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { + enhancedRestTemplateInterceptor = list.get(i); addIndex = i; } } - list.add(addIndex, - retryLoadBalancerInterceptor != null - ? retryLoadBalancerInterceptor - : loadBalancerInterceptor); + if (enhancedRestTemplateInterceptor != null) { + list.remove(addIndex); + list.add(enhancedRestTemplateInterceptor); + } + } + else { + if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { + addIndex = i; + } + } + list.add(addIndex, + retryLoadBalancerInterceptor != null + ? retryLoadBalancerInterceptor + : loadBalancerInterceptor); + } } restTemplate.setInterceptors(list); }; From 91bc164ad144f9dd429dff84f69822c2be985f9d Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Mon, 22 Apr 2024 16:24:01 +0800 Subject: [PATCH 02/19] fix:fix NullPointerException when properties contain kv with null value. --- CHANGELOG.md | 1 + .../config/listener/PolarisConfigListenerContext.java | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 168274ddc..29813ebfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,3 +21,4 @@ - [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) - fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. +- fix:fix NullPointerException when properties contain kv with null value. diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java index 0c2df3149..85bd2ab42 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java @@ -118,6 +118,11 @@ public static ExecutorService executor() { * @param ret origin properties map */ static void initialize(Map ret) { + for (Map.Entry entry : ret.entrySet()) { + if (entry.getValue() == null) { + ret.put(entry.getKey(), ""); + } + } properties.putAll(ret); } @@ -144,6 +149,9 @@ static Map merge(Map ret) { ret.keySet().parallelStream().forEach(key -> { Object oldValue = properties.getIfPresent(key); Object newValue = ret.get(key); + if (newValue == null) { + newValue = ""; + } if (oldValue != null) { if (!newValue.equals(oldValue)) { properties.put(key, newValue); From c4eca72bb62856e4e50eac027d38c43093b66c36 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:13:12 +0800 Subject: [PATCH 03/19] fix: memory not released while using wildcard api call with circuitbreaker (#1361) * fix: memory not released while using wildcard api call with circuitbreaker enabled * fix: change version 1.13.3-Hoxton.SR12-SNAPSHOT * fix: update polaris verion to 1.15.9 release * Update CHANGELOG.md --- CHANGELOG.md | 1 + pom.xml | 2 +- spring-cloud-tencent-dependencies/pom.xml | 4 +- .../callee/QuickstartCalleeController.java | 12 +++ .../callee/QuickstartCalleeController.java | 21 +++++ .../CircuitBreakerController.java | 19 +++++ ...CircuitBreakerQuickstartCalleeService.java | 9 +++ ...reakerQuickstartCalleeServiceFallback.java | 5 ++ ...erQuickstartCalleeServiceWithFallback.java | 9 +++ spring-cloud-tencent-polaris-context/pom.xml | 78 +++++++++++++++++++ 10 files changed, 157 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29813ebfe..369f99823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,3 +22,4 @@ - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) - fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. - fix:fix NullPointerException when properties contain kv with null value. +- [fix: memory not released while using wildcard api call with circuitbreaker](https://github.com/Tencent/spring-cloud-tencent/pull/1361) \ No newline at end of file diff --git a/pom.xml b/pom.xml index 402cf97b3..5f6f2ef04 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.13.1-Hoxton.SR12 + 1.13.3-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 2cfa7bdfa..19a9f7029 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,10 +70,10 @@ - 1.13.1-Hoxton.SR12 + 1.13.3-Hoxton.SR12-SNAPSHOT - 1.15.0 + 1.15.9 32.0.1-jre 1.2.13 3.0.0 diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 072255d85..2370d4c17 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -106,6 +107,17 @@ public String circuitBreak() { return String.format("Quickstart Callee Service [%s:%s] is called right.", ip, port); } + /** + * Check circuit break. + * + * @return circuit break info + */ + @GetMapping("/circuitBreak/wildcard/{uid}") + public String circuitBreakWildcard(@PathVariable String uid) throws InterruptedException { + LOG.info("Quickstart Callee Service uid {} [{}:{}] is called right.", uid, ip, port); + return String.format("Quickstart Callee Service %s [%s:%s] is called right.", uid, ip, port); + } + @GetMapping("/faultDetect") public String health() { LOG.info("Quickstart Callee Service [{}:{}] is detected right.", ip, port); diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index d4de94f3d..9f923950a 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -30,6 +30,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -119,6 +120,26 @@ public ResponseEntity circuitBreak() throws InterruptedException { return new ResponseEntity<>(String.format("Quickstart Callee Service [%s:%s] is called right.", ip, port), HttpStatus.OK); } + /** + * Check circuit break. + * + * @return circuit break info + */ + @GetMapping("/circuitBreak/wildcard/{uid}") + public ResponseEntity circuitBreakWildcard(@PathVariable String uid) throws InterruptedException { + if (ifBadGateway) { + LOG.info("Quickstart Callee Service with uid {} [{}:{}] is called wrong.", uid, ip, port); + return new ResponseEntity<>("failed for call quickstart callee service wildcard.", HttpStatus.BAD_GATEWAY); + } + if (ifDelay) { + Thread.sleep(200); + LOG.info("Quickstart Callee Service uid {} [{}:{}] is called slow.", uid, ip, port); + return new ResponseEntity<>(String.format("Quickstart Callee Service [%s:%s] is called slow.", ip, port), HttpStatus.OK); + } + LOG.info("Quickstart Callee Service uid {} [{}:{}] is called right.", uid, ip, port); + return new ResponseEntity<>(String.format("Quickstart Callee Service %s [%s:%s] is called right.", uid, ip, port), HttpStatus.OK); + } + @GetMapping("/setBadGateway") public String setBadGateway(@RequestParam boolean param) { this.ifBadGateway = param; diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java index 4d902aaa2..5b348144b 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java @@ -25,6 +25,7 @@ import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @@ -84,6 +85,24 @@ public String circuitBreakFeignFallbackFromCode() { return circuitBreakerQuickstartCalleeServiceWithFallback.circuitBreak(); } + /** + * Feign circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/feign/fallbackFromPolaris/wildcard/{uid}") + public String circuitBreakFeignFallbackFromPolarisWildcard(@PathVariable String uid) { + return circuitBreakerQuickstartCalleeService.circuitBreakWildcard(uid); + } + + /** + * Feign circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/feign/fallbackFromCode/wildcard/{uid}") + public String circuitBreakFeignFallbackFromCodeWildcard(@PathVariable String uid) { + return circuitBreakerQuickstartCalleeServiceWithFallback.circuitBreakWildcard(uid); + } + /** * RestTemplate circuit breaker. * @return circuit breaker information of callee diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java index 64821b9a9..b96052840 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeService.java @@ -19,6 +19,7 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; /** * Circuit breaker example callee provider. @@ -35,4 +36,12 @@ public interface CircuitBreakerQuickstartCalleeService { */ @GetMapping("/quickstart/callee/circuitBreak") String circuitBreak(); + + /** + * Check circuit break with uid. + * @param uid uid variable + * @return circuit break info + */ + @GetMapping("/quickstart/callee/circuitBreak/wildcard/{uid}") + String circuitBreakWildcard(@PathVariable String uid); } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java index 06a2df366..dbc2b9af8 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceFallback.java @@ -31,4 +31,9 @@ public class CircuitBreakerQuickstartCalleeServiceFallback implements CircuitBre public String circuitBreak() { return "fallback: trigger the refuse for service callee."; } + + @Override + public String circuitBreakWildcard(String uid) { + return String.format("fallback: trigger the refuse for service callee %s.", uid); + } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java index f71a7650e..fe4a9daf8 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerQuickstartCalleeServiceWithFallback.java @@ -19,6 +19,7 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; /** * CircuitBreakerQuickstartCalleeServiceWithFallback. @@ -35,4 +36,12 @@ public interface CircuitBreakerQuickstartCalleeServiceWithFallback { */ @GetMapping("/quickstart/callee/circuitBreak") String circuitBreak(); + + /** + * Check circuit break with uid. + * @param uid uid variable + * @return circuit break info + */ + @GetMapping("/circuitBreak/wildcard/{uid}") + String circuitBreakWildcard(@PathVariable String uid); } diff --git a/spring-cloud-tencent-polaris-context/pom.xml b/spring-cloud-tencent-polaris-context/pom.xml index f525ce672..972fe0046 100644 --- a/spring-cloud-tencent-polaris-context/pom.xml +++ b/spring-cloud-tencent-polaris-context/pom.xml @@ -49,6 +49,84 @@ + + com.tencent.polaris + polaris-circuitbreaker-factory + + + com.tencent.polaris + router-rule + + + com.tencent.polaris + router-nearby + + + com.tencent.polaris + router-metadata + + + com.tencent.polaris + circuitbreaker-errrate + + + com.tencent.polaris + circuitbreaker-errcount + + + com.tencent.polaris + circuitbreaker-composite + + + com.tencent.polaris + stat-prometheus + + + com.tencent.polaris + healthchecker-http + + + com.tencent.polaris + healthchecker-tcp + + + com.tencent.polaris + healthchecker-udp + + + + + + com.tencent.polaris + polaris-ratelimit-factory + + + com.tencent.polaris + router-rule + + + com.tencent.polaris + router-nearby + + + com.tencent.polaris + router-metadata + + + com.tencent.polaris + ratelimiter-reject + + + com.tencent.polaris + ratelimiter-unirate + + + com.tencent.polaris + stat-prometheus + + + + com.tencent.polaris polaris-client From f863225777b5dd570782d28187050eb8620f6230 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:37:35 +0800 Subject: [PATCH 04/19] release 1.13.3-Hoxton.SR12 (#1362) * fix: memory not released while using wildcard api call with circuitbreaker enabled * fix: change version 1.13.3-Hoxton.SR12-SNAPSHOT * fix: update polaris verion to 1.15.9 release * Update CHANGELOG.md * release: 1.13.3-Hoxton.SR12 --- 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 5f6f2ef04..7d30b9cf0 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.13.3-Hoxton.SR12-SNAPSHOT + 1.13.3-Hoxton.SR12 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 19a9f7029..68b534076 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.13.3-Hoxton.SR12-SNAPSHOT + 1.13.3-Hoxton.SR12 1.15.9 From af225c220b145cac10bc1cb63c517b42cb212679 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:26:11 +0800 Subject: [PATCH 05/19] fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis (#1392) --- CHANGELOG.md | 3 +- .../PolarisCircuitBreakerFactory.java | 27 ++++++++- .../ReactivePolarisCircuitBreakerFactory.java | 26 ++++++++- ...olarisCircuitBreakerAutoConfiguration.java | 7 ++- .../PolarisCircuitBreakerProperties.java | 57 +++++++++++++++++++ ...olarisCircuitBreakerAutoConfiguration.java | 7 ++- .../util/PolarisCircuitBreakerUtils.java | 6 +- ...itional-spring-configuration-metadata.json | 9 ++- .../PolarisCircuitBreakerMockServerTest.java | 6 +- .../PolarisCircuitBreakerTest.java | 21 ++++++- .../ReactivePolarisCircuitBreakerTest.java | 20 ++++++- ...risCircuitBreakerFeignIntegrationTest.java | 6 +- ...sCircuitBreakerGatewayIntegrationTest.java | 6 +- ...uitBreakerRestTemplateIntegrationTest.java | 5 +- .../CircuitBreakerController.java | 20 +++++++ .../src/main/resources/bootstrap.yml | 2 + 16 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 369f99823..b5564a601 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,4 +22,5 @@ - [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) - fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. - fix:fix NullPointerException when properties contain kv with null value. -- [fix: memory not released while using wildcard api call with circuitbreaker](https://github.com/Tencent/spring-cloud-tencent/pull/1361) \ No newline at end of file +- [fix: memory not released while using wildcard api call with circuitbreaker](https://github.com/Tencent/spring-cloud-tencent/pull/1361) +- [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1392) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java index 1c789befe..331926223 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java @@ -17,13 +17,21 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils; import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.utils.ThreadPoolUtils; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; +import com.tencent.polaris.client.util.NamedThreadFactory; +import org.springframework.beans.factory.DisposableBean; import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; @@ -33,7 +41,7 @@ * @author seanyu 2023-02-27 */ public class PolarisCircuitBreakerFactory - extends CircuitBreakerFactory { + extends CircuitBreakerFactory implements DisposableBean { private Function defaultConfiguration = id -> { @@ -50,9 +58,19 @@ public class PolarisCircuitBreakerFactory private final ConsumerAPI consumerAPI; - public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-circuitbreaker-cleanup", true)); + + public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; this.consumerAPI = consumerAPI; + cleanupService.scheduleWithFixedDelay( + () -> { + getConfigurations().clear(); + }, + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS); } @Override @@ -73,4 +91,9 @@ public void configureDefault(Function { + ReactiveCircuitBreakerFactory implements DisposableBean { private Function defaultConfiguration = id -> { @@ -49,9 +57,19 @@ public class ReactivePolarisCircuitBreakerFactory extends private final ConsumerAPI consumerAPI; - public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-reactive-circuitbreaker-cleanup", true)); + + public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; this.consumerAPI = consumerAPI; + cleanupService.scheduleWithFixedDelay( + () -> { + getConfigurations().clear(); + }, + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS); } @Override @@ -73,4 +91,8 @@ public void configureDefault( this.defaultConfiguration = defaultConfiguration; } + @Override + public void destroy() { + ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[]{cleanupService}); + } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java index 6ba7d4435..9bc24303e 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java @@ -38,6 +38,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider; @@ -54,6 +55,7 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisCircuitBreakerEnabled +@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class) @AutoConfigureAfter(RpcEnhancementAutoConfiguration.class) public class PolarisCircuitBreakerAutoConfiguration { @@ -89,9 +91,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) { + public CircuitBreakerFactory polarisCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( - polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI()); + polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java new file mode 100644 index 000000000..7f2680305 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java @@ -0,0 +1,57 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.circuitbreaker.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties of Polaris CircuitBreaker . + * + */ +@ConfigurationProperties("spring.cloud.polaris.circuitbreaker") +public class PolarisCircuitBreakerProperties { + + /** + * Whether enable polaris circuit-breaker function. + */ + @Value("${spring.cloud.polaris.circuitbreaker.enabled:#{true}}") + private boolean enabled = true; + + /** + * Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond. + */ + @Value("${spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval:#{300000}}") + private long configurationCleanupInterval = 300000; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public long getConfigurationCleanupInterval() { + return configurationCleanupInterval; + } + + public void setConfigurationCleanupInterval(long configurationCleanupInterval) { + this.configurationCleanupInterval = configurationCleanupInterval; + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java index 23c3f281d..1b0f24b2f 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; import org.springframework.context.annotation.Bean; @@ -45,6 +46,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = {"reactor.core.publisher.Mono", "reactor.core.publisher.Flux"}) @ConditionalOnPolarisCircuitBreakerEnabled +@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class) @AutoConfigureAfter(RpcEnhancementAutoConfiguration.class) public class ReactivePolarisCircuitBreakerAutoConfiguration { @@ -67,9 +69,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class) - public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) { + public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { ReactivePolarisCircuitBreakerFactory factory = new ReactivePolarisCircuitBreakerFactory( - polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI()); + polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java index 961c30802..4c7502c92 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java @@ -55,12 +55,12 @@ public static String[] resolveCircuitBreakerId(String id) { Assert.hasText(id, "A CircuitBreaker must have an id. Id could be : namespace#service#method or service#method or service"); String[] polarisCircuitBreakerMetaData = id.split("#"); if (polarisCircuitBreakerMetaData.length == 2) { - return new String[]{MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]}; + return new String[] {MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]}; } if (polarisCircuitBreakerMetaData.length == 3) { - return new String[]{polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]}; + return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]}; } - return new String[]{MetadataContext.LOCAL_NAMESPACE, id, ""}; + return new String[] {MetadataContext.LOCAL_NAMESPACE, id, ""}; } public static void reportStatus(ConsumerAPI consumerAPI, diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 99dc05518..2f222b999 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -3,7 +3,14 @@ { "name": "spring.cloud.polaris.circuitbreaker.enabled", "type": "java.lang.Boolean", - "defaultValue": "true" + "defaultValue": "true", + "description": "If polaris circuitbreaker enabled." + }, + { + "name": "spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval", + "type": "java.lang.Long", + "defaultValue": "300000", + "description": "Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond." } ], "hints": [] diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java index fcde4e4f9..90e8134a6 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java @@ -30,6 +30,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.core.ConsumerAPI; @@ -111,7 +112,8 @@ public void testCircuitBreaker() { CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties = new PolarisCircuitBreakerProperties(); + PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); // trigger fallback for 5 times @@ -132,7 +134,7 @@ public void testCircuitBreaker() { assertThat(resList).isEqualTo(Arrays.asList("invoke success", "fallback", "fallback", "fallback", "fallback")); // always fallback - ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); ReactiveCircuitBreaker rcb = reactivePolarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); assertThat(Mono.just("foobar").transform(it -> rcb.run(it, t -> Mono.just("fallback"))) diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java index bf35fa8f9..47f9df697 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java @@ -18,13 +18,19 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.lang.reflect.Method; +import java.util.Map; + import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ReflectionUtils; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import com.tencent.polaris.client.util.Utils; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -56,7 +62,8 @@ public class PolarisCircuitBreakerTest { LoadBalancerAutoConfiguration.class, PolarisCircuitBreakerFeignClientAutoConfiguration.class, PolarisCircuitBreakerAutoConfiguration.class)) - .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000"); private static MockedStatic mockedApplicationContextAwareUtils; @@ -92,6 +99,18 @@ public void run() { throw new RuntimeException("boom"); }, t -> "fallback")).isEqualTo("fallback"); + Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class, + "getConfigurations"); + Assertions.assertNotNull(getConfigurationsMethod); + ReflectionUtils.makeAccessible(getConfigurationsMethod); + Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); + Assertions.assertNotNull(values); + + Assertions.assertEquals(1, values.size()); + + Utils.sleepUninterrupted(10 * 1000); + + Assertions.assertEquals(0, values.size()); }); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java index f06502c87..7507ae43c 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java @@ -17,15 +17,20 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; +import java.util.Map; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ReflectionUtils; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; import com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import com.tencent.polaris.client.util.Utils; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -58,7 +63,8 @@ public class ReactivePolarisCircuitBreakerTest { RpcEnhancementAutoConfiguration.class, LoadBalancerAutoConfiguration.class, ReactivePolarisCircuitBreakerAutoConfiguration.class)) - .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000"); private static MockedStatic mockedApplicationContextAwareUtils; @@ -97,6 +103,18 @@ public void run() { assertThat(Flux.error(new RuntimeException("boom")).transform(it -> cb.run(it, t -> Flux.just("fallback"))) .collectList().block()).isEqualTo(Collections.singletonList("fallback")); + + Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class, + "getConfigurations"); + Assertions.assertNotNull(getConfigurationsMethod); + ReflectionUtils.makeAccessible(getConfigurationsMethod); + Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); + Assertions.assertNotNull(values); + Assertions.assertEquals(1, values.size()); + + Utils.sleepUninterrupted(10 * 1000); + + Assertions.assertEquals(0, values.size()); }); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index a37ccd786..f360e068c 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -31,6 +31,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; @@ -230,8 +231,9 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc } @Bean - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { + PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java index 2511722bc..2ed360ab6 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java @@ -32,6 +32,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; @@ -216,8 +217,9 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { + PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java index 1be0a170c..beccd9759 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java @@ -32,6 +32,7 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; @@ -287,9 +288,9 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, - PolarisSDKContextManager polarisSDKContextManager) { + PolarisSDKContextManager polarisSDKContextManager, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( - circuitBreakAPI, polarisSDKContextManager.getConsumerAPI()); + circuitBreakAPI, polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java index 5b348144b..1dbd829a3 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java @@ -116,6 +116,26 @@ public String circuitBreakRestTemplate() { ); } + /** + * RestTemplate wildcard circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/rest/fallbackFromPolaris/wildcard/{uid}") + public ResponseEntity circuitBreakRestTemplateFallbackFromPolarisWildcard(@PathVariable String uid) { + String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid); + return restTemplateFallbackFromPolaris.getForEntity(path, String.class); + } + + /** + * RestTemplate wildcard circuit breaker with fallback from code. + * @return circuit breaker information of callee + */ + @GetMapping("/rest/fallbackFromCode/wildcard/{uid}") + public ResponseEntity circuitBreakRestTemplateFallbackFromCodeWildcard(@PathVariable String uid) { + String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid); + return restTemplateFallbackFromCode.getForEntity(path, String.class); + } + /** * RestTemplate circuit breaker with fallback from Polaris. * @return circuit breaker information of callee diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml index 0db7fd89a..c61c418ec 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml @@ -18,6 +18,8 @@ spring: address: grpc://119.91.66.223:8091 namespace: default enabled: true + circuitbreaker: + enabled: true contract: exposure: true report: From 3ba943b8b81fc71f890a45f880816ba1610cba65 Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:40:04 +0800 Subject: [PATCH 06/19] fix: CHANGE VERSION TO 1.13.4-Hoxton.SR12-SNAPSHOT (#1407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoked by wildcard apis * Update CHANGELOG.md * fix: restore PolarisCircuitBreakerUtils and use ThreadPoolUtils.waitAndStopThreadPools instead * fix: 修复命名不一致问题 * fix: CHANGE VERSION TO 1.13.4-Hoxton.SR12-SNAPSHOT --- 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 7d30b9cf0..f9594768c 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.13.3-Hoxton.SR12 + 1.13.4-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 68b534076..8ee793035 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,7 +70,7 @@ - 1.13.3-Hoxton.SR12 + 1.13.4-Hoxton.SR12-SNAPSHOT 1.15.9 From cd1930a9afd4cd84f224351e0dacf408f802130f Mon Sep 17 00:00:00 2001 From: andrew shan <45474304+andrewshan@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:11:13 +0800 Subject: [PATCH 07/19] Update polaris version to 1.15.10-SNAPSHOT --- 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 8ee793035..a19c21c6a 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.13.4-Hoxton.SR12-SNAPSHOT - 1.15.9 + 1.15.10-SNAPSHOT 32.0.1-jre 1.2.13 3.0.0 From c2558fcf038e132c47de972fc7190c121d15c525 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Wed, 4 Sep 2024 14:57:46 +0800 Subject: [PATCH 08/19] fix:fix rate limit window update bug. --- 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 a19c21c6a..77ca98c07 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.13.4-Hoxton.SR12-SNAPSHOT - 1.15.10-SNAPSHOT + 1.15.11-SNAPSHOT 32.0.1-jre 1.2.13 3.0.0 From 2ddaab8baf2de0455500594ef5d595c98214e550 Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:11:23 +0800 Subject: [PATCH 09/19] fix: fix npe when feign.hystrix.enabled=false (#1436) --- CHANGELOG.md | 3 +- ...sFeignCircuitBreakerInvocationHandler.java | 4 ++ ...ignIntegrationDisableFeignHystrixTest.java | 56 +++++++++++++++++++ ...risCircuitBreakerFeignIntegrationTest.java | 3 + 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b5564a601..864bc5f5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,4 +23,5 @@ - fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. - fix:fix NullPointerException when properties contain kv with null value. - [fix: memory not released while using wildcard api call with circuitbreaker](https://github.com/Tencent/spring-cloud-tencent/pull/1361) -- [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1392) \ No newline at end of file +- [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1392) +- [fix: fix npe when feign.hystrix.enabled=false](https://github.com/Tencent/spring-cloud-tencent/pull/1436) \ No newline at end of file diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java index b8419a29c..581e18cf1 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java @@ -113,6 +113,10 @@ else if ("hashCode".equals(method.getName())) { else if ("toString".equals(method.getName())) { return toString(); } + // disable feign.hystrix + if (circuitBreakerNameResolver == null) { + return this.dispatch.get(method).invoke(args); + } String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method); CircuitBreaker circuitBreaker = factory.create(circuitName); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java new file mode 100644 index 000000000..689eed2e4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java @@ -0,0 +1,56 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.circuitbreaker.feign; + + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * @author Shedfree Wu + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class, + properties = { + "feign.hystrix.enabled=false", + "spring.cloud.gateway.enabled=false", + "feign.circuitbreaker.enabled=true", + "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, + "spring.cloud.polaris.service=test" + }) +public class PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest { + + @Autowired + private PolarisCircuitBreakerFeignIntegrationTest.EchoService echoService; + + @Test + public void testFeignClient() { + assertThatThrownBy(() -> { + echoService.echo("test"); + }).isInstanceOf(RuntimeException.class).hasMessageContaining("Load balancer does not have available server for client"); + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index f360e068c..0f0c6ec1d 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -52,6 +52,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.Customizer; @@ -80,6 +81,7 @@ @SpringBootTest(webEnvironment = RANDOM_PORT, classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class, properties = { + "feign.hystrix.enabled=true", "spring.cloud.gateway.enabled=false", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, @@ -246,6 +248,7 @@ public PolarisCircuitBreakerNameResolver polarisCircuitBreakerNameResolver() { @Bean @Primary @ConditionalOnBean(CircuitBreakerFactory.class) + @ConditionalOnProperty(value = "feign.hystrix.enabled", havingValue = "true") public PolarisFeignCircuitBreakerTargeter polarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { return new PolarisFeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerNameResolver); } From f88b4c3cc40cf696031010246b2366642c0825a5 Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Fri, 27 Sep 2024 16:14:57 +0800 Subject: [PATCH 10/19] feat: support 2.0.0 feature --- pom.xml | 4 +- spring-cloud-starter-tencent-all/pom.xml | 5 + .../pom.xml | 24 + .../MetadataTransferAutoConfiguration.java | 77 +- .../DecodeTransferMetadataReactiveFilter.java | 50 +- .../DecodeTransferMetadataServletFilter.java | 45 +- ...codeTransferMedataFeignEnhancedPlugin.java | 145 ++++ .../EncodeTransferMedataFeignInterceptor.java | 102 --- ...sferMedataRestTemplateEnhancedPlugin.java} | 68 +- ...ncodeTransferMedataScgEnhancedPlugin.java} | 65 +- ...ransferMedataWebClientEnhancedPlugin.java} | 61 +- ...deTransferMetadataZuulEnhancedPlugin.java} | 58 +- .../FeignRequestTemplateMetadataProvider.java | 75 ++ .../provider/ReactiveMetadataProvider.java | 71 ++ .../RestTemplateMetadataProvider.java | 70 ++ .../provider/ServletMetadataProvider.java | 72 ++ ...MetadataTransferAutoConfigurationTest.java | 55 +- ...odeTransferMetadataReactiveFilterTest.java | 3 +- ...odeTransferMedataFeignInterceptorTest.java | 2 +- ...sferMedataRestTemplateInterceptorTest.java | 50 +- .../EncodeTransferMedataScgFilterTest.java | 134 +++- ...codeTransferMedataWebClientFilterTest.java | 2 +- .../EncodeTransferMetadataZuulFilterTest.java | 85 --- .../provider/MetadataProviderTest.java | 139 ++++ .../pom.xml | 5 +- .../circuitbreaker/PolarisCircuitBreaker.java | 9 +- .../PolarisCircuitBreakerFactory.java | 23 +- .../ReactivePolarisCircuitBreaker.java | 3 +- .../ReactivePolarisCircuitBreakerFactory.java | 22 +- .../PolarisCircuitBreakerConfigBuilder.java | 40 +- .../PolarisCircuitBreakerEndpoint.java | 2 +- .../PolarisCircuitBreakerNameResolver.java | 21 +- ...sFeignCircuitBreakerInvocationHandler.java | 36 +- .../PolarisCircuitBreakerFilterFactory.java | 28 +- ...CircuitBreakerRestTemplateInterceptor.java | 13 +- .../util/PolarisCircuitBreakerUtils.java | 19 +- .../zuul/PolarisCircuitBreakerZuulFilter.java | 5 +- .../PolarisFeignCircuitBreakerTargeter.java | 3 +- .../PolarisCircuitBreakerMockServerTest.java | 14 +- ...PolarisCircuitBreakerNameResolverTest.java | 4 +- ...sCircuitBreakerGatewayIntegrationTest.java | 3 +- ...uitBreakerRestTemplateIntegrationTest.java | 4 + .../util/PolarisCircuitBreakerUtilsTests.java | 8 +- .../resources/application-test-gateway.yml | 2 +- .../pom.xml | 4 + .../polaris/config/ConfigurationModifier.java | 51 +- .../PolarisConfigAutoConfiguration.java | 14 +- ...larisConfigBootstrapAutoConfiguration.java | 15 +- ...fectedConfigurationPropertiesRebinder.java | 8 +- .../PolarisConfigCustomExtensionLayer.java | 5 +- .../adapter/PolarisConfigFileLocator.java | 67 +- .../PolarisConfigPropertyAutoRefresher.java | 34 +- .../config/adapter/PolarisPropertySource.java | 5 +- .../adapter/PolarisPropertySourceManager.java | 20 +- ...olarisRefreshAffectedContextRefresher.java | 7 +- .../PolarisRefreshEntireContextRefresher.java | 8 +- .../adapter/PolarisServiceLoaderUtil.java | 13 +- .../PolarisConfigAnnotationProcessor.java | 3 +- .../config/config/ConfigFileGroup.java | 17 +- .../config/PolarisConfigProperties.java | 41 ++ .../endpoint/PolarisConfigEndpoint.java | 8 +- ...olarisConfigEndpointAutoConfiguration.java | 6 +- .../PolarisConfigChangeEventListener.java | 1 - .../PolarisConfigListenerContext.java | 2 - ...arisConfigRefreshOptimizationListener.java | 9 +- ...olarisConfigLoggerApplicationListener.java | 2 +- .../spring/annotation/PolarisProcessor.java | 1 - ...arisAdaptorTsfConfigAutoConfiguration.java | 58 ++ .../PolarisAdaptorTsfConfigController.java | 70 ++ .../tsf/encrypt/ConfigEncryptAESProvider.java | 48 ++ .../tsf/encrypt/ConfigEncryptProvider.java | 44 ++ .../encrypt/ConfigEncryptProviderFactory.java | 39 + .../config/tsf/encrypt/EncryptAlgorithm.java | 146 ++++ .../config/tsf/encrypt/EncryptConfig.java | 114 +++ .../utils/PolarisPropertySourceUtils.java | 34 + .../config/watch/ConfigChangeCallback.java | 28 + .../config/watch/ConfigChangeListener.java | 40 ++ .../consul/config/watch/ConfigProperty.java | 46 ++ .../TsfConsulConfigRefreshEventListener.java | 122 ++++ .../main/resources/META-INF/spring.factories | 9 +- .../adapter/PolarisConfigFileLocatorTest.java | 23 +- ...arisPropertiesSourceAutoRefresherTest.java | 14 +- .../ConditionalOnReflectRefreshTypeTest.java | 2 - .../endpoint/PolarisConfigEndpointTest.java | 13 +- ...hOptimizationListenerNotTriggeredTest.java | 17 +- ...reshOptimizationListenerTriggeredTest.java | 17 +- .../pom.xml | 23 +- .../contract/PolarisContractReporter.java | 119 ++- .../contract/config/ContractProperties.java | 4 + .../config/PolarisContractModifier.java | 3 +- .../config/PolarisContractProperties.java | 39 +- ...isContractPropertiesAutoConfiguration.java | 6 +- .../PolarisSwaggerAutoConfiguration.java | 108 ++- .../contract/filter/ApiDocServletFilter.java | 11 +- .../contract/filter/ApiDocWebFluxFilter.java | 5 +- .../contract/tsf/TsfApiMetadataGrapher.java | 137 ++++ .../tsf/TsfSwaggerAutoConfiguration.java | 46 ++ .../polaris/contract/utils/PackageUtil.java | 89 +-- .../api/AbstractOpenApiResourceUtil.java | 37 + .../webflux/api/OpenApiWebFluxUtil.java | 36 + .../webmvc/api/OpenApiWebMvcUtil.java | 35 + .../main/resources/META-INF/spring.factories | 6 +- .../pom.xml | 21 +- .../polaris/DiscoveryConfigModifier.java | 4 + .../DiscoveryPropertiesAutoConfiguration.java | 53 +- .../polaris/PolarisDiscoveryProperties.java | 30 + .../ConditionalOnPolarisDiscoveryEnabled.java | 2 +- .../discovery/PolarisServiceDiscovery.java | 2 +- .../PolarisReactiveDiscoveryClient.java | 9 +- .../PolarisServiceStatusChangeListener.java | 6 +- .../endpoint/PolarisDiscoveryEndpoint.java | 2 +- .../extend/consul/ConsulConfigModifier.java | 117 --- .../consul/ConsulContextProperties.java | 129 ---- .../consul/ConsulDiscoveryConfigModifier.java | 157 ++++ .../consul/ConsulDiscoveryProperties.java | 679 ++++++++++++++++++ .../extend/consul/ConsulDiscoveryUtil.java | 179 +++++ .../consul/ConsulHeartbeatProperties.java | 118 +++ .../ConditionalOnPolarisRegisterEnabled.java | 2 +- .../PolarisAutoServiceRegistration.java | 5 - .../polaris/registry/PolarisRegistration.java | 26 +- .../registry/PolarisServiceRegistry.java | 42 +- ...larisServiceRegistryAutoConfiguration.java | 4 +- .../registry/RegisterEnabledCondition.java | 4 +- .../TsfApiPolarisRegistrationCustomizer.java | 62 ++ ...TsfDiscoveryRegistryAutoConfiguration.java | 71 ++ .../TsfPortPolarisRegistrationCustomizer.java | 65 ++ .../TsfServletRegistrationCustomizer.java | 66 ++ ...itional-spring-configuration-metadata.json | 12 + .../main/resources/META-INF/spring.factories | 5 +- .../lossless/LosslessRegistryAspectTest.java | 193 +++++ .../config/LosslessConfigModifierTest.java | 90 +++ ...coveryPropertiesAutoConfigurationTest.java | 23 +- ...pertiesBootstrapAutoConfigurationTest.java | 3 +- .../PolarisDiscoveryPropertiesTest.java | 4 +- ...PolarisDiscoveryAutoConfigurationTest.java | 3 +- .../discovery/PolarisDiscoveryClientTest.java | 1 + ...ctiveDiscoveryClientConfigurationTest.java | 3 +- .../PolarisReactiveDiscoveryClientTest.java | 2 + .../PolarisDiscoveryEndpointTest.java | 2 +- ...ava => ConsulDiscoveryPropertiesTest.java} | 20 +- .../PolarisAutoServiceRegistrationTest.java | 27 + .../registry/PolarisRegistrationTest.java | 11 +- .../registry/PolarisServiceRegistryTest.java | 3 +- .../AutoServiceRegistrationUtils.java | 29 + .../pom.xml | 9 + ...sRateLimitPropertiesAutoConfiguration.java | 2 +- .../config/RateLimitConfigModifier.java | 4 +- .../PolarisRateLimitRuleEndpoint.java | 2 +- .../filter/QuotaCheckReactiveFilter.java | 4 +- .../filter/QuotaCheckServletFilter.java | 4 +- ...RateLimitRuleArgumentReactiveResolver.java | 18 +- ...larisRateLimiterLabelReactiveResolver.java | 1 + ...olarisRateLimiterLabelServletResolver.java | 2 + .../ratelimit/utils/RateLimitUtils.java | 6 +- .../context/CalleeControllerTests.java | 10 +- .../cloud/polaris/context/TestController.java | 2 +- .../PolarisRateLimitRuleEndpointTests.java | 7 +- .../pom.xml | 4 + .../PolarisLoadBalancerCompositeRule.java | 2 + .../polaris/router/PolarisRouterContext.java | 36 +- .../polaris/router/RouterConfigModifier.java | 71 ++ .../router/config/FeignAutoConfiguration.java | 15 +- .../config/RouterAutoConfiguration.java | 76 +- .../PolarisMetadataRouterProperties.java | 1 - .../PolarisNamespaceRouterProperties.java | 59 ++ .../PolarisNearByRouterProperties.java | 14 +- .../PolarisRuleBasedRouterProperties.java | 17 +- .../RouterBootstrapAutoConfiguration.java | 36 + ...RouterConfigModifierAutoConfiguration.java | 46 ++ .../endpoint/PolarisRouterEndpoint.java | 2 +- .../feign/FeignExpressionLabelUtils.java | 98 --- .../feign/PolarisFeignLoadBalancer.java | 5 +- .../feign/RouterLabelFeignInterceptor.java | 109 +-- .../MetadataRouterRequestInterceptor.java | 32 +- .../NamespaceRouterRequestInterceptor.java | 55 ++ .../NearbyRouterRequestInterceptor.java | 21 +- .../RuleBasedRouterRequestInterceptor.java | 39 +- .../RouterLabelRestTemplateInterceptor.java | 53 ++ .../router/scg/RouterLabelGlobalFilter.java | 57 ++ .../router/zuul/RouterLabelZuulFilter.java | 66 ++ ...itional-spring-configuration-metadata.json | 47 +- .../main/resources/META-INF/spring.factories | 3 + .../router/MockApplicationContext.java | 244 +++++++ .../PolarisLoadBalancerCompositeRuleTest.java | 64 +- .../router/PolarisRouterContextTest.java | 17 - ...ancerInterceptorBeanPostProcessorTest.java | 86 --- .../PolarisNearByRouterPropertiesTest.java | 4 +- .../PolarisRuleBasedRouterPropertiesTest.java | 2 +- .../feign/FeignExpressionLabelUtilsTest.java | 161 ----- .../feign/PolarisFeignLoadBalancerTest.java | 4 +- .../RouterLabelFeignInterceptorTest.java | 142 ++-- .../RouterContextFactoryTest.java | 4 +- ...outerLabelRestTemplateInterceptorTest.java | 128 ++++ .../scg/RouterLabelGlobalFilterTest.java | 96 +++ .../PolarisInstanceTransformerTest.java | 55 ++ spring-cloud-tencent-commons/pom.xml | 23 +- .../common/constant/MetadataConstant.java | 4 +- .../cloud/common/constant/OrderConstant.java | 22 +- .../cloud/common/constant/RouterConstant.java | 3 +- .../cloud/common/constant/WarmupCons.java | 38 + .../common/metadata/MetadataContext.java | 218 ++++-- .../metadata/MetadataContextHolder.java | 133 ++-- .../metadata/StaticMetadataManager.java | 9 +- .../endpoint/PolarisMetadataEndpoint.java | 4 +- .../common/pojo/PolarisServiceInstance.java | 26 + .../tsf/ConditionalOnTsfConsulEnabled.java | 63 ++ .../common/tsf/ConditionalOnTsfEnabled.java | 50 ++ .../cloud/common/util/AddressUtils.java | 72 +- .../util/ApplicationContextAwareUtils.java | 26 +- .../cloud/common/util/BeanFactoryUtils.java | 38 +- .../tencent/cloud/common/util/GzipUtil.java | 88 +++ .../cloud/common/util/JacksonUtils.java | 6 +- .../cloud/common}/util/OkHttpUtil.java | 12 +- .../cloud/common/util/ReflectionUtils.java | 16 + .../tencent/cloud/common/util/UrlUtils.java | 78 ++ .../expresstion/ExpressionLabelUtils.java | 23 +- .../util/expresstion/ExpressionParserV1.java | 6 +- .../ServletExpressionLabelUtils.java | 8 +- .../SpringWebExpressionLabelUtils.java | 28 +- .../common/util/inet/PolarisInetUtils.java | 320 +++++++++ .../PolarisInetUtilsAutoConfiguration.java | 42 ++ ...olarisInetUtilsBootstrapConfiguration.java | 30 + .../tsf/core/context/TsfContext.java | 78 ++ .../springframework/tsf/core/entity/Tag.java | 144 ++++ .../main/resources/META-INF/spring.factories | 3 + .../metadata/MetadataContextHolderTest.java | 4 +- .../config/MetadataLocalPropertiesTest.java | 3 +- .../common/util/ExpressionLabelUtilsTest.java | 2 +- .../cloud/common}/util/OkHttpUtilTest.java | 12 +- .../cloud/common/util/UrlUtilsTest.java | 68 ++ .../src/test/resources/application-test.yml | 2 + spring-cloud-tencent-coverage/pom.xml | 10 + spring-cloud-tencent-dependencies/pom.xml | 76 +- .../lossless-callee-service/pom.xml | 63 ++ .../callee/LosslessCalleeController.java | 95 +++ .../callee/LosslessCalleeService.java | 29 + .../src/main/resources/bootstrap.yml | 36 + .../lossless-nacos-callee-service/pom.xml | 69 ++ .../callee/LosslessNacosCalleeController.java | 95 +++ .../callee/LosslessNacosCalleeService.java | 31 + .../src/main/resources/bootstrap.yml | 20 + .../lossless-example/pom.xml | 19 + .../front/GrayReleaseFrontApplication.java | 2 + .../GrayReleaseGatewayApplication.java | 2 + .../middle/GrayReleaseMiddleApplication.java | 2 + .../pom.xml | 24 + .../pom.xml | 70 ++ .../cloud/lane/callee/CustomMetadata.java} | 35 +- .../callee/LaneRouterCalleeApplication.java | 29 + .../callee/LaneRouterCalleeController.java | 91 +++ .../src/main/resources/application.yml | 36 + .../pom.xml | 75 ++ .../cloud/lane/caller/CustomMetadata.java | 36 +- .../lane/caller/LaneRouterCalleeService.java | 41 ++ .../caller/LaneRouterCallerApplication.java | 57 ++ .../caller/LaneRouterCallerController.java | 114 +++ .../src/main/resources/application.yml | 42 ++ .../router-grayrelease-lane-gateway/pom.xml | 48 ++ .../gateway/LaneRouterGatewayApplication.java | 29 + .../src/main/resources/application.yml | 37 + spring-cloud-tencent-examples/pom.xml | 3 + .../quickstart/callee/CustomMetadata.java | 5 - .../callee/QuickstartCalleeController.java | 6 + .../quickstart/callee/CustomMetadata.java | 5 - .../caller/QuickstartCallerController.java | 32 +- .../CircuitBreakerController.java | 21 +- .../src/main/resources/bootstrap.yml | 5 +- .../quickstart-gateway-service/pom.xml | 5 - .../src/main/resources/bootstrap.yml | 2 +- .../tsf-example/consumer-demo/pom.xml | 89 +++ .../demo/consumer/ConsumerApplication.java | 44 ++ .../controller/ConsumerController.java | 102 +++ .../demo/consumer/entity/CustomMetadata.java | 32 + .../consumer/proxy/ProviderDemoService.java | 36 + .../demo/consumer/proxy/ProviderService.java | 44 ++ .../src/main/resources/bootstrap.yml | 17 + .../tsf-example/pom.xml | 41 ++ .../tsf-example/provider-demo/pom.xml | 76 ++ .../demo/provider/ProviderApplication.java | 31 + .../provider/ProviderConfigController.java | 36 + .../tsf/demo/provider/ProviderController.java | 156 ++++ .../provider/config/ProviderNameConfig.java | 37 + .../ProviderNameConfigChangeListener.java | 40 ++ .../controller/SwaggerApiController.java | 145 ++++ .../provider/swagger/model/MessageBox.java | 102 +++ .../provider/swagger/model/MessageModel.java | 92 +++ .../provider/swagger/model/MessageUser.java | 69 ++ .../src/main/resources/bootstrap.yml | 30 + spring-cloud-tencent-plugin-starters/pom.xml | 3 + ...acosDiscoveryAdapterAutoConfiguration.java | 9 + .../NacosRegistrationTransformer.java | 48 ++ .../pom.xml | 35 + .../threadlocal/TaskExecutorWrapper.java | 45 ++ .../threadlocal/TaskExecutorWrapperTest.java | 62 ++ .../pom.xml | 24 + .../plugin/trace/SpanAttributesProvider.java | 28 + .../TraceServerMetadataEnhancedPlugin.java | 84 +++ .../trace/config/TraceConfigModifier.java | 41 ++ .../TraceConfigModifierAutoConfiguration.java | 37 + ...figModifierBootstrapAutoConfiguration.java | 30 + .../TraceEnhancedPluginAutoConfiguration.java | 43 ++ .../trace/tsf/TsfSpanAttributesProvider.java | 52 ++ .../TsfTracePropertiesAutoConfiguration.java | 39 + .../main/resources/META-INF/spring.factories | 6 + .../pom.xml | 64 ++ .../lossless/LosslessRegistryAspect.java | 107 +++ .../SpringCloudLosslessActionProvider.java | 95 +++ .../config/LosslessAutoConfiguration.java | 54 ++ .../config/LosslessConfigModifier.java | 59 ++ .../lossless/config/LosslessProperties.java | 75 ++ .../LosslessPropertiesAutoConfiguration.java | 44 ++ ...slessPropertiesBootstrapConfiguration.java | 35 + ...itional-spring-configuration-metadata.json | 10 + .../main/resources/META-INF/spring.factories | 4 + .../lossless/LosslessPropertiesTest.java | 40 ++ spring-cloud-tencent-polaris-context/pom.xml | 24 +- .../cloud/polaris/context/ModifyAddress.java | 10 + .../PolarisConfigurationConfigModifier.java | 6 +- .../context/PolarisSDKContextManager.java | 197 +++-- .../context/PostInitPolarisSDKContext.java | 8 +- .../PolarisContextAutoConfiguration.java | 23 + .../config/PolarisContextProperties.java | 3 +- .../extend/consul/ConsulProperties.java | 106 +++ .../tsf/TsfContextAutoConfiguration.java | 44 ++ .../tsf/TsfContextBootstrapConfiguration.java | 32 + .../extend/tsf/TsfContextConfigModifier.java | 64 ++ .../tsf/TsfCoreEnvironmentPostProcessor.java | 174 +++++ .../config/extend/tsf/TsfCoreProperties.java | 294 ++++++++ .../tsf/TsfInstanceMetadataProvider.java | 82 +++ .../PolarisLoggingApplicationListener.java | 4 +- .../tsf/annotation/EnableTsf.java | 45 ++ .../main/resources/META-INF/spring.factories | 8 +- .../context/PolarisContextGetHostTest.java | 11 +- .../PostInitPolarisSDKContextTest.java | 8 +- .../context/ServiceRuleManagerTest.java | 1 - .../PolarisContextAutoConfigurationTest.java | 3 +- .../extend/consul/ConsulPropertiesTest.java | 72 ++ .../PolarisLoggingPathSystemPropertyTest.java | 2 +- .../src/test/resources/bootstrap.yml | 3 +- ...itional-spring-configuration-metadata.json | 66 +- .../RpcEnhancementAutoConfiguration.java | 18 + .../feign/EnhancedFeignClient.java | 7 +- .../plugin/EnhancedPluginContext.java | 10 + .../plugin/PluginOrderConstant.java | 31 + .../EnhancedRestTemplateInterceptor.java | 1 + .../scg/EnhancedGatewayGlobalFilter.java | 12 +- .../stat/config/StatConfigModifier.java | 2 +- .../transformer/InstanceTransformer.java | 53 ++ .../PolarisInstanceTransformer.java | 48 ++ .../PolarisRegistrationTransformer.java | 27 + .../transformer/RegistrationTransformer.java | 58 ++ ...hancedWebClientExchangeFilterFunction.java | 14 +- .../zuul/EnhancedPreZuulFilter.java | 1 + 353 files changed, 12607 insertions(+), 2439 deletions(-) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java delete mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataRestTemplateInterceptor.java => EncodeTransferMedataRestTemplateEnhancedPlugin.java} (56%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataScgFilter.java => EncodeTransferMedataScgEnhancedPlugin.java} (55%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMedataWebClientFilter.java => EncodeTransferMedataWebClientEnhancedPlugin.java} (54%) rename spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/{EncodeTransferMetadataZuulFilter.java => EncodeTransferMetadataZuulEnhancedPlugin.java} (59%) create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java delete mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java create mode 100644 spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java create mode 100755 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java create mode 100644 spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java delete mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java delete mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java rename spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/{ConsulContextPropertiesTest.java => ConsulDiscoveryPropertiesTest.java} (81%) create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java delete mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java delete mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java delete mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java rename {spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris => spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common}/util/OkHttpUtil.java (87%) create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java create mode 100644 spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java create mode 100644 spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java rename {spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris => spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common}/util/OkHttpUtilTest.java (82%) create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java create mode 100644 spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/lossless-example/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml rename spring-cloud-tencent-examples/{quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java => polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java} (56%) create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java => spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java (54%) create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java create mode 100644 spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.java create mode 100644 spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-examples/tsf-example/pom.xml create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java create mode 100644 spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java rename spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java => spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java (80%) create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.java create mode 100644 spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.java create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java create mode 100644 spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java diff --git a/pom.xml b/pom.xml index f9594768c..070e126a8 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.13.4-Hoxton.SR12-SNAPSHOT + 2.0.0.0-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE @@ -102,7 +102,7 @@ Hoxton.SR12 - 0.8.8 + 0.8.12 3.2.0 1.2.7 3.0.1 diff --git a/spring-cloud-starter-tencent-all/pom.xml b/spring-cloud-starter-tencent-all/pom.xml index 79bba53e0..767a25866 100644 --- a/spring-cloud-starter-tencent-all/pom.xml +++ b/spring-cloud-starter-tencent-all/pom.xml @@ -49,6 +49,11 @@ com.tencent.cloud spring-cloud-starter-tencent-polaris-contract + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + diff --git a/spring-cloud-starter-tencent-metadata-transfer/pom.xml b/spring-cloud-starter-tencent-metadata-transfer/pom.xml index ad4714f7a..35b783daa 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/pom.xml +++ b/spring-cloud-starter-tencent-metadata-transfer/pom.xml @@ -19,6 +19,12 @@ com.tencent.cloud spring-cloud-tencent-commons + + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + @@ -56,6 +62,24 @@ spring-cloud-starter-netflix-ribbon test + + + com.tencent.polaris + polaris-test-mock-discovery + test + + + + com.tencent.polaris + polaris-test-common + test + + + + org.mockito + mockito-inline + test + diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index bbb033282..003bc062b 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -18,31 +18,23 @@ package com.tencent.cloud.metadata.config; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import com.netflix.zuul.ZuulFilter; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataScgFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientFilter; -import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulFilter; - -import org.springframework.beans.factory.SmartInitializingSingleton; -import org.springframework.beans.factory.annotation.Autowired; +import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulEnhancedPlugin; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; + import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.reactive.function.client.WebClient; import static javax.servlet.DispatcherType.ASYNC; import static javax.servlet.DispatcherType.ERROR; @@ -76,8 +68,8 @@ public FilterRegistrationBean metadataServl } @Bean - public DecodeTransferMetadataServletFilter metadataServletFilter() { - return new DecodeTransferMetadataServletFilter(); + public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextProperties polarisContextProperties) { + return new DecodeTransferMetadataServletFilter(polarisContextProperties); } } @@ -89,8 +81,8 @@ public DecodeTransferMetadataServletFilter metadataServletFilter() { protected static class MetadataReactiveFilterConfig { @Bean - public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() { - return new DecodeTransferMetadataReactiveFilter(); + public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisContextProperties polarisContextProperties) { + return new DecodeTransferMetadataReactiveFilter(polarisContextProperties); } } @@ -103,8 +95,8 @@ public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() { protected static class MetadataTransferZuulFilterConfig { @Bean - public ZuulFilter encodeTransferMetadataZuulFilter() { - return new EncodeTransferMetadataZuulFilter(); + public EncodeTransferMetadataZuulEnhancedPlugin encodeTransferMetadataZuulEnhancedPlugin() { + return new EncodeTransferMetadataZuulEnhancedPlugin(); } } @@ -114,11 +106,12 @@ public ZuulFilter encodeTransferMetadataZuulFilter() { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferScgFilterConfig { @Bean - public GlobalFilter encodeTransferMedataScgFilter() { - return new EncodeTransferMedataScgFilter(); + public EncodeTransferMedataScgEnhancedPlugin encodeTransferMedataScgEnhancedPlugin() { + return new EncodeTransferMedataScgEnhancedPlugin(); } } @@ -127,11 +120,12 @@ public GlobalFilter encodeTransferMedataScgFilter() { */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "feign.Feign") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferFeignInterceptorConfig { @Bean - public EncodeTransferMedataFeignInterceptor encodeTransferMedataFeignInterceptor() { - return new EncodeTransferMedataFeignInterceptor(); + public EncodeTransferMedataFeignEnhancedPlugin encodeTransferMedataFeignEnhancedPlugin() { + return new EncodeTransferMedataFeignEnhancedPlugin(); } } @@ -140,23 +134,12 @@ public EncodeTransferMedataFeignInterceptor encodeTransferMedataFeignInterceptor */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferRestTemplateConfig { - @Autowired(required = false) - private List restTemplates = Collections.emptyList(); - @Bean - public EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor() { - return new EncodeTransferMedataRestTemplateInterceptor(); - } - - @Bean - public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTemplate(EncodeTransferMedataRestTemplateInterceptor interceptor) { - return () -> restTemplates.forEach(restTemplate -> { - List list = new ArrayList<>(restTemplate.getInterceptors()); - list.add(interceptor); - restTemplate.setInterceptors(list); - }); + public EncodeTransferMedataRestTemplateEnhancedPlugin encodeTransferMedataRestTemplateEnhancedPlugin() { + return new EncodeTransferMedataRestTemplateEnhancedPlugin(); } } @@ -165,20 +148,12 @@ public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTem */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient") + @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferWebClientConfig { - @Autowired(required = false) - private List webClientBuilder = Collections.emptyList(); - - @Bean - public EncodeTransferMedataWebClientFilter encodeTransferMedataWebClientFilter() { - return new EncodeTransferMedataWebClientFilter(); - } @Bean - public SmartInitializingSingleton addEncodeTransferMetadataFilterForWebClient(EncodeTransferMedataWebClientFilter filter) { - return () -> webClientBuilder.forEach(webClient -> { - webClient.filter(filter); - }); + public EncodeTransferMedataWebClientEnhancedPlugin encodeTransferMedataWebClientEnhancedPlugin() { + return new EncodeTransferMedataWebClientEnhancedPlugin(); } } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java index 4268f6e79..d279aa0c5 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -18,8 +18,6 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -27,6 +25,10 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; @@ -34,14 +36,14 @@ import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL_IP; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -52,6 +54,11 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class); + private PolarisContextProperties polarisContextProperties; + + public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) { + this.polarisContextProperties = polarisContextProperties; + } @Override public int getOrder() { @@ -63,17 +70,32 @@ public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain web // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); - Map internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA); + // transitive metadata + // from specific header + Map internalTransitiveMetadata = getInternalMetadata(serverHttpRequest, CUSTOM_METADATA); + // from header with specific prefix Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); - Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); + // disposable metadata + // from specific header + Map internalDisposableMetadata = getInternalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); + // application metadata + Map internalApplicationMetadata = getInternalMetadata(serverHttpRequest, APPLICATION_METADATA); + Map mergedApplicationMetadata = new HashMap<>(internalApplicationMetadata); + + String callerIp = ""; + if (StringUtils.isNotBlank(mergedApplicationMetadata.get(LOCAL_IP))) { + callerIp = mergedApplicationMetadata.get(LOCAL_IP); + } + // message metadata + ReactiveMetadataProvider callerMessageMetadataProvider = new ReactiveMetadataProvider(serverHttpRequest, callerIp); + + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider); // Save to ServerWebExchange. serverWebExchange.getAttributes().put( @@ -87,17 +109,9 @@ public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain web .doFinally((type) -> MetadataContextHolder.remove()); } - private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { + private Map getInternalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); - String customMetadataStr = httpHeaders.getFirst(headerName); - try { - if (StringUtils.hasText(customMetadataStr)) { - customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); - } - } - catch (UnsupportedEncodingException e) { - LOG.error("Runtime system does not support utf-8 coding.", e); - } + String customMetadataStr = UrlUtils.decode(httpHeaders.getFirst(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); return JacksonUtils.deserialize2Map(customMetadataStr); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index e1d26efcc..ec060a4ff 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -19,8 +19,6 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -32,17 +30,21 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.metadata.provider.ServletMetadataProvider; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.lang.NonNull; -import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL_IP; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -55,21 +57,42 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); + private PolarisContextProperties polarisContextProperties; + + public DecodeTransferMetadataServletFilter(PolarisContextProperties polarisContextProperties) { + this.polarisContextProperties = polarisContextProperties; + } + @Override protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + // transitive metadata + // from specific header Map internalTransitiveMetadata = getInternalMetadata(httpServletRequest, CUSTOM_METADATA); + // from header with specific prefix Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest); - Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); + // disposable metadata + // from specific header Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); + // application metadata + Map internalApplicationMetadata = getInternalMetadata(httpServletRequest, APPLICATION_METADATA); + Map mergedApplicationMetadata = new HashMap<>(internalApplicationMetadata); + + String callerIp = ""; + if (StringUtils.isNotBlank(mergedApplicationMetadata.get(LOCAL_IP))) { + callerIp = mergedApplicationMetadata.get(LOCAL_IP); + } + // message metadata + ServletMetadataProvider callerMessageMetadataProvider = new ServletMetadataProvider(httpServletRequest, callerIp); + + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider); TransHeadersTransfer.transfer(httpServletRequest); try { @@ -83,15 +106,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, private Map getInternalMetadata(HttpServletRequest httpServletRequest, String headerName) { // Get custom metadata string from http header. - String customMetadataStr = httpServletRequest.getHeader(headerName); - try { - if (StringUtils.hasText(customMetadataStr)) { - customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); - } - } - catch (UnsupportedEncodingException e) { - LOG.error("Runtime system does not support utf-8 coding.", e); - } + String customMetadataStr = UrlUtils.decode(httpServletRequest.getHeader(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); // create custom metadata. diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java new file mode 100644 index 000000000..3e07c3bf0 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java @@ -0,0 +1,145 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.metadata.core; + +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.ReflectionUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; + +import org.springframework.util.CollectionUtils; + +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; + +/** + * Pre EnhancedPlugin for feign to encode transfer metadata. + * + * @author Shedfree Wu + */ +public class EncodeTransferMedataFeignEnhancedPlugin implements EnhancedPlugin { + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; + } + + @Override + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof Request)) { + return; + } + Request request = (Request) context.getOriginRequest(); + + // get metadata of current thread + MetadataContext metadataContext = MetadataContextHolder.get(); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); + Map transHeaders = metadataContext.getTransHeadersKV(); + + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(request, calleeTransitiveHeaders); + + // build custom disposable metadata request header + this.buildMetadataHeader(request, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // process custom metadata + this.buildMetadataHeader(request, customMetadata, CUSTOM_METADATA); + + // add application metadata + this.buildMetadataHeader(request, applicationMetadata, APPLICATION_METADATA); + + // set headers that need to be transmitted from the upstream + this.buildTransmittedHeader(request, transHeaders); + } + + private void buildTransmittedHeader(Request request, Map transHeaders) { + if (!CollectionUtils.isEmpty(transHeaders)) { + Map> headers = getModifiableHeaders(request); + transHeaders.entrySet().stream().forEach(entry -> { + headers.remove(entry.getKey()); + headers.put(entry.getKey(), Arrays.asList(entry.getValue())); + }); + } + } + + /** + * Set metadata into the request header for {@link Request} . + * @param request instance of {@link Request} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(Request request, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); + } + } + + + /** + * Set headerMap into the request header for {@link Request} . + * @param request instance of {@link Request} + * @param headerMap header map . + */ + private void buildHeaderMap(Request request, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + Map> headers = getModifiableHeaders(request); + headerMap.forEach((key, value) -> headers.put(key, Arrays.asList(UrlUtils.encode(value)))); + } + } + + /** + * The value obtained directly from the headers method is an unmodifiable map. + * If the Feign client uses the URL, the original headers are unmodifiable. + * @param request feign request + * @return modifiable headers + */ + private Map> getModifiableHeaders(Request request) { + Map> headers; + headers = (Map>) ReflectionUtils.getFieldValue(request, "headers"); + + if (!(headers instanceof LinkedHashMap)) { + headers = new LinkedHashMap<>(headers); + ReflectionUtils.setFieldValue(request, "headers", headers); + } + return headers; + } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java deleted file mode 100644 index edbf5f0bc..000000000 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.metadata.core; - -import java.io.UnsupportedEncodingException; -import java.util.Map; - -import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.util.JacksonUtils; -import feign.RequestInterceptor; -import feign.RequestTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.core.Ordered; -import org.springframework.util.CollectionUtils; -import org.springframework.web.client.RestTemplate; - -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; -import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; -import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static java.net.URLEncoder.encode; - -/** - * Interceptor used for adding the metadata in http headers from context when web client - * is Feign. - * - * @author Haotian Zhang - */ -public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, Ordered { - - private static final Logger LOG = LoggerFactory.getLogger(EncodeTransferMedataFeignInterceptor.class); - - @Override - public int getOrder() { - return OrderConstant.Client.Feign.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; - } - - @Override - public void apply(RequestTemplate requestTemplate) { - // get metadata of current thread - MetadataContext metadataContext = MetadataContextHolder.get(); - Map customMetadata = metadataContext.getCustomMetadata(); - Map disposableMetadata = metadataContext.getDisposableMetadata(); - Map transHeaders = metadataContext.getTransHeadersKV(); - - this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - - // process custom metadata - this.buildMetadataHeader(requestTemplate, customMetadata, CUSTOM_METADATA); - - // set headers that need to be transmitted from the upstream - this.buildTransmittedHeader(requestTemplate, transHeaders); - } - - private void buildTransmittedHeader(RequestTemplate requestTemplate, Map transHeaders) { - if (!CollectionUtils.isEmpty(transHeaders)) { - transHeaders.entrySet().stream().forEach(entry -> { - requestTemplate.removeHeader(entry.getKey()); - requestTemplate.header(entry.getKey(), entry.getValue()); - }); - } - } - - /** - * Set metadata into the request header for {@link RestTemplate} . - * @param requestTemplate instance of {@link RestTemplate} - * @param metadata metadata map . - * @param headerName target metadata http header name . - */ - private void buildMetadataHeader(RequestTemplate requestTemplate, Map metadata, String headerName) { - if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - requestTemplate.removeHeader(headerName); - try { - requestTemplate.header(headerName, encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - LOG.error("Set header failed.", e); - requestTemplate.header(headerName, encodedMetadata); - } - } - } -} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java similarity index 56% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java index cbf4901b3..f3637494e 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java @@ -18,49 +18,55 @@ package com.tencent.cloud.metadata.core; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; -import com.tencent.cloud.common.constant.OrderConstant; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; -import org.springframework.core.Ordered; import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; -import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Interceptor used for adding the metadata in http headers from context when web client - * is RestTemplate. + * Pre EnhancedPlugin for rest template to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { - +public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedPlugin { @Override - public int getOrder() { - return OrderConstant.Client.RestTemplate.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes, - @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof HttpRequest)) { + return; + } + HttpRequest httpRequest = (HttpRequest) context.getOriginRequest(); + // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(httpRequest, calleeTransitiveHeaders); // build custom disposable metadata request header this.buildMetadataHeader(httpRequest, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); @@ -68,10 +74,11 @@ public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull b // build custom metadata request header this.buildMetadataHeader(httpRequest, customMetadata, CUSTOM_METADATA); + // build application metadata request header + this.buildMetadataHeader(httpRequest, applicationMetadata, APPLICATION_METADATA); + // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(httpRequest, transHeaders); - - return clientHttpRequestExecution.execute(httpRequest, bytes); } private void buildTransmittedHeader(HttpRequest request, Map transHeaders) { @@ -82,6 +89,12 @@ private void buildTransmittedHeader(HttpRequest request, Map tra } } + private void buildHeaderMap(HttpRequest request, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> request.getHeaders().set(key, UrlUtils.encode(value))); + } + } + /** * Set metadata into the request header for {@link HttpRequest} . * @@ -91,13 +104,12 @@ private void buildTransmittedHeader(HttpRequest request, Map tra */ private void buildMetadataHeader(HttpRequest request, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - request.getHeaders().set(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - request.getHeaders().set(headerName, encodedMetadata); - } + buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java similarity index 55% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java index 2eacd21a7..7974bd71d 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java @@ -18,42 +18,47 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; -import reactor.core.publisher.Mono; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Scg filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for scg to encode transfer metadata. * - * @author Haotian Zhang + * @author Shedfree Wu */ -public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { - +public class EncodeTransferMedataScgEnhancedPlugin implements EnhancedPlugin { @Override - public int getOrder() { - return OrderConstant.Client.Scg.ENCODE_TRANSFER_METADATA_FILTER_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof ServerWebExchange)) { + return; + } + ServerWebExchange exchange = (ServerWebExchange) context.getOriginRequest(); + // get request builder ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); @@ -65,12 +70,25 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); + + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(builder, calleeTransitiveHeaders); this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - + this.buildMetadataHeader(builder, applicationMetadata, APPLICATION_METADATA); TransHeadersTransfer.transfer(exchange.getRequest()); - return chain.filter(exchange.mutate().request(builder.build()).build()); + + context.setOriginRequest(exchange.mutate().request(builder.build()).build()); + } + + private void buildHeaderMap(ServerHttpRequest.Builder builder, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> builder.header(key, UrlUtils.encode(value))); + } } /** @@ -81,13 +99,12 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { */ private void buildMetadataHeader(ServerHttpRequest.Builder builder, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - builder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - builder.header(headerName, encodedMetadata); - } + buildHeaderMap(builder, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java similarity index 54% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java index 3547add0e..441b33446 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java @@ -18,48 +18,64 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.Map; +import com.google.common.collect.ImmutableMap; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; -import reactor.core.publisher.Mono; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.client.ClientRequest; -import org.springframework.web.reactive.function.client.ClientResponse; -import org.springframework.web.reactive.function.client.ExchangeFilterFunction; -import org.springframework.web.reactive.function.client.ExchangeFunction; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * web client filter used for writing metadata in HTTP request header. + * Pre EnhancedPlugin for web client to encode transfer metadata. * - * @author sean yu + * @author Shedfree Wu */ -public class EncodeTransferMedataWebClientFilter implements ExchangeFilterFunction { +public class EncodeTransferMedataWebClientEnhancedPlugin implements EnhancedPlugin { + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; + } @Override - public Mono filter(ClientRequest clientRequest, ExchangeFunction next) { + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof ClientRequest)) { + return; + } + ClientRequest clientRequest = (ClientRequest) context.getOriginRequest(); + MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); ClientRequest.Builder requestBuilder = ClientRequest.from(clientRequest); + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(requestBuilder, calleeTransitiveHeaders); + this.buildMetadataHeader(requestBuilder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestBuilder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + this.buildMetadataHeader(requestBuilder, applicationMetadata, APPLICATION_METADATA); this.buildTransmittedHeader(requestBuilder, transHeaders); - ClientRequest request = requestBuilder.build(); - - return next.exchange(request); + context.setOriginRequest(requestBuilder.build()); } private void buildTransmittedHeader(ClientRequest.Builder requestBuilder, Map transHeaders) { @@ -68,6 +84,11 @@ private void buildTransmittedHeader(ClientRequest.Builder requestBuilder, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> requestBuilder.header(key, UrlUtils.encode(value))); + } + } /** * Set metadata into the request header for {@link ClientRequest} . @@ -77,14 +98,12 @@ private void buildTransmittedHeader(ClientRequest.Builder requestBuilder, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - String encodedMetadata = JacksonUtils.serialize2Json(metadata); - try { - requestBuilder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); - } - catch (UnsupportedEncodingException e) { - requestBuilder.header(headerName, encodedMetadata); - } + buildHeaderMap(requestBuilder, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java similarity index 59% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java index 6aa2a1e05..585a40eb3 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java @@ -22,59 +22,68 @@ import java.net.URLEncoder; import java.util.Map; -import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; import org.springframework.util.CollectionUtils; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE; -/** - * Zuul filter used for writing metadata in HTTP request header. - * - * @author Haotian Zhang - */ -public class EncodeTransferMetadataZuulFilter extends ZuulFilter { - @Override - public String filterType() { - return ROUTE_TYPE; - } +public class EncodeTransferMetadataZuulEnhancedPlugin implements EnhancedPlugin { @Override - public int filterOrder() { - return OrderConstant.Client.Zuul.ENCODE_TRANSFER_METADATA_FILTER_ORDER; + public EnhancedPluginType getType() { + return EnhancedPluginType.Client.PRE; } @Override - public boolean shouldFilter() { - return true; - } + public void run(EnhancedPluginContext context) throws Throwable { + if (!(context.getOriginRequest() instanceof RequestContext)) { + return; + } - @Override - public Object run() { // get request context - RequestContext requestContext = RequestContext.getCurrentContext(); + RequestContext requestContext = (RequestContext) context.getOriginRequest(); // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); + + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); + Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + + // currently only support transitive header from calleeMessageMetadataContainer + this.buildHeaderMap(requestContext, calleeTransitiveHeaders); // Rebuild Metadata Header this.buildMetadataHeader(requestContext, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestContext, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + this.buildMetadataHeader(requestContext, applicationMetadata, APPLICATION_METADATA); TransHeadersTransfer.transfer(requestContext.getRequest()); - return null; + + } + + private void buildHeaderMap(RequestContext requestContext, Map headerMap) { + if (!CollectionUtils.isEmpty(headerMap)) { + headerMap.forEach((key, value) -> requestContext.addZuulRequestHeader(key, UrlUtils.encode(value))); + } } /** @@ -95,4 +104,9 @@ private void buildMetadataHeader(RequestContext context, Map met } } } + + @Override + public int getOrder() { + return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.java new file mode 100644 index 000000000..1d62416a5 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.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.metadata.provider; + +import java.net.URI; +import java.util.Collection; +import java.util.Map; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; +import feign.RequestTemplate; + +/** + * MetadataProvider used for Feign RequestTemplate. + * + * @author Haotian Zhang + */ +public class FeignRequestTemplateMetadataProvider implements MetadataProvider { + + private final RequestTemplate requestTemplate; + + public FeignRequestTemplateMetadataProvider(RequestTemplate requestTemplate) { + this.requestTemplate = requestTemplate; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return requestTemplate.method(); + case MessageMetadataContainer.LABEL_KEY_PATH: + URI uri = URI.create(requestTemplate.request().url()); + return UrlUtils.decode(uri.getPath()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + Map> headers = requestTemplate.headers(); + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(headers, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(ExpressionLabelUtils.getCookieFirstValue(headers, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(requestTemplate.queries(), mapKey)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java new file mode 100644 index 000000000..d39d74ed8 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; + +import org.springframework.http.server.reactive.ServerHttpRequest; + +/** + * MetadataProvider used for Reactive. + * + * @author Shedfree Wu + */ +public class ReactiveMetadataProvider implements MetadataProvider { + + private ServerHttpRequest serverHttpRequest; + + private String callerIp; + + public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest, String callerIp) { + this.serverHttpRequest = serverHttpRequest; + this.callerIp = callerIp; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return serverHttpRequest.getMethod().name(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(serverHttpRequest.getPath().toString()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return callerIp; + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(serverHttpRequest, mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(serverHttpRequest, mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(serverHttpRequest, mapKey, null)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java new file mode 100644 index 000000000..31eea10f8 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java @@ -0,0 +1,70 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; + +import org.springframework.http.HttpRequest; + +/** + * MetadataProvider used for RestTemplate HttpRequest. + * + * @author Haotian Zhang + */ +public class RestTemplateMetadataProvider implements MetadataProvider { + + private final HttpRequest request; + + public RestTemplateMetadataProvider(HttpRequest request) { + this.request = request; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return request.getMethod().toString(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(request.getURI().getPath()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(request, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(request, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(request, mapKey)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java new file mode 100644 index 000000000..082e13f11 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.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.metadata.provider; +import javax.servlet.http.HttpServletRequest; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; +import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; + + +/** + * MetadataProvider used for Servlet. + * + * @author Shedfree Wu + */ +public class ServletMetadataProvider implements MetadataProvider { + + private HttpServletRequest httpServletRequest; + + private String callerIp; + + public ServletMetadataProvider(HttpServletRequest httpServletRequest, String callerIp) { + this.httpServletRequest = httpServletRequest; + this.callerIp = callerIp; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return httpServletRequest.getMethod(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(httpServletRequest.getRequestURI()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return callerIp; + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(httpServletRequest.getHeader(mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(ServletExpressionLabelUtils.getCookieValue(httpServletRequest.getCookies(), mapKey, null)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(ExpressionLabelUtils.getQueryValue(httpServletRequest.getQueryString(), mapKey, null)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java index cd23e7615..4da4dc8d3 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java @@ -18,25 +18,18 @@ package com.tencent.cloud.metadata.config; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; -import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientFilter; +import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; @@ -59,35 +52,10 @@ public void test1() { this.applicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); + assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateInterceptor.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); - assertThat(context).hasSingleBean(GlobalFilter.class); - }); - } - - - @Test - public void test2() { - this.applicationContextRunner - .withConfiguration( - AutoConfigurations.of(MetadataTransferAutoConfiguration.class, RestTemplateConfiguration.class)) - .run(context -> { - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); - EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor = context.getBean(EncodeTransferMedataRestTemplateInterceptor.class); - Map restTemplateMap = context.getBeansOfType(RestTemplate.class); - assertThat(restTemplateMap.size()).isEqualTo(2); - for (String beanName : Arrays.asList("restTemplate", "loadBalancedRestTemplate")) { - RestTemplate restTemplate = restTemplateMap.get(beanName); - assertThat(restTemplate).isNotNull(); - List encodeTransferMedataFeignInterceptorList = restTemplate.getInterceptors() - .stream() - .filter(interceptor -> Objects.equals(interceptor, encodeTransferMedataRestTemplateInterceptor)) - .collect(Collectors.toList()); - //EncodeTransferMetadataFeignInterceptor is not added repeatedly - assertThat(encodeTransferMedataFeignInterceptorList.size()).isEqualTo(1); - } }); } @@ -95,16 +63,15 @@ public void test2() { * Reactive web application. */ @Test - public void test3() { - this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class)) + public void test2() { + this.reactiveWebApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class, PolarisContextProperties.class)) .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataFeignInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateInterceptor.class); + assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); - assertThat(context).hasSingleBean(GlobalFilter.class); - assertThat(context).hasSingleBean(EncodeTransferMedataWebClientFilter.class); + assertThat(context).hasSingleBean(EncodeTransferMedataWebClientEnhancedPlugin.class); }); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java index bbee696c9..ff27c0c4d 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java @@ -20,6 +20,7 @@ import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -54,7 +55,7 @@ public class DecodeTransferMetadataReactiveFilterTest { @BeforeEach public void setUp() { - this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(); + this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(new PolarisContextProperties()); } @Test diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java index df3e883f1..e34f4e9ae 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java @@ -40,7 +40,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; /** - * Test for {@link EncodeTransferMedataFeignInterceptor}. + * Test for {@link EncodeTransferMedataFeignEnhancedPlugin}. * * @author Haotian Zhang */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java index 275784bbb..b0ce9217c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -17,8 +17,14 @@ package com.tencent.cloud.metadata.core; +import java.net.URI; +import java.util.Arrays; +import java.util.Map; + import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,6 +32,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -39,7 +46,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataRestTemplateInterceptor}. + * Test for {@link EncodeTransferMedataRestTemplateEnhancedPlugin}. * * @author Haotian Zhang */ @@ -72,7 +79,13 @@ protected static class TestApplication { @Bean public RestTemplate restTemplate() { - return new RestTemplate(); + + EncodeTransferMedataRestTemplateEnhancedPlugin plugin = new EncodeTransferMedataRestTemplateEnhancedPlugin(); + EnhancedRestTemplateInterceptor interceptor = new EnhancedRestTemplateInterceptor( + new DefaultEnhancedPluginRunner(Arrays.asList(plugin), new MockRegistration(), null)); + RestTemplate template = new RestTemplate(); + template.setInterceptors(Arrays.asList(interceptor)); + return template; } @RequestMapping("/test") @@ -80,4 +93,37 @@ public String test() { return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } } + + static class MockRegistration implements Registration { + + @Override + public String getServiceId() { + return "test"; + } + + @Override + public String getHost() { + return "localhost"; + } + + @Override + public int getPort() { + return 0; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public URI getUri() { + return null; + } + + @Override + public Map getMetadata() { + return null; + } + } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java index 97f55f731..cbc1116bc 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilterTest.java @@ -18,59 +18,129 @@ package com.tencent.cloud.metadata.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Map; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; +import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter; +import org.assertj.core.util.Maps; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.route.Route; import org.springframework.context.ApplicationContext; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.server.ServerWebExchange; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; +import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; /** - * @author quan + * Test for {@link EncodeTransferMedataScgEnhancedPlugin}. + * @author quan, Shedfree Wu */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = RANDOM_PORT, classes = EncodeTransferMedataScgFilterTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) +@ExtendWith(MockitoExtension.class) public class EncodeTransferMedataScgFilterTest { - @Autowired - private ApplicationContext applicationContext; - + private static MockedStatic mockedApplicationContextAwareUtils; + @Mock + Registration registration; @Mock - private GatewayFilterChain chain; + GatewayFilterChain chain; - @Test - public void testTransitiveMetadataFromApplicationConfig() throws UnsupportedEncodingException { - EncodeTransferMedataScgFilter filter = applicationContext.getBean(EncodeTransferMedataScgFilter.class); - MockServerHttpRequest.BaseBuilder builder = MockServerHttpRequest.get(""); - MockServerWebExchange exchange = MockServerWebExchange.from(builder); - filter.filter(exchange, chain); - String metadataStr = exchange.getRequest().getHeaders().getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA); - String decode = URLDecoder.decode(metadataStr, UTF_8); - Map transitiveMap = JacksonUtils.deserialize2Map(decode); - assertThat(transitiveMap.size()).isEqualTo(1); - assertThat(transitiveMap.get("b")).isEqualTo("2"); + @BeforeAll + static void beforeAll() { + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + ApplicationContext applicationContext = mock(ApplicationContext.class); + MetadataLocalProperties metadataLocalProperties = mock(MetadataLocalProperties.class); + StaticMetadataManager staticMetadataManager = mock(StaticMetadataManager.class); + doReturn(metadataLocalProperties).when(applicationContext).getBean(MetadataLocalProperties.class); + doReturn(staticMetadataManager).when(applicationContext).getBean(StaticMetadataManager.class); + mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext) + .thenReturn(applicationContext); + } + + @AfterAll + static void afterAll() { + mockedApplicationContextAwareUtils.close(); } - @SpringBootApplication - protected static class TestApplication { + @BeforeEach + void setUp() { + MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST; + MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER; + } + + @Test + public void testRun() throws URISyntaxException { + + Route route = mock(Route.class); + URI uri = new URI("http://TEST/"); + doReturn(uri).when(route).getUri(); + + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Maps.newHashMap("t-key", "t-value")); + metadataContext.setDisposableMetadata(Maps.newHashMap("d-key", "d-value")); + + MockServerHttpRequest mockServerHttpRequest = MockServerHttpRequest.get("/test").build(); + + EncodeTransferMedataScgEnhancedPlugin plugin = new EncodeTransferMedataScgEnhancedPlugin(); + plugin.getOrder(); + EnhancedGatewayGlobalFilter filter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(Arrays.asList(plugin), registration, null)); + filter.getOrder(); + + MockServerWebExchange mockServerWebExchange = MockServerWebExchange.builder(mockServerHttpRequest).build(); + mockServerWebExchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route); + mockServerWebExchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("http://0.0.0.0/")); + mockServerWebExchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT, metadataContext); + doReturn(Mono.empty()).when(chain).filter(any()); + + + filter.filter(mockServerWebExchange, chain).block(); + + + ArgumentCaptor captor = ArgumentCaptor.forClass(ServerWebExchange.class); + // capture the result exchange + Mockito.verify(chain).filter(captor.capture()); + ServerWebExchange filteredExchange = captor.getValue(); + + assertThat(filteredExchange.getRequest().getHeaders().get(CUSTOM_METADATA)).isNotNull(); + assertThat(filteredExchange.getRequest().getHeaders().get(CUSTOM_DISPOSABLE_METADATA)).isNotNull(); + + // test metadataContext init in EnhancedPlugin + mockServerWebExchange.getAttributes().remove(MetadataConstant.HeaderName.METADATA_CONTEXT); + assertThatCode(() -> filter.filter(mockServerWebExchange, chain).block()).doesNotThrowAnyException(); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java index 85c8b2d35..fe7c30d27 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientFilterTest.java @@ -37,7 +37,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataWebClientFilter}. + * Test for {@link EncodeTransferMedataWebClientEnhancedPlugin}. * * @author sean yu */ diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java deleted file mode 100644 index 56895ee25..000000000 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.metadata.core; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Map; - -import com.netflix.zuul.context.RequestContext; -import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.util.JacksonUtils; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.web.MockMultipartHttpServletRequest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; - -/** - * Test for {@link EncodeTransferMetadataZuulFilter}. - * - * @author quan - */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = RANDOM_PORT, - classes = EncodeTransferMetadataZuulFilterTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) -public class EncodeTransferMetadataZuulFilterTest { - - private final MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); - @Autowired - private ApplicationContext applicationContext; - - @BeforeEach - void setUp() { - RequestContext ctx = RequestContext.getCurrentContext(); - ctx.clear(); - ctx.setRequest(this.request); - } - - @Test - public void multiplePartNamesWithMultipleParts() throws UnsupportedEncodingException { - EncodeTransferMetadataZuulFilter filter = applicationContext.getBean(EncodeTransferMetadataZuulFilter.class); - filter.run(); - final RequestContext ctx = RequestContext.getCurrentContext(); - Map zuulRequestHeaders = ctx.getZuulRequestHeaders(); - String metadata = zuulRequestHeaders.get(MetadataConstant.HeaderName.CUSTOM_METADATA.toLowerCase()); - Assertions.assertThat(metadata).isNotNull(); - - String decode = URLDecoder.decode(metadata, UTF_8); - Map transitiveMap = JacksonUtils.deserialize2Map(decode); - Assertions.assertThat(transitiveMap.size()).isEqualTo(1); - Assertions.assertThat(transitiveMap.get("b")).isEqualTo("2"); - } - - @SpringBootApplication - protected static class TestApplication { - - } -} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java new file mode 100644 index 000000000..dab78d99a --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java @@ -0,0 +1,139 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import org.junit.jupiter.api.Test; + +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpMethod; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.MockCookie; +import org.springframework.mock.web.MockHttpServletRequest; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link ReactiveMetadataProvider} and {@link ServletMetadataProvider}. + * + * @author quan, Shedfree Wu + */ +public class MetadataProviderTest { + + private static final String notExistKey = "empty"; + + @Test + public void testReactiveMetadataProvider() { + String headerKey1 = "header1"; + String headerKey2 = "header2"; + String headerValue1 = "value1"; + String headerValue2 = "value2/test"; + String queryKey1 = "qk1"; + String queryKey2 = "qk2"; + String queryValue1 = "qv1"; + String queryValue2 = "qv2/test"; + String cookieKey1 = "ck1"; + String cookieKey2 = "ck2"; + String cookieValue1 = "cv1"; + String cookieValue2 = "cv2/test"; + String path = "/echo/test"; + String callerIp = "localhost"; + MockServerHttpRequest request = MockServerHttpRequest.get(path) + .header(headerKey1, headerValue1) + .header(headerKey2, UrlUtils.encode(headerValue2)) + .queryParam(queryKey1, queryValue1) + .queryParam(queryKey2, UrlUtils.encode(queryValue2)) + .cookie(new HttpCookie(cookieKey1, cookieValue1)) + .cookie(new HttpCookie(cookieKey2, UrlUtils.encode(cookieValue2))) + .build(); + + ReactiveMetadataProvider reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); + // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); + assertThat(reactiveMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); + + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); + + request = MockServerHttpRequest.get("/echo/" + UrlUtils.decode("a@b")).build(); + reactiveMetadataProvider = new ReactiveMetadataProvider(request, callerIp); + assertThat(reactiveMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); + } + + @Test + public void testServletMetadataProvider() { + String headerKey1 = "header1"; + String headerKey2 = "header2"; + String headerValue1 = "value1"; + String headerValue2 = "value2/test"; + String queryKey1 = "qk1"; + String queryKey2 = "qk2"; + String queryValue1 = "qv1"; + String queryValue2 = "qv2/test"; + String cookieKey1 = "ck1"; + String cookieKey2 = "ck2"; + String cookieValue1 = "cv1"; + String cookieValue2 = "cv2/test"; + String path = "/echo/test"; + String callerIp = "localhost"; + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(headerKey1, headerValue1); + request.addHeader(headerKey2, UrlUtils.encode(headerValue2)); + request.setCookies(new MockCookie(cookieKey1, cookieValue1), new MockCookie(cookieKey2, UrlUtils.encode(cookieValue2))); + request.setMethod(HttpMethod.GET.name()); + request.setRequestURI(path); + request.setQueryString(queryKey1 + "=" + queryValue1 + "&" + queryKey2 + "=" + UrlUtils.encode(queryValue2)); + + ServletMetadataProvider servletMetadataProvider = new ServletMetadataProvider(request, callerIp); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey1)).isEqualTo(headerValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerKey2)).isEqualTo(headerValue2); + // com.tencent.polaris.metadata.core.manager.ComposeMetadataProvider.getRawMetadataMapValue need return null when key don't exist + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, notExistKey)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey1)).isEqualTo(cookieValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, cookieKey2)).isEqualTo(cookieValue2); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, notExistKey)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey1)).isEqualTo(queryValue1); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, queryKey2)).isEqualTo(queryValue2); + assertThat(servletMetadataProvider.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, notExistKey)).isNull(); + assertThat(servletMetadataProvider.getRawMetadataMapValue(notExistKey, queryKey1)).isNull(); + + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo("GET"); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo(path); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_CALLER_IP)).isEqualTo(callerIp); + assertThat(servletMetadataProvider.getRawMetadataStringValue(notExistKey)).isNull(); + + request.setRequestURI("/echo/" + UrlUtils.decode("a@b")); + assertThat(servletMetadataProvider.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/echo/a@b"); + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml index 6a760d13f..7525a4c92 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml @@ -26,7 +26,6 @@ true - org.springframework.cloud spring-cloud-starter-openfeign @@ -64,6 +63,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java index 3f247093d..c086fda91 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java @@ -44,15 +44,20 @@ public class PolarisCircuitBreaker implements CircuitBreaker, InvokeHandler { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreaker.class); + + private final FunctionalDecorator decorator; + private final PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf; + private final ConsumerAPI consumerAPI; - private final FunctionalDecorator decorator; + private final InvokeHandler invokeHandler; public PolarisCircuitBreaker(PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf, ConsumerAPI consumerAPI, CircuitBreakAPI circuitBreakAPI) { - FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest(new ServiceKey(conf.getNamespace(), conf.getService()), conf.getMethod()); + FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest( + new ServiceKey(conf.getNamespace(), conf.getService()), conf.getProtocol(), conf.getMethod(), conf.getPath()); makeDecoratorRequest.setSourceService(new ServiceKey(conf.getSourceNamespace(), conf.getSourceService())); makeDecoratorRequest.setResultToErrorCode(new PolarisResultToErrorCode()); this.consumerAPI = consumerAPI; diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java index 331926223..70c3c3395 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java @@ -43,24 +43,25 @@ public class PolarisCircuitBreakerFactory extends CircuitBreakerFactory implements DisposableBean { + private final CircuitBreakAPI circuitBreakAPI; + + private final ConsumerAPI consumerAPI; + + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-circuitbreaker-cleanup", true)); + private Function defaultConfiguration = id -> { String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id); return new PolarisCircuitBreakerConfigBuilder() .namespace(metadata[0]) .service(metadata[1]) - .method(metadata[2]) + .path(metadata[2]) + .protocol(metadata[3]) + .method(metadata[4]) .build(); }; - - private final CircuitBreakAPI circuitBreakAPI; - - private final ConsumerAPI consumerAPI; - - private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( - new NamedThreadFactory("sct-circuitbreaker-cleanup", true)); - public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; @@ -83,7 +84,7 @@ public CircuitBreaker create(String id) { @Override protected PolarisCircuitBreakerConfigBuilder configBuilder(String id) { String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id); - return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2]); + return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2], metadata[3], metadata[4]); } @Override @@ -93,7 +94,7 @@ public void configureDefault(Function implements DisposableBean { + private final CircuitBreakAPI circuitBreakAPI; + + private final ConsumerAPI consumerAPI; + + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-reactive-circuitbreaker-cleanup", true)); + private Function defaultConfiguration = id -> { String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id); return new PolarisCircuitBreakerConfigBuilder() .namespace(metadata[0]) .service(metadata[1]) - .method(metadata[2]) + .path(metadata[2]) + .protocol(metadata[3]) + .method(metadata[4]) .build(); }; - private final CircuitBreakAPI circuitBreakAPI; - - private final ConsumerAPI consumerAPI; - - private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( - new NamedThreadFactory("sct-reactive-circuitbreaker-cleanup", true)); - public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; @@ -82,7 +84,7 @@ public ReactiveCircuitBreaker create(String id) { @Override protected PolarisCircuitBreakerConfigBuilder configBuilder(String id) { String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id); - return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2]); + return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2], metadata[3], metadata[4]); } @Override @@ -93,6 +95,6 @@ public void configureDefault( @Override public void destroy() { - ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[]{cleanupService}); + ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[] {cleanupService}); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java index 733180491..d33a92638 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java @@ -32,15 +32,21 @@ public class PolarisCircuitBreakerConfigBuilder implements ConfigBuilder target String path = ""; // Get path in @FeignClient. - if (StringUtils.hasText(target.url())) { + if (StringUtils.isNotBlank(target.url())) { URI uri = null; try { uri = new URI(target.url()); @@ -58,16 +61,24 @@ public String resolveCircuitBreakerName(String feignClientName, Target target } } - // Get path in @RequestMapping. + // Get path and method in @RequestMapping. RequestMapping requestMapping = findMergedAnnotation(method, RequestMapping.class); + String httpMethod = Request.HttpMethod.GET.name(); if (requestMapping != null) { path += requestMapping.path().length == 0 ? requestMapping.value().length == 0 ? "" : requestMapping.value()[0] : requestMapping.path()[0]; + + RequestMethod[] requestMethods = requestMapping.method(); + if (CollectionUtils.isNotEmpty(requestMethods)) { + httpMethod = requestMethods[0].name(); + } } - return "".equals(path) ? + + + return StringUtils.isBlank(path) ? MetadataContext.LOCAL_NAMESPACE + "#" + serviceName : - MetadataContext.LOCAL_NAMESPACE + "#" + serviceName + "#" + path; + MetadataContext.LOCAL_NAMESPACE + "#" + serviceName + "#" + path + "#http#" + httpMethod; } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java index 581e18cf1..131941097 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java @@ -76,24 +76,6 @@ public PolarisFeignCircuitBreakerInvocationHandler(CircuitBreakerFactory factory this.decoder = decoder; } - /** - * If the method param of {@link InvocationHandler#invoke(Object, Method, Object[])} - * is not accessible, i.e in a package-private interface, the fallback call will cause - * of access restrictions. But methods in dispatch are copied methods. So setting - * access to dispatch method doesn't take effect to the method in - * InvocationHandler.invoke. Use map to store a copy of method to invoke the fallback - * to bypass this and reducing the count of reflection calls. - * @return cached methods map for fallback invoking - */ - static Map toFallbackMethod(Map dispatch) { - Map result = new LinkedHashMap<>(); - for (Method method : dispatch.keySet()) { - method.setAccessible(true); - result.put(method, method); - } - return result; - } - @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { // early exit if the invoked method is from java.lang.Object @@ -188,6 +170,24 @@ private Supplier asSupplier(final Method method, final Object[] args) { }; } + /** + * If the method param of {@link InvocationHandler#invoke(Object, Method, Object[])} + * is not accessible, i.e in a package-private interface, the fallback call will cause + * of access restrictions. But methods in dispatch are copied methods. So setting + * access to dispatch method doesn't take effect to the method in + * InvocationHandler.invoke. Use map to store a copy of method to invoke the fallback + * to bypass this and reducing the count of reflection calls. + * @return cached methods map for fallback invoking + */ + static Map toFallbackMethod(Map dispatch) { + Map result = new LinkedHashMap<>(); + for (Method method : dispatch.keySet()) { + method.setAccessible(true); + result.put(method, method); + } + return result; + } + @Override public boolean equals(Object obj) { if (obj instanceof PolarisFeignCircuitBreakerInvocationHandler) { diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java index 0b474f8e5..250a84c63 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.stream.Collectors; +import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.polaris.api.pojo.CircuitBreakerStatus; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; import reactor.core.publisher.Flux; @@ -186,20 +187,21 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { serviceName = route.getUri().getHost(); } String path = exchange.getRequest().getPath().value(); - ReactiveCircuitBreaker cb = reactiveCircuitBreakerFactory.create(serviceName + "#" + path); + String method = exchange.getRequest().getMethod() == null ? + "GET" : exchange.getRequest().getMethod().name(); + ReactiveCircuitBreaker cb = reactiveCircuitBreakerFactory.create(MetadataContext.LOCAL_NAMESPACE + "#" + serviceName + "#" + path + "#http#" + method); return cb.run( - chain.filter(exchange) - .doOnSuccess(v -> { - // throw CircuitBreakerStatusCodeException by default for all need checking status - // so polaris can report right error status - Set statusNeedToCheck = new HashSet<>(); - statusNeedToCheck.addAll(statuses); - statusNeedToCheck.addAll(getDefaultStatus()); - HttpStatus status = exchange.getResponse().getStatusCode(); - if (statusNeedToCheck.contains(status)) { - throw new CircuitBreakerStatusCodeException(status); - } - }), + chain.filter(exchange).doOnSuccess(v -> { + // throw CircuitBreakerStatusCodeException by default for all need checking status + // so polaris can report right error status + Set statusNeedToCheck = new HashSet<>(); + statusNeedToCheck.addAll(statuses); + statusNeedToCheck.addAll(getDefaultStatus()); + HttpStatus status = exchange.getResponse().getStatusCode(); + if (statusNeedToCheck.contains(status)) { + throw new CircuitBreakerStatusCodeException(status); + } + }), t -> { // pre-check CircuitBreakerStatusCodeException's status matches input status if (t instanceof CircuitBreakerStatusCodeException) { diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java index 8cb26902f..f2bc52ab7 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.lang.reflect.Method; +import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.circuitbreaker.exception.FallbackWrapperException; import com.tencent.polaris.api.pojo.CircuitBreakerStatus; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; @@ -59,13 +60,18 @@ public PolarisCircuitBreakerRestTemplateInterceptor( this.polarisCircuitBreaker = polarisCircuitBreaker; this.applicationContext = applicationContext; this.circuitBreakerFactory = circuitBreakerFactory; - this.restTemplate = restTemplate; + this.restTemplate = restTemplate; } @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { try { - return circuitBreakerFactory.create(request.getURI().getHost() + "#" + request.getURI().getPath()).run( + String httpMethod = "GET"; + if (request.getMethod() != null) { + httpMethod = request.getMethod().name(); + } + return circuitBreakerFactory.create(MetadataContext.LOCAL_NAMESPACE + "#" + request.getURI() + .getHost() + "#" + request.getURI().getPath() + "#http#" + httpMethod).run( () -> { try { ClientHttpResponse response = execution.execute(request, body); @@ -84,7 +90,8 @@ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttp CircuitBreakerStatus.FallbackInfo fallbackInfo = new CircuitBreakerStatus.FallbackInfo(200, null, polarisCircuitBreaker.fallback()); return new PolarisCircuitBreakerHttpResponse(fallbackInfo); } - if (!PolarisCircuitBreakerFallback.class.toGenericString().equals(polarisCircuitBreaker.fallbackClass().toGenericString())) { + if (!PolarisCircuitBreakerFallback.class.toGenericString() + .equals(polarisCircuitBreaker.fallbackClass().toGenericString())) { Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerFallback.class, "fallback"); PolarisCircuitBreakerFallback polarisCircuitBreakerFallback = applicationContext.getBean(polarisCircuitBreaker.fallbackClass()); return (PolarisCircuitBreakerHttpResponse) ReflectionUtils.invokeMethod(method, polarisCircuitBreakerFallback); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java index 4c7502c92..349af2326 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java @@ -45,29 +45,36 @@ private PolarisCircuitBreakerUtils() { } /** + * Format: + * 0. namespace#service#path#protocol#method + * 1. namespace#service#method + * 2. service#method + * 3. service + * namespace set as default spring.cloud.polaris.namespace if absent. * * @param id CircuitBreakerId - * Format: namespace#service#method or service#method or service , - * namespace set as default spring.cloud.polaris.namespace if absent * @return String[]{namespace, service, method} */ public static String[] resolveCircuitBreakerId(String id) { Assert.hasText(id, "A CircuitBreaker must have an id. Id could be : namespace#service#method or service#method or service"); String[] polarisCircuitBreakerMetaData = id.split("#"); if (polarisCircuitBreakerMetaData.length == 2) { - return new String[] {MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]}; + return new String[] {MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], "http", ""}; } if (polarisCircuitBreakerMetaData.length == 3) { - return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]}; + return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2], "http", ""}; } - return new String[] {MetadataContext.LOCAL_NAMESPACE, id, ""}; + if (polarisCircuitBreakerMetaData.length == 5) { + return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2], polarisCircuitBreakerMetaData[3], polarisCircuitBreakerMetaData[4]}; + } + return new String[] {MetadataContext.LOCAL_NAMESPACE, id, "", "http", ""}; } public static void reportStatus(ConsumerAPI consumerAPI, PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf, CallAbortedException e) { try { ServiceCallResult result = new ServiceCallResult(); - result.setMethod(conf.getMethod()); + result.setMethod(conf.getPath()); result.setNamespace(conf.getNamespace()); result.setService(conf.getService()); result.setRuleName(e.getRuleName()); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java index 37eccb6da..a74fa769c 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java @@ -97,11 +97,12 @@ public boolean shouldFilter() { @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); + String serviceId = ZuulFilterUtils.getServiceId(context); String path = ZuulFilterUtils.getPath(context); - String circuitName = "".equals(path) ? + String circuitName = com.tencent.polaris.api.utils.StringUtils.isBlank(path) ? MetadataContext.LOCAL_NAMESPACE + "#" + serviceId : - MetadataContext.LOCAL_NAMESPACE + "#" + serviceId + "#" + path; + MetadataContext.LOCAL_NAMESPACE + "#" + serviceId + "#" + path + "#http#" + context.getRequest().getMethod(); CircuitBreaker circuitBreaker = circuitBreakerFactory.create(circuitName); if (circuitBreaker instanceof PolarisCircuitBreaker) { PolarisCircuitBreaker polarisCircuitBreaker = (PolarisCircuitBreaker) circuitBreaker; diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java index 9ac2ad59b..7ff9064e9 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java @@ -36,7 +36,8 @@ public class PolarisFeignCircuitBreakerTargeter implements Targeter { private final PolarisCircuitBreakerNameResolver circuitBreakerNameResolver; - public PolarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { + public PolarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, + PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { this.circuitBreakerFactory = circuitBreakerFactory; this.circuitBreakerNameResolver = circuitBreakerNameResolver; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java index 90e8134a6..dc720bd4a 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java @@ -84,15 +84,12 @@ public static void beforeAll() throws IOException { ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_CIRCUIT_BREAKER); - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerMockServerTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerMockServerTest.class.getClassLoader().getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder().addRules(circuitBreakerRule).build(); namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); } @@ -143,8 +140,7 @@ public void testCircuitBreaker() { assertThat(Mono.error(new RuntimeException("boom")).transform(it -> rcb.run(it, t -> Mono.just("fallback"))) .block()).isEqualTo("fallback"); - assertThat(Flux.just("foobar", "hello world") - .transform(it -> rcb.run(it, t -> Flux.just("fallback", "fallback"))) + assertThat(Flux.just("foobar", "hello world").transform(it -> rcb.run(it, t -> Flux.just("fallback", "fallback"))) .collectList().block()) .isEqualTo(Arrays.asList("fallback", "fallback")); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java index 52e9e4650..27ea51f4f 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java @@ -93,7 +93,7 @@ public void test2() { Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerNameResolverTest.class, "mockRequestMapping2"); PolarisCircuitBreakerNameResolver resolver = new PolarisCircuitBreakerNameResolver(); String polarisCircuitBreakerName = resolver.resolveCircuitBreakerName("test", target, method); - assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/"); + assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/#http#GET"); } @Test @@ -103,7 +103,7 @@ public void test3() { Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerNameResolverTest.class, "mockRequestMapping3"); PolarisCircuitBreakerNameResolver resolver = new PolarisCircuitBreakerNameResolver(); String polarisCircuitBreakerName = resolver.resolveCircuitBreakerName("test", target, method); - assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/"); + assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/#http#GET"); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java index 2ed360ab6..2d4f9bbf0 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java @@ -70,7 +70,6 @@ import org.springframework.web.bind.annotation.RestController; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.Consts.SERVICE_CIRCUIT_BREAKER; import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; @@ -84,7 +83,7 @@ properties = { "spring.cloud.gateway.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, - "spring.cloud.polaris.service=" + SERVICE_CIRCUIT_BREAKER, + "spring.cloud.polaris.service=test", "spring.main.web-application-type=reactive" }, classes = PolarisCircuitBreakerGatewayIntegrationTest.TestApplication.class diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java index beccd9759..14e41ae8b 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java @@ -52,6 +52,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; import org.springframework.cloud.client.circuitbreaker.Customizer; @@ -275,18 +276,21 @@ public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) { } @Bean + @ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class) public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, CircuitBreakAPI circuitBreakAPI) { return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); } @Bean + @ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class) public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, CircuitBreakAPI circuitBreakAPI) { return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); } @Bean + @ConditionalOnMissingBean(CircuitBreakerFactory.class) public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, PolarisSDKContextManager polarisSDKContextManager, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java index d05a0dcc2..eb752701b 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java @@ -71,9 +71,11 @@ public void testReportStatus() { @Test public void testResolveCircuitBreakerId() { - assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc")).isEqualTo(new String[]{NAMESPACE_TEST, "test_svc", ""}); - assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc#test_path")).isEqualTo(new String[]{NAMESPACE_TEST, "test_svc", "test_path"}); - assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path")).isEqualTo(new String[]{"test_ns", "test_svc", "test_path"}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc")).isEqualTo(new String[] {NAMESPACE_TEST, "test_svc", "", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc#test_path")).isEqualTo(new String[] {NAMESPACE_TEST, "test_svc", "test_path", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path")).isEqualTo(new String[] {"test_ns", "test_svc", "test_path", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path")).isEqualTo(new String[] {"test_ns", "test_svc", "test_path", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path#tcp#POST")).isEqualTo(new String[] {"test_ns", "test_svc", "test_path", "tcp", "POST"}); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml index 06481f254..6094b46e5 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml @@ -13,7 +13,7 @@ spring: feature-env: enabled: true polaris: - address: grpc://127.0.0.1:10081 + address: grpc://127.0.0.1:8091 namespace: default enabled: true gateway: diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml index e7262c29f..fceb2487f 100644 --- a/spring-cloud-starter-tencent-polaris-config/pom.xml +++ b/spring-cloud-starter-tencent-polaris-config/pom.xml @@ -34,6 +34,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java index 3c5e87c5a..993b3f978 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java @@ -13,7 +13,6 @@ * 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.config; @@ -26,27 +25,27 @@ import com.tencent.cloud.common.util.AddressUtils; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.config.PolarisCryptoConfigProperties; -import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.PolarisConfigurationConfigModifier; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.factory.config.configuration.ConfigFilterConfigImpl; +import com.tencent.polaris.factory.config.configuration.ConnectorConfigImpl; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; +import static com.tencent.polaris.api.config.plugin.DefaultPlugins.LOCAL_FILE_CONNECTOR_TYPE; + /** * Read configuration from spring cloud's configuration file and override polaris.yaml. * * @author lepdou 2022-03-10 */ -public class ConfigurationModifier implements PolarisConfigModifier { +public class ConfigurationModifier implements PolarisConfigurationConfigModifier { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationModifier.class); - private static final String DATA_SOURCE_POLARIS = "polaris"; - private static final String DATA_SOURCE_LOCAL = "local"; - private final PolarisConfigProperties polarisConfigProperties; private final PolarisCryptoConfigProperties polarisCryptoConfigProperties; @@ -63,16 +62,14 @@ public ConfigurationModifier(PolarisConfigProperties polarisConfigProperties, @Override public void modify(ConfigurationImpl configuration) { - if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), DATA_SOURCE_POLARIS)) { - initByPolarisDataSource(configuration); - } - else if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), DATA_SOURCE_LOCAL)) { - initByLocalDataSource(configuration); - } - else { - throw new RuntimeException("Unsupported config data source"); + configuration.getGlobal().getAPI().setReportEnable(false); + + if (!polarisContextProperties.getEnabled() || !polarisConfigProperties.isEnabled()) { + return; } + initDataSource(configuration); + ConfigFilterConfigImpl configFilterConfig = configuration.getConfigFile().getConfigFilterConfig(); configFilterConfig.setEnable(polarisCryptoConfigProperties.isEnabled()); if (polarisCryptoConfigProperties.isEnabled()) { @@ -81,18 +78,15 @@ else if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), D } } - private void initByLocalDataSource(ConfigurationImpl configuration) { - configuration.getConfigFile().getServerConnector().setConnectorType("localFile"); - - String localFileRootPath = polarisConfigProperties.getLocalFileRootPath(); - configuration.getConfigFile().getServerConnector().setPersistDir(localFileRootPath); - - LOGGER.info("[SCT] Run spring cloud tencent config with local data source. localFileRootPath = {}", localFileRootPath); - } - - private void initByPolarisDataSource(ConfigurationImpl configuration) { + private void initDataSource(ConfigurationImpl configuration) { // set connector type - configuration.getConfigFile().getServerConnector().setConnectorType("polaris"); + configuration.getConfigFile().getServerConnector().setConnectorType(polarisConfigProperties.getDataSource()); + if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), LOCAL_FILE_CONNECTOR_TYPE)) { + String localFileRootPath = polarisConfigProperties.getLocalFileRootPath(); + configuration.getConfigFile().getServerConnector().setPersistDir(localFileRootPath); + LOGGER.info("[SCT] Run spring cloud tencent config with local data source. localFileRootPath = {}", localFileRootPath); + return; + } // set config server address List configAddresses; @@ -114,6 +108,11 @@ private void initByPolarisDataSource(ConfigurationImpl configuration) { configuration.getConfigFile().getServerConnector().setAddresses(configAddresses); + if (StringUtils.isNotEmpty(polarisConfigProperties.getToken())) { + ConnectorConfigImpl connectorConfig = configuration.getConfigFile().getServerConnector(); + connectorConfig.setToken(polarisConfigProperties.getToken()); + } + LOGGER.info("[SCT] Run spring cloud tencent config in polaris data source."); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java index 0d5855b86..7b39f4bd1 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java @@ -21,7 +21,6 @@ import com.tencent.cloud.polaris.config.adapter.AffectedConfigurationPropertiesRebinder; import com.tencent.cloud.polaris.config.adapter.PolarisConfigPropertyRefresher; import com.tencent.cloud.polaris.config.adapter.PolarisConfigRefreshScopeAnnotationDetector; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshAffectedContextRefresher; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefresher; import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProcessor; @@ -68,7 +67,6 @@ public PolarisConfigLoggerApplicationListener polarisConfigLoggerApplicationList return new PolarisConfigLoggerApplicationListener(); } - @Bean @Primary @ConditionalOnReflectRefreshType @@ -79,9 +77,9 @@ public ConfigurationPropertiesRebinder affectedConfigurationPropertiesRebinder( @Bean @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) - public PolarisConfigPropertyRefresher polarisRefreshContextPropertySourceAutoRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, ContextRefresher contextRefresher) { - return new PolarisRefreshEntireContextRefresher(polarisConfigProperties, polarisPropertySourceManager, contextRefresher); + public PolarisConfigPropertyRefresher polarisRefreshContextPropertySourceAutoRefresher( + PolarisConfigProperties polarisConfigProperties, ContextRefresher contextRefresher) { + return new PolarisRefreshEntireContextRefresher(polarisConfigProperties, contextRefresher); } @Configuration(proxyBeanMethods = false) @@ -105,10 +103,10 @@ public SpringValueProcessor springValueProcessor(PlaceholderHelper placeholderHe } @Bean - public PolarisConfigPropertyRefresher polarisReflectPropertySourceAutoRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, SpringValueRegistry springValueRegistry, + public PolarisConfigPropertyRefresher polarisReflectPropertySourceAutoRefresher( + PolarisConfigProperties polarisConfigProperties, SpringValueRegistry springValueRegistry, PlaceholderHelper placeholderHelper) { - return new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, polarisPropertySourceManager, + return new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, springValueRegistry, placeholderHelper); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java index 2383cbf6b..b7be26460 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java @@ -20,7 +20,6 @@ import com.tencent.cloud.polaris.config.adapter.AffectedConfigurationPropertiesRebinder; import com.tencent.cloud.polaris.config.adapter.PolarisConfigFileLocator; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.condition.ConditionalOnReflectRefreshType; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.config.PolarisCryptoConfigProperties; @@ -37,6 +36,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; /** @@ -59,16 +59,10 @@ public PolarisCryptoConfigProperties polarisCryptoConfigProperties() { return new PolarisCryptoConfigProperties(); } - @Bean - @ConditionalOnMissingBean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return new PolarisPropertySourceManager(); - } - @Bean @ConditionalOnConnectRemoteServerEnabled public ConfigFileService configFileService(PolarisSDKContextManager polarisSDKContextManager) { - return ConfigFileServiceFactory.createConfigFileService(polarisSDKContextManager.getSDKContext()); + return ConfigFileServiceFactory.createConfigFileService(polarisSDKContextManager.getConfigSDKContext()); } @Bean @@ -77,11 +71,9 @@ public PolarisConfigFileLocator polarisConfigFileLocator( PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, - PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { return new PolarisConfigFileLocator(polarisConfigProperties, - polarisContextProperties, configFileService, - polarisPropertySourceManager, environment); + polarisContextProperties, configFileService, environment); } @Bean @@ -93,6 +85,7 @@ public ConfigurationModifier configurationModifier(PolarisConfigProperties polar } @Bean + @Primary @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) @ConditionalOnReflectRefreshType public ConfigurationPropertiesRebinder affectedConfigurationPropertiesRebinder( diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java index bbd6f3e55..711df1483 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java @@ -43,13 +43,16 @@ /** * Optimize {@link ConfigurationPropertiesRebinder}, only rebuild affected beans. - * @author weihubeats 2022-7-10 + * + * @author weihubeats */ public class AffectedConfigurationPropertiesRebinder extends ConfigurationPropertiesRebinder { + private static final Logger LOGGER = LoggerFactory.getLogger(AffectedConfigurationPropertiesRebinder.class); private ApplicationContext applicationContext; private Map propertiesBeans = new HashMap<>(); + private final Map> propertiesBeanDefaultValues = new ConcurrentHashMap<>(); public AffectedConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) { @@ -125,8 +128,7 @@ private void initPropertiesBeanDefaultValues(Map defaultValues = new HashMap<>(); try { - Object instance = propertiesBean.getInstance().getClass().getDeclaredConstructor((Class[]) null) - .newInstance(); + Object instance = propertiesBean.getInstance().getClass().getDeclaredConstructor((Class[]) null).newInstance(); ReflectionUtils.doWithFields(instance.getClass(), field -> { try { field.setAccessible(true); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java index 2549f0773..592368c68 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java @@ -29,10 +29,13 @@ * @author juanyinyang */ public interface PolarisConfigCustomExtensionLayer { + boolean isEnabled(); + void initRegisterConfig(PolarisConfigPropertyAutoRefresher polarisConfigPropertyAutoRefresher); - void initConfigFiles(Environment environment, CompositePropertySource compositePropertySource, PolarisPropertySourceManager polarisPropertySourceManager, ConfigFileService configFileService); + void initConfigFiles(Environment environment, CompositePropertySource compositePropertySource, ConfigFileService configFileService); void executeAfterLocateConfigReturning(CompositePropertySource compositePropertySource); + boolean executeRegisterPublishChangeListener(PolarisPropertySource polarisPropertySource); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java index 0e67d7a18..56a3d08ad 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java @@ -13,7 +13,6 @@ * 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.config.adapter; @@ -65,39 +64,40 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { private final ConfigFileService configFileService; - private final PolarisPropertySourceManager polarisPropertySourceManager; - private final Environment environment; // this class provides customized logic for some customers to configure special business group files private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil.getPolarisConfigCustomExtensionLayer(); - public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { + public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, Environment environment) { this.polarisConfigProperties = polarisConfigProperties; this.polarisContextProperties = polarisContextProperties; this.configFileService = configFileService; - this.polarisPropertySourceManager = polarisPropertySourceManager; this.environment = environment; } @Override public PropertySource locate(Environment environment) { - CompositePropertySource compositePropertySource = new CompositePropertySource(POLARIS_CONFIG_PROPERTY_SOURCE_NAME); - try { - // load custom config extension files - initCustomPolarisConfigExtensionFiles(compositePropertySource); - // load spring boot default config files - initInternalConfigFiles(compositePropertySource); - // load custom config files - List configFileGroups = polarisConfigProperties.getGroups(); - if (CollectionUtils.isEmpty(configFileGroups)) { + if (polarisConfigProperties.isEnabled()) { + CompositePropertySource compositePropertySource = new CompositePropertySource(POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + try { + // load custom config extension files + initCustomPolarisConfigExtensionFiles(compositePropertySource); + // load spring boot default config files + initInternalConfigFiles(compositePropertySource); + // load custom config files + List configFileGroups = polarisConfigProperties.getGroups(); + if (CollectionUtils.isEmpty(configFileGroups)) { + return compositePropertySource; + } + initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); return compositePropertySource; } - initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); - return compositePropertySource; - } - finally { - afterLocatePolarisConfigExtension(compositePropertySource); + finally { + afterLocatePolarisConfigExtension(compositePropertySource); + } } + return null; } private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compositePropertySource) { @@ -105,7 +105,7 @@ private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compo LOGGER.debug("[SCT Config] PolarisConfigCustomExtensionLayer is not init, ignore the following execution steps"); return; } - polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, polarisPropertySourceManager, configFileService); + polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, configFileService); } private void afterLocatePolarisConfigExtension(CompositePropertySource compositePropertySource) { @@ -117,6 +117,9 @@ private void afterLocatePolarisConfigExtension(CompositePropertySource composite } private void initInternalConfigFiles(CompositePropertySource compositePropertySource) { + if (!polarisConfigProperties.isInternalEnabled()) { + return; + } List internalConfigFiles = getInternalConfigFiles(); for (ConfigFileMetadata configFile : internalConfigFiles) { @@ -124,7 +127,7 @@ private void initInternalConfigFiles(CompositePropertySource compositePropertySo compositePropertySource.addPropertySource(polarisPropertySource); - polarisPropertySourceManager.addPropertySource(polarisPropertySource); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); LOGGER.info("[SCT Config] Load and inject polaris config file. file = {}", configFile); } @@ -191,8 +194,12 @@ private void initCustomPolarisConfigFiles(CompositePropertySource compositePrope String namespace = polarisContextProperties.getNamespace(); for (ConfigFileGroup configFileGroup : configFileGroups) { - String group = configFileGroup.getName(); + String groupNamespace = configFileGroup.getNamespace(); + if (!StringUtils.hasText(groupNamespace)) { + groupNamespace = namespace; + } + String group = configFileGroup.getName(); if (!StringUtils.hasText(group)) { throw new IllegalArgumentException("polaris config group name cannot be empty."); } @@ -203,26 +210,26 @@ private void initCustomPolarisConfigFiles(CompositePropertySource compositePrope } for (String fileName : files) { - PolarisPropertySource polarisPropertySource = loadPolarisPropertySource(namespace, group, fileName); + PolarisPropertySource polarisPropertySource = loadPolarisPropertySource(groupNamespace, group, fileName); compositePropertySource.addPropertySource(polarisPropertySource); - polarisPropertySourceManager.addPropertySource(polarisPropertySource); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); - LOGGER.info("[SCT Config] Load and inject polaris config file success. namespace = {}, group = {}, fileName = {}", namespace, group, fileName); + LOGGER.info("[SCT Config] Load and inject polaris config file success. namespace = {}, group = {}, fileName = {}", groupNamespace, group, fileName); } } } private PolarisPropertySource loadPolarisPropertySource(String namespace, String group, String fileName) { ConfigKVFile configKVFile; - // unknown extension is resolved as properties file - if (ConfigFileFormat.isPropertyFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) { - configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName); - } - else if (ConfigFileFormat.isYamlFile(fileName)) { + // unknown extension is resolved as yaml file + if (ConfigFileFormat.isYamlFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) { configKVFile = configFileService.getConfigYamlFile(namespace, group, fileName); } + else if (ConfigFileFormat.isPropertyFile(fileName)) { + configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName); + } else { LOGGER.warn("[SCT Config] Unsupported config file. namespace = {}, group = {}, fileName = {}", namespace, group, fileName); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java index 47ff8d951..dc6989066 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java @@ -18,14 +18,17 @@ package com.tencent.cloud.polaris.config.adapter; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.logger.PolarisConfigLoggerContext; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import com.tencent.polaris.configuration.client.internal.CompositeConfigFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +41,7 @@ * 1. Listen to the Polaris server configuration publishing event 2. Write the changed * configuration content to propertySource 3. Refresh the context through contextRefresher * - * @author lepdou 2022-03-28 + * @author lepdou */ public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationListener, PolarisConfigPropertyRefresher { @@ -46,16 +49,13 @@ public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationL private final PolarisConfigProperties polarisConfigProperties; - private final PolarisPropertySourceManager polarisPropertySourceManager; - private final AtomicBoolean registered = new AtomicBoolean(false); // this class provides customized logic for some customers to configure special business group files private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil.getPolarisConfigCustomExtensionLayer(); - public PolarisConfigPropertyAutoRefresher(PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager) { + public PolarisConfigPropertyAutoRefresher(PolarisConfigProperties polarisConfigProperties) { this.polarisConfigProperties = polarisConfigProperties; - this.polarisPropertySourceManager = polarisPropertySourceManager; } @Override @@ -68,7 +68,7 @@ private void registerPolarisConfigPublishEvent() { return; } - List polarisPropertySources = polarisPropertySourceManager.getAllPropertySources(); + List polarisPropertySources = PolarisPropertySourceManager.getAllPropertySources(); if (CollectionUtils.isEmpty(polarisPropertySources)) { return; } @@ -82,8 +82,18 @@ private void registerPolarisConfigPublishEvent() { // register polaris config publish event for (PolarisPropertySource polarisPropertySource : polarisPropertySources) { - registerPolarisConfigPublishChangeListener(polarisPropertySource); - customRegisterPolarisConfigPublishChangeListener(polarisPropertySource); + if (polarisPropertySource.getConfigKVFile() instanceof CompositeConfigFile) { + CompositeConfigFile configKVFile = (CompositeConfigFile) polarisPropertySource.getConfigKVFile(); + for (ConfigKVFile cf : configKVFile.getConfigKVFiles()) { + PolarisPropertySource p = new PolarisPropertySource(cf.getNamespace(), cf.getFileGroup(), cf.getFileName(), cf, new HashMap<>()); + registerPolarisConfigPublishChangeListener(p); + customRegisterPolarisConfigPublishChangeListener(p); + } + } + else { + registerPolarisConfigPublishChangeListener(polarisPropertySource); + customRegisterPolarisConfigPublishChangeListener(polarisPropertySource); + } } } @@ -96,6 +106,7 @@ private void customInitRegisterPolarisConfig(PolarisConfigPropertyAutoRefresher } public void registerPolarisConfigPublishChangeListener(PolarisPropertySource polarisPropertySource) { + LOGGER.info("{} will register polaris config publish listener", polarisPropertySource.getPropertySourceName()); polarisPropertySource.getConfigKVFile() .addChangeListener((ConfigKVFileChangeListener) configKVFileChangeEvent -> { @@ -144,4 +155,11 @@ private void customRegisterPolarisConfigPublishChangeListener(PolarisPropertySou } polarisConfigCustomExtensionLayer.executeRegisterPublishChangeListener(polarisPropertySource); } + + /** + * Just for junit test. + */ + public void setRegistered(boolean registered) { + this.registered.set(registered); + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java index c1dcefa51..34da59376 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java @@ -20,6 +20,7 @@ import java.util.Map; +import com.tencent.cloud.polaris.config.utils.PolarisPropertySourceUtils; import com.tencent.polaris.configuration.api.core.ConfigKVFile; import org.springframework.core.env.MapPropertySource; @@ -40,7 +41,7 @@ public class PolarisPropertySource extends MapPropertySource { private final ConfigKVFile configKVFile; public PolarisPropertySource(String namespace, String group, String fileName, ConfigKVFile configKVFile, Map source) { - super(namespace + "-" + group + "-" + fileName, source); + super(PolarisPropertySourceUtils.generateName(namespace, group, fileName), source); this.namespace = namespace; this.group = group; @@ -64,7 +65,7 @@ public String getPropertySourceName() { return namespace + "-" + group + "-" + fileName; } - ConfigKVFile getConfigKVFile() { + public ConfigKVFile getConfigKVFile() { return configKVFile; } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java index f8736e20e..096ab7d96 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java @@ -28,15 +28,25 @@ * * @author lepdou 2022-03-28 */ -public class PolarisPropertySourceManager { +public final class PolarisPropertySourceManager { - private final Map polarisPropertySources = new ConcurrentHashMap<>(); + private static final Map polarisPropertySources = new ConcurrentHashMap<>(); - public void addPropertySource(PolarisPropertySource polarisPropertySource) { - polarisPropertySources.putIfAbsent(polarisPropertySource.getPropertySourceName(), polarisPropertySource); + private PolarisPropertySourceManager() { } - public List getAllPropertySources() { + public static void addPropertySource(PolarisPropertySource polarisPropertySource) { + polarisPropertySources.put(polarisPropertySource.getPropertySourceName(), polarisPropertySource); + } + + public static List getAllPropertySources() { return new ArrayList<>(polarisPropertySources.values()); } + + /** + * Just for test. + */ + public static void clearPropertySources() { + polarisPropertySources.clear(); + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java index dffb23adf..146648ca3 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java @@ -59,9 +59,8 @@ public class PolarisRefreshAffectedContextRefresher extends PolarisConfigPropert private TypeConverter typeConverter; public PolarisRefreshAffectedContextRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, SpringValueRegistry springValueRegistry, - PlaceholderHelper placeholderHelper) { - super(polarisConfigProperties, polarisPropertySourceManager); + SpringValueRegistry springValueRegistry, PlaceholderHelper placeholderHelper) { + super(polarisConfigProperties); this.springValueRegistry = springValueRegistry; this.placeholderHelper = placeholderHelper; } @@ -100,7 +99,7 @@ private void updateSpringValue(SpringValue springValue) { * Logic transplanted from DefaultListableBeanFactory. * * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, - * java.lang.String, java.util.Set, org.springframework.beans.TypeConverter) + * String, Set, TypeConverter) */ private Object resolvePropertyValue(SpringValue springValue) { // value will never be null diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java index a13a68be5..3c2ca5ac7 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java @@ -35,12 +35,16 @@ public class PolarisRefreshEntireContextRefresher extends PolarisConfigPropertyA private final ContextRefresher contextRefresher; public PolarisRefreshEntireContextRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, ContextRefresher contextRefresher) { - super(polarisConfigProperties, polarisPropertySourceManager); + super(polarisConfigProperties); this.contextRefresher = contextRefresher; } + @Override + public void refreshSpringValue(String changedKey) { + // do nothing,all config will be refreshed by contextRefresher.refresh + } + @Override public void refreshConfigurationProperties(Set changeKeys) { contextRefresher.refresh(); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java index 343a5b319..bf61aac4d 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java @@ -30,20 +30,25 @@ public final class PolarisServiceLoaderUtil { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisServiceLoaderUtil.class); - private PolarisServiceLoaderUtil() { - } // this class provides customized logic for some customers to configure special business group files private static PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer; + static { ServiceLoader polarisConfigCustomExtensionLayerLoader = ServiceLoader.load(PolarisConfigCustomExtensionLayer.class); Iterator polarisConfigCustomExtensionLayerIterator = polarisConfigCustomExtensionLayerLoader.iterator(); // Generally, there is only one implementation class. If there are multiple, the last one is loaded while (polarisConfigCustomExtensionLayerIterator.hasNext()) { - polarisConfigCustomExtensionLayer = polarisConfigCustomExtensionLayerIterator.next(); - LOGGER.info("[SCT Config] PolarisConfigFileLocator init polarisConfigCustomExtensionLayer:{}", polarisConfigCustomExtensionLayer); + PolarisConfigCustomExtensionLayer temp = polarisConfigCustomExtensionLayerIterator.next(); + if (temp.isEnabled()) { + polarisConfigCustomExtensionLayer = temp; + LOGGER.info("[SCT Config] PolarisConfigFileLocator init polarisConfigCustomExtensionLayer:{}", polarisConfigCustomExtensionLayer); + } } } + private PolarisServiceLoaderUtil() { + } + public static PolarisConfigCustomExtensionLayer getPolarisConfigCustomExtensionLayer() { return polarisConfigCustomExtensionLayer; } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java index 85e1f2259..ee0a3d277 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java @@ -108,7 +108,8 @@ public boolean isAsync() { Set interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null; Set interestedKeyPrefixes = - annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null; + annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) + : null; addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java index 0b5c2c335..80cff02b8 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java @@ -15,7 +15,6 @@ * specific language governing permissions and limitations under the License. * */ - package com.tencent.cloud.polaris.config.config; import java.util.List; @@ -27,6 +26,8 @@ */ public class ConfigFileGroup { + private String namespace; + /** * group name. */ @@ -37,6 +38,14 @@ public class ConfigFileGroup { */ private List files; + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + public String getName() { return name; } @@ -55,6 +64,10 @@ public void setFiles(List files) { @Override public String toString() { - return "ConfigFileGroup{" + "name='" + name + '\'' + ", file=" + files + '}'; + return "ConfigFileGroup{" + + "namespace='" + namespace + '\'' + + ", name='" + name + '\'' + + ", files=" + files + + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java index 6a014aa04..4586134ee 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java @@ -50,6 +50,8 @@ public class PolarisConfigProperties { @Value("${spring.cloud.polaris.config.port:#{'8093'}}") private int port = 8093; + private String token; + /** * Whether to automatically update to the spring context when the configuration file. * is updated @@ -89,6 +91,11 @@ public class PolarisConfigProperties { */ private String localFileRootPath = "./polaris/backup/config"; + /** + * If internal config file enabled. + */ + private boolean internalEnabled = true; + public boolean isEnabled() { return enabled; } @@ -113,6 +120,14 @@ public void setPort(int port) { this.port = port; } + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + public boolean isAutoRefresh() { return autoRefresh; } @@ -168,4 +183,30 @@ public String getLocalFileRootPath() { public void setLocalFileRootPath(String localFileRootPath) { this.localFileRootPath = localFileRootPath; } + + public boolean isInternalEnabled() { + return internalEnabled; + } + + public void setInternalEnabled(boolean internalEnabled) { + this.internalEnabled = internalEnabled; + } + + @Override + public String toString() { + return "PolarisConfigProperties{" + + "enabled=" + enabled + + ", address='" + address + '\'' + + ", port=" + port + + ", token='" + token + '\'' + + ", autoRefresh=" + autoRefresh + + ", shutdownIfConnectToConfigServerFailed=" + shutdownIfConnectToConfigServerFailed + + ", preference=" + preference + + ", refreshType=" + refreshType + + ", groups=" + groups + + ", dataSource='" + dataSource + '\'' + + ", localFileRootPath='" + localFileRootPath + '\'' + + ", internalEnabled=" + internalEnabled + + '}'; + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java index 108c74095..52bdff756 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java @@ -33,15 +33,13 @@ * * @author shuiqingliu **/ -@Endpoint(id = "polaris-config") +@Endpoint(id = "polarisconfig") public class PolarisConfigEndpoint { private final PolarisConfigProperties polarisConfigProperties; - private final PolarisPropertySourceManager polarisPropertySourceManager; - public PolarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager) { + public PolarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties) { this.polarisConfigProperties = polarisConfigProperties; - this.polarisPropertySourceManager = polarisPropertySourceManager; } @ReadOperation @@ -49,7 +47,7 @@ public Map polarisConfig() { Map configInfo = new HashMap<>(); configInfo.put("PolarisConfigProperties", polarisConfigProperties); - List propertySourceList = polarisPropertySourceManager.getAllPropertySources(); + List propertySourceList = PolarisPropertySourceManager.getAllPropertySources(); configInfo.put("PolarisPropertySource", propertySourceList); return configInfo; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java index 815d5798e..3f530c3ab 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java @@ -18,7 +18,6 @@ package com.tencent.cloud.polaris.config.endpoint; import com.tencent.cloud.polaris.config.ConditionalOnPolarisConfigEnabled; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; @@ -41,8 +40,7 @@ public class PolarisConfigEndpointAutoConfiguration { @Bean @ConditionalOnAvailableEndpoint @ConditionalOnMissingBean - public PolarisConfigEndpoint polarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager) { - return new PolarisConfigEndpoint(polarisConfigProperties, polarisPropertySourceManager); + public PolarisConfigEndpoint polarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties) { + return new PolarisConfigEndpoint(polarisConfigProperties); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java index 330e62fb0..e05a939d8 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java @@ -66,7 +66,6 @@ public final class PolarisConfigChangeEventListener implements ApplicationListen */ @Override public void onApplicationEvent(@NonNull ApplicationEvent event) { - // Initialize application all environment properties . if (event instanceof ApplicationStartedEvent && started.compareAndSet(false, true)) { ApplicationStartedEvent applicationStartedEvent = (ApplicationStartedEvent) event; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java index 85bd2ab42..120ef7c73 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java @@ -52,11 +52,9 @@ *

This source file was reference from: * * AbstractConfig - * * @author Palmer Xu 2022-06-06 */ public final class PolarisConfigListenerContext { - /** * Logger instance. */ diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java index 54f0c6246..598978112 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java @@ -21,7 +21,6 @@ import java.util.Collections; import com.tencent.cloud.polaris.config.adapter.PolarisConfigRefreshScopeAnnotationDetector; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefresher; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.enums.RefreshType; @@ -44,7 +43,7 @@ import static com.tencent.cloud.polaris.config.condition.ReflectRefreshTypeCondition.POLARIS_CONFIG_REFRESH_TYPE; /** - * When {@link com.tencent.cloud.polaris.config.adapter.PolarisConfigRefreshScopeAnnotationDetector} detects that + * When {@link PolarisConfigRefreshScopeAnnotationDetector} detects that * the annotation {@code @RefreshScope} exists and is used, but the config refresh type * {@code spring.cloud.polaris.config.refresh-type} is still {@code RefreshType.REFLECT}, then the framework will * automatically switch the config refresh type to {@code RefreshType.REFRESH_CONTEXT}. @@ -112,7 +111,7 @@ private void removeRelatedBeansOfReflect(ConfigurableApplicationContext applicat beanFactory.removeBeanDefinition(REFLECT_REBINDER_BEAN_NAME); } catch (BeansException e) { - // If there is a removeBean exception in this code, do not affect the main process startup. Some user usage may cause the polarisReflectPropertySourceAutoRefresher to not load, and the removeBeanDefinition will report an error + // If there is a removeBean exception in this code, do not affect the main process startup. Some user usage may cause the polarisReflectPropertySourceAutoRefresher to not load, and the removeBeanDefinition will report an error LOGGER.debug("removeRelatedBeansOfReflect occur error:", e); } } @@ -122,12 +121,10 @@ private void registerRefresherBeanOfRefreshContext(ConfigurableApplicationContex AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(PolarisRefreshEntireContextRefresher.class); PolarisConfigProperties polarisConfigProperties = beanFactory.getBean(PolarisConfigProperties.class); - PolarisPropertySourceManager polarisPropertySourceManager = beanFactory.getBean(PolarisPropertySourceManager.class); ContextRefresher contextRefresher = beanFactory.getBean(ContextRefresher.class); ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues(); constructorArgumentValues.addIndexedArgumentValue(0, polarisConfigProperties); - constructorArgumentValues.addIndexedArgumentValue(1, polarisPropertySourceManager); - constructorArgumentValues.addIndexedArgumentValue(2, contextRefresher); + constructorArgumentValues.addIndexedArgumentValue(1, contextRefresher); beanFactory.registerBeanDefinition(REFRESH_CONTEXT_REFRESHER_BEAN_NAME, beanDefinition); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java index 6a1058cd4..ce34ab954 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java @@ -32,7 +32,7 @@ public class PolarisConfigLoggerApplicationListener implements ApplicationListener { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisConfigLoggerApplicationListener.class); /** - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + * @see ApplicationListener#onApplicationEvent(ApplicationEvent) */ @Override public void onApplicationEvent(ApplicationEvent event) { diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java index 42f69f8d7..cfbc5385b 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java @@ -13,7 +13,6 @@ * 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.config.spring.annotation; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java new file mode 100644 index 000000000..6270836ca --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.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.config.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.config.ConditionalOnPolarisConfigEnabled; +import com.tencent.cloud.polaris.config.tsf.controller.PolarisAdaptorTsfConfigController; +import com.tencent.tsf.consul.config.watch.TsfConsulConfigRefreshEventListener; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author juanyinyang + * @Date Jul 23, 2023 3:52:48 PM + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +@ConditionalOnPolarisConfigEnabled +public class PolarisAdaptorTsfConfigAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled", matchIfMissing = true) + public TsfConsulConfigRefreshEventListener polarisAdaptorTsfConsulRefreshEventListener() { + return new TsfConsulConfigRefreshEventListener(); + } + + /** + * 初始化本类的条件: + * 1、关闭Spring Cloud Consul Config配置开关(如果开启Consul Config配置开关,那么初始化的是tsf自身的类ConfigController) + * 2、开启北极星配置(本类通过注解@ConditionalOnPolarisConfigEnabled开启) + * 3、tsf.config.instance.released-config.lookup.enabled的开关是打开的(默认不配置就是打开的). + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "tsf.config.instance.released-config.lookup.enabled", matchIfMissing = true) + public PolarisAdaptorTsfConfigController polarisAdaptorTsfConfigController() { + return new PolarisAdaptorTsfConfigController(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java new file mode 100755 index 000000000..bf9a044a2 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java @@ -0,0 +1,70 @@ +/* + * 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.config.tsf.controller; + + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author juanyinyang + * @Date 2023年8月2日 下午5:08:29 + */ +@RestController +public class PolarisAdaptorTsfConfigController { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisAdaptorTsfConfigController.class); + + @Autowired + Environment environment; + + public PolarisAdaptorTsfConfigController() { + LOG.info("init PolarisAdaptorTsfConfigController"); + } + + /** + * 兼容目前TSF控制台的用法,提供北极星查询当前SDK配置接口. + */ + @RequestMapping("/tsf/innerApi/config/findAllConfig") + public Map findAllConfig() { + List propertySourceList = PolarisPropertySourceManager.getAllPropertySources(); + + Set keys = new HashSet<>(); + for (PolarisPropertySource propertySource : propertySourceList) { + keys.addAll(Arrays.asList(propertySource.getPropertyNames())); + } + + return keys.stream() + .collect(HashMap::new, (map, key) -> map.put(key, environment.getProperty(key)), HashMap::putAll); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.java new file mode 100644 index 000000000..d6084889e --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.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.config.tsf.encrypt; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConfigEncryptAESProvider extends ConfigEncryptProvider { + + private static final Logger log = LoggerFactory.getLogger(ConfigEncryptAESProvider.class); + + @Override + public String encrypt(String content, String password) { + try { + return EncryptAlgorithm.AES256.encrypt(content, password); + } + catch (Exception e) { + log.error("Error on encrypting.", e); + throw e; + } + } + + @Override + public String decrypt(String encryptedContent, String password) { + try { + return EncryptAlgorithm.AES256.decrypt(encryptedContent, password); + } + catch (Exception e) { + log.error("Error on decrypting.", e); + throw e; + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.java new file mode 100644 index 000000000..e5cafca17 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.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.config.tsf.encrypt; + +/** + * TSF 配置加密提供器接口. + * + * @author hongweizhu + */ +public abstract class ConfigEncryptProvider { + + /** + * 加密. + * + * @param content 明文 + * @param password 密码 + * @return 密文 + */ + public abstract String encrypt(String content, String password); + + /** + * 解密. + * + * @param encryptedContent 密文 + * @param password 密码 + * @return 明文 + */ + public abstract String decrypt(String encryptedContent, String password); +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java new file mode 100644 index 000000000..980417bb4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java @@ -0,0 +1,39 @@ +/* + * 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.config.tsf.encrypt; + +public final class ConfigEncryptProviderFactory { + + private static ConfigEncryptProvider configEncryptProvider = null; + + private ConfigEncryptProviderFactory() { + } + + public static ConfigEncryptProvider getInstance() { + if (null == configEncryptProvider) { + try { + Class providerClass = Class.forName(EncryptConfig.getProviderClass()); + configEncryptProvider = (ConfigEncryptProvider) providerClass.newInstance(); + } + catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + return configEncryptProvider; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java new file mode 100644 index 000000000..1ce56b75a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java @@ -0,0 +1,146 @@ +/* + * 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.config.tsf.encrypt; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Base64; + +public class EncryptAlgorithm { + public static class AES256 { + + /** + * 加密. + * + * @param content 明文 + * @param password 密钥 + * @return 密文 + */ + public static final String encrypt(String content, String password) { + if (null == password || "".equals(password)) { + throw new PasswordNotFoundException(); + } + try { + // AES SK生成器 + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + // SHA-256摘要密钥后生成安全随机数 + SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); + sr.setSeed(SHA256.encode(password)); + kgen.init(256, sr); + // 生成秘密(对称)密钥 + SecretKey secretKey = kgen.generateKey(); + // 返回基本编码格式的密钥 + byte[] enCodeFormat = secretKey.getEncoded(); + // 根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称 + SecretKeySpec skSpec = new SecretKeySpec(enCodeFormat, "AES"); + // 将提供程序添加到下一个可用位置 + Security.addProvider(new BouncyCastleProvider()); + // 创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。 + // "AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称 + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + // 初始化cipher:加密模式 + cipher.init(Cipher.ENCRYPT_MODE, skSpec); + byte[] byteContent = content.getBytes(StandardCharsets.UTF_8); + byte[] cryptograph = cipher.doFinal(byteContent); + byte[] enryptedContent = Base64.encode(cryptograph); + return new String(enryptedContent); + } + catch (Exception e) { + throw new RuntimeException("Failed encrypt.", e); + } + } + + /** + * 解密. + * + * @param encryptedContent 密文 + * @param password 密钥 + * @return 明文 + */ + public static final String decrypt(String encryptedContent, String password) { + if (null == password || "".equals(password)) { + throw new PasswordNotFoundException(); + } + try { + // AES SK生成器 + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + // SHA-256摘要密钥后生成安全随机数 + SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); + sr.setSeed(SHA256.encode(password)); + kgen.init(256, sr); + // 生成秘密(对称)密钥 + SecretKey secretKey = kgen.generateKey(); + // 返回基本编码格式的密钥 + byte[] enCodeFormat = secretKey.getEncoded(); + // 根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称 + SecretKeySpec skSpec = new SecretKeySpec(enCodeFormat, "AES"); + // 将提供程序添加到下一个可用位置 + Security.addProvider(new BouncyCastleProvider()); + // 创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。 + // "AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称 + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + // 初始化cipher:解密模式 + cipher.init(Cipher.DECRYPT_MODE, skSpec); + byte[] result = cipher.doFinal(Base64.decode(encryptedContent.getBytes(StandardCharsets.UTF_8))); + return new String(result); + } + catch (Exception e) { + throw new RuntimeException("Failed decrypt.", e); + } + } + } + + public static class SHA256 { + + /** + * 计算SHA-256摘要. + * + * @param content 原文 + * @return 摘要 + * @throws NoSuchAlgorithmException 算法不存在时抛出 + */ + public static byte[] encode(String content) throws NoSuchAlgorithmException { + MessageDigest digester = MessageDigest.getInstance("SHA-256"); + digester.update(content.getBytes(StandardCharsets.UTF_8)); + return digester.digest(); + } + } + + public static class PasswordNotFoundException extends RuntimeException { + + /** + * serialVersionUID. + */ + private static final long serialVersionUID = -2843758461182470411L; + + public PasswordNotFoundException() { + super("Password not found."); + } + + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java new file mode 100644 index 000000000..125fb46a9 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.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.config.tsf.encrypt; + +import org.springframework.util.StringUtils; + +public final class EncryptConfig { + + private static final String PASSWORD_KEY = "tsf_config_encrypt_password"; + /** + * 加密前缀. + */ + public static String ENCRYPT_PREFIX = "ENC("; + /** + * 加密后缀. + */ + public static String ENCRYPT_SUFFIX = ")"; + /** + * 密码. + */ + private static String password; + /** + * 加解密提供器类名. + */ + private static String providerClass = "com.tencent.cloud.polaris.config.tsf.encrypt.ConfigEncryptAESProvider"; + + static { + // 环境变量 + if (null != System.getenv(PASSWORD_KEY)) { + password = System.getenv(PASSWORD_KEY); + } + // JVM参数 + if (null != System.getProperty(PASSWORD_KEY)) { + password = System.getProperty(PASSWORD_KEY); + } + } + + private EncryptConfig() { + + } + + /** + * 是否开启配置,判断 password 是否为空. + */ + public static Boolean getEnabled() { + return !StringUtils.isEmpty(password); + } + + public static String getPassword() { + return EncryptConfig.password; + } + + public static void setPassword(String password) { + EncryptConfig.password = password; + } + + public static ConfigEncryptProvider getProvider() { + return ConfigEncryptProviderFactory.getInstance(); + } + + public static String getProviderClass() { + return providerClass; + } + + public static void setProviderClass(String providerClass) { + EncryptConfig.providerClass = providerClass; + } + + /** + * 是否需要进行解密. + * + * @param content 判断对象 + * @return true:需要解密;false:不需要解密 + */ + public static Boolean needDecrypt(Object content) { + if (null == content) { + return false; + } + else { + String stringValue = String.valueOf(content); + return stringValue.startsWith(ENCRYPT_PREFIX) && stringValue.endsWith(ENCRYPT_SUFFIX); + } + } + + /** + * 获取真实密文. + * + * @param content 原始配置值 + * @return 真实密文 + */ + public static String realContent(Object content) { + if (null != content) { + String stringValue = String.valueOf(content); + return stringValue.substring(ENCRYPT_PREFIX.length(), stringValue.length() - ENCRYPT_SUFFIX.length()); + } + return null; + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java new file mode 100644 index 000000000..6eea01f4b --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java @@ -0,0 +1,34 @@ +/* + * 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.config.utils; + +/** + * Utils for PolarisPropertySource. + * + * @author Haotian Zhang + */ +public final class PolarisPropertySourceUtils { + + private PolarisPropertySourceUtils() { + + } + + public static String generateName(String namespace, String group, String fileName) { + return namespace + "-" + group + "-" + fileName; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java new file mode 100644 index 000000000..8845ac391 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java @@ -0,0 +1,28 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.tsf.consul.config.watch; + +public interface ConfigChangeCallback { + + /** + * 配置变更回调函数. + * @param lastConfigProperty 旧的配置属性 + * @param newConfigProperty 新的配置属性 + */ + void callback(ConfigProperty lastConfigProperty, ConfigProperty newConfigProperty); +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.java new file mode 100644 index 000000000..7f5115384 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.java @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.tsf.consul.config.watch; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface ConfigChangeListener { + String prefix() default ""; + + String[] value() default {}; + + boolean async() default false; + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.java new file mode 100644 index 000000000..45418efb1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.java @@ -0,0 +1,46 @@ +/* + * 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.tsf.consul.config.watch; + +public class ConfigProperty { + + private String key; + + private Object value; + + public ConfigProperty(String key, Object value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.java new file mode 100644 index 000000000..688ffbe93 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.java @@ -0,0 +1,122 @@ +/* + * 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.tsf.consul.config.watch; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent; +import com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext; +import com.tencent.cloud.polaris.config.listener.SyncConfigChangeListener; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.lang.NonNull; +import org.springframework.util.StringUtils; + +public class TsfConsulConfigRefreshEventListener implements BeanPostProcessor, PriorityOrdered { + private static final String DOT = "."; + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + @Override + public Object postProcessBeforeInitialization(@NonNull Object obj, @NonNull String beanName) throws BeansException { + return obj; + } + + @Override + public Object postProcessAfterInitialization(@NonNull Object obj, @NonNull String beanName) throws BeansException { + Class clz = obj.getClass(); + if (!clz.isAnnotationPresent(ConfigChangeListener.class) || !ConfigChangeCallback.class.isAssignableFrom(clz)) { + return obj; + } + + ConfigChangeListener targetAnno = clz.getAnnotation(ConfigChangeListener.class); + String watchedPrefix = targetAnno.prefix(); + String[] watchedConfirmedValue = targetAnno.value(); + boolean isAsync = targetAnno.async(); + if (watchedConfirmedValue.length == 0 && StringUtils.isEmpty(watchedPrefix)) { + return obj; + } + + ConfigChangeCallback bean = (ConfigChangeCallback) obj; + com.tencent.cloud.polaris.config.listener.ConfigChangeListener listener = new SyncConfigChangeListener() { + @Override + public void onChange(ConfigChangeEvent changeEvent) { + List paramList = parseConfigChangeEventToTsfCallbackParam(changeEvent); + for (TsfCallbackParam param : paramList) { + if (isAsync()) { + PolarisConfigListenerContext.executor() + .execute(() -> bean.callback(param.oldValue, param.newValue)); + } + else { + bean.callback(param.oldValue, param.newValue); + } + } + } + + @Override + public boolean isAsync() { + return isAsync; + } + }; + + Set interestedKeys = new HashSet<>(); + Set interestedKeyPrefixes = new HashSet<>(); + if (watchedConfirmedValue.length > 0) { + for (String value : watchedConfirmedValue) { + interestedKeys.add(StringUtils.isEmpty(watchedPrefix) ? value : watchedPrefix + DOT + value); + } + } + else { + interestedKeyPrefixes.add(watchedPrefix); + } + + PolarisConfigListenerContext.addChangeListener(listener, interestedKeys, interestedKeyPrefixes); + return bean; + } + + private List parseConfigChangeEventToTsfCallbackParam(ConfigChangeEvent event) { + List result = new ArrayList<>(); + Set changedKeys = event.changedKeys(); + for (String changedKey : changedKeys) { + ConfigProperty oldValue = new ConfigProperty(changedKey, event.getChange(changedKey).getOldValue()); + ConfigProperty newValue = new ConfigProperty(changedKey, event.getChange(changedKey).getNewValue()); + TsfCallbackParam param = new TsfCallbackParam(oldValue, newValue); + result.add(param); + } + return result; + } + + static class TsfCallbackParam { + ConfigProperty oldValue; + ConfigProperty newValue; + + TsfCallbackParam(ConfigProperty oldValue, ConfigProperty newValue) { + this.oldValue = oldValue; + this.newValue = newValue; + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories index 98221a39a..f9eb6a0bd 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories @@ -1,5 +1,8 @@ -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration,\ - com.tencent.cloud.polaris.config.endpoint.PolarisConfigEndpointAutoConfiguration + com.tencent.cloud.polaris.config.endpoint.PolarisConfigEndpointAutoConfiguration,\ + com.tencent.cloud.polaris.config.tsf.PolarisAdaptorTsfConfigAutoConfiguration,\ + com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration + diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java index acdeb050c..42dbd028f 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java @@ -29,6 +29,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.configuration.api.core.ConfigFileService; import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -42,8 +43,7 @@ /** * test for {@link PolarisConfigFileLocator}. - * - * @author lepdou 2022-06-11 + *@author lepdou 2022-06-11 */ @ExtendWith(MockitoExtension.class) public class PolarisConfigFileLocatorTest { @@ -57,14 +57,17 @@ public class PolarisConfigFileLocatorTest { @Mock private ConfigFileService configFileService; @Mock - private PolarisPropertySourceManager polarisPropertySourceManager; - @Mock private Environment environment; + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testLoadApplicationPropertiesFile() { PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, - configFileService, polarisPropertySourceManager, environment); + configFileService, environment); when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); when(polarisContextProperties.getService()).thenReturn(testServiceName); @@ -86,7 +89,9 @@ public void testLoadApplicationPropertiesFile() { when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yaml")).thenReturn(emptyConfigFile); + when(polarisConfigProperties.isEnabled()).thenReturn(true); when(polarisConfigProperties.getGroups()).thenReturn(null); + when(polarisConfigProperties.isInternalEnabled()).thenReturn(true); when(environment.getActiveProfiles()).thenReturn(new String[] {}); PropertySource propertySource = locator.locate(environment); @@ -99,7 +104,7 @@ public void testLoadApplicationPropertiesFile() { @Test public void testActiveProfileFilesPriorityBiggerThanDefault() { PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, - configFileService, polarisPropertySourceManager, environment); + configFileService, environment); when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); when(polarisContextProperties.getService()).thenReturn(testServiceName); @@ -133,7 +138,9 @@ public void testActiveProfileFilesPriorityBiggerThanDefault() { when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yml")).thenReturn(emptyConfigFile); when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yaml")).thenReturn(emptyConfigFile); + when(polarisConfigProperties.isEnabled()).thenReturn(true); when(polarisConfigProperties.getGroups()).thenReturn(null); + when(polarisConfigProperties.isInternalEnabled()).thenReturn(true); when(environment.getActiveProfiles()).thenReturn(new String[] {"dev"}); PropertySource propertySource = locator.locate(environment); @@ -146,7 +153,7 @@ public void testActiveProfileFilesPriorityBiggerThanDefault() { @Test public void testGetCustomFiles() { PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, - configFileService, polarisPropertySourceManager, environment); + configFileService, environment); when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); when(polarisContextProperties.getService()).thenReturn(testServiceName); @@ -170,7 +177,9 @@ public void testGetCustomFiles() { configFileGroup.setFiles(Lists.newArrayList(customFile1, customFile2)); customFiles.add(configFileGroup); + when(polarisConfigProperties.isEnabled()).thenReturn(true); when(polarisConfigProperties.getGroups()).thenReturn(customFiles); + when(polarisConfigProperties.isInternalEnabled()).thenReturn(true); when(environment.getActiveProfiles()).thenReturn(new String[] {}); // file1.properties diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java index ba38d135e..0d10255fa 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java @@ -24,7 +24,6 @@ import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; import com.tencent.cloud.polaris.config.spring.property.SpringValue; @@ -32,6 +31,7 @@ import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -59,8 +59,6 @@ public class PolarisPropertiesSourceAutoRefresherTest { private final String testFileName = "application.properties"; @Mock private PolarisConfigProperties polarisConfigProperties; - @Mock - private PolarisPropertySourceManager polarisPropertySourceManager; @Mock private SpringValueRegistry springValueRegistry; @@ -68,10 +66,14 @@ public class PolarisPropertiesSourceAutoRefresherTest { @Mock private PlaceholderHelper placeholderHelper; + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testConfigFileChanged() throws Exception { - PolarisRefreshAffectedContextRefresher refresher = new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, - polarisPropertySourceManager, springValueRegistry, placeholderHelper); + PolarisRefreshAffectedContextRefresher refresher = new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, springValueRegistry, placeholderHelper); ConfigurableApplicationContext applicationContext = mock(ConfigurableApplicationContext.class); ConfigurableListableBeanFactory beanFactory = mock(ConfigurableListableBeanFactory.class); TypeConverter typeConverter = mock(TypeConverter.class); @@ -99,7 +101,7 @@ public void testConfigFileChanged() throws Exception { PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, file, content); - when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); ConfigPropertyChangeInfo changeInfo2 = new ConfigPropertyChangeInfo("k4", null, "v4", ChangeType.ADDED); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java index ebde3e470..058d4d1ba 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java @@ -24,7 +24,6 @@ import com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshAffectedContextRefresher; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefresher; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; @@ -107,7 +106,6 @@ public void testWithoutReflectEnabled() { .withPropertyValues("spring.cloud.polaris.config.enabled=true"); contextRunner.run(context -> { assertThat(context).hasSingleBean(PolarisConfigProperties.class); - assertThat(context).hasSingleBean(PolarisPropertySourceManager.class); assertThat(context).hasSingleBean(ContextRefresher.class); assertThat(context).hasSingleBean(PolarisRefreshEntireContextRefresher.class); }); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java index 92933fcc7..0389f1607 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java @@ -26,13 +26,13 @@ import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; /** * Test for polaris config endpoint. @@ -48,8 +48,11 @@ public class PolarisConfigEndpointTest { @Mock private PolarisConfigProperties polarisConfigProperties; - @Mock - private PolarisPropertySourceManager polarisPropertySourceManager; + + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } @Test public void testPolarisConfigEndpoint() { @@ -60,9 +63,9 @@ public void testPolarisConfigEndpoint() { MockedConfigKVFile file = new MockedConfigKVFile(content); PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, file, content); - when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); - PolarisConfigEndpoint endpoint = new PolarisConfigEndpoint(polarisConfigProperties, polarisPropertySourceManager); + PolarisConfigEndpoint endpoint = new PolarisConfigEndpoint(polarisConfigProperties); Map info = endpoint.polarisConfig(); assertThat(polarisConfigProperties).isEqualTo(info.get("PolarisConfigProperties")); assertThat(Lists.newArrayList(polarisPropertySource)).isEqualTo(info.get("PolarisPropertySource")); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java index eef16a89f..191af7110 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.adapter.MockedConfigKVFile; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; @@ -31,6 +30,7 @@ import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -77,6 +77,11 @@ public class PolarisConfigRefreshOptimizationListenerNotTriggeredTest { @Autowired private ConfigurableApplicationContext context; + @BeforeAll + static void beforeAll() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testNotSwitchConfigRefreshType() { RefreshType actualRefreshType = context.getEnvironment() @@ -100,12 +105,12 @@ public void testConfigFileChanged() { PolarisPropertySource polarisPropertySource = new PolarisPropertySource(TEST_NAMESPACE, TEST_SERVICE_NAME, TEST_FILE_NAME, file, content); - PolarisPropertySourceManager manager = context.getBean(PolarisPropertySourceManager.class); - when(manager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); PolarisRefreshAffectedContextRefresher refresher = context.getBean(PolarisRefreshAffectedContextRefresher.class); PolarisRefreshAffectedContextRefresher spyRefresher = Mockito.spy(refresher); + refresher.setRegistered(false); spyRefresher.onApplicationEvent(null); ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); @@ -134,12 +139,6 @@ public void testConfigFileChanged() { @SpringBootApplication protected static class TestApplication { - @Primary - @Bean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return mock(PolarisPropertySourceManager.class); - } - @Primary @Bean public ContextRefresher contextRefresher() { diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java index 24aa7ae08..ef273483e 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.adapter.MockedConfigKVFile; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; @@ -31,6 +30,7 @@ import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -78,6 +78,11 @@ public class PolarisConfigRefreshOptimizationListenerTriggeredTest { @Autowired private ConfigurableApplicationContext context; + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testSwitchConfigRefreshType() { RefreshType actualRefreshType = context.getEnvironment() @@ -101,12 +106,12 @@ public void testConfigFileChanged() { PolarisPropertySource polarisPropertySource = new PolarisPropertySource(TEST_NAMESPACE, TEST_SERVICE_NAME, TEST_FILE_NAME, file, content); - PolarisPropertySourceManager manager = context.getBean(PolarisPropertySourceManager.class); - when(manager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); PolarisRefreshEntireContextRefresher refresher = context.getBean(PolarisRefreshEntireContextRefresher.class); PolarisRefreshEntireContextRefresher spyRefresher = Mockito.spy(refresher); + refresher.setRegistered(false); spyRefresher.onApplicationEvent(null); ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); @@ -135,12 +140,6 @@ public void testConfigFileChanged() { @SpringBootApplication protected static class TestApplication { - @Primary - @Bean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return mock(PolarisPropertySourceManager.class); - } - @Primary @Bean public ContextRefresher contextRefresher() { diff --git a/spring-cloud-starter-tencent-polaris-contract/pom.xml b/spring-cloud-starter-tencent-polaris-contract/pom.xml index c17c92b32..39aca1001 100644 --- a/spring-cloud-starter-tencent-polaris-contract/pom.xml +++ b/spring-cloud-starter-tencent-polaris-contract/pom.xml @@ -36,28 +36,13 @@ - io.springfox - springfox-boot-starter - - - swagger-models - io.swagger - - - swagger-annotations - io.swagger - - + org.springdoc + springdoc-openapi-ui - io.swagger - swagger-models - - - - io.swagger - swagger-annotations + org.springdoc + springdoc-openapi-webflux-ui diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java index 1470136e8..c380be0c3 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java @@ -17,27 +17,33 @@ package com.tencent.cloud.polaris.contract; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import com.tencent.cloud.common.util.JacksonUtils; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tencent.cloud.common.util.GzipUtil; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import com.tencent.polaris.api.core.ProviderAPI; import com.tencent.polaris.api.plugin.server.InterfaceDescriptor; import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest; import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse; -import io.swagger.models.HttpMethod; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; +import com.tencent.polaris.api.utils.StringUtils; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import springfox.documentation.service.Documentation; -import springfox.documentation.spring.web.DocumentationCache; -import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; +import org.springdoc.api.AbstractOpenApiResource; +import org.springdoc.api.AbstractOpenApiResourceUtil; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.OpenApiWebFluxUtil; +import org.springdoc.webmvc.api.OpenApiWebMvcUtil; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; @@ -52,50 +58,79 @@ public class PolarisContractReporter implements ApplicationListener { private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class); - private final ServiceModelToSwagger2Mapper swagger2Mapper; - private final DocumentationCache documentationCache; + + private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource; + private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; private final PolarisContractProperties polarisContractProperties; private final ProviderAPI providerAPI; private final PolarisDiscoveryProperties polarisDiscoveryProperties; - public PolarisContractReporter(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper swagger2Mapper, - PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, PolarisDiscoveryProperties polarisDiscoveryProperties) { - this.swagger2Mapper = swagger2Mapper; - this.documentationCache = documentationCache; + private final ObjectMapperProvider springdocObjectMapperProvider; + + public PolarisContractReporter(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, + PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, + PolarisDiscoveryProperties polarisDiscoveryProperties, ObjectMapperProvider springdocObjectMapperProvider) { + this.multipleOpenApiWebMvcResource = multipleOpenApiWebMvcResource; + this.multipleOpenApiWebFluxResource = multipleOpenApiWebFluxResource; this.polarisContractProperties = polarisContractProperties; this.providerAPI = providerAPI; this.polarisDiscoveryProperties = polarisDiscoveryProperties; + this.springdocObjectMapperProvider = springdocObjectMapperProvider; } @Override public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) { if (polarisContractProperties.isReportEnabled()) { try { - Documentation documentation = documentationCache.documentationByGroup(polarisContractProperties.getGroup()); - Swagger swagger = swagger2Mapper.mapDocumentation(documentation); - if (swagger != null) { + AbstractOpenApiResource openApiResource = null; + if (multipleOpenApiWebMvcResource != null) { + openApiResource = OpenApiWebMvcUtil.getOpenApiResourceOrThrow(multipleOpenApiWebMvcResource, polarisContractProperties.getGroup()); + } + else if (multipleOpenApiWebFluxResource != null) { + openApiResource = OpenApiWebFluxUtil.getOpenApiResourceOrThrow(multipleOpenApiWebFluxResource, polarisContractProperties.getGroup()); + } + OpenAPI openAPI = null; + if (openApiResource != null) { + openAPI = AbstractOpenApiResourceUtil.getOpenApi(openApiResource); + } + if (openAPI != null) { ReportServiceContractRequest request = new ReportServiceContractRequest(); - request.setName(polarisDiscoveryProperties.getService()); + String name = polarisContractProperties.getName(); + if (StringUtils.isBlank(name)) { + name = polarisDiscoveryProperties.getService(); + } + request.setName(name); request.setNamespace(polarisDiscoveryProperties.getNamespace()); request.setService(polarisDiscoveryProperties.getService()); request.setProtocol("http"); request.setVersion(polarisDiscoveryProperties.getVersion()); - List interfaceDescriptorList = getInterfaceDescriptorFromSwagger(swagger); + List interfaceDescriptorList = getInterfaceDescriptorFromSwagger(openAPI); request.setInterfaceDescriptors(interfaceDescriptorList); + String jsonValue; + if (springdocObjectMapperProvider != null && springdocObjectMapperProvider.jsonMapper() != null) { + jsonValue = springdocObjectMapperProvider.jsonMapper().writeValueAsString(openAPI); + } + else { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonValue = mapper.writeValueAsString(openAPI); + } + String serviceApiMeta = GzipUtil.compressBase64Encode(jsonValue, "utf-8"); + request.setContent(serviceApiMeta); ReportServiceContractResponse response = providerAPI.reportServiceContract(request); LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.", request.getNamespace(), request.getName(), request.getService(), request.getProtocol(), request.getVersion(), request.getInterfaceDescriptors().size()); if (LOG.isDebugEnabled()) { - String jsonValue = JacksonUtils.serialize2Json(swagger); LOG.debug("OpenApi json data: {}", jsonValue); + LOG.debug("OpenApi json base64 data: {}", serviceApiMeta); } } else { - LOG.warn("Swagger or json is null, documentationCache keys:{}, group:{}", documentationCache.all() - .keySet(), polarisContractProperties.getGroup()); + LOG.warn("OpenAPI or json is null, group:{}", polarisContractProperties.getGroup()); } } catch (Throwable t) { @@ -104,11 +139,11 @@ public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEv } } - private List getInterfaceDescriptorFromSwagger(Swagger swagger) { + private List getInterfaceDescriptorFromSwagger(OpenAPI openAPI) { List interfaceDescriptorList = new ArrayList<>(); - Map paths = swagger.getPaths(); - for (Map.Entry p : paths.entrySet()) { - Path path = p.getValue(); + Paths paths = openAPI.getPaths(); + for (Map.Entry p : paths.entrySet()) { + PathItem path = p.getValue(); Map operationMap = getOperationMapFromPath(path); if (CollectionUtils.isEmpty(operationMap)) { continue; @@ -117,36 +152,50 @@ private List getInterfaceDescriptorFromSwagger(Swagger swag InterfaceDescriptor interfaceDescriptor = new InterfaceDescriptor(); interfaceDescriptor.setPath(p.getKey()); interfaceDescriptor.setMethod(o.getKey()); - interfaceDescriptor.setContent(JacksonUtils.serialize2Json(p.getValue())); + try { + String jsonValue; + if (springdocObjectMapperProvider != null && springdocObjectMapperProvider.jsonMapper() != null) { + jsonValue = springdocObjectMapperProvider.jsonMapper().writeValueAsString(o.getValue()); + } + else { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonValue = mapper.writeValueAsString(o.getValue()); + } + interfaceDescriptor.setContent(GzipUtil.compressBase64Encode(jsonValue, "utf-8")); + } + catch (IOException ioe) { + LOG.warn("Encode operation [{}] failed.", o.getValue(), ioe); + } interfaceDescriptorList.add(interfaceDescriptor); } } return interfaceDescriptorList; } - private Map getOperationMapFromPath(Path path) { + private Map getOperationMapFromPath(PathItem path) { Map operationMap = new HashMap<>(); if (path.getGet() != null) { - operationMap.put(HttpMethod.GET.name(), path.getGet()); + operationMap.put(PathItem.HttpMethod.GET.name(), path.getGet()); } if (path.getPut() != null) { - operationMap.put(HttpMethod.PUT.name(), path.getPut()); + operationMap.put(PathItem.HttpMethod.PUT.name(), path.getPut()); } if (path.getPost() != null) { - operationMap.put(HttpMethod.POST.name(), path.getPost()); + operationMap.put(PathItem.HttpMethod.POST.name(), path.getPost()); } if (path.getHead() != null) { - operationMap.put(HttpMethod.HEAD.name(), path.getHead()); + operationMap.put(PathItem.HttpMethod.HEAD.name(), path.getHead()); } if (path.getDelete() != null) { - operationMap.put(HttpMethod.DELETE.name(), path.getDelete()); + operationMap.put(PathItem.HttpMethod.DELETE.name(), path.getDelete()); } if (path.getPatch() != null) { - operationMap.put(HttpMethod.PATCH.name(), path.getPatch()); + operationMap.put(PathItem.HttpMethod.PATCH.name(), path.getPatch()); } if (path.getOptions() != null) { - operationMap.put(HttpMethod.OPTIONS.name(), path.getOptions()); + operationMap.put(PathItem.HttpMethod.OPTIONS.name(), path.getOptions()); } return operationMap; diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java index 7a34c8360..21d098cae 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java @@ -51,4 +51,8 @@ public interface ContractProperties { boolean isReportEnabled(); void setReportEnabled(boolean reportEnabled); + + String getName(); + + void setName(String name); } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java index f48a01d24..b1b50f518 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java @@ -41,7 +41,8 @@ public PolarisContractModifier(PolarisContractProperties polarisContractProperti public void modify(ConfigurationImpl configuration) { List registerConfigs = configuration.getProvider().getRegisters(); for (RegisterConfigImpl registerConfig : registerConfigs) { - registerConfig.setReportServiceContractEnable(polarisContractProperties.isEnabled()); + registerConfig.setReportServiceContractEnable( + polarisContractProperties.isEnabled() && polarisContractProperties.isReportEnabled()); } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java index 2b43226a5..8ac200710 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java @@ -17,10 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import java.util.Objects; - -import javax.annotation.Nullable; - import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -32,8 +28,6 @@ @ConfigurationProperties("spring.cloud.polaris.contract") public class PolarisContractProperties implements ContractProperties { - private final ExtendedContractProperties extendContractProperties; - private boolean enabled = true; /** * Packages to be scanned. Split by ",". @@ -46,7 +40,7 @@ public class PolarisContractProperties implements ContractProperties { /** * Group to create swagger docket. */ - private String group = "default"; + private String group = "polaris"; /** * Base paths to be scanned. Split by ",". */ @@ -57,15 +51,10 @@ public class PolarisContractProperties implements ContractProperties { @Value("${spring.cloud.polaris.contract.report.enabled:true}") private boolean reportEnabled = true; - public PolarisContractProperties(@Nullable ExtendedContractProperties extendContractProperties) { - this.extendContractProperties = extendContractProperties; - } + private String name; @Override public boolean isEnabled() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.isEnabled(); - } return enabled; } @@ -76,9 +65,6 @@ public void setEnabled(boolean enabled) { @Override public String getBasePackage() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getBasePackage(); - } return basePackage; } @@ -89,9 +75,6 @@ public void setBasePackage(String basePackage) { @Override public String getExcludePath() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getExcludePath(); - } return excludePath; } @@ -102,9 +85,6 @@ public void setExcludePath(String excludePath) { @Override public String getGroup() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getGroup(); - } return group; } @@ -115,9 +95,6 @@ public void setGroup(String group) { @Override public String getBasePath() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getBasePath(); - } return basePath; } @@ -128,9 +105,6 @@ public void setBasePath(String basePath) { @Override public boolean isExposure() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.isExposure(); - } return exposure; } @@ -148,4 +122,13 @@ public boolean isReportEnabled() { public void setReportEnabled(boolean reportEnabled) { this.reportEnabled = reportEnabled; } + + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java index d3e0edb35..051f8bc20 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java @@ -17,8 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import javax.annotation.Nullable; - import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -36,8 +34,8 @@ public class PolarisContractPropertiesAutoConfiguration { @Bean @ConditionalOnMissingBean - public PolarisContractProperties polarisContractProperties(@Nullable ExtendedContractProperties extendedContractProperties) { - return new PolarisContractProperties(extendedContractProperties); + public PolarisContractProperties polarisContractProperties() { + return new PolarisContractProperties(); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java index e0ace300c..ca8c36bea 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java @@ -17,11 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import java.time.LocalDate; -import java.util.Date; -import java.util.List; -import java.util.function.Predicate; - import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; @@ -30,13 +25,14 @@ import com.tencent.cloud.polaris.contract.filter.ApiDocServletFilter; import com.tencent.cloud.polaris.contract.filter.ApiDocWebFluxFilter; import com.tencent.cloud.polaris.contract.utils.PackageUtil; -import springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.service.Contact; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.DocumentationCache; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.GroupedOpenApi; +import org.springdoc.core.SpringDocConfiguration; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.MultipleOpenApiWebFluxResource; +import org.springdoc.webmvc.api.MultipleOpenApiWebMvcResource; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -45,6 +41,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +import static com.tencent.cloud.polaris.contract.utils.PackageUtil.SPLITTER; /** * Auto configuration for Polaris swagger. @@ -54,7 +54,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisEnabled @ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true) -@Import(OpenApiAutoConfiguration.class) +@Import(SpringDocConfiguration.class) public class PolarisSwaggerAutoConfiguration { static { @@ -64,65 +64,45 @@ public class PolarisSwaggerAutoConfiguration { } @Bean - public Docket polarisDocket(PolarisContractProperties polarisContractProperties) { - List> excludePathList = PackageUtil.getExcludePathPredicates(polarisContractProperties.getExcludePath()); - List> basePathList = PackageUtil.getBasePathPredicates(polarisContractProperties.getBasePath()); + public GroupedOpenApi polarisGroupedOpenApi(PolarisContractProperties polarisContractProperties) { String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage()); - - Predicate basePathListOr = null; - for (Predicate basePathPredicate : basePathList) { - if (basePathListOr == null) { - basePathListOr = basePathPredicate; - } - else { - basePathListOr = basePathListOr.or(basePathPredicate); - } - } - - Predicate excludePathListOr = null; - for (Predicate excludePathPredicate : excludePathList) { - if (excludePathListOr == null) { - excludePathListOr = excludePathPredicate; - } - else { - excludePathListOr = excludePathListOr.or(excludePathPredicate); - } + String[] basePaths = {}; + if (StringUtils.hasText(polarisContractProperties.getBasePath())) { + basePaths = polarisContractProperties.getBasePath().split(SPLITTER); } - - Predicate pathsPredicate = basePathListOr; - - if (excludePathListOr != null) { - excludePathListOr = excludePathListOr.negate(); - pathsPredicate = pathsPredicate.and(excludePathListOr); + String[] excludePaths = {}; + if (StringUtils.hasText(polarisContractProperties.getExcludePath())) { + excludePaths = polarisContractProperties.getExcludePath().split(SPLITTER); } + return GroupedOpenApi.builder() + .packagesToScan(basePackage) + .pathsToMatch(basePaths) + .pathsToExclude(excludePaths) + .group(polarisContractProperties.getGroup()) + .build(); + } - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(PackageUtil.basePackage(basePackage)) - .paths(pathsPredicate) - .build() - .groupName(polarisContractProperties.getGroup()) - .enable(polarisContractProperties.isEnabled()) - .directModelSubstitute(LocalDate.class, Date.class) - .apiInfo(new ApiInfoBuilder() - .title("Polaris Swagger API") - .description("This is to show polaris api description.") - .license("BSD-3-Clause") - .licenseUrl("https://opensource.org/licenses/BSD-3-Clause") - .termsOfServiceUrl("") - .version("1.0.0") - .contact(new Contact("", "", "")) - .build()); + @Bean + @ConditionalOnMissingBean + public OpenAPI polarisOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("Polaris Contract") + .description("This is to show polaris contract description.") + .license(new License().name("BSD-3-Clause").url("https://opensource.org/licenses/BSD-3-Clause")) + .version("1.0.0")); } @Bean - @ConditionalOnBean(Docket.class) + @ConditionalOnBean(OpenAPI.class) @ConditionalOnMissingBean - public PolarisContractReporter polarisContractReporter(DocumentationCache documentationCache, - ServiceModelToSwagger2Mapper swagger2Mapper, PolarisContractProperties polarisContractProperties, - PolarisSDKContextManager polarisSDKContextManager, PolarisDiscoveryProperties polarisDiscoveryProperties) { - return new PolarisContractReporter(documentationCache, swagger2Mapper, polarisContractProperties, - polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties); + public PolarisContractReporter polarisContractReporter( + @Nullable MultipleOpenApiWebMvcResource multipleOpenApiWebMvcResource, + @Nullable MultipleOpenApiWebFluxResource multipleOpenApiWebFluxResource, + PolarisContractProperties polarisContractProperties, PolarisSDKContextManager polarisSDKContextManager, + PolarisDiscoveryProperties polarisDiscoveryProperties, ObjectMapperProvider springdocObjectMapperProvider) { + return new PolarisContractReporter(multipleOpenApiWebMvcResource, multipleOpenApiWebFluxResource, + polarisContractProperties, polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties, springdocObjectMapperProvider); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java index 38aa3d7c9..98e925024 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java @@ -26,7 +26,6 @@ import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; -import org.springframework.lang.NonNull; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX; @@ -51,11 +50,9 @@ public ApiDocServletFilter(PolarisContractProperties polarisContractProperties) } @Override - public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, - @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) - throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!polarisContractProperties.isExposure()) { - String path = httpServletRequest.getServletPath(); + String path = request.getServletPath(); if (path.startsWith(SWAGGER_V2_API_DOC_URL) || path.startsWith(SWAGGER_V3_API_DOC_URL) || path.startsWith(SWAGGER_UI_V2_URL) || @@ -63,11 +60,11 @@ public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, path.startsWith(SWAGGER_RESOURCE_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) { - httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); return; } } - filterChain.doFilter(httpServletRequest, httpServletResponse); + filterChain.doFilter(request, response); } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java index 7e7ea199a..ac9c23d8a 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java @@ -17,13 +17,13 @@ package com.tencent.cloud.polaris.contract.filter; - import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.NonNull; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; @@ -42,6 +42,7 @@ * @author Haotian Zhang */ public class ApiDocWebFluxFilter implements WebFilter { + private final PolarisContractProperties polarisContractProperties; public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) { @@ -49,7 +50,7 @@ public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) } @Override - public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { + public Mono filter(ServerWebExchange serverWebExchange, @NonNull WebFilterChain webFilterChain) { if (!polarisContractProperties.isExposure()) { String path = serverWebExchange.getRequest().getURI().getPath(); if (path.startsWith(SWAGGER_V2_API_DOC_URL) || diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java new file mode 100644 index 000000000..4278d7093 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java @@ -0,0 +1,137 @@ +/* + * 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.contract.tsf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tencent.cloud.common.util.GzipUtil; +import io.swagger.v3.oas.models.OpenAPI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springdoc.api.AbstractOpenApiResource; +import org.springdoc.api.AbstractOpenApiResourceUtil; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.OpenApiWebFluxUtil; +import org.springdoc.webmvc.api.OpenApiWebMvcUtil; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.SmartLifecycle; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +public class TsfApiMetadataGrapher implements SmartLifecycle { + + private final AtomicBoolean isRunning = new AtomicBoolean(false); + private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource; + private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; + private final ObjectMapperProvider springdocObjectMapperProvider; + private Logger logger = LoggerFactory.getLogger(TsfApiMetadataGrapher.class); + private ApplicationContext applicationContext; + private String groupName; + + public TsfApiMetadataGrapher(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, + String groupName, ApplicationContext applicationContext, ObjectMapperProvider springdocObjectMapperProvider) { + this.applicationContext = applicationContext; + this.multipleOpenApiWebMvcResource = multipleOpenApiWebMvcResource; + this.multipleOpenApiWebFluxResource = multipleOpenApiWebFluxResource; + this.groupName = groupName; + this.springdocObjectMapperProvider = springdocObjectMapperProvider; + } + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void stop(Runnable runnable) { + runnable.run(); + stop(); + } + + @Override + public void start() { + if (!isRunning.compareAndSet(false, true)) { + return; + } + try { + AbstractOpenApiResource openApiResource = null; + if (multipleOpenApiWebMvcResource != null) { + openApiResource = OpenApiWebMvcUtil.getOpenApiResourceOrThrow(multipleOpenApiWebMvcResource, groupName); + } + else if (multipleOpenApiWebFluxResource != null) { + openApiResource = OpenApiWebFluxUtil.getOpenApiResourceOrThrow(multipleOpenApiWebFluxResource, groupName); + } + OpenAPI openAPI = null; + if (openApiResource != null) { + openAPI = AbstractOpenApiResourceUtil.getOpenApi(openApiResource); + } + String jsonValue; + if (springdocObjectMapperProvider != null && springdocObjectMapperProvider.jsonMapper() != null) { + jsonValue = springdocObjectMapperProvider.jsonMapper().writeValueAsString(openAPI); + } + else { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonValue = mapper.writeValueAsString(openAPI); + } + if (openAPI != null && !StringUtils.isEmpty(jsonValue)) { + String serviceApiMeta = GzipUtil.compressBase64Encode(jsonValue, "utf-8"); + Environment environment = applicationContext.getEnvironment(); + String tsfToken = environment.getProperty("tsf_token"); + String tsfGroupId = environment.getProperty("tsf_group_id"); + if (StringUtils.isEmpty(tsfGroupId) || StringUtils.isEmpty(tsfToken)) { + logger.info("[tsf-swagger] auto smart check application start with local consul, api registry not work"); + return; + } + logger.info("[tsf-swagger] api_meta len: {}", serviceApiMeta.length()); + String applicationName = environment.getProperty("spring.application.name"); + if (logger.isDebugEnabled()) { + logger.debug("[tsf-swagger] service: {} openApi json data: {}", applicationName, jsonValue); + logger.debug("[tsf-swagger] service: {} api_meta info: {}", applicationName, serviceApiMeta); + } + + System.setProperty(String.format("$%s", "api_metas"), serviceApiMeta); + } + else { + logger.warn("[tsf-swagger] swagger or json is null, openApiResource keys:{}, group:{}", openApiResource, groupName); + } + } + catch (Throwable t) { + logger.error("[tsf swagger] init TsfApiMetadataGrapher failed. occur exception: ", t); + } + } + + @Override + public void stop() { + isRunning.set(true); + } + + @Override + public boolean isRunning() { + return isRunning.get(); + } + + @Override + public int getPhase() { + return -2; + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.java new file mode 100644 index 000000000..65322d1d8 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.java @@ -0,0 +1,46 @@ +/* + * 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.contract.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; +import io.swagger.v3.oas.models.OpenAPI; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.MultipleOpenApiWebFluxResource; +import org.springdoc.webmvc.api.MultipleOpenApiWebMvcResource; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; + +@Configuration +@ConditionalOnTsfConsulEnabled +@ConditionalOnProperty(value = "tsf.swagger.enabled", havingValue = "true", matchIfMissing = true) +public class TsfSwaggerAutoConfiguration { + + @Bean + @ConditionalOnBean(OpenAPI.class) + public TsfApiMetadataGrapher tsfApiMetadataGrapher(@Nullable MultipleOpenApiWebMvcResource multipleOpenApiWebMvcResource, + @Nullable MultipleOpenApiWebFluxResource multipleOpenApiWebFluxResource, ApplicationContext context, + PolarisContractProperties polarisContractProperties, ObjectMapperProvider springdocObjectMapperProvider) { + return new TsfApiMetadataGrapher(multipleOpenApiWebMvcResource, multipleOpenApiWebFluxResource, + polarisContractProperties.getGroup(), context, springdocObjectMapperProvider); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java index 1ce380cf5..1afcb709d 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java @@ -17,26 +17,17 @@ package com.tencent.cloud.polaris.contract.utils; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.function.Predicate; -import com.google.common.base.Function; -import com.google.common.base.Optional; import com.tencent.cloud.polaris.contract.SwaggerContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import springfox.documentation.RequestHandler; -import springfox.documentation.builders.PathSelectors; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.util.StringUtils; -import static com.google.common.base.Optional.fromNullable; - /** * Util for package processing. * @@ -44,87 +35,15 @@ */ public final class PackageUtil { + /** + * splitter for property. + */ + public static final String SPLITTER = ","; private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class); - private static final String SPLITTER = ","; - private PackageUtil() { } - public static Predicate basePackage(String basePackage) { - return input -> declaringClass(input).transform(handlerPackage(basePackage, SPLITTER)).or(false); - } - - public static Optional> declaringClass(RequestHandler input) { - if (input == null) { - return Optional.absent(); - } - return fromNullable(input.declaringClass()); - } - - public static Function, Boolean> handlerPackage(String basePackage, String splitter) { - return input -> { - try { - if (StringUtils.isEmpty(basePackage)) { - return false; - } - String[] packages = basePackage.trim().split(splitter); - // Loop to determine matching - for (String strPackage : packages) { - if (input == null) { - continue; - } - Package pkg = input.getPackage(); - if (pkg == null) { - continue; - } - String name = pkg.getName(); - if (StringUtils.isEmpty(name)) { - continue; - } - boolean isMatch = name.startsWith(strPackage); - if (isMatch) { - return true; - } - } - } - catch (Exception e) { - LOG.error("handler package error", e); - } - return false; - }; - } - - public static List> getExcludePathPredicates(String excludePath) { - List> excludePathList = new ArrayList<>(); - if (StringUtils.isEmpty(excludePath)) { - return excludePathList; - } - String[] exs = excludePath.split(SPLITTER); - for (String ex : exs) { - if (!StringUtils.isEmpty(ex)) { - excludePathList.add(PathSelectors.ant(ex)); - } - } - return excludePathList; - } - - public static List> getBasePathPredicates(String basePath) { - List> basePathList = new ArrayList<>(); - if (!StringUtils.isEmpty(basePath)) { - String[] bps = basePath.split(SPLITTER); - for (String bp : bps) { - if (!StringUtils.isEmpty(bp)) { - basePathList.add(PathSelectors.ant(bp)); - } - } - } - if (basePathList.isEmpty()) { - basePathList.add(PathSelectors.ant("/**")); - } - return basePathList; - } - public static String scanPackage(String configBasePackage) { String validScanPackage; // Externally configured scan package diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java new file mode 100644 index 000000000..8ef24531c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springdoc.api; + +import java.util.Locale; + +import io.swagger.v3.oas.models.OpenAPI; + +/** + * Util for {@link AbstractOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class AbstractOpenApiResourceUtil { + + private AbstractOpenApiResourceUtil() { + } + + public static OpenAPI getOpenApi(AbstractOpenApiResource openApiResource) { + return openApiResource.getOpenApi(Locale.getDefault()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java new file mode 100644 index 000000000..8f146bff4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springdoc.webflux.api; + +import org.springdoc.api.AbstractOpenApiResource; + +/** + * Util for {@link MultipleOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class OpenApiWebFluxUtil { + + private OpenApiWebFluxUtil() { + } + + public static AbstractOpenApiResource getOpenApiResourceOrThrow( + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, String groupName) { + return multipleOpenApiWebFluxResource.getOpenApiResourceOrThrow(groupName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java new file mode 100644 index 000000000..6e4967cfb --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springdoc.webmvc.api; + +import org.springdoc.api.AbstractOpenApiResource; + +/** + * Util for {@link MultipleOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class OpenApiWebMvcUtil { + private OpenApiWebMvcUtil() { + } + + public static AbstractOpenApiResource getOpenApiResourceOrThrow( + org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, String groupName) { + return multipleOpenApiWebMvcResource.getOpenApiResourceOrThrow(groupName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories index 86a23f5be..e831b84ce 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories @@ -1,7 +1,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.contract.config.PolarisSwaggerAutoConfiguration,\ - com.tencent.cloud.polaris.contract.config.PolarisContractProperties + com.tencent.cloud.polaris.contract.config.PolarisContractProperties,\ + com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesAutoConfiguration,\ + com.tencent.cloud.polaris.contract.tsf.TsfSwaggerAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesAutoConfiguration + com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesBootstrapConfiguration org.springframework.context.ApplicationListener=\ com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener diff --git a/spring-cloud-starter-tencent-polaris-discovery/pom.xml b/spring-cloud-starter-tencent-polaris-discovery/pom.xml index 7b881c93e..261f2e6c7 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/pom.xml +++ b/spring-cloud-starter-tencent-polaris-discovery/pom.xml @@ -23,6 +23,10 @@ com.tencent.cloud spring-cloud-tencent-rpc-enhancement + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + @@ -32,12 +36,6 @@ test - - com.tencent.polaris - connector-consul - test - - com.tencent.polaris connector-nacos @@ -92,6 +90,17 @@ true + + joda-time + joda-time + + + + org.mockito + mockito-inline + test + + io.projectreactor reactor-test 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 1725519f3..73f4e1071 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 @@ -51,6 +51,10 @@ public void modify(ConfigurationImpl configuration) { // Set ServiceRefreshInterval configuration.getConsumer().getLocalCache() .setServiceListRefreshInterval(polarisDiscoveryProperties.getServiceListRefreshInterval()); + + configuration.getConsumer().getZeroProtection().setEnable(polarisDiscoveryProperties.isZeroProtectionEnabled()); + configuration.getConsumer().getZeroProtection() + .setNeedTestConnectivity(polarisDiscoveryProperties.isZeroProtectionNeedTestConnectivity()); } @Override diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java index 43ca4b99a..8839880f1 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java @@ -17,18 +17,25 @@ */ package com.tencent.cloud.polaris; +import com.tencent.cloud.common.util.inet.PolarisInetUtils; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.extend.consul.ConsulConfigModifier; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryConfigModifier; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulHeartbeatProperties; import com.tencent.cloud.polaris.extend.nacos.NacosConfigModifier; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; /** * Common configuration of discovery. @@ -45,12 +52,6 @@ public PolarisDiscoveryProperties polarisDiscoveryProperties() { return new PolarisDiscoveryProperties(); } - @Bean - @ConditionalOnMissingBean - public ConsulContextProperties consulContextProperties() { - return new ConsulContextProperties(); - } - @Bean @ConditionalOnMissingBean public NacosContextProperties nacosContextProperties() { @@ -70,12 +71,6 @@ public DiscoveryConfigModifier discoveryConfigModifier(PolarisDiscoveryPropertie return new DiscoveryConfigModifier(polarisDiscoveryProperties); } - @Bean - @ConditionalOnMissingBean - public ConsulConfigModifier consulConfigModifier(@Autowired(required = false) ConsulContextProperties consulContextProperties) { - return new ConsulConfigModifier(consulContextProperties); - } - @Bean @ConditionalOnMissingBean public PolarisDiscoveryConfigModifier polarisDiscoveryConfigModifier(PolarisDiscoveryProperties polarisDiscoveryProperties) { @@ -87,4 +82,34 @@ public PolarisDiscoveryConfigModifier polarisDiscoveryConfigModifier(PolarisDisc public NacosConfigModifier nacosConfigModifier(@Autowired(required = false) NacosContextProperties nacosContextProperties) { return new NacosConfigModifier(nacosContextProperties); } + + /** + * Create when consul is enabled. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(value = "spring.cloud.consul.enabled", havingValue = "true") + protected static class ConsulDiscoveryConfiguration { + + @Bean + @ConditionalOnMissingBean + public ConsulDiscoveryProperties consulDiscoveryProperties(PolarisInetUtils polarisInetUtils) { + return new ConsulDiscoveryProperties(polarisInetUtils); + } + + @Bean + @ConditionalOnMissingBean + public ConsulHeartbeatProperties consulHeartbeatProperties() { + return new ConsulHeartbeatProperties(); + } + + @Bean + @ConditionalOnMissingBean + public ConsulDiscoveryConfigModifier consulDiscoveryConfigModifier( + PolarisDiscoveryProperties polarisDiscoveryProperties, ConsulProperties consulProperties, + ConsulDiscoveryProperties consulContextProperties, ConsulHeartbeatProperties consulHeartbeatProperties, + @Nullable TsfCoreProperties tsfCoreProperties, ApplicationContext applicationContext) { + return new ConsulDiscoveryConfigModifier(polarisDiscoveryProperties, consulProperties, consulContextProperties, + consulHeartbeatProperties, tsfCoreProperties, applicationContext); + } + } } 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 0477ebfb9..83c089e5a 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 @@ -101,6 +101,18 @@ public class PolarisDiscoveryProperties { */ private Long serviceListRefreshInterval = 60000L; + /** + * Zero protection switch. + */ + @Value("${spring.cloud.polaris.discovery.zero-protection.enabled:false}") + private boolean zeroProtectionEnabled = false; + + /** + * Zero protection test connectivity switch. + */ + @Value("${spring.cloud.polaris.discovery.zero-protection.is-need-test-connectivity:false}") + private boolean zeroProtectionNeedTestConnectivity = false; + public String getInstanceId() { return instanceId; } @@ -192,6 +204,22 @@ public void setHeartbeatInterval(Integer heartbeatInterval) { this.heartbeatInterval = heartbeatInterval; } + public boolean isZeroProtectionEnabled() { + return zeroProtectionEnabled; + } + + public void setZeroProtectionEnabled(boolean zeroProtectionEnabled) { + this.zeroProtectionEnabled = zeroProtectionEnabled; + } + + public boolean isZeroProtectionNeedTestConnectivity() { + return zeroProtectionNeedTestConnectivity; + } + + public void setZeroProtectionNeedTestConnectivity(boolean zeroProtectionNeedTestConnectivity) { + this.zeroProtectionNeedTestConnectivity = zeroProtectionNeedTestConnectivity; + } + public Boolean getEnabled() { return enabled; } @@ -227,6 +255,8 @@ public String toString() { ", heartbeatInterval=" + heartbeatInterval + ", healthCheckUrl='" + healthCheckUrl + '\'' + ", serviceListRefreshInterval=" + serviceListRefreshInterval + + ", zeroProtectionEnabled=" + zeroProtectionEnabled + + ", zeroProtectionNeedTestConnectivity=" + zeroProtectionNeedTestConnectivity + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java index 78f95ae9a..82ae9d5d8 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java @@ -33,7 +33,7 @@ * @author Haotian Zhang, Andrew Shan, Jie Cheng */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ElementType.TYPE, ElementType.METHOD}) @ConditionalOnDiscoveryEnabled @ConditionalOnPolarisEnabled @Conditional(DiscoveryEnabledCondition.class) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java index 7cbc84f50..379c7dff3 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java @@ -69,7 +69,7 @@ public List getInstances(String serviceId) throws PolarisExcept InstancesResponse filteredInstances = polarisDiscoveryHandler.getHealthyInstances(serviceId); ServiceInstances serviceInstances = filteredInstances.toServiceInstances(); for (Instance instance : serviceInstances.getInstances()) { - instances.add(new PolarisServiceInstance(instance)); + instances.add(new PolarisServiceInstance(instance, filteredInstances.getMetadata())); } return instances; } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java index 70140f1bc..a3e7b9fe4 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java @@ -38,9 +38,9 @@ */ public class PolarisReactiveDiscoveryClient implements ReactiveDiscoveryClient { - private static final Logger LOG = LoggerFactory.getLogger(PolarisReactiveDiscoveryClient.class); + private static final Logger log = LoggerFactory.getLogger(PolarisReactiveDiscoveryClient.class); - private final PolarisServiceDiscovery polarisServiceDiscovery; + private PolarisServiceDiscovery polarisServiceDiscovery; public PolarisReactiveDiscoveryClient(PolarisServiceDiscovery polarisServiceDiscovery) { this.polarisServiceDiscovery = polarisServiceDiscovery; @@ -53,6 +53,7 @@ public String description() { @Override public Flux getInstances(String serviceId) { + return Mono.justOrEmpty(serviceId).flatMapMany(loadInstancesFromPolaris()) .subscribeOn(Schedulers.boundedElastic()); } @@ -63,7 +64,7 @@ private Function> loadInstancesFromPolaris() return Flux.fromIterable(polarisServiceDiscovery.getInstances(serviceId)); } catch (PolarisException e) { - LOG.error("get service instance[{}] from polaris error!", serviceId, e); + log.error("get service instance[{}] from polaris error!", serviceId, e); return Flux.empty(); } }; @@ -76,7 +77,7 @@ public Flux getServices() { return Flux.fromIterable(polarisServiceDiscovery.getServices()); } catch (Exception e) { - LOG.error("get services from polaris server fail,", e); + log.error("get services from polaris server fail,", e); return Flux.empty(); } }).subscribeOn(Schedulers.boundedElastic()); 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 048b5c147..68852aacd 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 @@ -81,10 +81,8 @@ else if (newValue.getEventType() == ServiceEventKey.EventType.INSTANCE) { 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()))) { + 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. diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java index 248e7943b..80e649108 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java @@ -38,7 +38,7 @@ * * @author shuiqingliu */ -@Endpoint(id = "polaris-discovery") +@Endpoint(id = "polarisdiscovery") public class PolarisDiscoveryEndpoint { private final PolarisDiscoveryProperties polarisDiscoveryProperties; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java deleted file mode 100644 index af8431a5c..000000000 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java +++ /dev/null @@ -1,117 +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.polaris.extend.consul; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; - -import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.polaris.context.PolarisConfigModifier; -import com.tencent.polaris.api.config.plugin.DefaultPlugins; -import com.tencent.polaris.factory.config.ConfigurationImpl; -import com.tencent.polaris.factory.config.consumer.DiscoveryConfigImpl; -import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; -import com.tencent.polaris.factory.config.provider.RegisterConfigImpl; -import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.CollectionUtils; - -/** - * @author lingxiao.wlx - */ -public class ConsulConfigModifier implements PolarisConfigModifier { - - private static final Logger LOGGER = LoggerFactory.getLogger(ConsulConfigModifier.class); - - private static final String ID = "consul"; - - private final ConsulContextProperties consulContextProperties; - - public ConsulConfigModifier(ConsulContextProperties consulContextProperties) { - this.consulContextProperties = consulContextProperties; - } - - @Override - public void modify(ConfigurationImpl configuration) { - if (consulContextProperties != null && consulContextProperties.isEnabled()) { - // Check if Consul client Available - boolean consulAvailable = false; - try { - consulAvailable = null != Class.forName("com.ecwid.consul.v1.ConsulClient"); - } - catch (Throwable ignored) { - - } - if (!consulAvailable) { - LOGGER.error("Please import \"connector-consul\" dependency when enabling consul service registration and discovery.\n" - + "Add dependency configuration below to pom.xml:\n" - + "\n" - + "\tcom.tencent.polaris\n" - + "\tconnector-consul\n" - + ""); - throw new RuntimeException("Dependency \"connector-consul\" not found."); - } - if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) { - configuration.getGlobal().setServerConnectors(new ArrayList<>()); - } - if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors()) - && null != configuration.getGlobal().getServerConnector()) { - configuration.getGlobal().getServerConnectors().add(configuration.getGlobal().getServerConnector()); - } - ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl(); - serverConnectorConfig.setId(ID); - serverConnectorConfig.setAddresses( - Collections.singletonList(consulContextProperties.getHost() + ":" + consulContextProperties.getPort())); - serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL); - Map metadata = serverConnectorConfig.getMetadata(); - if (StringUtils.isNotBlank(consulContextProperties.getServiceName())) { - metadata.put(ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY, consulContextProperties.getServiceName()); - } - if (StringUtils.isNotBlank(consulContextProperties.getInstanceId())) { - metadata.put(ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY, consulContextProperties.getInstanceId()); - } - if (consulContextProperties.isPreferIpAddress() - && StringUtils.isNotBlank(consulContextProperties.getIpAddress())) { - metadata.put(ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY, - String.valueOf(consulContextProperties.isPreferIpAddress())); - metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulContextProperties.getIpAddress()); - } - configuration.getGlobal().getServerConnectors().add(serverConnectorConfig); - - DiscoveryConfigImpl discoveryConfig = new DiscoveryConfigImpl(); - discoveryConfig.setServerConnectorId(ID); - discoveryConfig.setEnable(consulContextProperties.isDiscoveryEnabled()); - configuration.getConsumer().getDiscoveries().add(discoveryConfig); - - RegisterConfigImpl registerConfig = new RegisterConfigImpl(); - registerConfig.setServerConnectorId(ID); - registerConfig.setEnable(consulContextProperties.isRegister()); - configuration.getProvider().getRegisters().add(registerConfig); - } - } - - @Override - public int getOrder() { - return OrderConstant.Modifier.CONSUL_DISCOVERY_CONFIG_ORDER; - } -} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java deleted file mode 100644 index ad98e009b..000000000 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java +++ /dev/null @@ -1,129 +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.polaris.extend.consul; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Discovery configuration of Consul. - * - * @author Haotian Zhang - */ -@ConfigurationProperties("spring.cloud.consul") -public class ConsulContextProperties { - - /** - * Host of consul(or consul agent). - */ - private String host; - - private int port; - - private boolean enabled = false; - - @Value("${spring.cloud.consul.discovery.register:#{'true'}}") - private boolean register; - - @Value("${spring.cloud.consul.discovery.enabled:#{'true'}}") - private boolean discoveryEnabled; - - @Value("${spring.cloud.consul.discovery.instance-id:}") - private String instanceId; - - @Value("${spring.cloud.consul.discovery.service-name:${spring.application.name:}}") - private String serviceName; - - @Value("${spring.cloud.consul.discovery.ip-address:}") - private String ipAddress; - - @Value("${spring.cloud.consul.discovery.prefer-ip-address:#{'false'}}") - private boolean preferIpAddress; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isRegister() { - return register; - } - - public boolean isDiscoveryEnabled() { - return discoveryEnabled; - } - - public void setRegister(boolean register) { - this.register = register; - } - - public void setDiscoveryEnabled(boolean discoveryEnabled) { - this.discoveryEnabled = discoveryEnabled; - } - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } - - public String getServiceName() { - return serviceName; - } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - } - - public boolean isPreferIpAddress() { - return preferIpAddress; - } - - public void setPreferIpAddress(boolean preferIpAddress) { - this.preferIpAddress = preferIpAddress; - } -} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java new file mode 100644 index 000000000..f73794958 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java @@ -0,0 +1,157 @@ +/* + * 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.extend.consul; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.PolarisDiscoveryProperties; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.polaris.api.config.plugin.DefaultPlugins; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.consumer.DiscoveryConfigImpl; +import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; +import com.tencent.polaris.factory.config.provider.RegisterConfigImpl; +import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.lang.Nullable; +import org.springframework.util.CollectionUtils; + +/** + * Modifier for Consul discovery. + * + * @author lingxiao.wlx, Haotian Zhang + */ +public class ConsulDiscoveryConfigModifier implements PolarisConfigModifier { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulDiscoveryConfigModifier.class); + + private final PolarisDiscoveryProperties polarisDiscoveryProperties; + + private final ConsulProperties consulProperties; + + private final ConsulDiscoveryProperties consulDiscoveryProperties; + + private final ConsulHeartbeatProperties consulHeartbeatProperties; + + private final ApplicationContext context; + + private final TsfCoreProperties tsfCoreProperties; + + public ConsulDiscoveryConfigModifier(PolarisDiscoveryProperties polarisDiscoveryProperties, ConsulProperties consulProperties, + ConsulDiscoveryProperties consulDiscoveryProperties, ConsulHeartbeatProperties consulHeartbeatProperties, + @Nullable TsfCoreProperties tsfCoreProperties, ApplicationContext context) { + this.polarisDiscoveryProperties = polarisDiscoveryProperties; + this.consulProperties = consulProperties; + this.consulDiscoveryProperties = consulDiscoveryProperties; + this.consulHeartbeatProperties = consulHeartbeatProperties; + this.tsfCoreProperties = tsfCoreProperties; + this.context = context; + } + + @Override + public void modify(ConfigurationImpl configuration) { + // init server connectors. + if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) { + configuration.getGlobal().setServerConnectors(new ArrayList<>()); + } + + // init consul connector. + ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl(); + serverConnectorConfig.setId(ConsulDiscoveryUtil.ID); + serverConnectorConfig.setAddresses( + Collections.singletonList(consulProperties.getHost() + ":" + consulProperties.getPort())); + LOGGER.info("Will register to consul server: [" + consulProperties.getHost() + ":" + consulProperties.getPort() + "]"); + serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL); + // set consul connector metadata. + Map metadata = serverConnectorConfig.getMetadata(); + // namespace + if (StringUtils.isNotBlank(polarisDiscoveryProperties.getNamespace())) { + metadata.put(ConsulConstant.MetadataMapKey.NAMESPACE_KEY, polarisDiscoveryProperties.getNamespace()); + } + // service name + String appName = ConsulDiscoveryUtil.getAppName(consulDiscoveryProperties, context.getEnvironment()); + if (StringUtils.isNotBlank(appName)) { + metadata.put(ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY, ConsulDiscoveryUtil.normalizeForDns(appName)); + } + // instance ID + String instanceId = ConsulDiscoveryUtil.getInstanceId(consulDiscoveryProperties, context); + if (StringUtils.isNotBlank(instanceId)) { + metadata.put(ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY, instanceId); + } + // token + if (StringUtils.isNotBlank(consulProperties.getAclToken())) { + serverConnectorConfig.setToken(consulProperties.getAclToken()); + } + // default query tag + if (StringUtils.isNotBlank(consulDiscoveryProperties.getDefaultQueryTag())) { + metadata.put(ConsulConstant.MetadataMapKey.QUERY_TAG_KEY, consulDiscoveryProperties.getDefaultQueryTag()); + } + // query passing + metadata.put(ConsulConstant.MetadataMapKey.QUERY_PASSING_KEY, String.valueOf(consulDiscoveryProperties.isQueryPassing())); + // prefer ip address + if (consulDiscoveryProperties.isPreferIpAddress() + && StringUtils.isNotBlank(consulDiscoveryProperties.getIpAddress())) { + metadata.put(ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY, + String.valueOf(consulDiscoveryProperties.isPreferIpAddress())); + metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulDiscoveryProperties.getIpAddress()); + } + // is not prefer agent address + if (!consulDiscoveryProperties.isPreferAgentAddress()) { + metadata.put(ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY, + String.valueOf(consulDiscoveryProperties.isPreferIpAddress())); + metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulDiscoveryProperties.getHostname()); + } + if (tsfCoreProperties != null) { + // tags + metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags())); + } + configuration.getGlobal().getServerConnectors().add(serverConnectorConfig); + + // discovery + DiscoveryConfigImpl discoveryConfig = new DiscoveryConfigImpl(); + discoveryConfig.setServerConnectorId(ConsulDiscoveryUtil.ID); + discoveryConfig.setEnable(consulDiscoveryProperties.isEnabled()); + configuration.getConsumer().getDiscoveries().add(discoveryConfig); + + // register + RegisterConfigImpl registerConfig = new RegisterConfigImpl(); + registerConfig.setServerConnectorId(ConsulDiscoveryUtil.ID); + registerConfig.setEnable(consulDiscoveryProperties.isRegister()); + configuration.getProvider().getRegisters().add(registerConfig); + + // heartbeat + polarisDiscoveryProperties.setHeartbeatInterval(Long.valueOf( + consulHeartbeatProperties.computeHeartbeatInterval().toStandardDuration().getMillis()).intValue()); + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.CONSUL_DISCOVERY_CONFIG_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java new file mode 100644 index 000000000..1782b63f2 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java @@ -0,0 +1,679 @@ +/* + * 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.extend.consul; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.ecwid.consul.v1.ConsistencyMode; +import com.tencent.cloud.common.util.inet.PolarisInetUtils; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.commons.util.InetUtils.HostInfo; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.core.style.ToStringCreator; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Copy from org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties. + * Defines configuration for service discovery and registration. + * + * @author Spencer Gibb + * @author Donnabell Dmello + * @author Venil Noronha + * @author Richard Kettelerij + */ +@ConfigurationProperties(ConsulDiscoveryProperties.PREFIX) +public class ConsulDiscoveryProperties { + + /** + * Consul discovery properties prefix. + */ + public static final String PREFIX = "spring.cloud.consul.discovery"; + + protected static final String MANAGEMENT = "management"; + + private HostInfo hostInfo; + + /** Tags to use when registering service. */ + private List tags = new ArrayList<>(); + + /** Metadata to use when registering service. */ + private Map metadata = new LinkedHashMap<>(); + + /** Enable tag override for the registered service. */ + private Boolean enableTagOverride; + + /** Is service discovery enabled? */ + private boolean enabled = true; + + /** Tags to use when registering management service. */ + private List managementTags = new ArrayList<>(); + + /** Enable tag override for the registered management service. */ + private Boolean managementEnableTagOverride; + + /** Metadata to use when registering management service. */ + private Map managementMetadata; + + /** Alternate server path to invoke for health checking. */ + private String healthCheckPath = "/actuator/health"; + + /** Custom health check url to override default. */ + private String healthCheckUrl; + + /** Headers to be applied to the Health Check calls. */ + private Map> healthCheckHeaders = new HashMap<>(); + + /** How often to perform the health check (e.g. 10s), defaults to 10s. */ + private String healthCheckInterval = "10s"; + + /** Timeout for health check (e.g. 10s). */ + private String healthCheckTimeout; + + /** + * Timeout to deregister services critical for longer than timeout (e.g. 30m). + * Requires consul version 7.x or higher. + */ + private String healthCheckCriticalTimeout; + + /** + * IP address to use when accessing service (must also set preferIpAddress to use). + */ + private String ipAddress; + + /** Hostname to use when accessing server. */ + private String hostname; + + /** Port to register the service under (defaults to listening port). */ + private Integer port; + + /** Port to register the management service under (defaults to management port). */ + private Integer managementPort; + + private Lifecycle lifecycle = new Lifecycle(); + + /** Use ip address rather than hostname during registration. */ + private boolean preferIpAddress = true; + + /** Source of how we will determine the address to use. */ + private boolean preferAgentAddress = false; + + /** The delay between calls to watch consul catalog in millis, default is 1000. */ + private int catalogServicesWatchDelay = 1000; + + /** The number of seconds to block while watching consul catalog, default is 2. */ + private int catalogServicesWatchTimeout = 55; + + /** Service name. */ + private String serviceName; + + /** Unique service instance id. */ + private String instanceId; + + /** Service instance zone. */ + private String instanceZone; + + /** Service instance group. */ + private String instanceGroup; + + /** + * Whether hostname is included into the default instance id when registering service. + */ + private boolean includeHostnameInInstanceId = false; + + /** + * Consistency mode for health service request. + */ + private ConsistencyMode consistencyMode = ConsistencyMode.DEFAULT; + + /** + * Service instance zone comes from metadata. This allows changing the metadata tag + * name. + */ + private String defaultZoneMetadataName = "zone"; + + /** Whether to register an http or https service. */ + private String scheme = "http"; + + /** Suffix to use when registering management service. */ + private String managementSuffix = MANAGEMENT; + + /** + * Map of serviceId's -> tag to query for in server list. This allows filtering + * services by one more tags. Multiple tags can be specified with a comma separated + * value. + */ + private Map serverListQueryTags = new HashMap<>(); + + /** + * Map of serviceId's -> datacenter to query for in server list. This allows looking + * up services in another datacenters. + */ + private Map datacenters = new HashMap<>(); + + /** + * Tag to query for in service list if one is not listed in serverListQueryTags. + * Multiple tags can be specified with a comma separated value. + */ + private String defaultQueryTag; + + /** + * Add the 'passing` parameter to /v1/health/service/serviceName. This pushes health + * check passing to the server. + */ + private boolean queryPassing = true; + + /** Register as a service in consul. */ + private boolean register = true; + + /** Disable automatic de-registration of service in consul. */ + private boolean deregister = true; + + /** Register health check in consul. Useful during development of a service. */ + private boolean registerHealthCheck = true; + + /** + * Throw exceptions during service registration if true, otherwise, log warnings + * (defaults to true). + */ + private boolean failFast = true; + + /** + * Skips certificate verification during service checks if true, otherwise runs + * certificate verification. + */ + private Boolean healthCheckTlsSkipVerify; + + /** + * Order of the discovery client used by `CompositeDiscoveryClient` for sorting + * available clients. + */ + private int order = 0; + + @SuppressWarnings("unused") + private ConsulDiscoveryProperties() { + this(new PolarisInetUtils(new InetUtilsProperties())); + } + + public ConsulDiscoveryProperties(PolarisInetUtils polarisInetUtils) { + this.managementTags.add(MANAGEMENT); + this.hostInfo = polarisInetUtils.findFirstNonLoopbackHostInfo(); + this.ipAddress = this.hostInfo.getIpAddress(); + this.hostname = this.hostInfo.getHostname(); + } + + /** + * Gets the tag to use when looking up the instances for a particular service. If the + * service has an entry in {@link #serverListQueryTags} that will be used. Otherwise + * the content of {@link #defaultQueryTag} will be used. + * @param serviceId the service whose instances are being looked up + * @return the tag to filter the service instances by or null if no tags are + * configured for the service and the default query tag is not configured + */ + public String getQueryTagForService(String serviceId) { + String tag = this.serverListQueryTags.get(serviceId); + return tag != null ? tag : this.defaultQueryTag; + } + + /** + * Gets the array of tags to use when looking up the instances for a particular + * service. If the service has an entry in {@link #serverListQueryTags} that will be + * used. Otherwise the content of {@link #defaultQueryTag} will be used. This differs + * from {@link #getQueryTagForService(String)} in that it assumes the configured tag + * property value may represent multiple tags when separated by commas. When the tag + * property is set to a single tag then this method behaves identical to its + * aforementioned counterpart except that it returns a single element array with the + * single tag value. + *

+ * The expected format of the tag property value is {@code tag1,tag2,..,tagN}. + * Whitespace will be trimmed off each entry. + * @param serviceId the service whose instances are being looked up + * @return the array of tags to filter the service instances by - it will be null if + * no tags are configured for the service and the default query tag is not configured + * or if a single tag is configured and it is the empty string + */ + @Nullable + public String[] getQueryTagsForService(String serviceId) { + String queryTagStr = getQueryTagForService(serviceId); + if (queryTagStr == null || queryTagStr.isEmpty()) { + return null; + } + return StringUtils.tokenizeToStringArray(queryTagStr, ","); + } + + public String getHostname() { + return this.preferIpAddress ? this.ipAddress : this.hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + this.hostInfo.override = true; + } + + private HostInfo getHostInfo() { + return this.hostInfo; + } + + private void setHostInfo(HostInfo hostInfo) { + this.hostInfo = hostInfo; + } + + public List getTags() { + return this.tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public boolean isEnableTagOverride() { + return enableTagOverride; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public List getManagementTags() { + return this.managementTags; + } + + public void setManagementTags(List managementTags) { + this.managementTags = managementTags; + } + + public String getHealthCheckPath() { + return this.healthCheckPath; + } + + public void setHealthCheckPath(String healthCheckPath) { + this.healthCheckPath = healthCheckPath; + } + + public String getHealthCheckUrl() { + return this.healthCheckUrl; + } + + public void setHealthCheckUrl(String healthCheckUrl) { + this.healthCheckUrl = healthCheckUrl; + } + + public Map> getHealthCheckHeaders() { + return this.healthCheckHeaders; + } + + public void setHealthCheckHeaders(Map> healthCheckHeaders) { + this.healthCheckHeaders = healthCheckHeaders; + } + + public String getHealthCheckInterval() { + return this.healthCheckInterval; + } + + public void setHealthCheckInterval(String healthCheckInterval) { + this.healthCheckInterval = healthCheckInterval; + } + + public String getHealthCheckTimeout() { + return this.healthCheckTimeout; + } + + public void setHealthCheckTimeout(String healthCheckTimeout) { + this.healthCheckTimeout = healthCheckTimeout; + } + + public String getHealthCheckCriticalTimeout() { + return this.healthCheckCriticalTimeout; + } + + public void setHealthCheckCriticalTimeout(String healthCheckCriticalTimeout) { + this.healthCheckCriticalTimeout = healthCheckCriticalTimeout; + } + + public String getIpAddress() { + return this.ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + this.hostInfo.override = true; + } + + public Integer getPort() { + return this.port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Integer getManagementPort() { + return this.managementPort; + } + + public void setManagementPort(Integer managementPort) { + this.managementPort = managementPort; + } + + public Lifecycle getLifecycle() { + return this.lifecycle; + } + + public void setLifecycle(Lifecycle lifecycle) { + this.lifecycle = lifecycle; + } + + public boolean isPreferIpAddress() { + return this.preferIpAddress; + } + + public void setPreferIpAddress(boolean preferIpAddress) { + this.preferIpAddress = preferIpAddress; + } + + public boolean isPreferAgentAddress() { + return this.preferAgentAddress; + } + + public void setPreferAgentAddress(boolean preferAgentAddress) { + this.preferAgentAddress = preferAgentAddress; + } + + public int getCatalogServicesWatchDelay() { + return this.catalogServicesWatchDelay; + } + + public void setCatalogServicesWatchDelay(int catalogServicesWatchDelay) { + this.catalogServicesWatchDelay = catalogServicesWatchDelay; + } + + public int getCatalogServicesWatchTimeout() { + return this.catalogServicesWatchTimeout; + } + + public void setCatalogServicesWatchTimeout(int catalogServicesWatchTimeout) { + this.catalogServicesWatchTimeout = catalogServicesWatchTimeout; + } + + public String getServiceName() { + return this.serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getInstanceId() { + return this.instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getInstanceZone() { + return this.instanceZone; + } + + public void setInstanceZone(String instanceZone) { + this.instanceZone = instanceZone; + } + + public String getInstanceGroup() { + return this.instanceGroup; + } + + public void setInstanceGroup(String instanceGroup) { + this.instanceGroup = instanceGroup; + } + + public boolean isIncludeHostnameInInstanceId() { + return includeHostnameInInstanceId; + } + + public void setIncludeHostnameInInstanceId(boolean includeHostnameInInstanceId) { + this.includeHostnameInInstanceId = includeHostnameInInstanceId; + } + + public ConsistencyMode getConsistencyMode() { + return consistencyMode; + } + + public void setConsistencyMode(ConsistencyMode consistencyMode) { + this.consistencyMode = consistencyMode; + } + + public String getDefaultZoneMetadataName() { + return this.defaultZoneMetadataName; + } + + public void setDefaultZoneMetadataName(String defaultZoneMetadataName) { + this.defaultZoneMetadataName = defaultZoneMetadataName; + } + + public String getScheme() { + return this.scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getManagementSuffix() { + return this.managementSuffix; + } + + public void setManagementSuffix(String managementSuffix) { + this.managementSuffix = managementSuffix; + } + + public Map getServerListQueryTags() { + return this.serverListQueryTags; + } + + public void setServerListQueryTags(Map serverListQueryTags) { + this.serverListQueryTags = serverListQueryTags; + } + + public Map getDatacenters() { + return this.datacenters; + } + + public void setDatacenters(Map datacenters) { + this.datacenters = datacenters; + } + + public String getDefaultQueryTag() { + return this.defaultQueryTag; + } + + public void setDefaultQueryTag(String defaultQueryTag) { + this.defaultQueryTag = defaultQueryTag; + } + + public boolean isQueryPassing() { + return this.queryPassing; + } + + public void setQueryPassing(boolean queryPassing) { + this.queryPassing = queryPassing; + } + + public boolean isRegister() { + return this.register; + } + + public void setRegister(boolean register) { + this.register = register; + } + + public boolean isDeregister() { + return this.deregister; + } + + public void setDeregister(boolean deregister) { + this.deregister = deregister; + } + + public boolean isRegisterHealthCheck() { + return this.registerHealthCheck; + } + + public void setRegisterHealthCheck(boolean registerHealthCheck) { + this.registerHealthCheck = registerHealthCheck; + } + + public boolean isFailFast() { + return this.failFast; + } + + public void setFailFast(boolean failFast) { + this.failFast = failFast; + } + + public Boolean getHealthCheckTlsSkipVerify() { + return this.healthCheckTlsSkipVerify; + } + + public void setHealthCheckTlsSkipVerify(Boolean healthCheckTlsSkipVerify) { + this.healthCheckTlsSkipVerify = healthCheckTlsSkipVerify; + } + + public int getOrder() { + return this.order; + } + + public void setOrder(int order) { + this.order = order; + } + + public Map getManagementMetadata() { + return this.managementMetadata; + } + + public void setManagementMetadata(Map managementMetadata) { + this.managementMetadata = managementMetadata; + } + + public Boolean getEnableTagOverride() { + return this.enableTagOverride; + } + + public void setEnableTagOverride(boolean enableTagOverride) { + this.enableTagOverride = enableTagOverride; + } + + public void setEnableTagOverride(Boolean enableTagOverride) { + this.enableTagOverride = enableTagOverride; + } + + public Boolean getManagementEnableTagOverride() { + return this.managementEnableTagOverride; + } + + public void setManagementEnableTagOverride(Boolean managementEnableTagOverride) { + this.managementEnableTagOverride = managementEnableTagOverride; + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("catalogServicesWatchDelay", this.catalogServicesWatchDelay) + .append("catalogServicesWatchTimeout", this.catalogServicesWatchTimeout) + .append("consistencyMode", this.consistencyMode) + .append("datacenters", this.datacenters) + .append("defaultQueryTag", this.defaultQueryTag) + .append("defaultZoneMetadataName", this.defaultZoneMetadataName) + .append("deregister", this.deregister) + .append("enabled", this.enabled) + .append("enableTagOverride", this.enableTagOverride) + .append("failFast", this.failFast) + .append("hostInfo", this.hostInfo) + .append("healthCheckCriticalTimeout", this.healthCheckCriticalTimeout) + .append("healthCheckHeaders", this.healthCheckHeaders) + .append("healthCheckInterval", this.healthCheckInterval) + .append("healthCheckPath", this.healthCheckPath) + .append("healthCheckTimeout", this.healthCheckTimeout) + .append("healthCheckTlsSkipVerify", this.healthCheckTlsSkipVerify) + .append("healthCheckUrl", this.healthCheckUrl) + .append("hostname", this.hostname) + .append("includeHostnameInInstanceId", this.includeHostnameInInstanceId) + .append("instanceId", this.instanceId) + .append("instanceGroup", this.instanceGroup) + .append("instanceZone", this.instanceZone) + .append("ipAddress", this.ipAddress) + .append("lifecycle", this.lifecycle) + .append("metadata", this.metadata) + .append("managementEnableTagOverride", this.managementEnableTagOverride) + .append("managementMetadata", this.managementMetadata) + .append("managementPort", this.managementPort) + .append("managementSuffix", this.managementSuffix) + .append("managementTags", this.managementTags) + .append("order", this.order) + .append("port", this.port) + .append("preferAgentAddress", this.preferAgentAddress) + .append("preferIpAddress", this.preferIpAddress) + .append("queryPassing", this.queryPassing) + .append("register", this.register) + .append("registerHealthCheck", this.registerHealthCheck) + .append("scheme", this.scheme) + .append("serviceName", this.serviceName) + .append("serverListQueryTags", this.serverListQueryTags) + .append("tags", this.tags) + .toString(); + } + + /** + * Properties releated to the lifecycle. + */ + public static class Lifecycle { + + private boolean enabled = true; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public String toString() { + return "Lifecycle{" + "enabled=" + this.enabled + '}'; + } + + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java new file mode 100644 index 000000000..f7b1bee92 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java @@ -0,0 +1,179 @@ +/* + * 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.extend.consul; + +import java.util.Map; + +import com.ecwid.consul.v1.agent.model.NewService; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.polaris.api.config.Configuration; +import com.tencent.polaris.api.utils.IPAddressUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; +import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.discovery.ManagementServerPortUtils; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.cloud.commons.util.IdUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; + +/** + * TSF registration utils. + * + * @author Haotian Zhang + */ +public final class ConsulDiscoveryUtil { + /** + * - 分隔符. + */ + public static final char SEPARATOR = '-'; + + /** + * Server connector ID. + */ + public static final String ID = "consul"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulDiscoveryUtil.class); + + private ConsulDiscoveryUtil() { + } + + public static String getAppName(ConsulDiscoveryProperties properties, Environment env) { + String appName = properties.getServiceName(); + if (StringUtils.isNotBlank(appName)) { + return appName; + } + return env.getProperty("spring.application.name", "application"); + } + + public static String getInstanceId(ConsulDiscoveryProperties properties, ApplicationContext context) { + // tsf consul 不支持 dns,所以这里不需要 normalize,并且由于优雅下线,readiness probe 联动都是依赖 service id 的,normalize 后两边对不上,所以需要去掉 normalize + if (StringUtils.isBlank(properties.getInstanceId())) { + return IdUtils.getDefaultInstanceId(context.getEnvironment(), false); + } + else { + return properties.getInstanceId(); + } + } + + public static String normalizeForDns(String s) { + if (s == null) { + throw new IllegalArgumentException("Consul service ids must not be empty"); + } + + StringBuilder normalized = new StringBuilder(); + Character prev = null; + for (char curr : s.toCharArray()) { + Character toAppend = null; + if (Character.isLetterOrDigit(curr)) { + toAppend = curr; + } + else if (prev == null || !(prev == SEPARATOR)) { + toAppend = SEPARATOR; + } + if (toAppend != null) { + normalized.append(toAppend); + prev = toAppend; + } + } + + return normalized.toString(); + } + + public static void setCheck(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, TsfCoreProperties tsfCoreProperties, ApplicationContext context, + ConsulHeartbeatProperties consulHeartbeatProperties, Registration registration, Configuration configuration) { + if (properties.isRegisterHealthCheck()) { + Integer checkPort; + if (shouldRegisterManagement(autoServiceRegistrationProperties, properties, context)) { + checkPort = getManagementPort(properties, context); + } + else { + checkPort = registration.getPort(); + } + Assert.notNull(checkPort, "checkPort may not be null"); + + for (ServerConnectorConfigImpl config : configuration.getGlobal().getServerConnectors()) { + if (org.apache.commons.lang.StringUtils.equals(config.getId(), ID)) { + Map metadata = config.getMetadata(); + NewService.Check check = createCheck(checkPort, consulHeartbeatProperties, properties, tsfCoreProperties); + String checkJson = JacksonUtils.serialize2Json(check); + LOGGER.debug("Check is : {}", checkJson); + metadata.put(ConsulConstant.MetadataMapKey.CHECK_KEY, checkJson); + } + } + + } + } + + public static NewService.Check createCheck(Integer port, ConsulHeartbeatProperties ttlConfig, + ConsulDiscoveryProperties properties, TsfCoreProperties tsfCoreProperties) { + NewService.Check check = new NewService.Check(); + if (ttlConfig.isEnabled()) { + check.setTtl(ttlConfig.getTtl()); + return check; + } + + Assert.notNull(port, "createCheck port must not be null"); + Assert.isTrue(port > 0, "createCheck port must be greater than 0"); + + if (properties.getHealthCheckUrl() != null) { + check.setHttp(properties.getHealthCheckUrl()); + } + else { + check.setHttp(String.format("%s://%s:%s%s", tsfCoreProperties.getScheme(), + IPAddressUtils.getIpCompatible(properties.getHostname()), port, + properties.getHealthCheckPath())); + } + check.setInterval(properties.getHealthCheckInterval()); + check.setTimeout(properties.getHealthCheckTimeout()); + if (StringUtils.isNotBlank(properties.getHealthCheckCriticalTimeout())) { + check.setDeregisterCriticalServiceAfter(properties.getHealthCheckCriticalTimeout()); + } + check.setTlsSkipVerify(properties.getHealthCheckTlsSkipVerify()); + return check; + } + + /** + * @return if the management service should be registered with the {@link ServiceRegistry} + */ + public static boolean shouldRegisterManagement(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, ApplicationContext context) { + return autoServiceRegistrationProperties.isRegisterManagement() + && getManagementPort(properties, context) != null + && ManagementServerPortUtils.isDifferent(context); + } + + /** + * @return the port of the Management Service + */ + public static Integer getManagementPort(ConsulDiscoveryProperties properties, ApplicationContext context) { + // If an alternate external port is specified, use it instead + if (properties.getManagementPort() != null) { + return properties.getManagementPort(); + } + return ManagementServerPortUtils.getPort(context); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java new file mode 100644 index 000000000..ef709e4ea --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java @@ -0,0 +1,118 @@ +/* + * 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.extend.consul; + +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +import org.joda.time.Period; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.style.ToStringCreator; +import org.springframework.validation.annotation.Validated; + +/** + * Copy from org.springframework.cloud.consul.discovery.HeartbeatProperties. + * Properties related to heartbeat verification. + * + * @author Spencer Gibb + * @author Chris Bono + */ +@ConfigurationProperties(prefix = "spring.cloud.consul.discovery.heartbeat") +@Validated +public class ConsulHeartbeatProperties { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulHeartbeatProperties.class); + // TODO: change enabled to default to true when I stop seeing messages like + // [WARN] agent: Check 'service:testConsulApp:xtest:8080' missed TTL, is now critical + boolean enabled = true; + + @Min(1) + private int ttlValue = 30; + + @NotNull + private String ttlUnit = "s"; + + @DecimalMin("0.1") + @DecimalMax("0.9") + private double intervalRatio = 2.0 / 3.0; + + //TODO: did heartbeatInterval need to be a field? + + protected Period computeHeartbeatInterval() { + // heartbeat rate at ratio * ttl, but no later than ttl -1s and, (under lesser + // priority), no sooner than 1s from now + double interval = ttlValue * intervalRatio; + double max = Math.max(interval, 1); + int ttlMinus1 = ttlValue - 1; + double min = Math.min(ttlMinus1, max); + Period heartbeatInterval = new Period(Math.round(1000 * min)); + LOGGER.debug("Computed heartbeatInterval: " + heartbeatInterval); + return heartbeatInterval; + } + + public String getTtl() { + return ttlValue + ttlUnit; + } + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public @Min(1) int getTtlValue() { + return this.ttlValue; + } + + public void setTtlValue(@Min(1) int ttlValue) { + this.ttlValue = ttlValue; + } + + public @NotNull String getTtlUnit() { + return this.ttlUnit; + } + + public void setTtlUnit(@NotNull String ttlUnit) { + this.ttlUnit = ttlUnit; + } + + public @DecimalMin("0.1") @DecimalMax("0.9") double getIntervalRatio() { + return this.intervalRatio; + } + + public void setIntervalRatio(@DecimalMin("0.1") @DecimalMax("0.9") double intervalRatio) { + this.intervalRatio = intervalRatio; + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("enabled", enabled) + .append("ttlValue", ttlValue) + .append("ttlUnit", ttlUnit) + .append("intervalRatio", intervalRatio) + .toString(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java index 3b186d27a..2d7391ff8 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java @@ -32,7 +32,7 @@ * @author Haotian Zhang, Andrew Shan, Jie Cheng */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ElementType.TYPE, ElementType.METHOD}) @ConditionalOnPolarisEnabled @Conditional(RegisterEnabledCondition.class) public @interface ConditionalOnPolarisRegisterEnabled { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java index 1c81588ac..c7dad59f8 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java @@ -17,9 +17,7 @@ package com.tencent.cloud.polaris.registry; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; -import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.assembly.api.AssemblyAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,9 +71,6 @@ protected void register() { log.debug("Registration disabled."); return; } - if (assemblyAPI != null) { - assemblyAPI.initService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); - } super.register(); } 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 0a3d09ae8..2dfb36404 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 @@ -26,7 +26,7 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.polaris.client.api.SDKContext; import org.apache.commons.lang.StringUtils; @@ -48,8 +48,6 @@ */ public class PolarisRegistration implements Registration { - private static final String METADATA_KEY_IP = "internal-ip"; - private static final String METADATA_KEY_ADDRESS = "internal-address"; private static final String GROUP_SERVER_ID_FORMAT = "%s__%s"; private static final String NACOS_CLUSTER = "nacos.cluster"; @@ -67,13 +65,14 @@ public class PolarisRegistration implements Registration { private final List customizers; private boolean registerEnabled = false; private Map metadata; + private Map> extendedMetadata; private int port; private String instanceId; public PolarisRegistration( PolarisDiscoveryProperties polarisDiscoveryProperties, @Nullable PolarisContextProperties polarisContextProperties, - @Nullable ConsulContextProperties consulContextProperties, + @Nullable ConsulDiscoveryProperties consulDiscoveryProperties, SDKContext context, StaticMetadataManager staticMetadataManager, @Nullable NacosContextProperties nacosContextProperties, @Nullable ServletWebServerApplicationContext servletWebServerApplicationContext, @@ -115,10 +114,6 @@ public PolarisRegistration( if (CollectionUtils.isEmpty(metadata)) { Map instanceMetadata = new HashMap<>(); - // put internal metadata - instanceMetadata.put(METADATA_KEY_IP, host); - instanceMetadata.put(METADATA_KEY_ADDRESS, host + ":" + port); - // put internal-nacos-cluster if necessary if (Objects.nonNull(nacosContextProperties)) { String clusterName = nacosContextProperties.getClusterName(); @@ -132,12 +127,14 @@ public PolarisRegistration( this.metadata = instanceMetadata; } + this.extendedMetadata = new HashMap<>(); + // generate registerEnabled if (null != polarisDiscoveryProperties) { registerEnabled = polarisDiscoveryProperties.isRegisterEnabled(); } - if (null != consulContextProperties && consulContextProperties.isEnabled()) { - registerEnabled |= consulContextProperties.isRegister(); + if (null != consulDiscoveryProperties) { + registerEnabled |= consulDiscoveryProperties.isRegister(); } if (null != nacosContextProperties && nacosContextProperties.isEnabled()) { registerEnabled |= nacosContextProperties.isRegisterEnabled(); @@ -146,7 +143,7 @@ public PolarisRegistration( public static PolarisRegistration registration(PolarisDiscoveryProperties polarisDiscoveryProperties, @Nullable PolarisContextProperties polarisContextProperties, - @Nullable ConsulContextProperties consulContextProperties, + @Nullable ConsulDiscoveryProperties consulContextProperties, SDKContext context, StaticMetadataManager staticMetadataManager, @Nullable NacosContextProperties nacosContextProperties, @Nullable ServletWebServerApplicationContext servletWebServerApplicationContext, @@ -217,6 +214,13 @@ public Map getMetadata() { return metadata; } + public Map> getExtendedMetadata() { + if (extendedMetadata == null) { + extendedMetadata = new HashMap<>(); + } + return extendedMetadata; + } + @Override public String getInstanceId() { return instanceId; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java index ce7acf08b..582f80198 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java @@ -25,10 +25,10 @@ import java.util.concurrent.ScheduledExecutorService; import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.util.OkHttpUtil; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.util.OkHttpUtil; import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties; import com.tencent.polaris.api.config.global.StatReporterConfig; import com.tencent.polaris.api.core.ProviderAPI; @@ -44,6 +44,9 @@ import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.client.util.NamedThreadFactory; import com.tencent.polaris.factory.config.provider.ServiceConfigImpl; +import com.tencent.polaris.metadata.core.TransitiveType; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -96,7 +99,8 @@ public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryPropert @Override public void register(PolarisRegistration registration) { - if (StringUtils.isEmpty(registration.getServiceId())) { + + if (StringUtils.isBlank(registration.getServiceId())) { LOGGER.warn("No service to register for polaris client..."); return; } @@ -116,9 +120,18 @@ public void register(PolarisRegistration registration) { instanceRegisterRequest.setCampus(staticMetadataManager.getCampus()); instanceRegisterRequest.setTtl(polarisDiscoveryProperties.getHeartbeatInterval()); instanceRegisterRequest.setMetadata(registration.getMetadata()); + instanceRegisterRequest.setExtendedMetadata(registration.getExtendedMetadata()); instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol()); instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion()); instanceRegisterRequest.setInstanceId(polarisDiscoveryProperties.getInstanceId()); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_NAMESPACE, polarisDiscoveryProperties.getNamespace(), TransitiveType.DISPOSABLE); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_SERVICE, serviceId, TransitiveType.DISPOSABLE); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_IP, registration.getHost(), TransitiveType.DISPOSABLE); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_PORT, String.valueOf(registration.getPort()), TransitiveType.DISPOSABLE); try { ProviderAPI providerClient = polarisSDKContextManager.getProviderAPI(); InstanceRegisterResponse instanceRegisterResponse; @@ -129,12 +142,14 @@ public void register(PolarisRegistration registration) { instanceRegisterResponse = providerClient.register(instanceRegisterRequest); InstanceHeartbeatRequest heartbeatRequest = new InstanceHeartbeatRequest(); BeanUtils.copyProperties(instanceRegisterRequest, heartbeatRequest); + heartbeatRequest.setInstanceID(instanceRegisterResponse.getInstanceId()); // Start the heartbeat thread after the registration is successful. heartbeat(heartbeatRequest); } registration.setInstanceId(instanceRegisterResponse.getInstanceId()); - LOGGER.info("polaris registry, {} {} {}:{} {} register finished", polarisDiscoveryProperties.getNamespace(), - registration.getServiceId(), registration.getHost(), registration.getPort(), + LOGGER.info("polaris registry, {} {} {} {}:{} {} {} {} {} register finished", polarisDiscoveryProperties.getNamespace(), + registration.getServiceId(), registration.getInstanceId(), registration.getHost(), registration.getPort(), + staticMetadataManager.getRegion(), staticMetadataManager.getZone(), staticMetadataManager.getCampus(), staticMetadataManager.getMergedStaticMetadata()); if (Objects.nonNull(polarisStatProperties) && polarisStatProperties.isEnabled()) { try { @@ -175,7 +190,7 @@ public void register(PolarisRegistration registration) { public void deregister(PolarisRegistration registration) { LOGGER.info("De-registering from Polaris Server now..."); - if (StringUtils.isEmpty(registration.getServiceId())) { + if (StringUtils.isEmpty(registration.getServiceId()) || !PolarisSDKContextManager.isRegistered) { LOGGER.warn("No dom to de-register for polaris client..."); return; } @@ -190,6 +205,8 @@ public void deregister(PolarisRegistration registration) { try { ProviderAPI providerClient = polarisSDKContextManager.getProviderAPI(); providerClient.deRegister(deRegisterRequest); + PolarisSDKContextManager.isRegistered = false; + LOGGER.info("De-registration finished."); } catch (Exception e) { LOGGER.error("ERR_POLARIS_DEREGISTER, de-register failed...{},", registration, e); @@ -198,8 +215,6 @@ public void deregister(PolarisRegistration registration) { if (null != heartbeatExecutor) { heartbeatExecutor.shutdown(); } - LOGGER.info("De-registration finished."); - PolarisSDKContextManager.isRegistered = false; } } @@ -237,21 +252,14 @@ public Object getStatus(PolarisRegistration registration) { public void heartbeat(InstanceHeartbeatRequest heartbeatRequest) { heartbeatExecutor.scheduleWithFixedDelay(() -> { try { - String healthCheckEndpoint = polarisDiscoveryProperties.getHealthCheckUrl(); // If the health check passes, the heartbeat will be reported. // If it does not pass, the heartbeat will not be reported. - if (!healthCheckEndpoint.startsWith("/")) { - healthCheckEndpoint = "/" + healthCheckEndpoint; - } - - String healthCheckUrl = String.format("http://%s:%s%s", heartbeatRequest.getHost(), - heartbeatRequest.getPort(), healthCheckEndpoint); - Map headers = new HashMap<>(1); headers.put(HttpHeaders.USER_AGENT, "polaris"); - if (!OkHttpUtil.get(healthCheckUrl, headers)) { + if (!OkHttpUtil.checkUrl(heartbeatRequest.getHost(), heartbeatRequest.getPort(), + polarisDiscoveryProperties.getHealthCheckUrl(), headers)) { LOGGER.error("backend service health check failed. health check endpoint = {}", - healthCheckEndpoint); + polarisDiscoveryProperties.getHealthCheckUrl()); return; } diff --git a/spring-cloud-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 1cf7a83a9..126678ae4 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 @@ -25,7 +25,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties; @@ -68,7 +68,7 @@ public PolarisServiceRegistry polarisServiceRegistry( public PolarisRegistration polarisRegistration( PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisContextProperties polarisContextProperties, - @Autowired(required = false) ConsulContextProperties consulContextProperties, + @Autowired(required = false) ConsulDiscoveryProperties consulContextProperties, PolarisSDKContextManager polarisSDKContextManager, StaticMetadataManager staticMetadataManager, NacosContextProperties nacosContextProperties, @Autowired(required = false) ServletWebServerApplicationContext servletWebServerApplicationContext, diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java index a8386a0ec..310110d42 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java @@ -30,8 +30,8 @@ public class RegisterEnabledCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { - boolean isRegisterEnabled = Boolean.parseBoolean(conditionContext.getEnvironment() - .getProperty("spring.cloud.polaris.discovery.register", "true")); + boolean isRegisterEnabled = Boolean.parseBoolean( + conditionContext.getEnvironment().getProperty("spring.cloud.polaris.discovery.register", "true")); boolean isConsulRegisterEnabled = Boolean.parseBoolean( conditionContext.getEnvironment().getProperty("spring.cloud.consul.enabled", "false")) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java new file mode 100644 index 000000000..c193f06c3 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.tsf.registry; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.util.StringUtils; + +import static com.tencent.polaris.api.config.plugin.DefaultPlugins.SERVER_CONNECTOR_CONSUL; + +/** + * Set API data to registration metadata. + * + * @author Haotian Zhang + */ +public class TsfApiPolarisRegistrationCustomizer implements PolarisRegistrationCustomizer { + private static final Logger LOG = LoggerFactory.getLogger(TsfApiPolarisRegistrationCustomizer.class); + + private static final String API_META_KEY = "TSF_API_METAS"; + private final ApplicationContext context; + + public TsfApiPolarisRegistrationCustomizer(ApplicationContext context) { + this.context = context; + } + + @Override + public void customize(PolarisRegistration registration) { + String apiMetaData = context.getEnvironment().getProperty("$api_metas"); + Map> metadata = registration.getExtendedMetadata(); + if (StringUtils.hasText(apiMetaData)) { + if (!metadata.containsKey(SERVER_CONNECTOR_CONSUL)) { + metadata.put(SERVER_CONNECTOR_CONSUL, new HashMap<>()); + } + metadata.get(SERVER_CONNECTOR_CONSUL).put(API_META_KEY, apiMetaData); + } + else { + LOG.warn("apiMetaData is null, service:{}", registration.getServiceId()); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java new file mode 100644 index 000000000..dc4e9caba --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java @@ -0,0 +1,71 @@ +/* + * 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.tsf.registry; +import javax.servlet.ServletContext; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulHeartbeatProperties; +import com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Auto configuration for TSF discovery. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +@AutoConfigureBefore(PolarisServiceRegistryAutoConfiguration.class) +public class TsfDiscoveryRegistryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfPortPolarisRegistrationCustomizer tsfPortPolarisRegistrationCustomizer( + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ApplicationContext context, ConsulDiscoveryProperties consulDiscoveryProperties, TsfCoreProperties tsfCoreProperties, + ConsulHeartbeatProperties consulHeartbeatProperties, PolarisSDKContextManager polarisSDKContextManager) { + return new TsfPortPolarisRegistrationCustomizer(autoServiceRegistrationProperties, context, + consulDiscoveryProperties, tsfCoreProperties, consulHeartbeatProperties, polarisSDKContextManager.getSDKContext()); + } + + @Bean + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) + @ConditionalOnMissingBean + public TsfServletRegistrationCustomizer tsfServletConsulCustomizer(ObjectProvider servletContext) { + return new TsfServletRegistrationCustomizer(servletContext); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "tsf.swagger.enabled", havingValue = "true", matchIfMissing = true) + public TsfApiPolarisRegistrationCustomizer tsfApiPolarisRegistrationCustomizer(ApplicationContext context) { + return new TsfApiPolarisRegistrationCustomizer(context); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java new file mode 100644 index 000000000..68a13a365 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java @@ -0,0 +1,65 @@ +/* + * 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.tsf.registry; + +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryUtil; +import com.tencent.cloud.polaris.extend.consul.ConsulHeartbeatProperties; +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; +import com.tencent.polaris.client.api.SDKContext; + +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.context.ApplicationContext; + +/** + * 服务注册时端口相关逻辑. + * + * @author Haotian Zhang + */ +public class TsfPortPolarisRegistrationCustomizer implements PolarisRegistrationCustomizer { + + private final AutoServiceRegistrationProperties autoServiceRegistrationProperties; + private final ApplicationContext context; + private final ConsulDiscoveryProperties consulDiscoveryProperties; + private final TsfCoreProperties tsfCoreProperties; + private final ConsulHeartbeatProperties consulHeartbeatProperties; + private final SDKContext sdkContext; + + public TsfPortPolarisRegistrationCustomizer(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ApplicationContext context, ConsulDiscoveryProperties consulDiscoveryProperties, TsfCoreProperties tsfCoreProperties, + ConsulHeartbeatProperties consulHeartbeatProperties, SDKContext sdkContext) { + this.autoServiceRegistrationProperties = autoServiceRegistrationProperties; + this.context = context; + this.consulDiscoveryProperties = consulDiscoveryProperties; + this.tsfCoreProperties = tsfCoreProperties; + this.consulHeartbeatProperties = consulHeartbeatProperties; + this.sdkContext = sdkContext; + } + + @Override + public void customize(PolarisRegistration registration) { + if (consulDiscoveryProperties.getPort() != null) { + registration.setPort(consulDiscoveryProperties.getPort()); + } + // we know the port and can set the check + ConsulDiscoveryUtil.setCheck(autoServiceRegistrationProperties, consulDiscoveryProperties, tsfCoreProperties, context, + consulHeartbeatProperties, registration, sdkContext.getConfig()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java new file mode 100644 index 000000000..f4321b743 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.tsf.registry; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; + +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; +import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.util.StringUtils; + +import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.TAGS_KEY; + +/** + * @author Piotr Wielgolaski + */ +public class TsfServletRegistrationCustomizer implements PolarisRegistrationCustomizer { + private final ObjectProvider servletContext; + + public TsfServletRegistrationCustomizer(ObjectProvider servletContext) { + this.servletContext = servletContext; + } + + @Override + public void customize(PolarisRegistration registration) { + if (servletContext == null) { + return; + } + ServletContext sc = servletContext.getIfAvailable(); + if (sc != null + && StringUtils.hasText(sc.getContextPath()) + && StringUtils.hasText(sc.getContextPath().replaceAll("/", ""))) { + Map metadata = registration.getMetadata(); + + List tags = Arrays.asList(JacksonUtils.deserialize(metadata.get(TAGS_KEY), String[].class)); + if (tags == null) { + tags = new ArrayList<>(); + } + tags.add("contextPath=" + sc.getContextPath()); + metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(tags)); + } + } +} 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 947982852..a8ebda064 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 @@ -66,6 +66,18 @@ "defaultValue": 60000, "description": "Millis interval of refresh of service info list. Default: 60000." }, + { + "name": "spring.cloud.polaris.discovery.zero-protection.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "Zero protection switch. Default: false." + }, + { + "name": "spring.cloud.polaris.discovery.zero-protection.is-need-test-connectivity", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "Zero protection test connectivity switch. Default: false." + }, { "name": "spring.cloud.nacos.discovery.enabled", "type": "java.lang.Boolean", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories index e8deb25e8..dc65b01e0 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories @@ -1,8 +1,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration,\ com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\ - com.tencent.cloud.polaris.ribbon.PolarisDiscoveryRibbonAutoConfiguration,\ com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration,\ - com.tencent.cloud.polaris.endpoint.PolarisDiscoveryEndpointAutoConfiguration + com.tencent.cloud.polaris.endpoint.PolarisDiscoveryEndpointAutoConfiguration,\ + com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerAutoConfiguration,\ + com.tencent.cloud.polaris.tsf.registry.TsfDiscoveryRegistryAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.tencent.cloud.polaris.DiscoveryPropertiesBootstrapAutoConfiguration diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java new file mode 100644 index 000000000..ba05d6619 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java @@ -0,0 +1,193 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless; + +import java.util.Collections; + +import com.tencent.cloud.common.util.OkHttpUtil; +import com.tencent.cloud.plugin.lossless.config.LosslessAutoConfiguration; +import com.tencent.cloud.plugin.lossless.config.LosslessPropertiesBootstrapConfiguration; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration; +import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration; +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisServiceRegistry; +import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationUtils; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +/** + * Test for {@link LosslessRegistryAspect}. + * + * @author Shedfree Wu + */ +public class LosslessRegistryAspectTest { + + private static String NAMESPACE_TEST = "Test"; + + private static String SERVICE_PROVIDER = "java_provider_test"; + + private static String HOST = "127.0.0.1"; + + private static int APPLICATION_PORT = 19091; + + private static int LOSSLESS_PORT_1 = 28083; + + private static NamingServer namingServer; + + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + LosslessAutoConfiguration.class, + LosslessPropertiesBootstrapConfiguration.class, + PolarisContextAutoConfiguration.class, + PolarisPropertiesConfiguration.class, + PolarisDiscoveryClientConfiguration.class, + PolarisDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") + .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) + .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) + .withPropertyValues("server.port=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) + .withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") + .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); + + private final WebApplicationContextRunner contextRunner2 = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + LosslessAutoConfiguration.class, + LosslessPropertiesBootstrapConfiguration.class, + PolarisContextAutoConfiguration.class, + PolarisPropertiesConfiguration.class, + PolarisDiscoveryClientConfiguration.class, + PolarisDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=1000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/test") + .withPropertyValues("spring.cloud.polaris.lossless.port=28082") + .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) + .withPropertyValues("server.port=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) + .withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT) + .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") + .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); + + @BeforeAll + static void beforeAll() throws Exception { + namingServer = NamingServer.startNamingServer(10081); + + // add service + namingServer.getNamingService().addService(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER)); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } + + @BeforeEach + void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + public void testRegister() { + this.contextRunner.run(context -> { + + AbstractAutoServiceRegistration autoServiceRegistration = context.getBean(AbstractAutoServiceRegistration.class); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.register(autoServiceRegistration); + }).doesNotThrowAnyException(); + Thread.sleep(1000); + // before register online status is false + assertThatCode(() -> { + assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isFalse(); + }).doesNotThrowAnyException(); + // delay register after 10s + Thread.sleep(10000); + PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); + PolarisRegistration registration = context.getBean(PolarisRegistration.class); + + assertThatCode(() -> { + assertThat(registry.getStatus(registration)).isEqualTo("DOWN"); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isTrue(); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/offline", Collections.EMPTY_MAP)).isTrue(); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.deRegister(autoServiceRegistration); + }).doesNotThrowAnyException(); + + assertThatCode(() -> { + assertThat(registry.getStatus(registration)).isEqualTo("DOWN"); + }).doesNotThrowAnyException(); + }); + } + + @Test + public void testRegister2() { + this.contextRunner2.run(context -> { + + AbstractAutoServiceRegistration autoServiceRegistration = context.getBean(AbstractAutoServiceRegistration.class); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.register(autoServiceRegistration); + }).doesNotThrowAnyException(); + + Thread.sleep(2000); + + assertThatCode(() -> { + AutoServiceRegistrationUtils.deRegister(autoServiceRegistration); + }).doesNotThrowAnyException(); + }); + } + + @Configuration + @EnableAutoConfiguration + static class PolarisPropertiesConfiguration { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java new file mode 100644 index 000000000..9152f04f2 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java @@ -0,0 +1,90 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless.config; + +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.config.provider.LosslessConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link LosslessConfigModifier}. + * + * @author Shedfree Wu + */ +public class LosslessConfigModifierTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.port=20000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") + .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=10") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=5") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + private final ApplicationContextRunner disabledContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=false") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + + @BeforeEach + void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + void testModify() { + contextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getProvider().getLossless(); + assertThat(losslessConfig.getHost()).isEqualTo("0.0.0.0"); + assertThat(losslessConfig.getPort()).isEqualTo(20000); + assertThat(losslessConfig.getDelayRegisterInterval()).isEqualTo(10); + assertThat(losslessConfig.getHealthCheckInterval()).isEqualTo(5); + }); + } + + + @Test + void testDisabled() { + disabledContextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getProvider().getLossless(); + assertThat(losslessConfig.isEnable()).isFalse(); + }); + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java index eb1aedb50..3dee04d67 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java @@ -19,13 +19,11 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; @@ -45,26 +43,9 @@ public void testDefaultInitialization() { applicationContextRunner.run(context -> { assertThat(context).hasSingleBean(DiscoveryPropertiesAutoConfiguration.class); assertThat(context).hasSingleBean(PolarisDiscoveryProperties.class); - assertThat(context).hasSingleBean(ConsulContextProperties.class); + assertThat(context).doesNotHaveBean(ConsulDiscoveryProperties.class); assertThat(context).hasSingleBean(PolarisDiscoveryHandler.class); assertThat(context).hasSingleBean(DiscoveryConfigModifier.class); }); } - - @Configuration - static class TestConfiguration { - @Bean - public PolarisDiscoveryProperties polarisDiscoveryProperties() { - PolarisDiscoveryProperties polarisDiscoveryProperties = new PolarisDiscoveryProperties(); - polarisDiscoveryProperties.setEnabled(false); - return polarisDiscoveryProperties; - } - - @Bean - public ConsulContextProperties consulContextProperties() { - ConsulContextProperties consulContextProperties = new ConsulContextProperties(); - consulContextProperties.setEnabled(true); - return consulContextProperties; - } - } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java index dc0149295..0618ab3d1 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java @@ -35,8 +35,7 @@ public class DiscoveryPropertiesBootstrapAutoConfigurationTest { @Test public void testDefaultInitialization() { ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner().withConfiguration( - AutoConfigurations.of( - PolarisContextAutoConfiguration.class, + AutoConfigurations.of(PolarisContextAutoConfiguration.class, DiscoveryPropertiesBootstrapAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.enabled=true"); applicationContextRunner.run(context -> { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java index 1a5e875dc..0345bf43f 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java @@ -101,6 +101,8 @@ public void testGetAndSet() { + ", registerEnabled=true" + ", heartbeatInterval=20" + ", healthCheckUrl='/health'" - + ", serviceListRefreshInterval=1000}"); + + ", serviceListRefreshInterval=1000" + + ", zeroProtectionEnabled=false" + + ", zeroProtectionNeedTestConnectivity=false}"); } } 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 895fd05a8..88279eda2 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 @@ -49,7 +49,8 @@ public class PolarisDiscoveryAutoConfigurationTest { .withConfiguration(AutoConfigurations.of( PolarisContextAutoConfiguration.class, PolarisDiscoveryAutoConfiguration.class, - PolarisDiscoveryClientConfiguration.class)) + PolarisDiscoveryClientConfiguration.class, + PolarisContextAutoConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + PORT) .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); 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 c50e1a60e..262d89b34 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 @@ -51,6 +51,7 @@ public class PolarisDiscoveryClientTest { @Test public void testGetInstances() { + when(polarisServiceDiscovery.getInstances(anyString())) .thenReturn(singletonList(mock(PolarisServiceInstance.class))); 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 3c0156cbc..d4efe34e7 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 @@ -74,8 +74,7 @@ void setUp() { @Test public void testDefaultInitialization() { - this.contextRunner.run(context -> assertThat(context) - .hasSingleBean(PolarisReactiveDiscoveryClient.class)); + this.contextRunner.run(context -> assertThat(context).hasSingleBean(PolarisReactiveDiscoveryClient.class)); } @Test 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 95724e79c..b4d41f903 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 @@ -57,6 +57,7 @@ public class PolarisReactiveDiscoveryClientTest { @Test public void testGetInstances() throws PolarisException { + when(serviceDiscovery.getInstances(anyString())).thenAnswer(invocation -> { String serviceName = invocation.getArgument(0); if (SERVICE_PROVIDER.equalsIgnoreCase(serviceName)) { @@ -78,6 +79,7 @@ public void testGetInstances() throws PolarisException { @Test public void testGetServices() throws PolarisException { + when(serviceDiscovery.getServices()).thenAnswer(invocation -> { if (count == 0) { count++; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java index dc9b41d9d..bb1bbb481 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java @@ -53,7 +53,7 @@ public class PolarisDiscoveryEndpointTest { private static NamingServer namingServer; - private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( PolarisPropertiesConfiguration.class, PolarisDiscoveryClientConfiguration.class, diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulContextPropertiesTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryPropertiesTest.java similarity index 81% rename from spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulContextPropertiesTest.java rename to spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryPropertiesTest.java index 1d545b4e5..ac096d862 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulContextPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryPropertiesTest.java @@ -37,21 +37,20 @@ import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY; import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY; import static com.tencent.polaris.test.common.Consts.HOST; -import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link ConsulContextProperties}. + * Test for {@link ConsulDiscoveryPropertiesTest}. * * @author Haotian Zhang */ @ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ConsulContextPropertiesTest.TestApplication.class) +@SpringBootTest(classes = ConsulDiscoveryPropertiesTest.TestApplication.class) @ActiveProfiles("test") -public class ConsulContextPropertiesTest { +public class ConsulDiscoveryPropertiesTest { @Autowired - private ConsulContextProperties consulContextProperties; + private ConsulDiscoveryProperties consulDiscoveryProperties; @Autowired private PolarisSDKContextManager polarisSDKContextManager; @@ -63,12 +62,9 @@ void setUp() { @Test public void testDefaultInitialization() { - assertThat(consulContextProperties).isNotNull(); - assertThat(consulContextProperties.isEnabled()).isTrue(); - assertThat(consulContextProperties.getHost()).isEqualTo("127.0.0.1"); - assertThat(consulContextProperties.getPort()).isEqualTo(8500); - assertThat(consulContextProperties.isRegister()).isTrue(); - assertThat(consulContextProperties.isDiscoveryEnabled()).isTrue(); + assertThat(consulDiscoveryProperties).isNotNull(); + assertThat(consulDiscoveryProperties.isRegister()).isTrue(); + assertThat(consulDiscoveryProperties.isEnabled()).isTrue(); } @Test @@ -84,7 +80,7 @@ public void testModify() { } } assertThat(metadata).isNotNull(); - assertThat(metadata.get(SERVICE_NAME_KEY)).isEqualTo(SERVICE_PROVIDER); + assertThat(metadata.get(SERVICE_NAME_KEY)).isEqualTo("java-provider-test"); assertThat(metadata.get(INSTANCE_ID_KEY)).isEqualTo("ins-test"); assertThat(metadata.get(PREFER_IP_ADDRESS_KEY)).isEqualTo("true"); assertThat(metadata.get(IP_ADDRESS_KEY)).isEqualTo(HOST); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java index 9d78c9033..e1c04a29b 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java @@ -71,6 +71,7 @@ public class PolarisAutoServiceRegistrationTest { @BeforeEach void setUp() { doNothing().when(serviceRegistry).register(nullable(PolarisRegistration.class)); + doNothing().when(serviceRegistry).deregister(nullable(PolarisRegistration.class)); polarisAutoServiceRegistration = new PolarisAutoServiceRegistration(serviceRegistry, autoServiceRegistrationProperties, registration, @@ -111,6 +112,32 @@ public void testRegisterManagement() { }).doesNotThrowAnyException(); } + @Test + public void testDeregister() { + doReturn(false).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.registerManagement(); + }).doesNotThrowAnyException(); + + doReturn(true).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.deregister(); + }).doesNotThrowAnyException(); + } + + @Test + public void testDeregisterManagement() { + doReturn(false).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.registerManagement(); + }).doesNotThrowAnyException(); + + doReturn(true).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.deregisterManagement(); + }).doesNotThrowAnyException(); + } + @Test public void testGetAppName() { doReturn("application").when(environment).getProperty(anyString(), anyString()); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java index cd60b31b6..f9b62d331 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java @@ -23,7 +23,7 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.config.global.APIConfig; @@ -76,9 +76,8 @@ void setUp() { PolarisContextProperties polarisContextProperties = mock(PolarisContextProperties.class); doReturn(testLocalPort).when(polarisContextProperties).getLocalPort(); - // mock ConsulContextProperties - ConsulContextProperties consulContextProperties = mock(ConsulContextProperties.class); - doReturn(true).when(consulContextProperties).isEnabled(); + // mock ConsulDiscoveryProperties + ConsulDiscoveryProperties consulContextProperties = mock(ConsulDiscoveryProperties.class); doReturn(true).when(consulContextProperties).isRegister(); // mock NacosContextProperties @@ -180,7 +179,7 @@ public void testGetMetadata() { Map metadata = polarisRegistration1.getMetadata(); assertThat(metadata).isNotNull(); assertThat(metadata).isNotEmpty(); - assertThat(metadata.size()).isEqualTo(4); + assertThat(metadata.size()).isEqualTo(2); assertThat(metadata.get("key1")).isEqualTo("value1"); } @@ -210,7 +209,7 @@ public void testGetNacosMetadata() { Map metadata = polarisRegistration1.getMetadata(); assertThat(metadata).isNotNull(); assertThat(metadata).isNotEmpty(); - assertThat(metadata.size()).isEqualTo(4); + assertThat(metadata.size()).isEqualTo(2); assertThat(metadata.get("nacos.cluster")).isEqualTo(clusterName); } } 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 2d96a9904..e51d9facc 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 @@ -122,7 +122,8 @@ public void testRegister() { @Test public void testDeRegister() { this.contextRunner.run(context -> { - PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); + PolarisServiceRegistry registry = context + .getBean(PolarisServiceRegistry.class); PolarisRegistration registration = Mockito.mock(PolarisRegistration.class); doReturn(null).when(registration).getServiceId(); assertThatCode(() -> { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java new file mode 100644 index 000000000..1c8e09f91 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java @@ -0,0 +1,29 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springframework.cloud.client.serviceregistry; + +public class AutoServiceRegistrationUtils { + + public static void register(AbstractAutoServiceRegistration autoServiceRegistration) { + autoServiceRegistration.register(); + } + + public static void deRegister(AbstractAutoServiceRegistration autoServiceRegistration) { + autoServiceRegistration.deregister(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml index 0b08cd790..642ef9322 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml +++ b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml @@ -19,6 +19,11 @@ com.tencent.cloud spring-cloud-tencent-rpc-enhancement + + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + @@ -34,6 +39,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-canary diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java index ac820aa9e..ebb9d7553 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java @@ -28,8 +28,8 @@ * @author Haotian Zhang */ @Configuration(proxyBeanMethods = false) -@ConditionalOnPolarisRateLimitEnabled @EnableConfigurationProperties(PolarisRateLimitProperties.class) +@ConditionalOnPolarisRateLimitEnabled public class PolarisRateLimitPropertiesAutoConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java index 1d6cee878..d062171cf 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java @@ -37,11 +37,13 @@ public RateLimitConfigModifier(PolarisRateLimitProperties polarisRateLimitProper @Override public void modify(ConfigurationImpl configuration) { // Update MaxQueuingTime. - configuration.getProvider().getRateLimit().setMaxQueuingTime(polarisRateLimitProperties.getMaxQueuingTime()); + configuration.getProvider().getRateLimit() + .setMaxQueuingTime(polarisRateLimitProperties.getMaxQueuingTime()); } @Override public int getOrder() { return OrderConstant.Modifier.RATE_LIMIT_ORDER; } + } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java index 8c2844928..a6218b27a 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java @@ -41,7 +41,7 @@ * * @author shuiqingliu **/ -@Endpoint(id = "polaris-ratelimit") +@Endpoint(id = "polarisratelimit") public class PolarisRateLimitRuleEndpoint { private static final Logger LOG = LoggerFactory.getLogger(PolarisRateLimitRuleEndpoint.class); diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java index f7ce8d21b..f6bf04706 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java @@ -128,12 +128,12 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( - quotaResponse.getActiveRule().getName().getValue(), UTF_8); + quotaResponse.getActiveRuleName(), UTF_8); response.getHeaders().add(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName); } catch (UnsupportedEncodingException e) { LOG.error("Cannot encode {} for header internal-callee-activerule.", - quotaResponse.getActiveRule().getName().getValue(), e); + quotaResponse.getActiveRuleName(), e); } } return response.writeWith(Mono.just(dataBuffer)); diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java index 2f4a56eac..7266e5b54 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java @@ -121,12 +121,12 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( - quotaResponse.getActiveRule().getName().getValue(), UTF_8); + quotaResponse.getActiveRuleName(), UTF_8); response.addHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName); } catch (UnsupportedEncodingException e) { LOG.error("Cannot encode {} for header internal-callee-activerule.", - quotaResponse.getActiveRule().getName().getValue(), e); + quotaResponse.getActiveRuleName(), e); } } return; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java index 13c57d817..43d9b7209 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java @@ -77,35 +77,29 @@ public Set getArguments(ServerWebExchange request, String namespace, S switch (matchArgument.getType()) { case CUSTOM: argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)) - .orElse(StringUtils.EMPTY)); + Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)).orElse(StringUtils.EMPTY)); break; case METHOD: argument = Argument.buildMethod(request.getRequest().getMethodValue()); break; case HEADER: argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildHeader(matchKey, Optional.ofNullable(request.getRequest().getHeaders() - .getFirst(matchKey)).orElse(StringUtils.EMPTY)); + Argument.buildHeader(matchKey, Optional.ofNullable(request.getRequest().getHeaders().getFirst(matchKey)).orElse(StringUtils.EMPTY)); break; case QUERY: argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildQuery(matchKey, Optional.ofNullable(request.getRequest().getQueryParams() - .getFirst(matchKey)).orElse(StringUtils.EMPTY)); + Argument.buildQuery(matchKey, Optional.ofNullable(request.getRequest().getQueryParams().getFirst(matchKey)).orElse(StringUtils.EMPTY)); break; case CALLER_SERVICE: - String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true) - .orElse(StringUtils.EMPTY); - String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true) - .orElse(StringUtils.EMPTY); + String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true).orElse(StringUtils.EMPTY); + String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true).orElse(StringUtils.EMPTY); if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) { argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName); } break; case CALLER_IP: InetSocketAddress remoteAddress = request.getRequest().getRemoteAddress(); - argument = Argument.buildCallerIP(remoteAddress != null ? remoteAddress.getAddress() - .getHostAddress() : StringUtils.EMPTY); + argument = Argument.buildCallerIP(remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : StringUtils.EMPTY); break; default: break; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java index 6f63cbc93..818769bfd 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java @@ -31,6 +31,7 @@ public interface PolarisRateLimiterLabelReactiveResolver { /** * Resolve custom label from request. + * * @param exchange the http request * @return resolved labels */ diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java index 1ec3a7a0c..8fe859092 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java @@ -31,8 +31,10 @@ public interface PolarisRateLimiterLabelServletResolver { /** * Resolve custom label from request. + * * @param request the http request * @return resolved labels */ Map resolve(HttpServletRequest request); + } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java index 6ddcad931..f55cea3a6 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java @@ -41,12 +41,12 @@ private RateLimitUtils() { public static String getRejectTips(PolarisRateLimitProperties polarisRateLimitProperties) { String tips = polarisRateLimitProperties.getRejectRequestTips(); - if (!StringUtils.isEmpty(tips)) { + if (StringUtils.hasText(tips)) { return tips; } String rejectFilePath = polarisRateLimitProperties.getRejectRequestTipsFilePath(); - if (!StringUtils.isEmpty(rejectFilePath)) { + if (StringUtils.hasText(rejectFilePath)) { try { tips = ResourceFileUtils.readFile(rejectFilePath); } @@ -56,7 +56,7 @@ public static String getRejectTips(PolarisRateLimitProperties polarisRateLimitPr } } - if (!StringUtils.isEmpty(tips)) { + if (StringUtils.hasText(tips)) { return tips; } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java index d4296c770..cf157182a 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java @@ -63,10 +63,9 @@ */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = { CalleeControllerTests.Config.class, TestController.class }, - properties = { "spring.application.name=java_provider_test", - "spring.cloud.polaris.discovery.namespace=Test", - "spring.cloud.polaris.address=grpc://127.0.0.1:10081" }) + classes = {CalleeControllerTests.Config.class, TestController.class}, + properties = {"spring.application.name=java_provider_test", "spring.cloud.polaris.discovery.namespace=Test", + "spring.cloud.polaris.address=grpc://127.0.0.1:10081"}) public class CalleeControllerTests { private static NamingServer namingServer; @@ -90,8 +89,7 @@ static void beforeAll() throws Exception { instanceParameter.setIsolated(false); instanceParameter.setWeight(100); ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER); - namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, - instanceParameter); + namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, instanceParameter); } @AfterAll diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java index c4e99a4d5..f56db9b4b 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java @@ -31,7 +31,7 @@ public class TestController { @GetMapping("/info") - public String info() { + public String info() throws Exception { return "hello service info"; } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java index dd4e43a68..9b1cbafc8 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java @@ -51,17 +51,16 @@ @ExtendWith(MockitoExtension.class) public class PolarisRateLimitRuleEndpointTests { - private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - PolarisRateLimitRuleEndpointTests.PolarisRateLimitAutoConfiguration.class, + PolarisRateLimitAutoConfiguration.class, PolarisRateLimitRuleEndpointAutoConfiguration.class, PolarisRateLimitAutoConfiguration.class, PolarisRateLimitAutoConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + PORT) .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") - .withPropertyValues( - "spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); private ServiceRuleManager serviceRuleManager; diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 56ac0fe50..3975201b4 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -48,6 +48,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + 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 index 96545d621..3b9e23c74 100644 --- 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 @@ -35,6 +35,7 @@ import com.netflix.loadbalancer.ZoneAvoidanceRule; import com.tencent.cloud.common.constant.RouterConstant; 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.common.util.JacksonUtils; import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; @@ -206,6 +207,7 @@ ProcessRoutersRequest buildProcessRoutersBaseRequest(ServiceInstances serviceIns serviceInfo.setNamespace(MetadataContext.LOCAL_NAMESPACE); serviceInfo.setService(MetadataContext.LOCAL_SERVICE); processRoutersRequest.setSourceService(serviceInfo); + processRoutersRequest.setMetadataContainerGroup(MetadataContextHolder.get().getMetadataContainerGroup(false)); return processRoutersRequest; } 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 index 6d380f5bb..ef87b68cb 100644 --- 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 @@ -13,14 +13,13 @@ * 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.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -28,11 +27,12 @@ import org.apache.commons.lang.StringUtils; import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * the context for router. * - * @author lepdou 2022-05-17 + * @author lepdou, Hoatian Zhang */ public class PolarisRouterContext { @@ -77,37 +77,19 @@ public String getLabel(String labelKey) { return routerLabels.get(labelKey); } - public Set getLabelAsSet(String labelKey) { - Map routerLabels = labels.get(RouterConstant.ROUTER_LABELS); - if (CollectionUtils.isEmpty(routerLabels)) { - return Collections.emptySet(); - } - - for (Map.Entry entry : routerLabels.entrySet()) { - if (StringUtils.equalsIgnoreCase(labelKey, entry.getKey())) { - String keysStr = entry.getValue(); - if (StringUtils.isNotBlank(keysStr)) { - String[] keysArr = StringUtils.split(keysStr, ","); - return new HashSet<>(Arrays.asList(keysArr)); - } - } - } - - return Collections.emptySet(); - } - public void putLabels(String labelType, Map subLabels) { if (this.labels == null) { this.labels = new HashMap<>(); } - labels.put(labelType, subLabels); + + Map subLabelMap = new LinkedCaseInsensitiveMap<>(); + if (!CollectionUtils.isEmpty(subLabels)) { + subLabelMap.putAll(subLabels); + } + labels.put(labelType, subLabelMap); } public Map> getLabels() { return labels; } - - public void setLabels(Map> labels) { - this.labels = labels; - } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java new file mode 100644 index 000000000..67376a187 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; +import com.tencent.polaris.plugins.router.nearby.NearbyRouterConfig; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; +import org.apache.commons.lang.StringUtils; + +/** + * RouterConfigModifier. + * + * @author sean yu + */ +public class RouterConfigModifier implements PolarisConfigModifier { + + private final PolarisNearByRouterProperties polarisNearByRouterProperties; + + public RouterConfigModifier(PolarisNearByRouterProperties polarisNearByRouterProperties) { + this.polarisNearByRouterProperties = polarisNearByRouterProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + // Set excludeCircuitBreakInstances to false + RecoverRouterConfig recoverRouterConfig = configuration.getConsumer().getServiceRouter() + .getPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, RecoverRouterConfig.class); + recoverRouterConfig.setExcludeCircuitBreakInstances(false); + + // Update modified config to source properties + configuration.getConsumer().getServiceRouter() + .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig); + + if (StringUtils.isNotBlank(polarisNearByRouterProperties.getMatchLevel())) { + RoutingProto.NearbyRoutingConfig.LocationLevel locationLevel = + RoutingProto.NearbyRoutingConfig.LocationLevel.valueOf(StringUtils.upperCase(polarisNearByRouterProperties.getMatchLevel())); + NearbyRouterConfig nearbyRouterConfig = configuration.getConsumer().getServiceRouter().getPluginConfig( + ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, NearbyRouterConfig.class); + nearbyRouterConfig.setMatchLevel(locationLevel); + configuration.getConsumer().getServiceRouter() + .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, nearbyRouterConfig); + } + + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.ROUTER_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java index 67f2aff2a..a71c2e8d3 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java @@ -18,21 +18,14 @@ package com.tencent.cloud.polaris.router.config; -import java.util.List; - -import com.tencent.cloud.common.metadata.StaticMetadataManager; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 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.lang.Nullable; /** * configuration for feign singleton components. @@ -47,12 +40,8 @@ public class FeignAutoConfiguration { @Bean - public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List routerLabelResolvers, - StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver, - PolarisContextProperties polarisContextProperties) { - return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager, - routerRuleLabelResolver, polarisContextProperties); + public RouterLabelFeignInterceptor routerLabelInterceptor() { + return new RouterLabelFeignInterceptor(); } @Bean 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 868d54b32..60a4e3f51 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 @@ -18,6 +18,8 @@ package com.tencent.cloud.polaris.router.config; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.tencent.cloud.common.metadata.StaticMetadataManager; @@ -28,17 +30,26 @@ import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.beanprocessor.RetryLoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNamespaceRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterceptor; +import com.tencent.cloud.polaris.router.interceptor.NamespaceRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor; import com.tencent.cloud.polaris.router.resttemplate.RouterContextFactory; +import com.tencent.cloud.polaris.router.resttemplate.RouterLabelRestTemplateInterceptor; +import com.tencent.cloud.polaris.router.scg.RouterLabelGlobalFilter; import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; import com.tencent.cloud.polaris.router.zuul.PolarisRibbonRoutingFilter; +import com.tencent.cloud.polaris.router.zuul.RouterLabelZuulFilter; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.netflix.ribbon.RibbonClients; @@ -47,8 +58,9 @@ import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; @@ -60,7 +72,6 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisRouterEnabled @RibbonClients(defaultConfiguration = {RibbonConfiguration.class}) -@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class}) public class RouterAutoConfiguration { @Bean @@ -93,9 +104,30 @@ public RuleBasedRouterRequestInterceptor ruleBasedRouterRequestInterceptor(Polar return new RuleBasedRouterRequestInterceptor(polarisRuleBasedRouterProperties); } + @Bean + @ConditionalOnProperty(value = "spring.cloud.polaris.router.namespace-router.enabled", matchIfMissing = true) + public NamespaceRouterRequestInterceptor namespaceRouterRequestInterceptor(PolarisNamespaceRouterProperties polarisNamespaceRouterProperties) { + return new NamespaceRouterRequestInterceptor(polarisNamespaceRouterProperties); + } + + /** + * Create when gateway application is SCG. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter") + protected static class RouterLabelScgFilterConfig { + + @Bean + public RouterLabelGlobalFilter routerLabelGlobalFilter() { + return new RouterLabelGlobalFilter(); + } + + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") public static class RestTemplateAutoConfiguration { + @Bean @Order(HIGHEST_PRECEDENCE) @ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor") @@ -125,6 +157,7 @@ public RouterContextFactory routerContextFactory(List restTemplates = Collections.emptyList(); + + @Bean + public RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor() { + return new RouterLabelRestTemplateInterceptor(); + } + + @Bean + public SmartInitializingSingleton addRouterLabelInterceptorForRestTemplate(RouterLabelRestTemplateInterceptor interceptor) { + return () -> restTemplates.forEach(restTemplate -> { + List list = new ArrayList<>(restTemplate.getInterceptors()); + int addIndex = list.size(); + for (int i = 0; i < list.size(); i++) { + if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { + addIndex = i; + } + } + list.add(addIndex, interceptor); + restTemplate.setInterceptors(list); + }); + } } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java index 949edc54a..79f1f5aaa 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java @@ -13,7 +13,6 @@ * 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.properties; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java new file mode 100644 index 000000000..16250b722 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.router.config.properties; + +import com.tencent.polaris.api.rpc.NamespaceRouterFailoverType; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * the configuration for namespace router. + * + * @author lepdou 2022-05-23 + */ +@ConfigurationProperties(prefix = "spring.cloud.polaris.router.namespace-router") +public class PolarisNamespaceRouterProperties { + + private boolean enabled = false; + + private NamespaceRouterFailoverType failOver = NamespaceRouterFailoverType.all; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public NamespaceRouterFailoverType getFailOver() { + return failOver; + } + + public void setFailOver(NamespaceRouterFailoverType failOver) { + this.failOver = failOver; + } + + @Override + public String toString() { + return "PolarisNamespaceRouterProperties{" + + "enabled=" + enabled + + ", failOver=" + failOver + + '}'; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java index 3cd69ca12..226195a13 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java @@ -13,7 +13,6 @@ * 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.properties; @@ -28,7 +27,9 @@ @ConfigurationProperties(prefix = "spring.cloud.polaris.router.nearby-router") public class PolarisNearByRouterProperties { - private boolean enabled = true; + private boolean enabled = false; + + private String matchLevel; public boolean isEnabled() { return enabled; @@ -38,10 +39,19 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + public String getMatchLevel() { + return matchLevel; + } + + public void setMatchLevel(String matchLevel) { + this.matchLevel = matchLevel; + } + @Override public String toString() { return "PolarisNearByRouterProperties{" + "enabled=" + enabled + + ", matchLevel='" + matchLevel + '\'' + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java index 67a17975f..e9ecceabf 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java @@ -13,11 +13,12 @@ * 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.properties; +import com.tencent.polaris.api.rpc.RuleBasedRouterFailoverType; + import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -30,6 +31,8 @@ public class PolarisRuleBasedRouterProperties { private boolean enabled = true; + private RuleBasedRouterFailoverType failOver = RuleBasedRouterFailoverType.all; + public boolean isEnabled() { return enabled; } @@ -38,11 +41,19 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + public RuleBasedRouterFailoverType getFailOver() { + return failOver; + } + + public void setFailOver(RuleBasedRouterFailoverType failOver) { + this.failOver = failOver; + } + @Override public String toString() { - return "PolarisNearByRouterProperties{" + + return "PolarisRuleBasedRouterProperties{" + "enabled=" + enabled + + ", failOver=" + failOver + '}'; } - } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java new file mode 100644 index 000000000..3b3934caa --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.config.properties; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * RouterBootstrapAutoConfiguration. + * + * @author sean yu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(RouterConfigModifierAutoConfiguration.class) +public class RouterBootstrapAutoConfiguration { + + +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java new file mode 100644 index 000000000..354b237b2 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java @@ -0,0 +1,46 @@ +/* + * 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.properties; + +import com.tencent.cloud.polaris.router.RouterConfigModifier; +import com.tencent.cloud.polaris.router.config.ConditionalOnPolarisRouterEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * RouterConfigModifierAutoConfiguration. + * + * @author sean yu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisRouterEnabled +@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class, + PolarisNamespaceRouterProperties.class}) +public class RouterConfigModifierAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public RouterConfigModifier routerConfigModifier(PolarisNearByRouterProperties polarisNearByRouterProperties) { + return new RouterConfigModifier(polarisNearByRouterProperties); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java index eac72ba12..b7a65e4e5 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java @@ -42,7 +42,7 @@ * Router actuator endpoint. * @author lepdou 2022-07-25 */ -@Endpoint(id = "polaris-router") +@Endpoint(id = "polarisrouter") public class PolarisRouterEndpoint { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisRouterEndpoint.class); 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 deleted file mode 100644 index 849d563c6..000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java +++ /dev/null @@ -1,98 +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.polaris.router.feign; - -import java.net.URI; -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.expresstion.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 final class FeignExpressionLabelUtils { - - private 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 (ExpressionLabelUtils.isHeaderLabel(labelKey)) { - String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); - if (StringUtils.isBlank(headerKey)) { - continue; - } - labels.put(labelKey, getHeaderValue(request, headerKey)); - } - else if (ExpressionLabelUtils.isQueryLabel(labelKey)) { - String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); - if (StringUtils.isBlank(queryKey)) { - continue; - } - labels.put(labelKey, getQueryValue(request, queryKey)); - } - else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { - String cookieKey = ExpressionLabelUtils.parseCookieKey(labelKey); - if (StringUtils.isBlank(cookieKey)) { - continue; - } - labels.put(labelKey, getCookieValue(request, cookieKey)); - } - else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { - labels.put(labelKey, request.method()); - } - else if (ExpressionLabelUtils.isUriLabel(labelKey)) { - URI uri = URI.create(request.request().url()); - labels.put(labelKey, uri.getPath()); - } - } - - 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); - } - - public static String getCookieValue(RequestTemplate request, String key) { - Map> headers = request.headers(); - return ExpressionLabelUtils.getCookieFirstValue(headers, 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 dea8ff1bf..b40792170 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 @@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -65,8 +66,8 @@ protected void customizeLoadBalancerCommandBuilder(RibbonRequest request, IClien PolarisRouterContext buildRouterContext(Map> headers) { Collection labelHeaderValues = headers.get(RouterConstant.ROUTER_LABEL_HEADER); - if (CollectionUtils.isEmpty(labelHeaderValues)) { - return null; + if (labelHeaderValues == null) { + labelHeaderValues = new ArrayList<>(0); } PolarisRouterContext routerContext = new PolarisRouterContext(); diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java index 0faa26a5a..eda50162f 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java @@ -18,63 +18,21 @@ package com.tencent.cloud.polaris.router.feign; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.constant.RouterConstant; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.metadata.StaticMetadataManager; -import com.tencent.cloud.common.util.JacksonUtils; -import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; +import com.tencent.cloud.metadata.provider.FeignRequestTemplateMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; import feign.RequestInterceptor; import feign.RequestTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; -import org.springframework.util.CollectionUtils; - -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; /** - * Resolver labels from request. + * Interceptor used for setting Feign RequestTemplate metadata provider. * - * @author lepdou, cheese8 + * @author lepdou, cheese8, Hoatian Zhang */ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered { - private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelFeignInterceptor.class); - - private final List routerLabelResolvers; - private final StaticMetadataManager staticMetadataManager; - private final RouterRuleLabelResolver routerRuleLabelResolver; - private final PolarisContextProperties polarisContextProperties; - - public RouterLabelFeignInterceptor(List routerLabelResolvers, - StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver, - PolarisContextProperties polarisContextProperties) { - if (!CollectionUtils.isEmpty(routerLabelResolvers)) { - routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder)); - this.routerLabelResolvers = routerLabelResolvers; - } - else { - this.routerLabelResolvers = null; - } - this.staticMetadataManager = staticMetadataManager; - this.routerRuleLabelResolver = routerRuleLabelResolver; - this.polarisContextProperties = polarisContextProperties; - } @Override public int getOrder() { @@ -83,62 +41,7 @@ public int getOrder() { @Override public void apply(RequestTemplate requestTemplate) { - // local service labels - Map labels = new HashMap<>(staticMetadataManager.getMergedStaticMetadata()); - - // labels from rule expression - String peerServiceName = requestTemplate.feignTarget().name(); - Set expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, - MetadataContext.LOCAL_SERVICE, peerServiceName); - - Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, expressionLabelKeys); - labels.putAll(ruleExpressionLabels); - - // labels from custom spi - if (!CollectionUtils.isEmpty(routerLabelResolvers)) { - routerLabelResolvers.forEach(resolver -> { - try { - Map customResolvedLabels = resolver.resolve(requestTemplate, expressionLabelKeys); - if (!CollectionUtils.isEmpty(customResolvedLabels)) { - labels.putAll(customResolvedLabels); - } - } - catch (Throwable t) { - LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t); - } - }); - } - - // labels from downstream - Map transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata(); - labels.putAll(transitiveLabels); - - // pass label by header - String encodedLabelsContent; - try { - encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(labels), UTF_8); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException("unsupported charset exception " + UTF_8); - } - requestTemplate.header(RouterConstant.ROUTER_LABEL_HEADER, encodedLabelsContent); - } - - private Map getRuleExpressionLabels(RequestTemplate requestTemplate, Set labelKeys) { - if (CollectionUtils.isEmpty(labelKeys)) { - return Collections.emptyMap(); - } - - //enrich labels from request - Map labels = FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys); - - //enrich caller ip label - for (String labelKey : labelKeys) { - if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) { - labels.put(labelKey, polarisContextProperties.getLocalIpAddress()); - } - } - - return labels; + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new FeignRequestTemplateMetadataProvider(requestTemplate)); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java index 8a4f7137b..3a97f7624 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java @@ -18,23 +18,19 @@ package com.tencent.cloud.polaris.router.interceptor; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.tencent.cloud.common.constant.RouterConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; -import com.tencent.polaris.api.pojo.RouteArgument; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.metadata.MetadataRouter; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; -import org.springframework.util.CollectionUtils; - /** * Router request interceptor for metadata router. - * @author lepdou 2022-07-06 + * @author lepdou, Hoatian Zhang */ public class MetadataRouterRequestInterceptor implements RouterRequestInterceptor { private static final String LABEL_KEY_METADATA_ROUTER_KEYS = "system-metadata-router-keys"; @@ -51,18 +47,10 @@ public void apply(ProcessRoutersRequest request, PolarisRouterContext routerCont return; } - // 1. get metadata router label keys - Set metadataRouterKeys = routerContext.getLabelAsSet(LABEL_KEY_METADATA_ROUTER_KEYS); - // 2. get metadata router labels - Map metadataRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS, - metadataRouterKeys); - // 3. set metadata router labels to request - Set routeArguments = new HashSet<>(); - if (!CollectionUtils.isEmpty(metadataRouterKeys)) { - for (Map.Entry entry : metadataRouterLabels.entrySet()) { - routeArguments.add(RouteArgument.fromLabel(entry.getKey(), entry.getValue())); - } - } - request.putRouterArgument(MetadataRouter.ROUTER_TYPE_METADATA, routeArguments); + // set metadata router label keys + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + String metadataRouteKeys = metadataContainer.getRawMetadataStringValue(LABEL_KEY_METADATA_ROUTER_KEYS); + metadataContainer.putMetadataMapValue(MetadataRouter.ROUTER_TYPE_METADATA, MetadataRouter.KEY_METADATA_KEYS, metadataRouteKeys, TransitiveType.NONE); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java new file mode 100644 index 000000000..e9dd95fe3 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java @@ -0,0 +1,55 @@ +/* + * 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.interceptor; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.config.properties.PolarisNamespaceRouterProperties; +import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; +import com.tencent.polaris.plugins.router.namespace.NamespaceRouter; +import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; + +/** + * Router request interceptor for namespace router. + * + * @author Hoatian Zhang + */ +public class NamespaceRouterRequestInterceptor implements RouterRequestInterceptor { + + private final PolarisNamespaceRouterProperties polarisNamespaceRouterProperties; + + public NamespaceRouterRequestInterceptor(PolarisNamespaceRouterProperties polarisNamespaceRouterProperties) { + this.polarisNamespaceRouterProperties = polarisNamespaceRouterProperties; + } + + @Override + public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { + // set namespace router enable + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataMapValue(NamespaceRouter.ROUTER_TYPE_NAMESPACE, NamespaceRouter.ROUTER_ENABLED, + String.valueOf(polarisNamespaceRouterProperties.isEnabled()), TransitiveType.NONE); + + // set namespace router fail over type. + request.setNamespaceRouterFailoverType(polarisNamespaceRouterProperties.getFailOver()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java index ca59f7788..6d40e0c55 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java @@ -18,13 +18,13 @@ package com.tencent.cloud.polaris.router.interceptor; -import java.util.HashSet; -import java.util.Set; - +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; -import com.tencent.polaris.api.pojo.RouteArgument; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.nearby.NearbyRouter; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; @@ -42,13 +42,10 @@ public NearbyRouterRequestInterceptor(PolarisNearByRouterProperties polarisNearB @Override public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { - if (!polarisNearByRouterProperties.isEnabled()) { - return; - } - - Set routeArguments = new HashSet<>(1); - routeArguments.add(RouteArgument.buildCustom(NearbyRouter.ROUTER_ENABLED, "true")); - - request.putRouterArgument(NearbyRouter.ROUTER_TYPE_NEAR_BY, routeArguments); + // set nearby router enable + boolean nearbyRouterEnabled = polarisNearByRouterProperties.isEnabled(); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataMapValue(NearbyRouter.ROUTER_TYPE_NEAR_BY, NearbyRouter.ROUTER_ENABLED, String.valueOf(nearbyRouterEnabled), TransitiveType.NONE); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java index 64d8c913f..39d9e37b8 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java @@ -13,28 +13,23 @@ * 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.interceptor; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.tencent.cloud.common.constant.RouterConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; -import com.tencent.polaris.api.pojo.RouteArgument; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; -import org.springframework.util.CollectionUtils; - /** * Router request interceptor for rule based router. - * @author lepdou 2022-07-06 + * @author lepdou, Hoatian Zhang */ public class RuleBasedRouterRequestInterceptor implements RouterRequestInterceptor { @@ -46,24 +41,12 @@ public RuleBasedRouterRequestInterceptor(PolarisRuleBasedRouterProperties polari @Override public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { + // set rule based router enable boolean ruleBasedRouterEnabled = polarisRuleBasedRouterProperties.isEnabled(); - - // set dynamic switch for rule based router - Set routeArguments = new HashSet<>(); - routeArguments.add(RouteArgument.buildCustom(RuleBasedRouter.ROUTER_ENABLED, String.valueOf(ruleBasedRouterEnabled))); - - // The label information that the rule based routing depends on - // is placed in the metadata of the source service for transmission. - // Later, can consider putting it in routerMetadata like other routers. - if (ruleBasedRouterEnabled) { - Map ruleRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS); - if (!CollectionUtils.isEmpty(ruleRouterLabels)) { - for (Map.Entry label : ruleRouterLabels.entrySet()) { - routeArguments.add(RouteArgument.fromLabel(label.getKey(), label.getValue())); - } - } - } - - request.putRouterArgument(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, routeArguments); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataMapValue(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, RuleBasedRouter.ROUTER_ENABLED, String.valueOf(ruleBasedRouterEnabled), TransitiveType.NONE); + // set rule based router fail over type. + request.setRuleBasedRouterFailoverType(polarisRuleBasedRouterProperties.getFailOver()); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.java new file mode 100644 index 000000000..d079f7b87 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.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.resttemplate; + +import java.io.IOException; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.provider.RestTemplateMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; + +import org.springframework.core.Ordered; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.NonNull; + +/** + * Interceptor used for setting RestTemplate HttpRequest metadata provider. + * + * @author liuye, Hoatian Zhang + */ +public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { + + @Override + public int getOrder() { + return OrderConstant.Client.RestTemplate.ROUTER_LABEL_INTERCEPTOR_ORDER; + } + + @Override + public ClientHttpResponse intercept(@NonNull HttpRequest request, @NonNull byte[] body, + @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new RestTemplateMetadataProvider(request)); + return clientHttpRequestExecution.execute(request, body); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java new file mode 100644 index 000000000..b0bb6ab8f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java @@ -0,0 +1,57 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.scg; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.web.server.ServerWebExchange; + +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; + +/** + * Interceptor used for setting SCG ServerWebExchange metadata provider. + * + * @author Hoatian Zhang + */ +public class RouterLabelGlobalFilter implements GlobalFilter, Ordered { + @Override + public int getOrder() { + return LOAD_BALANCER_CLIENT_FILTER_ORDER - 1; + } + + /** + * Copied from ReactiveLoadBalancerClientFilter, and create new RequestData for passing router labels. + */ + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new ReactiveMetadataProvider(exchange.getRequest(), + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP))); + return chain.filter(exchange); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java new file mode 100644 index 000000000..c4170153c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.zuul; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.provider.ServletMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; + +import org.springframework.core.Ordered; + +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; + +/** + * Interceptor used for setting Zuul metadata provider. + * + * @author Shedfree Wu + */ +public class RouterLabelZuulFilter extends ZuulFilter { + @Override + public String filterType() { + return PRE_TYPE; + } + + @Override + public int filterOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() throws ZuulException { + RequestContext context = RequestContext.getCurrentContext(); + + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new ServletMetadataProvider(context.getRequest(), + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP))); + + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 0c935af6e..92251c916 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -9,8 +9,14 @@ { "name": "spring.cloud.polaris.router.nearby-router.enabled", "type": "java.lang.Boolean", - "defaultValue": true, - "description": "the switch for near by router." + "defaultValue": false, + "description": "the switch for nearby router." + }, + { + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", + "type": "java.lang.String", + "defaultValue": "ZONE", + "description": "the match level for nearby router, options can be REGION/ZONE/CAMPUS." }, { "name": "spring.cloud.polaris.router.rule-router.enabled", @@ -18,11 +24,48 @@ "defaultValue": true, "description": "the switch for rule based router." }, + { + "name": "spring.cloud.polaris.router.rule-router.failOver", + "type": "java.lang.String", + "defaultValue": "all", + "description": "the fail over type for rule based router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "the switch for namespace router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.failOver", + "type": "java.lang.String", + "defaultValue": "all", + "description": "the fail over type for namespace router." + }, { "name": "spring.cloud.polaris.router.enabled", "type": "java.lang.Boolean", "defaultValue": true, "description": "the switch for router module." } + ], + "hints": [ + { + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", + "values": [ + { + "value": "CAMPUS" + }, + { + "value": "ZONE" + }, + { + "value": "REGION" + }, + { + "value": "ALL" + } + ] + } ] } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories index 75f7939ca..5170ed04b 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories @@ -1,4 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.polaris.router.config.properties.RouterConfigModifierAutoConfiguration,\ com.tencent.cloud.polaris.router.config.RouterAutoConfiguration,\ com.tencent.cloud.polaris.router.config.FeignAutoConfiguration,\ com.tencent.cloud.polaris.router.endpoint.PolarisRouterEndpointAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.polaris.router.config.RouterBootstrapAutoConfiguration diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java new file mode 100644 index 000000000..5d771e012 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java @@ -0,0 +1,244 @@ +package com.tencent.cloud.polaris.router; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Map; + +import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.core.ResolvableType; +import org.springframework.core.env.Environment; +import org.springframework.core.io.Resource; + +public class MockApplicationContext implements org.springframework.context.ApplicationContext{ + @Override + public String getId() { + return null; + } + + @Override + public String getApplicationName() { + return null; + } + + @Override + public String getDisplayName() { + return null; + } + + @Override + public long getStartupDate() { + return 0; + } + + @Override + public ApplicationContext getParent() { + return null; + } + + @Override + public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { + return null; + } + + @Override + public BeanFactory getParentBeanFactory() { + return null; + } + + @Override + public boolean containsLocalBean(String name) { + return false; + } + + @Override + public boolean containsBeanDefinition(String beanName) { + return false; + } + + @Override + public int getBeanDefinitionCount() { + return 0; + } + + @Override + public String[] getBeanDefinitionNames() { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(ResolvableType type) { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(Class type) { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) { + return new String[0]; + } + + @Override + public Map getBeansOfType(Class type) throws BeansException { + return null; + } + + @Override + public Map getBeansOfType(Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { + return null; + } + + @Override + public String[] getBeanNamesForAnnotation(Class annotationType) { + return new String[0]; + } + + @Override + public Map getBeansWithAnnotation(Class annotationType) throws BeansException { + return null; + } + + @Override + public A findAnnotationOnBean(String beanName, Class annotationType) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public Object getBean(String name) throws BeansException { + + return null; + } + + @Override + public T getBean(String name, Class requiredType) throws BeansException { + return null; + } + + @Override + public Object getBean(String name, Object... args) throws BeansException { + return null; + } + + @Override + public T getBean(Class requiredType) throws BeansException { + if (requiredType.equals(StaticMetadataManager.class)) { + return (T) new StaticMetadataManager(new MetadataLocalProperties(), new ArrayList<>()); + } + + return null; + } + + @Override + public T getBean(Class requiredType, Object... args) throws BeansException { + return null; + } + + @Override + public ObjectProvider getBeanProvider(Class requiredType) { + return null; + } + + @Override + public ObjectProvider getBeanProvider(ResolvableType requiredType) { + return null; + } + + @Override + public boolean containsBean(String name) { + return false; + } + + @Override + public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public Class getType(String name) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public String[] getAliases(String name) { + return new String[0]; + } + + @Override + public void publishEvent(Object event) { + + } + + @Override + public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) { + return null; + } + + @Override + public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException { + return null; + } + + @Override + public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException { + return null; + } + + @Override + public Environment getEnvironment() { + return null; + } + + @Override + public Resource[] getResources(String locationPattern) throws IOException { + return new Resource[0]; + } + + @Override + public Resource getResource(String location) { + return null; + } + + @Override + public ClassLoader getClassLoader() { + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java index a48840ace..41e8a17df 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java @@ -23,7 +23,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import com.netflix.client.config.DefaultClientConfigImpl; @@ -54,9 +53,11 @@ 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.RouteArgument; import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.metadata.MetadataRouter; import com.tencent.polaris.plugins.router.nearby.NearbyRouter; import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; @@ -218,35 +219,25 @@ public void testBuildMetadataRouteRequest() { try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) .thenReturn(testCallerService); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getApplicationContext()).thenReturn(new MockApplicationContext()); setTransitiveMetadata(); PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, polarisLoadBalancerProperties, config, requestInterceptors, null, null); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataStringValue("system-metadata-router-keys", "k2", TransitiveType.NONE); + ServiceInstances serviceInstances = assembleServiceInstances(); PolarisRouterContext routerContext = assembleRouterContext(); - Map oldRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS); - Map newRouterLabels = new HashMap<>(oldRouterLabels); - newRouterLabels.put("system-metadata-router-keys", "k2"); - routerContext.putLabels(RouterConstant.ROUTER_LABELS, newRouterLabels); - ProcessRoutersRequest request = compositeRule.buildProcessRoutersBaseRequest(serviceInstances); compositeRule.processRouterRequestInterceptors(request, routerContext); - Set routerMetadata = request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA); - - AssertionsForClassTypes.assertThat(routerMetadata.size()).isEqualTo(1); - AssertionsForClassTypes.assertThat(request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()) - .isEqualTo(0); - AssertionsForClassTypes.assertThat(request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) - .size()).isEqualTo(1); - - for (RouteArgument routeArgument : request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED)) { - AssertionsForClassTypes.assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED); - AssertionsForClassTypes.assertThat(routeArgument.getValue()).isEqualTo("false"); - } + String result = metadataContainer.getRawMetadataMapValue(MetadataRouter.ROUTER_TYPE_METADATA, MetadataRouter.KEY_METADATA_KEYS); + AssertionsForClassTypes.assertThat(result).isEqualTo("k2"); } } @@ -258,6 +249,7 @@ public void testBuildNearbyRouteRequest() { try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) .thenReturn(testCallerService); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getApplicationContext()).thenReturn(new MockApplicationContext()); setTransitiveMetadata(); @@ -270,24 +262,10 @@ public void testBuildNearbyRouteRequest() { ProcessRoutersRequest request = compositeRule.buildProcessRoutersBaseRequest(serviceInstances); compositeRule.processRouterRequestInterceptors(request, routerContext); - Set routerMetadata = request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY); - - AssertionsForClassTypes.assertThat(request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA).size()) - .isEqualTo(0); - AssertionsForClassTypes.assertThat(routerMetadata.size()).isEqualTo(1); - - for (RouteArgument routeArgument : routerMetadata) { - AssertionsForClassTypes.assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED); - AssertionsForClassTypes.assertThat(routeArgument.getValue()).isEqualTo("true"); - } - - AssertionsForClassTypes.assertThat(request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) - .size()).isEqualTo(1); - - for (RouteArgument routeArgument : request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED)) { - AssertionsForClassTypes.assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED); - AssertionsForClassTypes.assertThat(routeArgument.getValue()).isEqualTo("false"); - } + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + String result = metadataContainer.getRawMetadataMapValue(NearbyRouter.ROUTER_TYPE_NEAR_BY, NearbyRouter.ROUTER_ENABLED); + AssertionsForClassTypes.assertThat(result).isEqualTo("true"); } } @@ -299,6 +277,7 @@ public void testBuildRuleBasedRouteRequest() { try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())). thenReturn(testCallerService); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getApplicationContext()).thenReturn(new MockApplicationContext()); setTransitiveMetadata(); @@ -311,13 +290,10 @@ public void testBuildRuleBasedRouteRequest() { ProcessRoutersRequest request = compositeRule.buildProcessRoutersBaseRequest(serviceInstances); compositeRule.processRouterRequestInterceptors(request, routerContext); - Set routerMetadata = request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED); - - AssertionsForClassTypes.assertThat(routerMetadata.size()).isEqualTo(3); - AssertionsForClassTypes.assertThat(request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA).size()) - .isEqualTo(0); - AssertionsForClassTypes.assertThat(request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()) - .isEqualTo(0); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + String result = metadataContainer.getRawMetadataMapValue(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, RuleBasedRouter.ROUTER_ENABLED); + AssertionsForClassTypes.assertThat(result).isEqualTo("true"); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java index b87602087..b14415f0c 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java @@ -20,7 +20,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.Set; import com.google.common.collect.Sets; import com.tencent.cloud.common.constant.RouterConstant; @@ -97,20 +96,4 @@ public void testGetLabel() { String resolvedLabel = routerContext.getLabel("k1"); assertThat(resolvedLabel).isEqualTo("v1"); } - - @Test - public void testGetLabelAsSet() { - Map labels = new HashMap<>(); - labels.put("k1", "v1,v2,v3"); - - PolarisRouterContext routerContext = new PolarisRouterContext(); - routerContext.putLabels(RouterConstant.ROUTER_LABELS, labels); - - Set resolvedLabels = routerContext.getLabelAsSet("k1"); - - assertThat(resolvedLabels.size()).isEqualTo(3); - assertThat(resolvedLabels).contains("v1"); - assertThat(resolvedLabels).contains("v2"); - assertThat(resolvedLabels).contains("v3"); - } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java deleted file mode 100644 index 128d3523d..000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java +++ /dev/null @@ -1,86 +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.polaris.router.beanprocessor; - -import com.tencent.cloud.common.util.BeanFactoryUtils; -import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor; -import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; -import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; -import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -/** - * Test for ${@link LoadBalancerInterceptorBeanPostProcessor}. - * - * @author lepdou 2022-05-26 - */ -@ExtendWith(MockitoExtension.class) -public class LoadBalancerInterceptorBeanPostProcessorTest { - - @Mock - private LoadBalancerClient loadBalancerClient; - @Mock - private LoadBalancerRequestFactory loadBalancerRequestFactory; - @Mock - private BeanFactory beanFactory; - - @Test - public void testWrapperLoadBalancerInterceptor() { - when(beanFactory.getBean(LoadBalancerRequestFactory.class)).thenReturn(loadBalancerRequestFactory); - when(beanFactory.getBean(LoadBalancerClient.class)).thenReturn(loadBalancerClient); - - try (MockedStatic mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) { - mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, SpringWebRouterLabelResolver.class)) - .thenReturn(null); - LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(loadBalancerClient, loadBalancerRequestFactory); - - LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor(); - processor.setBeanFactory(beanFactory); - - Object bean = processor.postProcessBeforeInitialization(loadBalancerInterceptor, ""); - - assertThat(bean).isInstanceOf(PolarisLoadBalancerInterceptor.class); - } - } - - @Test - public void testNotWrapperLoadBalancerInterceptor() { - LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor(); - processor.setBeanFactory(beanFactory); - - OtherBean otherBean = new OtherBean(); - Object bean = processor.postProcessBeforeInitialization(otherBean, ""); - assertThat(bean).isNotInstanceOf(PolarisLoadBalancerInterceptor.class); - assertThat(bean).isInstanceOf(OtherBean.class); - } - - static class OtherBean { - - } -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java index 572b6f92b..7b2598f33 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java @@ -37,7 +37,7 @@ void setUp() { @Test public void isEnabled() { - assertThat(properties.isEnabled()).isEqualTo(true); + assertThat(properties.isEnabled()).isEqualTo(false); } @Test @@ -49,6 +49,6 @@ public void setEnabled() { @Test public void testToString() { assertThat(properties.toString()) - .isEqualTo("PolarisNearByRouterProperties{enabled=true}"); + .isEqualTo("PolarisNearByRouterProperties{enabled=false, matchLevel='null'}"); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java index 9a8fc5697..1cc5e43ad 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java @@ -49,7 +49,7 @@ public void setEnabled() { @Test public void testToString() { assertThat(properties.toString()) - .isEqualTo("PolarisNearByRouterProperties{enabled=true}"); + .isEqualTo("PolarisRuleBasedRouterProperties{enabled=true, failOver=all}"); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java deleted file mode 100644 index dc1410f5d..000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java +++ /dev/null @@ -1,161 +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.polaris.router.feign; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; - -import feign.Request; -import feign.RequestTemplate; -import org.junit.jupiter.api.Test; - -import static java.util.stream.Collectors.toSet; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test for {@link FeignExpressionLabelUtils}. - *@author lepdou 2022-05-26 - */ -public class FeignExpressionLabelUtilsTest { - - @Test - public void testGetHeaderLabel() { - String headerKey = "uid"; - String headerValue = "1000"; - String headerKey2 = "teacher.age"; - String headerValue2 = "1000"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.header(headerKey, headerValue); - requestTemplate.header(headerKey2, headerValue2); - - String labelKey1 = "${http.header.uid}"; - String labelKey2 = "${http.header.name}"; - String labelKey3 = "${http.headername}"; - String labelKey4 = "${http.header.}"; - String labelKey5 = "${http.header.teacher.age}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, - Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(headerValue); - assertThat(result.get(labelKey5)).isEqualTo(headerValue2); - assertThat(result.get(labelKey2)).isBlank(); - assertThat(result.get(labelKey3)).isBlank(); - assertThat(result.get(labelKey4)).isBlank(); - } - - @Test - public void testGetQueryLabel() { - String headerKey = "uid"; - String headerValue = "1000"; - String headerKey2 = "teacher.age"; - String headerValue2 = "1000"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.query(headerKey, headerValue); - requestTemplate.query(headerKey2, headerValue2); - - String labelKey1 = "${http.query.uid}"; - String labelKey2 = "${http.query.name}"; - String labelKey3 = "${http.queryname}"; - String labelKey4 = "${http.query.}"; - String labelKey5 = "${http.query.teacher.age}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, - Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(headerValue); - assertThat(result.get(labelKey5)).isEqualTo(headerValue2); - assertThat(result.get(labelKey2)).isBlank(); - assertThat(result.get(labelKey3)).isBlank(); - assertThat(result.get(labelKey4)).isBlank(); - } - - @Test - public void testGetMethod() { - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.method(Request.HttpMethod.GET); - - String labelKey1 = "${http.method}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo("GET"); - } - - @Test - public void testGetUri() { - String uri = "/user/get"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.uri(uri); - requestTemplate.method(Request.HttpMethod.GET); - requestTemplate.target("http://localhost"); - requestTemplate = requestTemplate.resolve(new HashMap<>()); - - String labelKey1 = "${http.uri}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(uri); - } - - @Test - public void testGetUri2() { - String uri = "/"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.uri(uri); - requestTemplate.method(Request.HttpMethod.GET); - requestTemplate.target("http://localhost"); - requestTemplate = requestTemplate.resolve(new HashMap<>()); - - String labelKey1 = "${http.uri}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(uri); - } - - @Test - public void testGetCookie() { - String uri = "/"; - String cookieValue = "zhangsan"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.uri(uri); - requestTemplate.method(Request.HttpMethod.GET); - requestTemplate.target("http://localhost"); - requestTemplate = requestTemplate.resolve(new HashMap<>()); - requestTemplate.header("cookie", Collections.singleton("uid=zhangsan; auth-token=dfhuwshfy77")); - - String labelKey1 = "${http.cookie.uid}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(cookieValue); - } -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java index 6c60c6200..0b798b121 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java @@ -114,7 +114,9 @@ public void testHasNoneRouterContext() { mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); PolarisRouterContext routerContext = polarisFeignLoadBalancer.buildRouterContext(headers); - assertThat(routerContext).isNull(); + + Map routerLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS); + assertThat(routerLabels).isEmpty(); } } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java index 0e381c96e..7fad43476 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java @@ -18,124 +18,82 @@ package com.tencent.cloud.polaris.router.feign; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; +import java.util.List; import java.util.Map; -import java.util.Set; import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.constant.RouterConstant; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.metadata.StaticMetadataManager; -import com.tencent.cloud.common.util.ApplicationContextAwareUtils; -import com.tencent.cloud.common.util.JacksonUtils; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; import feign.RequestTemplate; -import feign.Target; +import io.netty.handler.codec.http.HttpHeaderNames; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; /** * test for {@link RouterLabelFeignInterceptor}. * - * @author lepdou, cheese8 + * @author lepdou 2022-05-26 */ -@ExtendWith(MockitoExtension.class) +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = RouterLabelFeignInterceptorTest.TestApplication.class, + properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", + "spring.cloud.gateway.enabled=false", "spring.cloud.polaris.router.zuul.enabled=false"}) public class RouterLabelFeignInterceptorTest { - @Mock - private StaticMetadataManager staticMetadataManager; - @Mock - private RouterRuleLabelResolver routerRuleLabelResolver; - @Mock - private FeignRouterLabelResolver routerLabelResolver; - @Mock - private PolarisContextProperties polarisContextProperties; - @Test - public void testResolveRouterLabel() throws UnsupportedEncodingException { - RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor( - Collections.singletonList(routerLabelResolver), - staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); + public void testRouterLabel() { + RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor(); assertThat(routerLabelFeignInterceptor.getOrder()).isEqualTo(OrderConstant.Client.Feign.ROUTER_LABEL_INTERCEPTOR_ORDER); // mock request template - RequestTemplate requestTemplate = new RequestTemplate(); + RequestTemplate requestTemplate = mock(RequestTemplate.class); String headerUidKey = "uid"; String headerUidValue = "1000"; - requestTemplate.header(headerUidKey, headerUidValue); - String peerService = "peerService"; - Target.EmptyTarget target = Target.EmptyTarget.create(Object.class, peerService); - requestTemplate.feignTarget(target); - - // mock ApplicationContextAwareUtils#getProperties - try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { - String testService = "callerService"; - mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) - .thenReturn(testService); - - MetadataContext metadataContext = Mockito.mock(MetadataContext.class); - - // mock transitive metadata - Map transitiveLabels = new HashMap<>(); - transitiveLabels.put("k1", "v1"); - transitiveLabels.put("k2", "v22"); - when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels); - - // mock MetadataContextHolder#get - try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { - mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); - - // mock expression rule labels - Set expressionKeys = new HashSet<>(); - expressionKeys.add("${http.header.uid}"); - expressionKeys.add("${http.header.name}"); - when(routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, - MetadataContext.LOCAL_SERVICE, peerService)).thenReturn(expressionKeys); - - // mock custom resolved labels from request - Map customResolvedLabels = new HashMap<>(); - customResolvedLabels.put("k2", "v2"); - customResolvedLabels.put("k3", "v3"); - when(routerLabelResolver.resolve(requestTemplate, expressionKeys)).thenReturn(customResolvedLabels); - - Map localMetadata = new HashMap<>(); - localMetadata.put("k3", "v31"); - localMetadata.put("k4", "v4"); - when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata); - - routerLabelFeignInterceptor.apply(requestTemplate); - - Collection routerLabels = requestTemplate.headers().get(RouterConstant.ROUTER_LABEL_HEADER); + Map> headerMap = new HashMap<>(); + headerMap.put(headerUidKey, Collections.singletonList(headerUidValue)); + headerMap.put(HttpHeaderNames.COOKIE.toString(), Collections.singletonList("k1=v1")); + doReturn(headerMap).when(requestTemplate).headers(); + doReturn(Request.HttpMethod.POST.toString()).when(requestTemplate).method(); + Request request = mock(Request.class); + doReturn(request).when(requestTemplate).request(); + doReturn("http://callee/test/path").when(request).url(); + Map> queryMap = new HashMap<>(); + queryMap.put("q1", Collections.singletonList("a1")); + doReturn(queryMap).when(requestTemplate).queries(); + + routerLabelFeignInterceptor.apply(requestTemplate); + + // get message metadata container + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.MESSAGE, false); + // method + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString()); + // path + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path"); + // header + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerUidKey)).isEqualTo(headerUidValue); + // cookie + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1"); + // query + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1"); + } - assertThat(routerLabels).isNotNull(); - for (String value : routerLabels) { - Map labels = JacksonUtils.deserialize2Map(URLDecoder.decode(value, "UTF-8")); + @SpringBootApplication + protected static class TestApplication { - assertThat(labels.get("k1")).isEqualTo("v1"); - assertThat(labels.get("k2")).isEqualTo("v22"); - assertThat(labels.get("k3")).isEqualTo("v3"); - assertThat(labels.get("k4")).isEqualTo("v4"); - assertThat(labels.get("${http.header.uid}")).isEqualTo(headerUidValue); - assertThat(labels.get("${http.header.name}")).isEqualTo(""); - } - } - } } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java index 9e729a182..37da92570 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java @@ -45,6 +45,7 @@ import org.springframework.http.HttpRequest; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -82,7 +83,7 @@ public void testRouterContext() { Set expressionKeys = new HashSet<>(); expressionKeys.add("${http.method}"); expressionKeys.add("${http.uri}"); - when(routerRuleLabelResolver.getExpressionLabelKeys(callerService, callerService, calleeService)).thenReturn(expressionKeys); + when(routerRuleLabelResolver.getExpressionLabelKeys(any(), any(), any())).thenReturn(expressionKeys); // mock custom resolved from request Map customResolvedLabels = new HashMap<>(); @@ -111,7 +112,6 @@ public void testRouterContext() { PolarisRouterContext routerContext = routerContextFactory.create(request, null, calleeService); verify(staticMetadataManager).getMergedStaticMetadata(); - verify(routerRuleLabelResolver).getExpressionLabelKeys(callerService, callerService, calleeService); verify(springWebRouterLabelResolver).resolve(request, null, expressionKeys); assertThat(routerContext.getLabels(RouterConstant.TRANSITIVE_LABELS).get("k1")).isEqualTo("v1"); diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java new file mode 100644 index 000000000..88ad69970 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java @@ -0,0 +1,128 @@ +/* + * 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.net.URI; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; +import io.netty.handler.codec.http.HttpHeaderNames; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.mock.http.client.MockClientHttpResponse; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * Test for {@link RouterLabelRestTemplateInterceptor}. + * + * @author liuye, Haotian Zhang + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = RouterLabelRestTemplateInterceptorTest.TestApplication.class, + properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", + "spring.cloud.gateway.enabled=false", "spring.cloud.polaris.router.zuul.enabled=false"}) +public class RouterLabelRestTemplateInterceptorTest { + + @Mock + private ClientHttpRequestExecution clientHttpRequestExecution; + + @Test + public void testRouterLabel() throws Exception { + RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor = new RouterLabelRestTemplateInterceptor(); + + assertThat(routerLabelRestTemplateInterceptor.getOrder()).isEqualTo(OrderConstant.Client.RestTemplate.ROUTER_LABEL_INTERCEPTOR_ORDER); + + String calleeService = "calleeService"; + HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/test/path?q1=a1"); + + ClientHttpResponse mockedResponse = new MockClientHttpResponse(new byte[] {}, HttpStatus.OK); + when(clientHttpRequestExecution.execute(eq(request), any())).thenReturn(mockedResponse); + + routerLabelRestTemplateInterceptor.intercept(request, null, clientHttpRequestExecution); + + // get message metadata container + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.MESSAGE, false); + // method + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString()); + // path + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path"); + // header + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000"); + // cookie + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1"); + // query + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1"); + } + + static class MockedHttpRequest implements HttpRequest { + + private final URI uri; + + private final HttpHeaders httpHeaders = new HttpHeaders(); + + MockedHttpRequest(String url) { + this.uri = URI.create(url); + this.httpHeaders.add("uid", "1000"); + this.httpHeaders.add(HttpHeaderNames.COOKIE.toString(), "k1=v1"); + } + + @Override + public HttpMethod getMethod() { + return HttpMethod.POST; + } + @Override + public String getMethodValue() { + return HttpMethod.POST.toString(); + } + @Override + public URI getURI() { + return uri; + } + + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java new file mode 100644 index 000000000..15de9c6d1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java @@ -0,0 +1,96 @@ +/* + * 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.scg; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import reactor.core.publisher.Mono; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.http.HttpCookie; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.server.ServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; + +/** + * Test for ${@link RouterLabelGlobalFilter}. + * + * @author Haotian Zhang + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = RouterLabelGlobalFilterTest.TestApplication.class, + properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", + "spring.main.web-application-type=reactive", "spring.cloud.polaris.router.zuul.enabled=false"}) +public class RouterLabelGlobalFilterTest { + + @Test + public void testRouterLabel() { + RouterLabelGlobalFilter routerLabelGlobalFilter = new RouterLabelGlobalFilter(); + + assertThat(routerLabelGlobalFilter.getOrder()) + .isEqualTo(LOAD_BALANCER_CLIENT_FILTER_ORDER - 1); + + MockServerHttpRequest request = MockServerHttpRequest.post("/test/path") + .header("uid", "1000") + .cookie(new HttpCookie("k1", "v1")) + .queryParam("q1", "a1") + .build(); + MockServerWebExchange mockWebExchange = new MockServerWebExchange.Builder(request).build(); + + routerLabelGlobalFilter.filter(mockWebExchange, new EmptyGatewayFilterChain()); + + // get message metadata container + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.MESSAGE, false); + // method + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString()); + // path + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path"); + // header + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000"); + // cookie + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1"); + // query + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1"); + } + + static class EmptyGatewayFilterChain implements GatewayFilterChain { + + @Override + public Mono filter(ServerWebExchange exchange) { + return Mono.empty(); + } + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java new file mode 100644 index 000000000..0836cf1ea --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java @@ -0,0 +1,55 @@ +/* + * 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.transformer; + +import com.tencent.cloud.common.pojo.PolarisServiceInstance; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * PolarisInstanceTransformerTest. + * + * @author sean yu + */ +public class PolarisInstanceTransformerTest { + + @Test + public void test() { + try ( + MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace")) + .thenReturn("default"); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service")) + .thenReturn("test"); + PolarisInstanceTransformer polarisInstanceTransformer = new PolarisInstanceTransformer(); + DefaultInstance instance = new DefaultInstance(); + instance.setZone("zone"); + PolarisServiceInstance polarisServiceInstance = new PolarisServiceInstance(instance); + Instance instance1 = polarisInstanceTransformer.transform(polarisServiceInstance); + assertThat(instance1.getZone()).isEqualTo("zone"); + } + } +} diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml index b0ace1045..6ba7d16d7 100644 --- a/spring-cloud-tencent-commons/pom.xml +++ b/spring-cloud-tencent-commons/pom.xml @@ -14,8 +14,8 @@ Spring Cloud Tencent Commons - 2.5 - 2.7 + 2.6 + 2.11.0 @@ -24,8 +24,17 @@ com.tencent.polaris polaris-model + + com.tencent.polaris + polaris-metadata + + + com.tencent.cloud + spring-cloud-starter-tencent-threadlocal-plugin + + org.springframework.boot spring-boot-autoconfigure @@ -41,6 +50,11 @@ spring-boot-starter-json + + org.springframework.boot + spring-boot-starter-validation + + org.springframework.cloud spring-cloud-starter @@ -70,6 +84,11 @@ true + + com.google.code.gson + gson + + org.springframework.cloud spring-cloud-starter-openfeign 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 3f8bb2555..f132920eb 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 @@ -62,9 +62,9 @@ public static class HeaderName { public static final String CUSTOM_DISPOSABLE_METADATA = "SCT-CUSTOM-DISPOSABLE-METADATA"; /** - * System Metadata. + * Application Metadata. */ - public static final String SYSTEM_METADATA = "SCT-SYSTEM-METADATA"; + public static final String APPLICATION_METADATA = "SCT-APPLICATION-METADATA"; /** * Metadata context. diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java index 633f069b4..98a9cd422 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java @@ -17,13 +17,14 @@ package com.tencent.cloud.common.constant; -import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter; import org.springframework.core.Ordered; +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER; + /** * Constant for order. * @@ -66,18 +67,15 @@ public static class RestTemplate { * Order constant for Spring Cloud Gateway. */ public static class Scg { - /** * Order of encode transfer metadata filter. - * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. */ - public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = 10150 + 1; + public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = LOAD_BALANCER_CLIENT_FILTER_ORDER + 1; /** * Order of enhanced filter. - * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. */ - public static final int ENHANCED_FILTER_ORDER = 10150 + 1; + public static final int ENHANCED_FILTER_ORDER = LOAD_BALANCER_CLIENT_FILTER_ORDER + 1; } /** @@ -167,7 +165,7 @@ public static final class Modifier { /** * Address modifier order. */ - public static Integer ADDRESS_ORDER = Integer.MIN_VALUE; + public static Integer ADDRESS_ORDER = Integer.MIN_VALUE + 10; /** * Discovery config modifier order. @@ -214,9 +212,19 @@ public static final class Modifier { */ public static Integer STAT_REPORTER_ORDER = 1; + /** + * Order of lossless configuration modifier. + */ + public static Integer LOSSLESS_ORDER = 2; + /** * Order of service contract configuration modifier. */ public static Integer SERVICE_CONTRACT_ORDER = Integer.MAX_VALUE - 9; + + /** + * Order of trace configuration modifier. + */ + public static Integer TRACE_ORDER = 2; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java index 00d9633a7..b66de0100 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java @@ -13,7 +13,6 @@ * 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.constant; @@ -21,7 +20,7 @@ /** * Router constants. * - * @author lepdou 2022-05-17 + * @author lepdou, Hoatian Zhang */ public final class RouterConstant { diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java new file mode 100644 index 000000000..d590e22c8 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java @@ -0,0 +1,38 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.constant; + +/** + * 预热所需枚举. + * @author jiangfan + */ +public final class WarmupCons { + + /** + * 预热保护阈值. + */ + public static double DEFAULT_PROTECTION_THRESHOLD_KEY = 50; + /** + * TSF 启动时间。预热开始时间. + */ + public static String TSF_START_TIME = "TSF_START_TIME"; + + private WarmupCons() { + + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java index 8fcd89855..321cfa945 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java @@ -21,22 +21,25 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Optional; +import java.util.function.BiConsumer; +import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.DiscoveryUtil; -import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataMapValue; +import com.tencent.polaris.metadata.core.MetadataObjectValue; +import com.tencent.polaris.metadata.core.MetadataStringValue; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.MetadataValue; +import com.tencent.polaris.metadata.core.TransitiveType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; -/** - * Metadata Context. - * - * @author Haotian Zhang - */ -public class MetadataContext { +public class MetadataContext extends com.tencent.polaris.metadata.core.manager.MetadataContext { /** * transitive context. @@ -53,6 +56,16 @@ public class MetadataContext { */ public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable"; + /** + * disposable Context. + */ + public static final String FRAGMENT_APPLICATION = "application"; + + /** + * upstream disposable Context. + */ + public static final String FRAGMENT_UPSTREAM_APPLICATION = "upstream-application"; + /** * the key of the header(key) list needed to be transmitted from upstream to downstream. */ @@ -63,6 +76,11 @@ public class MetadataContext { */ public static final String FRAGMENT_RAW_TRANSHEADERS_KV = "trans-headers-kv"; + /** + * the key of the header(key-value) list needed to be store as loadbalance data. + */ + public static final String FRAGMENT_LB_METADATA = "load-balance-metadata"; + private static final Logger LOG = LoggerFactory.getLogger(MetadataContext.class); /** * Namespace of local instance. @@ -85,8 +103,6 @@ public class MetadataContext { if (!StringUtils.hasText(namespace)) { LOG.error("namespace should not be blank. please configure spring.cloud.polaris.namespace or " + "spring.cloud.polaris.discovery.namespace"); - throw new RuntimeException("namespace should not be blank. please configure spring.cloud.polaris.namespace or " - + "spring.cloud.polaris.discovery.namespace"); } namespace = DiscoveryUtil.rewriteNamespace(namespace); LOCAL_NAMESPACE = namespace; @@ -101,29 +117,87 @@ public class MetadataContext { if (!StringUtils.hasText(serviceName)) { LOG.error("service name should not be blank. please configure spring.cloud.polaris.service or " + "spring.cloud.polaris.discovery.service or spring.application.name"); - throw new RuntimeException("service name should not be blank. please configure spring.cloud.polaris.service or " - + "spring.cloud.polaris.discovery.service or spring.application.name"); } serviceName = DiscoveryUtil.rewriteServiceId(serviceName); LOCAL_SERVICE = serviceName; } - private final Map> fragmentContexts; + public MetadataContext() { + super(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX); + } - private final Map loadbalancerMetadata; + private Map getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller); + Map values = new HashMap<>(); + metadataContainer.iterateMetadataValues(new BiConsumer() { + @Override + public void accept(String s, MetadataValue metadataValue) { + if (metadataValue instanceof MetadataStringValue) { + MetadataStringValue metadataStringValue = (MetadataStringValue) metadataValue; + if (metadataStringValue.getTransitiveType() == transitiveType) { + values.put(s, metadataStringValue.getStringValue()); + } + } + } + }); + return values; + } + public void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream, Map values) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + for (Map.Entry entry : values.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), transitiveType); + } + } - public MetadataContext() { - this.fragmentContexts = new ConcurrentHashMap<>(); - this.loadbalancerMetadata = new ConcurrentHashMap<>(); + private Map getMapMetadataAsMap(MetadataType metadataType, String mapKey, TransitiveType transitiveType, boolean caller) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller); + Map values = new HashMap<>(); + MetadataValue metadataValue = metadataContainer.getMetadataValue(mapKey); + if (!(metadataValue instanceof MetadataMapValue)) { + return values; + } + MetadataMapValue metadataMapValue = (MetadataMapValue) metadataValue; + metadataMapValue.iterateMapValues(new BiConsumer() { + @Override + public void accept(String s, MetadataValue metadataValue) { + if (metadataValue instanceof MetadataStringValue) { + MetadataStringValue metadataStringValue = (MetadataStringValue) metadataValue; + if (metadataStringValue.getTransitiveType() == transitiveType) { + values.put(s, metadataStringValue.getStringValue()); + } + } + } + }); + return values; + } + + private void putMapMetadataAsMap(MetadataType metadataType, String mapKey, + TransitiveType transitiveType, boolean caller, Map values) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller); + for (Map.Entry entry : values.entrySet()) { + metadataContainer.putMetadataMapValue(mapKey, entry.getKey(), entry.getValue(), transitiveType); + } } public Map getDisposableMetadata() { - return this.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + return getFragmentContext(FRAGMENT_DISPOSABLE); + } + + public void setDisposableMetadata(Map disposableMetadata) { + putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); } public Map getTransitiveMetadata() { - return this.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + return getFragmentContext(FRAGMENT_TRANSITIVE); + } + + public void setTransitiveMetadata(Map transitiveMetadata) { + putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); + } + + public Map getApplicationMetadata() { + return getFragmentContext(FRAGMENT_APPLICATION); } public Map getCustomMetadata() { @@ -140,51 +214,72 @@ public Map getCustomMetadata() { } public Map getTransHeaders() { - return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS); + return this.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS); } public Map getTransHeadersKV() { - return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV); + return getFragmentContext(FRAGMENT_RAW_TRANSHEADERS_KV); } public Map getLoadbalancerMetadata() { - return this.loadbalancerMetadata; - } - - public void setTransitiveMetadata(Map transitiveMetadata) { - this.putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); + MetadataContainer metadataContainer = getMetadataContainer(MetadataType.APPLICATION, false); + MetadataValue metadataValue = metadataContainer.getMetadataValue(FRAGMENT_LB_METADATA); + Map values = new HashMap<>(); + if (metadataValue instanceof MetadataMapValue) { + MetadataMapValue metadataMapValue = (MetadataMapValue) metadataValue; + metadataMapValue.iterateMapValues(new BiConsumer() { + @Override + public void accept(String s, MetadataValue metadataValue) { + if (metadataValue instanceof MetadataObjectValue) { + Optional objectValue = ((MetadataObjectValue) metadataValue).getObjectValue(); + objectValue.ifPresent(o -> values.put(s, o)); + } + } + }); + } + return values; } - public void setDisposableMetadata(Map disposableMetadata) { - this.putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); + public void setLoadbalancer(String key, Object value) { + MetadataContainer metadataContainer = getMetadataContainer(MetadataType.APPLICATION, false); + metadataContainer.putMetadataMapObjectValue(FRAGMENT_LB_METADATA, key, value); } public void setUpstreamDisposableMetadata(Map upstreamDisposableMetadata) { - this.putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); + putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); } public void setTransHeadersKV(String key, String value) { - this.putContext(FRAGMENT_RAW_TRANSHEADERS_KV, key, value); + putContext(FRAGMENT_RAW_TRANSHEADERS_KV, key, value); } public void setTransHeaders(String key, String value) { - this.putContext(FRAGMENT_RAW_TRANSHEADERS, key, value); - } - - public void setLoadbalancer(String key, Object value) { - this.loadbalancerMetadata.put(key, value); + putContext(FRAGMENT_RAW_TRANSHEADERS, key, value); } public Map getFragmentContext(String fragment) { - Map fragmentContext = fragmentContexts.get(fragment); - if (fragmentContext == null) { - return Collections.emptyMap(); + switch (fragment) { + case FRAGMENT_TRANSITIVE: + return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.PASS_THROUGH, false); + case FRAGMENT_DISPOSABLE: + return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false); + case FRAGMENT_UPSTREAM_DISPOSABLE: + return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true); + case FRAGMENT_APPLICATION: + return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false); + case FRAGMENT_UPSTREAM_APPLICATION: + return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true); + case FRAGMENT_RAW_TRANSHEADERS: + return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false); + case FRAGMENT_RAW_TRANSHEADERS_KV: + return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.NONE, false); + default: + return getMapMetadataAsMap(MetadataType.CUSTOM, fragment, TransitiveType.NONE, false); } - return Collections.unmodifiableMap(fragmentContext); } public String getContext(String fragment, String key) { - Map fragmentContext = fragmentContexts.get(fragment); + Map fragmentContext = getFragmentContext(fragment); if (fragmentContext == null) { return null; } @@ -192,22 +287,37 @@ public String getContext(String fragment, String key) { } public void putContext(String fragment, String key, String value) { - Map fragmentContext = fragmentContexts.get(fragment); - if (fragmentContext == null) { - fragmentContext = new ConcurrentHashMap<>(); - fragmentContexts.put(fragment, fragmentContext); - } - fragmentContext.put(key, value); + Map values = new HashMap<>(); + values.put(key, value); + putFragmentContext(fragment, values); } public void putFragmentContext(String fragment, Map context) { - fragmentContexts.put(fragment, context); - } - - @Override - public String toString() { - return "MetadataContext{" + - "fragmentContexts=" + JacksonUtils.serialize2Json(fragmentContexts) + - '}'; + switch (fragment) { + case FRAGMENT_TRANSITIVE: + putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.PASS_THROUGH, false, context); + break; + case FRAGMENT_DISPOSABLE: + putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false, context); + break; + case FRAGMENT_UPSTREAM_DISPOSABLE: + putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true, context); + break; + case FRAGMENT_APPLICATION: + putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false, context); + break; + case FRAGMENT_UPSTREAM_APPLICATION: + putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true, context); + break; + case FRAGMENT_RAW_TRANSHEADERS: + putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false, context); + break; + case FRAGMENT_RAW_TRANSHEADERS_KV: + putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.NONE, false, context); + break; + default: + putMapMetadataAsMap(MetadataType.CUSTOM, fragment, TransitiveType.NONE, false, context); + break; + } } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index 4251b8d3d..2a1ec1e3e 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 @@ -22,8 +22,12 @@ import java.util.Map; import java.util.Optional; -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -38,48 +42,60 @@ */ public final class MetadataContextHolder { - private static final ThreadLocal METADATA_CONTEXT = new InheritableThreadLocal<>(); - - private static MetadataLocalProperties metadataLocalProperties; - private static StaticMetadataManager staticMetadataManager; + static { + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.setInitializer(MetadataContextHolder::createMetadataManager); + } + private MetadataContextHolder() { } - /** - * Get metadata context. Create if not existing. - * @return METADATA_CONTEXT - */ public static MetadataContext get() { - if (METADATA_CONTEXT.get() != null) { - return METADATA_CONTEXT.get(); - } + return (MetadataContext) com.tencent.polaris.metadata.core.manager.MetadataContextHolder.getOrCreate(); + } - if (metadataLocalProperties == null) { - metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext().getBean(MetadataLocalProperties.class); - } + private static MetadataContext createMetadataManager() { + MetadataContext metadataManager = new MetadataContext(); if (staticMetadataManager == null) { - staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext().getBean(StaticMetadataManager.class); + staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() + .getBean(StaticMetadataManager.class); } - - // init static transitive metadata - MetadataContext metadataContext = new MetadataContext(); - metadataContext.setTransitiveMetadata(staticMetadataManager.getMergedStaticTransitiveMetadata()); - metadataContext.setDisposableMetadata(staticMetadataManager.getMergedStaticDisposableMetadata()); - + // local custom metadata + MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); + Map mergedStaticMetadata = staticMetadataManager.getMergedStaticMetadata(); + for (Map.Entry entry : mergedStaticMetadata.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.NONE); + } + // local custom transitive metadata + Map mergedStaticTransitiveMetadata = staticMetadataManager.getMergedStaticTransitiveMetadata(); + for (Map.Entry entry : mergedStaticTransitiveMetadata.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); + } + // local custom disposable metadata + Map mergedStaticDisposableMetadata = staticMetadataManager.getMergedStaticDisposableMetadata(); + for (Map.Entry entry : mergedStaticDisposableMetadata.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } + // local trans header if (StringUtils.hasText(staticMetadataManager.getTransHeader())) { - metadataContext.setTransHeaders(staticMetadataManager.getTransHeader(), ""); + String transHeader = staticMetadataManager.getTransHeader(); + metadataContainer.putMetadataMapValue(MetadataContext.FRAGMENT_RAW_TRANSHEADERS, transHeader, "", TransitiveType.NONE); } - METADATA_CONTEXT.set(metadataContext); - - return METADATA_CONTEXT.get(); + // local application disposable metadata + MetadataContainer applicationMetadataContainer = metadataManager.getMetadataContainer(MetadataType.APPLICATION, false); + Map mergedApplicationMetadata = staticMetadataManager.getMergedStaticMetadata(); + for (Map.Entry entry : mergedApplicationMetadata.entrySet()) { + applicationMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } + return metadataManager; } /** * Get disposable metadata value from thread local . - * @param key metadata key . + * + * @param key metadata key . * @param upstream upstream disposable , otherwise will return local static disposable metadata . * @return target disposable metadata value . */ @@ -95,6 +111,7 @@ public static Optional getDisposableMetadata(String key, boolean upstrea /** * Get all disposable metadata value from thread local . + * * @param upstream upstream disposable , otherwise will return local static disposable metadata . * @return target disposable metadata value . */ @@ -112,44 +129,58 @@ public static Map getAllDisposableMetadata(boolean upstream) { /** * Set metadata context. + * * @param metadataContext metadata context */ public static void set(MetadataContext metadataContext) { - METADATA_CONTEXT.set(metadataContext); + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.set(metadataContext); } /** * Save metadata map to thread local. + * * @param dynamicTransitiveMetadata custom metadata collection - * @param dynamicDisposableMetadata custom disposable metadata connection + * @param dynamicDisposableMetadata custom disposable metadata collection + * @param dynamicApplicationMetadata application metadata collection + * @param callerMetadataProvider caller metadata provider */ - public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata) { - // Init ThreadLocal. - MetadataContextHolder.remove(); - MetadataContext metadataContext = MetadataContextHolder.get(); - - // Save transitive metadata to ThreadLocal. - if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { - Map staticTransitiveMetadata = metadataContext.getTransitiveMetadata(); - Map mergedTransitiveMetadata = new HashMap<>(); - mergedTransitiveMetadata.putAll(staticTransitiveMetadata); - mergedTransitiveMetadata.putAll(dynamicTransitiveMetadata); - metadataContext.setTransitiveMetadata(Collections.unmodifiableMap(mergedTransitiveMetadata)); - } - if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { - Map mergedUpstreamDisposableMetadata = new HashMap<>(dynamicDisposableMetadata); - metadataContext.setUpstreamDisposableMetadata(Collections.unmodifiableMap(mergedUpstreamDisposableMetadata)); - } - - Map staticDisposableMetadata = metadataContext.getFragmentContext(FRAGMENT_DISPOSABLE); - metadataContext.setDisposableMetadata(Collections.unmodifiableMap(staticDisposableMetadata)); - MetadataContextHolder.set(metadataContext); + public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata, + Map dynamicApplicationMetadata, MetadataProvider callerMetadataProvider) { + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> { + // caller transitive metadata to local custom transitive metadata + MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); + if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { + for (Map.Entry entry : dynamicTransitiveMetadata.entrySet()) { + metadataContainerUpstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); + } + } + // caller disposable metadata to caller custom disposable metadata + MetadataContainer metadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, true); + if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { + for (Map.Entry entry : dynamicDisposableMetadata.entrySet()) { + metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } + } + // caller application metadata to caller application disposable metadata + MetadataContainer applicationMetadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.APPLICATION, true); + if (!CollectionUtils.isEmpty(dynamicApplicationMetadata)) { + for (Map.Entry entry : dynamicApplicationMetadata.entrySet()) { + applicationMetadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } + } + + // caller message metadata + if (callerMetadataProvider != null) { + MessageMetadataContainer callerMessageContainer = metadataManager.getMetadataContainer(MetadataType.MESSAGE, true); + callerMessageContainer.setMetadataProvider(callerMetadataProvider); + } + }); } /** * Remove metadata context. */ public static void remove() { - METADATA_CONTEXT.remove(); + com.tencent.polaris.metadata.core.manager.MetadataContextHolder.remove(); } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java index f0171cebb..2a70e9f66 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java @@ -261,7 +261,8 @@ private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperti List instanceMetadataProviders) { // resolve region info if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { - Set providerRegions = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getRegion).filter(region -> !StringUtils.isBlank(region)).collect(Collectors.toSet()); + Set providerRegions = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getRegion) + .filter(region -> !StringUtils.isBlank(region)).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(providerRegions)) { if (providerRegions.size() > 1) { throw new IllegalArgumentException("Multiple Regions Provided in InstanceMetadataProviders"); @@ -278,7 +279,8 @@ private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperti // resolve zone info if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { - Set providerZones = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getZone).filter(zone -> !StringUtils.isBlank(zone)).collect(Collectors.toSet()); + Set providerZones = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getZone) + .filter(zone -> !StringUtils.isBlank(zone)).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(providerZones)) { if (providerZones.size() > 1) { throw new IllegalArgumentException("Multiple Zones Provided in InstanceMetadataProviders"); @@ -295,7 +297,8 @@ private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperti // resolve campus info if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { - Set providerCampus = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getCampus).filter(campus -> !StringUtils.isBlank(campus)).collect(Collectors.toSet()); + Set providerCampus = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getCampus) + .filter(campus -> !StringUtils.isBlank(campus)).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(providerCampus)) { if (providerCampus.size() > 1) { throw new IllegalArgumentException("Multiple Campus Provided in InstanceMetadataProviders"); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java index ea7954c37..b21ab2f92 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java @@ -30,7 +30,7 @@ * * @author shuiqingliu **/ -@Endpoint(id = "polaris-metadata") +@Endpoint(id = "polarismetadata") public class PolarisMetadataEndpoint { private final StaticMetadataManager staticMetadataManager; @@ -41,7 +41,7 @@ public PolarisMetadataEndpoint(StaticMetadataManager staticMetadataManager) { @ReadOperation public Map metadata() { - Map result = new HashMap<>(); + Map result = new HashMap<>(); result.put("Env", staticMetadataManager.getAllEnvMetadata()); result.put("EnvTransitive", staticMetadataManager.getEnvTransitiveMetadata()); result.put("ConfigTransitive", staticMetadataManager.getConfigTransitiveMetadata()); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java index d5f28e597..8af64d5e5 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java @@ -18,10 +18,12 @@ package com.tencent.cloud.common.pojo; import java.net.URI; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.utils.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.client.DefaultServiceInstance; @@ -40,7 +42,13 @@ public class PolarisServiceInstance implements ServiceInstance { private final String scheme; + private final Map serviceMetadata; + public PolarisServiceInstance(Instance instance) { + this(instance, null); + } + + public PolarisServiceInstance(Instance instance, Map metadata) { this.instance = instance; this.isSecure = StringUtils.equalsIgnoreCase(instance.getProtocol(), "https"); if (isSecure) { @@ -49,6 +57,10 @@ public PolarisServiceInstance(Instance instance) { else { scheme = "http"; } + this.serviceMetadata = new HashMap<>(); + if (CollectionUtils.isNotEmpty(metadata)) { + this.serviceMetadata.putAll(metadata); + } } public Instance getPolarisInstance() { @@ -95,6 +107,10 @@ public String getScheme() { return this.scheme; } + public Map getServiceMetadata() { + return serviceMetadata; + } + /** * To fix loadbalancer not working bug when importing spring-retry. * @param o object @@ -116,4 +132,14 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(instance, scheme); } + + @Override + public String toString() { + return "PolarisServiceInstance{" + + "instance=" + instance + + ", isSecure=" + isSecure + + ", scheme='" + scheme + '\'' + + ", serviceMetadata=" + serviceMetadata + + '}'; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java new file mode 100644 index 000000000..2044bcb01 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.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.common.tsf; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Condition that if Polaris enabled. + * + * @author Haotian Zhang + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Conditional(ConditionalOnTsfConsulEnabled.OnTsfEnabledCondition.class) +public @interface ConditionalOnTsfConsulEnabled { + + class OnTsfEnabledCondition implements Condition { + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + Environment environment = conditionContext.getEnvironment(); + boolean tsfConsulEnable = false; + + String tsfAppId = environment.getProperty("tsf_app_id", ""); + if (StringUtils.isNotBlank(tsfAppId)) { + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + String tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); + if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("tse_polaris_ip"))) { + tsePolarisAddress = "grpc://" + environment.getProperty("tse_polaris_ip") + ":8091"; + } + tsfConsulEnable = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); + } + + return tsfConsulEnable; + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java new file mode 100644 index 000000000..dee92deb0 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java @@ -0,0 +1,50 @@ +/* + * 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.tsf; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Condition that if Polaris enabled. + * + * @author Haotian Zhang + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Conditional(ConditionalOnTsfEnabled.OnTsfEnabledCondition.class) +public @interface ConditionalOnTsfEnabled { + + class OnTsfEnabledCondition implements Condition { + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + String tsfAppId = conditionContext.getEnvironment().getProperty("tsf_app_id", ""); + return StringUtils.isNotBlank(tsfAppId); + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java index c5509312e..880970499 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java @@ -19,18 +19,21 @@ package com.tencent.cloud.common.util; import java.io.IOException; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.NetworkInterface; import java.net.Socket; import java.net.URI; import java.util.ArrayList; import java.util.Collections; +import java.util.Enumeration; import java.util.List; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; /** * the utils of parse address. @@ -43,11 +46,17 @@ public final class AddressUtils { private static final String ADDRESS_SEPARATOR = ","; + private final static Boolean hasIpv6Address; + + static { + hasIpv6Address = hasIpv6Address(); + } + private AddressUtils() { } public static List parseAddressList(String addressInfo) { - if (StringUtils.isEmpty(addressInfo)) { + if (StringUtils.isBlank(addressInfo)) { return Collections.emptyList(); } List addressList = new ArrayList<>(); @@ -77,4 +86,63 @@ public static boolean accessible(String ip, int port, int timeout) { } return true; } + + public static boolean preferIpv6() { + if (Boolean.FALSE.equals(hasIpv6Address)) { + LOGGER.debug("AddressUtils.preferIpv6 hasIpv6Address = false"); + return false; + } + if ("true".equalsIgnoreCase(System.getenv("tsf_prefer_ipv6"))) { + LOGGER.debug("AddressUtils.preferIpv6 System.getenv = true"); + return true; + } + if ("true".equalsIgnoreCase(System.getProperty("tsf_prefer_ipv6"))) { + LOGGER.debug("AddressUtils.preferIpv6 System.getProperty = true"); + return true; + } + if ("true".equalsIgnoreCase(BeanFactoryUtils.resolve("${tsf_prefer_ipv6}"))) { + LOGGER.debug("AddressUtils.preferIpv6 BeanFactoryUtils.resolve = true"); + return true; + } + LOGGER.debug("AddressUtils.preferIpv6 result = false"); + return false; + } + + /** + * Determine whether environment has an ipv6 address. + */ + private static boolean hasIpv6Address() { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + LOGGER.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } + else if (result != null) { + continue; + } + + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements(); ) { + InetAddress address = addrs.nextElement(); + if (address instanceof Inet6Address + && !address.isLinkLocalAddress() + && !address.isLoopbackAddress()) { + LOGGER.trace("Found non-loopback interface: " + ifc.getDisplayName()); + return true; + } + } + } + } + } + catch (IOException ex) { + LOGGER.error("Cannot get first non-loopback address", ex); + } + return false; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java index 98a6a4341..60421b02c 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ApplicationContextAwareUtils.java @@ -17,6 +17,10 @@ package com.tencent.cloud.common.util; +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -29,6 +33,8 @@ */ public class ApplicationContextAwareUtils implements ApplicationContextAware { + private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationContextAwareUtils.class); + private static ApplicationContext applicationContext; /** @@ -50,7 +56,15 @@ public void setApplicationContext(@NonNull ApplicationContext applicationContext * @return property value */ public static String getProperties(String key) { - return applicationContext.getEnvironment().getProperty(key); + if (applicationContext != null) { + return applicationContext.getEnvironment().getProperty(key); + } + LOGGER.warn("applicationContext is null, try to get property from System.getenv or System.getProperty"); + String property = System.getenv(key); + if (StringUtils.isBlank(property)) { + property = System.getProperty(key); + } + return property; } /** @@ -60,6 +74,14 @@ public static String getProperties(String key) { * @return property value */ public static String getProperties(String key, String defaultValue) { - return applicationContext.getEnvironment().getProperty(key, defaultValue); + if (applicationContext != null) { + return applicationContext.getEnvironment().getProperty(key, defaultValue); + } + LOGGER.warn("applicationContext is null, try to get property from System.getenv or System.getProperty"); + String property = System.getenv(key); + if (StringUtils.isBlank(property)) { + property = System.getProperty(key, defaultValue); + } + return property; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java index e7729cf18..cd982c680 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java @@ -13,7 +13,6 @@ * 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; @@ -22,8 +21,15 @@ import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.stereotype.Component; import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; @@ -31,9 +37,30 @@ * the utils for bean factory. * @author lepdou 2022-05-23 */ -public final class BeanFactoryUtils { +@Component +public final class BeanFactoryUtils implements BeanFactoryAware { + + private static final Logger LOGGER = LoggerFactory.getLogger(BeanFactoryUtils.class); - private BeanFactoryUtils() { + private static BeanFactory beanFactory; + + /** + * Dynamic parsing of spring @Value. + * + * @param value something like ${} + * @return return null if the parsing fails or the object is not found. + */ + public static String resolve(String value) { + try { + if (beanFactory instanceof ConfigurableBeanFactory) { + return ((ConfigurableBeanFactory) beanFactory).resolveEmbeddedValue(value); + } + } + catch (Exception e) { + LOGGER.error("resolve {} failed.", value, e); + } + + return null; } public static List getBeans(BeanFactory beanFactory, Class requiredType) { @@ -45,4 +72,9 @@ public static List getBeans(BeanFactory beanFactory, Class requiredTyp Map beanMap = beansOfTypeIncludingAncestors((ListableBeanFactory) beanFactory, requiredType); return new ArrayList<>(beanMap.values()); } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + BeanFactoryUtils.beanFactory = beanFactory; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java new file mode 100644 index 000000000..89b1d37f3 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.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.common.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author kysonli + */ +public final class GzipUtil { + + private static final Logger LOG = LoggerFactory.getLogger(GzipUtil.class); + + private GzipUtil() { + } + + public static byte[] compress(String data, String charsetName) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(bos)) { + gzip.write(data.getBytes(charsetName)); + gzip.finish(); + return bos.toByteArray(); + } + catch (IOException e) { + LOG.error("compress data [{}] error", data, e); + throw e; + } + } + + public static String compressBase64Encode(String data, String charsetName) throws IOException { + byte[] compressData = compress(data, charsetName); + return new String(Base64.getEncoder().encode(compressData), charsetName); + } + + public static String compressBase64Encode(byte[] byteData, String charsetName) throws IOException { + byte[] compressData = compress(new String(byteData, charsetName), charsetName); + return Base64.getEncoder().encodeToString(compressData); + } + + + public static byte[] decompress(byte[] zipData) throws IOException { + try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData); GZIPInputStream gzip = new GZIPInputStream(bis); ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + byte[] buf = new byte[256]; + int num; + while ((num = gzip.read(buf)) != -1) { + bos.write(buf, 0, num); + } + bos.flush(); + return bos.toByteArray(); + } + catch (IOException e) { + LOG.error("decompress zip data error", e); + throw e; + } + } + + public static String base64DecodeDecompress(String data, String charsetName) throws IOException { + byte[] base64DecodeData = Base64.getDecoder().decode(data); + return new String(decompress(base64DecodeData), charsetName); + } + + public static String base64DecodeDecompress(String data) throws IOException { + return base64DecodeDecompress(data, "utf-8"); + } + +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java index a6c14a0d6..b4862ce05 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java @@ -31,7 +31,7 @@ /** * Utils for Jackson. * - * @author Haotian Zhang + * @author Haotian Zhang, cheese8 */ public final class JacksonUtils { @@ -93,7 +93,6 @@ public static T deserialize(String jsonStr, Class type) { * @param jsonStr Json String * @return Map */ - @SuppressWarnings("unchecked") public static Map deserialize2Map(String jsonStr) { try { if (StringUtils.hasText(jsonStr)) { @@ -107,7 +106,8 @@ public static Map deserialize2Map(String jsonStr) { return new HashMap<>(); } catch (JsonProcessingException e) { - LOG.error("Json to map failed. check if the format of the json string[{}] is correct.", jsonStr, e); + LOG.error( + "Json to map failed. check if the format of the json string[{}] is correct.", jsonStr, e); throw new RuntimeException("Json to map failed.", e); } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/util/OkHttpUtil.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java similarity index 87% rename from spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/util/OkHttpUtil.java rename to spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java index f8580ee19..a65219b2a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/util/OkHttpUtil.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.util; +package com.tencent.cloud.common.util; import java.io.BufferedReader; import java.io.InputStreamReader; @@ -55,7 +55,7 @@ private OkHttpUtil() { public static boolean get(String path, Map headers) { HttpURLConnection conn = null; try { - URL url = new java.net.URL(path); + URL url = new URL(path); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); @@ -87,4 +87,12 @@ public static boolean get(String path, Map headers) { } return false; } + + public static boolean checkUrl(String host, Integer port, String endpoint, Map headers) { + if (!endpoint.startsWith("/")) { + endpoint = "/" + endpoint; + } + String checkUrl = String.format("http://%s:%s%s", host, port, endpoint); + return get(checkUrl, headers); + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java index b9f75b94a..d822b1943 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java @@ -68,4 +68,20 @@ public static Object getFieldValue(Object instance, String fieldName) { } return null; } + + public static void setFieldValue(Object instance, String fieldName, Object value) { + Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName); + if (field == null) { + return; + } + + field.setAccessible(true); + + try { + setField(field, instance, value); + } + finally { + field.setAccessible(false); + } + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java new file mode 100644 index 000000000..6190f33c4 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/UrlUtils.java @@ -0,0 +1,78 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.util.StringUtils; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +/** + * Utils for URLDecoder/URLEncoder. + * + * @author Shedfree Wu + */ +public final class UrlUtils { + + private static final Logger LOG = LoggerFactory.getLogger(UrlUtils.class); + + private UrlUtils() { + } + + public static String decode(String s) { + return decode(s, UTF_8); + } + + public static String decode(String s, String enc) { + if (!StringUtils.hasText(s)) { + return s; + } + try { + return URLDecoder.decode(s, enc); + } + catch (UnsupportedEncodingException e) { + LOG.warn("Runtime system does not support {} coding. s:{}, msg:{}", enc, s, e.getMessage()); + // return original string + return s; + } + } + + public static String encode(String s) { + return encode(s, UTF_8); + } + + public static String encode(String s, String enc) { + if (!StringUtils.hasText(s)) { + return s; + } + try { + return URLEncoder.encode(s, enc); + } + catch (UnsupportedEncodingException e) { + LOG.warn("Runtime system does not support {} coding. s:{}, msg:{}", enc, s, e.getMessage()); + // return original string + return s; + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java index c7029deff..203fa4727 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java @@ -13,7 +13,6 @@ * 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.expresstion; @@ -138,12 +137,16 @@ public static boolean isCallerIPLabel(String expression) { } public static String getQueryValue(String queryString, String queryKey) { + return getQueryValue(queryString, queryKey, null); + } + + public static String getQueryValue(String queryString, String queryKey, String defaultValue) { if (StringUtils.isBlank(queryString)) { - return StringUtils.EMPTY; + return defaultValue; } String[] queries = StringUtils.split(queryString, "&"); if (queries == null || queries.length == 0) { - return StringUtils.EMPTY; + return defaultValue; } for (String query : queries) { String[] queryKV = StringUtils.split(query, "="); @@ -151,36 +154,36 @@ public static String getQueryValue(String queryString, String queryKey) { return queryKV[1]; } } - return StringUtils.EMPTY; + return defaultValue; } public static String getFirstValue(Map> valueMaps, String key) { if (CollectionUtils.isEmpty(valueMaps)) { - return StringUtils.EMPTY; + return null; } Collection values = valueMaps.get(key); if (CollectionUtils.isEmpty(values)) { - return StringUtils.EMPTY; + return null; } for (String value : values) { return value; } - return StringUtils.EMPTY; + return null; } public static String getCookieFirstValue(Map> valueMaps, String key) { if (CollectionUtils.isEmpty(valueMaps)) { - return StringUtils.EMPTY; + return null; } Collection values = valueMaps.get(HttpHeaderNames.COOKIE.toString()); if (CollectionUtils.isEmpty(values)) { - return StringUtils.EMPTY; + return null; } for (String value : values) { @@ -192,6 +195,6 @@ public static String getCookieFirstValue(Map> valueMa } } } - return StringUtils.EMPTY; + return null; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java index a5f28e8fd..dff35783a 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java @@ -53,7 +53,7 @@ public boolean isHeaderLabel(String expression) { @Override public String parseHeaderKey(String expression) { - return expression.substring(LABEL_HEADER_PREFIX_LEN, expression.length() - 1); + return StringUtils.substring(expression, LABEL_HEADER_PREFIX_LEN, expression.length() - 1); } @Override @@ -63,7 +63,7 @@ public boolean isQueryLabel(String expression) { @Override public String parseQueryKey(String expression) { - return expression.substring(LABEL_QUERY_PREFIX_LEN, expression.length() - 1); + return StringUtils.substring(expression, LABEL_QUERY_PREFIX_LEN, expression.length() - 1); } @Override @@ -73,7 +73,7 @@ public boolean isCookieLabel(String expression) { @Override public String parseCookieKey(String expression) { - return expression.substring(LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); + return StringUtils.substring(expression, LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); } @Override diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java index a054c8f65..45ad670b0 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ServletExpressionLabelUtils.java @@ -83,14 +83,18 @@ else if (ExpressionLabelUtils.isUriLabel(labelKey)) { } public static String getCookieValue(Cookie[] cookies, String key) { + return getCookieValue(cookies, key, StringUtils.EMPTY); + } + + public static String getCookieValue(Cookie[] cookies, String key, String defaultValue) { if (cookies == null || cookies.length == 0) { - return StringUtils.EMPTY; + return defaultValue; } for (Cookie cookie : cookies) { if (StringUtils.equals(cookie.getName(), key)) { return cookie.getValue(); } } - return StringUtils.EMPTY; + return defaultValue; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java index b8b1a59ad..7e4276d57 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java @@ -75,7 +75,7 @@ else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey)); } else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { - labels.put(labelKey, exchange.getRequest().getMethodValue()); + labels.put(labelKey, exchange.getRequest().getMethod().toString()); } else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, exchange.getRequest().getURI().getPath()); @@ -118,7 +118,7 @@ else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { labels.put(labelKey, getCookieValue(request, cookieKey)); } else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { - labels.put(labelKey, request.getMethodValue()); + labels.put(labelKey, request.getMethod().toString()); } else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, request.getURI().getPath()); @@ -129,29 +129,41 @@ else if (ExpressionLabelUtils.isUriLabel(labelKey)) { } public static String getHeaderValue(ServerHttpRequest request, String key) { + return getHeaderValue(request, key, null); + } + + public static String getHeaderValue(ServerHttpRequest request, String key, String defaultValue) { String value = request.getHeaders().getFirst(key); if (value == null) { - return StringUtils.EMPTY; + return defaultValue; } return value; } public static String getQueryValue(ServerHttpRequest request, String key) { + return getQueryValue(request, key, null); + } + + public static String getQueryValue(ServerHttpRequest request, String key, String defaultValue) { MultiValueMap queries = request.getQueryParams(); if (CollectionUtils.isEmpty(queries)) { - return StringUtils.EMPTY; + return defaultValue; } String value = queries.getFirst(key); if (value == null) { - return StringUtils.EMPTY; + return defaultValue; } return value; } public static String getCookieValue(ServerHttpRequest request, String key) { + return getCookieValue(request, key, null); + } + + public static String getCookieValue(ServerHttpRequest request, String key, String defaultValue) { HttpCookie cookie = request.getCookies().getFirst(key); if (cookie == null) { - return StringUtils.EMPTY; + return defaultValue; } return cookie.getValue(); } @@ -169,7 +181,7 @@ public static String getQueryValue(HttpRequest request, String key) { public static String getCookieValue(HttpRequest request, String key) { String first = request.getHeaders().getFirst(HttpHeaders.COOKIE); if (StringUtils.isEmpty(first)) { - return StringUtils.EMPTY; + return null; } String[] cookieArray = StringUtils.split(first, ";"); for (String cookieItem : cookieArray) { @@ -178,6 +190,6 @@ public static String getCookieValue(HttpRequest request, String key) { return cookieKv[1]; } } - return StringUtils.EMPTY; + return null; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java new file mode 100644 index 000000000..e0afb55b6 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java @@ -0,0 +1,320 @@ +/* + * 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.inet; + +import java.io.Closeable; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import com.tencent.cloud.common.util.AddressUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.commons.util.InetUtilsProperties; + + +/** + * Extend from {@link InetUtils}. + * + * @author Haotian Zhang + */ +public class PolarisInetUtils implements Closeable { + + private static final Logger logger = LoggerFactory.getLogger(PolarisInetUtils.class); + // TODO: maybe shutdown the thread pool if it isn't being used? + private final ExecutorService executorService; + private final InetUtilsProperties properties; + + public PolarisInetUtils(final InetUtilsProperties properties) { + this.properties = properties; + this.executorService = Executors + .newSingleThreadExecutor(r -> { + Thread thread = new Thread(r); + thread.setName(InetUtilsProperties.PREFIX); + thread.setDaemon(true); + return thread; + }); + } + + public static String getIpString(boolean _ipv6) { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + logger.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } + else if (result != null) { + continue; + } + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements(); ) { + InetAddress address = addrs.nextElement(); + if (_ipv6) { + if (address instanceof Inet6Address + && !address.isLinkLocalAddress() + && !address.isLoopbackAddress() + ) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + else { + if (address instanceof Inet4Address + && !address.isLoopbackAddress() + ) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + } + } + } + } + catch (IOException ex) { + logger.error("Cannot get first non-loopback address", ex); + } + + if (result == null) { + return null; + } + + if (result.getHostAddress().contains("%")) { + return result.getHostAddress().split("%")[0]; + } + else { + return result.getHostAddress(); + } + } + + @Override + public void close() { + executorService.shutdown(); + } + + public InetUtils.HostInfo findFirstNonLoopbackHostInfo() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address != null) { + return convertAddress(address); + } + InetUtils.HostInfo hostInfo = new InetUtils.HostInfo(); + hostInfo.setHostname(this.properties.getDefaultHostname()); + hostInfo.setIpAddress(this.properties.getDefaultIpAddress()); + return hostInfo; + } + + public InetAddress findFirstNonLoopbackAddress() { + boolean preferIpv6 = AddressUtils.preferIpv6(); + InetAddress result = findFirstNonLoopbackAddressByIpType(preferIpv6); + logger.debug("ipv6 before, preferIpv6:{}, result:{}", preferIpv6, result); + if (result == null) { + result = findFirstNonLoopbackAddressByIpType(!preferIpv6); + } + logger.debug("ipv6 after, preferIpv6:{}, result:{}", preferIpv6, result); + + if (result != null) { + return result; + } + + try { + return InetAddress.getLocalHost(); + } + catch (UnknownHostException e) { + logger.warn("Unable to retrieve localhost"); + } + + return null; + } + + /** for testing. */ + boolean isPreferredAddress(InetAddress address) { + + if (this.properties.isUseOnlySiteLocalInterfaces()) { + final boolean siteLocalAddress = address.isSiteLocalAddress(); + if (!siteLocalAddress) { + logger.trace("Ignoring address: " + address.getHostAddress()); + } + return siteLocalAddress; + } + final List preferredNetworks = this.properties.getPreferredNetworks(); + if (preferredNetworks.isEmpty()) { + return true; + } + for (String regex : preferredNetworks) { + final String hostAddress = address.getHostAddress(); + if (hostAddress.matches(regex) || hostAddress.startsWith(regex)) { + return true; + } + } + logger.trace("Ignoring address: " + address.getHostAddress()); + return false; + } + + /** for testing. */ + boolean ignoreInterface(String interfaceName) { + for (String regex : this.properties.getIgnoredInterfaces()) { + if (interfaceName.matches(regex)) { + logger.trace("Ignoring interface: " + interfaceName); + return true; + } + } + return false; + } + + public InetUtils.HostInfo convertAddress(final InetAddress address) { + InetUtils.HostInfo hostInfo = new InetUtils.HostInfo(); + Future result = executorService.submit(new Callable() { + @Override + public String call() throws Exception { + return address.getHostName(); + } + }); + + String hostname; + try { + hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS); + } + catch (Exception e) { + logger.info("Cannot determine local hostname"); + hostname = "localhost"; + } + if (hostname.contains("%")) { + hostInfo.setHostname(hostname.split("%")[0]); + } + else { + hostInfo.setHostname(hostname); + } + if (address.getHostAddress().contains("%")) { + hostInfo.setIpAddress(address.getHostAddress().split("%")[0]); + } + else { + hostInfo.setIpAddress(address.getHostAddress()); + } + return hostInfo; + } + + public String findIpInterface() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address.getHostAddress().contains("%")) { + return address.getHostAddress().split("%")[1]; + } + return ""; + } + + public String findIpAddress() { + InetAddress address = findFirstNonLoopbackAddress(); + return address.getHostAddress().split("%")[0]; + } + + /** + * + * @return "[ipv6]" + */ + public String findIpAddressWithBracket() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address.getHostAddress().contains("%")) { + return address.getHostAddress().split("%")[0]; + } + return address.getHostAddress(); + } + + /** + * @return ipv6%eth0 + * + */ + public String findIpAddressAndInterface() { + InetAddress address = findFirstNonLoopbackAddress(); + return address.getHostAddress(); + } + + public InetAddress findFirstNonLoopbackAddressByIpType(boolean _ipv6) { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + logger.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } + else if (result != null) { + continue; + } + + // @formatter:off + if (!ignoreInterface(ifc.getDisplayName())) { + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements();) { + InetAddress address = addrs.nextElement(); + if (_ipv6) { + if (address instanceof Inet6Address + && !address.isLinkLocalAddress() + && !address.isLoopbackAddress() + && isPreferredAddress(address)) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + else { + if (address instanceof Inet4Address + && !address.isLoopbackAddress() + && isPreferredAddress(address)) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + } + } + // @formatter:on + } + } + } + catch (IOException ex) { + logger.error("Cannot get first non-loopback address", ex); + } + + if (result != null) { + return result; + } + + + return null; + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java new file mode 100644 index 000000000..4160d7bb1 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java @@ -0,0 +1,42 @@ +/* + * 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.inet; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.cloud.commons.util.UtilAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + + +/** + * Auto configuration for PolarisInetUtils. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@Import(UtilAutoConfiguration.class) +public class PolarisInetUtilsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public PolarisInetUtils polarisInetUtils(InetUtilsProperties properties) { + return new PolarisInetUtils(properties); + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java new file mode 100644 index 000000000..9973573d9 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java @@ -0,0 +1,30 @@ +/* + * 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.inet; + +import org.springframework.context.annotation.Import; + +/** + * Auto configuration for PolarisInetUtils. + * + * @author Haotian Zhang + */ +@Import(PolarisInetUtilsAutoConfiguration.class) +public class PolarisInetUtilsBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java new file mode 100644 index 000000000..0e7c98a8f --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java @@ -0,0 +1,78 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package org.springframework.tsf.core.context; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; + +import org.springframework.tsf.core.entity.Tag; + +public final class TsfContext { + + static final int MAX_KEY_LENGTH = 32; + static final int MAX_VALUE_LENGTH = 128; + + private TsfContext() { + + } + + public static void putTags(Map tagMap, Tag.ControlFlag... flags) { + if (tagMap == null) { + return; + } + MetadataContext tsfCoreContext = MetadataContextHolder.get(); + TransitiveType transitive = TransitiveType.NONE; + if (null != flags) { + for (Tag.ControlFlag flag : flags) { + if (flag == Tag.ControlFlag.TRANSITIVE) { + transitive = TransitiveType.PASS_THROUGH; + break; + } + } + } + for (Map.Entry entry : tagMap.entrySet()) { + validateTag(entry.getKey(), entry.getValue()); + } + tsfCoreContext.putMetadataAsMap(MetadataType.CUSTOM, transitive, false, tagMap); + } + + public static void putTag(String key, String value, Tag.ControlFlag... flags) { + putTags(Collections.singletonMap(key, value), flags); + } + + private static void validateTag(String key, String value) { + int keyLength = key.getBytes(StandardCharsets.UTF_8).length; + int valueLength = value.getBytes(StandardCharsets.UTF_8).length; + + if (keyLength > MAX_KEY_LENGTH) { + throw new RuntimeException(String.format("Key \"%s\" length (after UTF-8 encoding) exceeding limit (%d)", key, + MAX_KEY_LENGTH)); + } + if (valueLength > MAX_VALUE_LENGTH) { + throw new RuntimeException(String.format("Value \"%s\" length (after UTF-8 encoding) exceeding limit (%d)", value, + MAX_VALUE_LENGTH)); + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java new file mode 100644 index 000000000..16d409a0c --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java @@ -0,0 +1,144 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package org.springframework.tsf.core.entity; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Tag implements Serializable { + + /** + * update version whenever change the content in tag. + */ + public static final int VERSION = 1; + + public enum ControlFlag { + + /** + * tag transitive by all services. + */ + @SerializedName("0") + TRANSITIVE, + + /** + * tag not used in auth. + */ + @SerializedName("1") + NOT_IN_AUTH, + + /** + * tag not used in route. + */ + @SerializedName("2") + NOT_IN_ROUTE, + + /** + * tag not used in trace. + */ + @SerializedName("3") + NOT_IN_SLEUTH, + + /** + * tag not used in lane. + */ + @SerializedName("4") + NOT_IN_LANE, + + /** + * tag not used in unit. + */ + @SerializedName("5") + IN_UNIT + } + + @SerializedName("k") + @Expose + private String key; + + @SerializedName("v") + @Expose + private String value; + + @SerializedName("f") + @Expose + private Set flags = new HashSet<>(); + + public Tag(String key, String value, ControlFlag... flags) { + this.key = key; + this.value = value; + this.flags = new HashSet<>(Arrays.asList(flags)); + } + + public Tag() { + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Set getFlags() { + return flags; + } + + public void setFlags(Set flags) { + this.flags = flags; + } + + @Override + public boolean equals(Object object) { + if (object instanceof Tag) { + Tag tag = (Tag) object; + return (key == null ? tag.key == null : key.equals(tag.key)) + && (flags == null ? tag.flags == null : flags.equals(tag.flags)); + } + return false; + } + + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) + (flags == null ? 0 : flags.hashCode()); + } + + + @Override + public String toString() { + return "Tag{" + + "key='" + key + '\'' + + ", value='" + value + '\'' + + ", flags=" + flags + + '}'; + } +} diff --git a/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories index 4c54d3372..d99cbf89a 100644 --- a/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories @@ -1,4 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.common.util.inet.PolarisInetUtilsAutoConfiguration,\ com.tencent.cloud.common.util.ApplicationContextAwareUtils,\ com.tencent.cloud.common.metadata.config.MetadataAutoConfiguration,\ com.tencent.cloud.common.metadata.endpoint.PolarisMetadataEndpointAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.common.util.inet.PolarisInetUtilsBootstrapConfiguration diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java index cc992ce19..6f54ff7ba 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 @@ -49,7 +49,7 @@ public void test1() { metadataContext.setTransitiveMetadata(customMetadata); MetadataContextHolder.set(metadataContext); - customMetadata = MetadataContextHolder.get().getTransitiveMetadata(); + metadataContext.setTransitiveMetadata(customMetadata); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("2"); @@ -63,7 +63,7 @@ public void test1() { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - MetadataContextHolder.init(customMetadata, new HashMap<>()); + MetadataContextHolder.init(customMetadata, new HashMap<>(), new HashMap<>(), null); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getTransitiveMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java index a7fcf2725..14bfac793 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 @@ -34,8 +34,7 @@ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MetadataLocalPropertiesTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) + properties = {"spring.config.location = classpath:application-test.yml", "spring.main.web-application-type=reactive"}) public class MetadataLocalPropertiesTest { @Autowired diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java index 6073268ae..66d4445aa 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java @@ -44,7 +44,7 @@ /** * test for {@link ExpressionLabelUtils}. * - * @author lepdou 2022-05-27, cheese8 + * @author lepdou, cheese8 */ @ExtendWith(MockitoExtension.class) public class ExpressionLabelUtilsTest { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/util/OkHttpUtilTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/OkHttpUtilTest.java similarity index 82% rename from spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/util/OkHttpUtilTest.java rename to spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/OkHttpUtilTest.java index b718e88e9..2e250e3d8 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/util/OkHttpUtilTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/OkHttpUtilTest.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.util; +package com.tencent.cloud.common.util; import org.assertj.core.util.Maps; import org.junit.jupiter.api.Test; @@ -37,7 +37,13 @@ * @author Haotian Zhang */ @ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = OkHttpUtilTest.TestApplication.class, properties = {"spring.application.name=test", "spring.cloud.polaris.discovery.register=false"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = OkHttpUtilTest.TestApplication.class, + properties = { + "spring.application.name=test", + "spring.cloud.polaris.discovery.register=false", + "spring.cloud.gateway.enabled=false" + }) public class OkHttpUtilTest { @LocalServerPort @@ -46,6 +52,8 @@ public class OkHttpUtilTest { @Test public void testGet() { assertThat(OkHttpUtil.get("http://localhost:" + port + "/test", Maps.newHashMap("key", "value"))).isTrue(); + assertThat(OkHttpUtil.checkUrl("localhost", port, "/test", Maps.newHashMap("key", "value"))).isTrue(); + assertThat(OkHttpUtil.checkUrl("localhost", port, "test", Maps.newHashMap("key", "value"))).isTrue(); assertThat(OkHttpUtil.get("http://localhost:" + port + "/error", Maps.newHashMap("key", "value"))).isFalse(); assertThat(OkHttpUtil.get("http://localhost:55555/error", Maps.newHashMap("key", "value"))).isFalse(); } diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java new file mode 100644 index 000000000..3d77d047c --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/UrlUtilsTest.java @@ -0,0 +1,68 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.common.util; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Utils for {@link UrlUtils}. + * + * @author Shedfree Wu + */ +public class UrlUtilsTest { + + @Test + public void testEncodeDecode1() { + String expectEncodeValue = "a%2Fb"; + String origin = "a/b"; + String encode1 = UrlUtils.encode(origin); + assertThat(expectEncodeValue).isEqualTo(encode1); + // encode twice is different + String encode2 = UrlUtils.encode(encode1); + assertThat(encode1).isNotEqualTo(encode2); + // test decode + assertThat(origin).isEqualTo(UrlUtils.decode(encode1)); + } + + @Test + public void testEncodeDecode2() { + + String origin = null; + String encode1 = UrlUtils.encode(origin); + assertThat(encode1).isNull(); + + origin = ""; + encode1 = UrlUtils.encode(origin); + assertThat(encode1).isEqualTo(origin); + } + + @Test + public void testError() { + String origin = "a/b"; + String encode = UrlUtils.encode(origin, "error-enc"); + assertThat(encode).isEqualTo(origin); + + encode = "a%2Fb"; + String decode = UrlUtils.decode(encode, "error-enc"); + assertThat(decode).isEqualTo(encode); + } + +} diff --git a/spring-cloud-tencent-commons/src/test/resources/application-test.yml b/spring-cloud-tencent-commons/src/test/resources/application-test.yml index bea1a0586..bf8666ddd 100644 --- a/spring-cloud-tencent-commons/src/test/resources/application-test.yml +++ b/spring-cloud-tencent-commons/src/test/resources/application-test.yml @@ -6,6 +6,8 @@ spring: - org.springframework.cloud.gateway.config.GatewayAutoConfiguration - org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration cloud: + gateway: + enabled: false tencent: metadata: content: diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 8a06ec039..ec6965414 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -74,6 +74,11 @@ spring-cloud-starter-tencent-polaris-contract + + com.tencent.cloud + spring-cloud-starter-tencent-discovery-adapter-plugin + + com.tencent.cloud spring-cloud-tencent-featureenv-plugin @@ -88,6 +93,11 @@ com.tencent.cloud spring-cloud-starter-tencent-discovery-adapter-plugin + + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 77ca98c07..578b8fe2e 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,18 +70,19 @@ - 1.13.4-Hoxton.SR12-SNAPSHOT + 2.0.0.0-Hoxton.SR12-SNAPSHOT - 1.15.11-SNAPSHOT + 2.0.0.0-SNAPSHOT 32.0.1-jre 1.2.13 - 3.0.0 + 1.7.0 1.5.24 4.5.1 1.12.10 2.12.7 3.21.7 + 2.9.9 2.0.2 @@ -93,6 +94,14 @@ + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + pom + import + + polaris-dependencies com.tencent.polaris @@ -193,6 +202,24 @@ ${revision} + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + ${revision} + + + + com.tencent.cloud + spring-cloud-starter-tencent-threadlocal-plugin + ${revision} + + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + ${revision} + + com.google.guava @@ -227,39 +254,15 @@ - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - - io.springfox - springfox-boot-starter - ${springfox.swagger2.version} - - - - io.swagger - swagger-models - ${io.swagger.version} + org.springdoc + springdoc-openapi-ui + ${springdoc.version} - io.swagger - swagger-annotations - ${io.swagger.version} + org.springdoc + springdoc-openapi-webflux-ui + ${springdoc.version} @@ -274,6 +277,13 @@ ${byte-buddy.version} + + + joda-time + joda-time + ${joda-time.version} + + org.mockito mockito-inline diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml new file mode 100644 index 000000000..9117a7314 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + + lossless-example + com.tencent.cloud + ${revision} + ../pom.xml + + lossless-callee-service + Spring Cloud Starter Tencent Lossless Callee Service Example + + + + com.tencent.cloud + spring-cloud-starter-tencent-all + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java new file mode 100644 index 000000000..ec7347c91 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeController.java @@ -0,0 +1,95 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.lossless.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +@RestController +@RequestMapping("/lossless/callee") +public class LosslessCalleeController { + + private static final Logger LOG = LoggerFactory.getLogger(LosslessCalleeController.class); + + @Value("${lossless.healthy.delay.second:0}") + private int healthyDelay; + + private final AtomicBoolean calledHealthyEndpoint = new AtomicBoolean(false); + + private final AtomicInteger healthy = new AtomicInteger(0); + + @GetMapping("/health") + public ResponseEntity health() { + if (healthy.get() == 1) { + return new ResponseEntity<>("OK", HttpStatus.OK); + } + else { + if (calledHealthyEndpoint.compareAndSet(false, true)) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + if (healthyDelay > 0) { + try { + Thread.sleep(healthyDelay * 1000L); + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + healthy.set(1); + } + }); + thread.start(); + } + return new ResponseEntity<>("NOK", HttpStatus.SERVICE_UNAVAILABLE); + } + } + + /** + * Get metadata in HTTP query. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, UTF_8)); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return metadataStr; + } + +} diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java new file mode 100644 index 000000000..542653ba0 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/java/com/tencent/cloud/lossless/callee/LosslessCalleeService.java @@ -0,0 +1,29 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.lossless.callee; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LosslessCalleeService { + public static void main(String[] args) { + SpringApplication.run(LosslessCalleeService.class, args); + } +} diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..4e8c2a8ce --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml @@ -0,0 +1,36 @@ +server: + port: 48090 +spring: + application: + name: LosslessCalleeService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + contract: + exposure: true + report: + enabled: true + stat: + enabled: true + port: 28084 + lossless: + enabled: true + port: 28084 + #healthCheckPath: /actuator/health + #healthCheckInterval: 5000 +lossless: + healthy: + delay: + second: 20 +management: + endpoints: + web: + exposure: + include: + - polaris-discovery + - health \ No newline at end of file diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml new file mode 100644 index 000000000..52c29f727 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + lossless-example + com.tencent.cloud + ${revision} + ../pom.xml + + com.tencent.polaris + lossless-nacos-callee-service + Spring Cloud Starter Tencent Lossless Nacos Callee Service Example + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + 2022.0.0.0 + + + + com.tencent.cloud + spring-cloud-starter-tencent-discovery-adapter-plugin + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java new file mode 100644 index 000000000..ea96f64b3 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeController.java @@ -0,0 +1,95 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.lossless.nacos.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +@RestController +@RequestMapping("/lossless/nacos/callee") +public class LosslessNacosCalleeController { + + private static final Logger LOG = LoggerFactory.getLogger(LosslessNacosCalleeController.class); + + @Value("${lossless.healthy.delay.second:0}") + private int healthyDelay; + + private final AtomicBoolean calledHealthyEndpoint = new AtomicBoolean(false); + + private final AtomicInteger healthy = new AtomicInteger(0); + + @GetMapping("/health") + public ResponseEntity health() { + if (healthy.get() == 1) { + return new ResponseEntity<>("OK", HttpStatus.OK); + } + else { + if (calledHealthyEndpoint.compareAndSet(false, true)) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + if (healthyDelay > 0) { + try { + Thread.sleep(healthyDelay * 1000L); + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + healthy.set(1); + } + }); + thread.start(); + } + return new ResponseEntity<>("NOK", HttpStatus.SERVICE_UNAVAILABLE); + } + } + + /** + * Get metadata in HTTP query. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, UTF_8)); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return metadataStr; + } + +} diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java new file mode 100644 index 000000000..a2d29436a --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/java/com/tencent/cloud/lossless/nacos/callee/LosslessNacosCalleeService.java @@ -0,0 +1,31 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.lossless.nacos.callee; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LosslessNacosCalleeService { + + public static void main(String[] args) { + SpringApplication.run(LosslessNacosCalleeService.class, args); + } + +} diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..39d7f2c51 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml @@ -0,0 +1,20 @@ +server: + port: 48091 +spring: + application: + name: LosslessNacosCalleeService + cloud: + nacos: + discovery: + server-addr: 127.0.0.1:8848 + enabled: true + polaris: + lossless: + enabled: true + port: 28085 + healthCheckPath: /actuator/health + healthCheckInterval: 5000 +lossless: + healthy: + delay: + second: 20 diff --git a/spring-cloud-tencent-examples/lossless-example/pom.xml b/spring-cloud-tencent-examples/lossless-example/pom.xml new file mode 100644 index 000000000..2873cb7b0 --- /dev/null +++ b/spring-cloud-tencent-examples/lossless-example/pom.xml @@ -0,0 +1,19 @@ + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + + lossless-callee-service + lossless-nacos-callee-service + + 4.0.0 + + lossless-example + pom + Spring Cloud Starter Tencent Lossless Example + + diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java index 79948b3e7..6d8653eeb 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java @@ -19,9 +19,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableDiscoveryClient @EnableFeignClients public class GrayReleaseFrontApplication { diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java index 77819ea41..a7b5a115e 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java @@ -19,9 +19,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableDiscoveryClient @EnableFeignClients public class GrayReleaseGatewayApplication { diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java index 3003093ee..4857030e2 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java @@ -19,9 +19,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableDiscoveryClient @EnableFeignClients public class GrayReleaseMiddleApplication { diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml new file mode 100644 index 000000000..6f602207d --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/pom.xml @@ -0,0 +1,24 @@ + + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + + router-grayrelease-lane-gateway + router-grayrelease-lane-caller-service + router-grayrelease-lane-callee-service + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + + pom + Spring Cloud Tencent Polaris Router Lane Example + Example of Spring Cloud Tencent Polaris Router Lane + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml new file mode 100644 index 000000000..3431f03d0 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/pom.xml @@ -0,0 +1,70 @@ + + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + ${revision} + ../pom.xml + + + route-grayrelease-lane-callee-service + + + + spring-cloud-starter-tencent-polaris-discovery + com.tencent.cloud + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java similarity index 56% rename from spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java rename to spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java index 18f3d0cac..ba623274e 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/CustomMetadata.java @@ -13,42 +13,35 @@ * 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.quickstart.caller.router; +package com.tencent.cloud.lane.callee; import java.util.HashMap; import java.util.Map; -import java.util.Set; -import com.google.gson.Gson; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; -import feign.RequestTemplate; +import com.tencent.cloud.common.spi.InstanceMetadataProvider; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** + * Custom metadata for instance. * - * Customize the business tag information obtained from the request - * - *@author lepdou 2022-05-12 + * @author Haotian Zhang */ @Component -public class CustomRouterLabelResolver implements FeignRouterLabelResolver { - private final Gson gson = new Gson(); - - @Override - public Map resolve(RequestTemplate requestTemplate, Set expressionLabelKeys) { - Map labels = new HashMap<>(); - - labels.put("label1", "value1"); +public class CustomMetadata implements InstanceMetadataProvider { - return labels; - } + @Value("${service.lane:base}") + private String lane; @Override - public int getOrder() { - return 0; + public Map getMetadata() { + Map metadata = new HashMap<>(); + if (!"base".equals(lane)) { + metadata.put("lane", lane); + } + return metadata; } } diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java new file mode 100644 index 000000000..5ffabdd2c --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeApplication.java @@ -0,0 +1,29 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.lane.callee; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LaneRouterCalleeApplication { + + public static void main(String[] args) { + SpringApplication.run(LaneRouterCalleeApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java new file mode 100644 index 000000000..d10859db7 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/java/com/tencent/cloud/lane/callee/LaneRouterCalleeController.java @@ -0,0 +1,91 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.lane.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + +@RestController +@RequestMapping("/lane/callee") +public class LaneRouterCalleeController { + + private static final Logger LOG = LoggerFactory.getLogger(LaneRouterCalleeController.class); + + @Value("${server.port:0}") + private int port; + + @Value("${spring.cloud.client.ip-address:127.0.0.1}") + private String ip; + + @Value("${appName:${spring.application.name}}") + private String appName; + + @Value("${service.lane:base}") + private String lane; + + /** + * Get sum of two value. + * @param value1 value 1 + * @param value2 value 2 + * @return sum + */ + @GetMapping("/sum") + public String sum(@RequestParam int value1, @RequestParam int value2) { + LOG.info("Lane [{}] Callee Service [{} - {}:{}] is called and sum is [{}].", lane, appName, ip, port, value1 + value2); + return String.format("Lane [%s] Callee Service [%s - %s:%s] is called and sum is [%s].", lane, appName, ip, port, value1 + value2); + } + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/info") + public String info() { + LOG.info("Lane [{}] Service [{} - {}:{}] is called.", lane, appName, ip, port); + return String.format("Lane [%s] Service [%s - %s:%s] is called.", lane, appName, ip, port); + } + + /** + * Get metadata in HTTP header. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, UTF_8)); + metadataStr = URLDecoder.decode(metadataStr, UTF_8); + return String.format("Lane [%s]: %s", lane, metadataStr); + } + +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml new file mode 100644 index 000000000..29d9d9c96 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml @@ -0,0 +1,36 @@ +server: + port: 48093 +spring: + application: + name: LaneCalleeService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + contract: + exposure: true + report: + enabled: true + stat: + enabled: true + port: 28083 + # pushgateway: + # enabled: true + # address: 127.0.0.1:9091 + config: + address: grpc://9.134.5.52:8093 + auto-refresh: true + groups: + - name: ${spring.application.name} + files: [ "config/callee.properties" ] +management: + endpoints: + web: + exposure: + include: + - polaris-discovery + - polaris-config \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml new file mode 100644 index 000000000..f1a48d81b --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + ${revision} + ../pom.xml + + + route-grayrelease-lane-caller-service + + + + spring-cloud-starter-tencent-polaris-discovery + com.tencent.cloud + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java similarity index 54% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java rename to spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java index 05e1366b4..51939912e 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/CustomMetadata.java @@ -15,27 +15,33 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.router.spi; +package com.tencent.cloud.lane.caller; +import java.util.HashMap; import java.util.Map; -import java.util.Set; -import feign.RequestTemplate; +import com.tencent.cloud.common.spi.InstanceMetadataProvider; -import org.springframework.core.Ordered; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; /** - * Router label resolver for feign request. - * @author lepdou 2022-07-20 + * Custom metadata for instance. + * + * @author Haotian Zhang */ -public interface FeignRouterLabelResolver extends Ordered { +@Component +public class CustomMetadata implements InstanceMetadataProvider { + + @Value("${service.lane:base}") + private String lane; - /** - * Resolve labels from feign request. User can customize expression parser to extract labels. - * - * @param requestTemplate the feign request. - * @param expressionLabelKeys the expression labels which are configured in router rule. - * @return resolved labels - */ - Map resolve(RequestTemplate requestTemplate, Set expressionLabelKeys); + @Override + public Map getMetadata() { + Map metadata = new HashMap<>(); + if (!"base".equals(lane)) { + metadata.put("lane", lane); + } + return metadata; + } } diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java new file mode 100644 index 000000000..b057f4ffe --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCalleeService.java @@ -0,0 +1,41 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.lane.caller; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Quickstart callee feign client. + * + * @author Haotian Zhang + */ +@FeignClient("LaneCalleeService") +public interface LaneRouterCalleeService { + + /** + * Get sum of two value. + * + * @param value1 value 1 + * @param value2 value 2 + * @return sum + */ + @GetMapping("/lane/callee/sum") + String sum(@RequestParam("value1") int value1, @RequestParam("value2") int value2); +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java new file mode 100644 index 000000000..6b387c7b1 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerApplication.java @@ -0,0 +1,57 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.lane.caller; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@SpringBootApplication +@EnableFeignClients +public class LaneRouterCallerApplication { + + public static void main(String[] args) { + SpringApplication.run(LaneRouterCallerApplication.class, args); + } + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + @Bean + @LoadBalanced + public RestTemplate defaultRestTemplate() { + DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService"); + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(uriBuilderFactory); + return restTemplate; + } + + @LoadBalanced + @Bean + WebClient.Builder webClientBuilder() { + return WebClient.builder().baseUrl("http://QuickstartCalleeService"); + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java new file mode 100644 index 000000000..90f990dbc --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/java/com/tencent/cloud/lane/caller/LaneRouterCallerController.java @@ -0,0 +1,114 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.lane.caller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; + +@RestController +@RequestMapping("/lane/caller") +public class LaneRouterCallerController { + + private static final Logger LOG = LoggerFactory.getLogger(LaneRouterCallerController.class); + + @Value("${server.port:0}") + private int port; + + @Value("${spring.cloud.client.ip-address:127.0.0.1}") + private String ip; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private LaneRouterCalleeService quickstartCalleeService; + + @Autowired + private WebClient.Builder webClientBuilder; + + @Value("${service.lane:base}") + private String lane; + + @Value("${appName:${spring.application.name}}") + private String appName; + + /** + * Get sum of two value. + * @param value1 value 1 + * @param value2 value 2 + * @return sum + */ + @GetMapping("/feign") + public String feign(@RequestParam int value1, @RequestParam int value2) { + String value = quickstartCalleeService.sum(value1, value2); + return String.format("Lane [%s] Caller Service [%s - %s:%s] -> %s", lane, appName, ip, port, value); + } + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/rest") + public String rest() { + String value = restTemplate.getForObject("http://LaneCalleeService/lane/callee/info", String.class); + return String.format("Lane [%s] Caller Service [%s - %s:%s] -> %s", lane, appName, ip, port, value); + } + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/webclient") + public Mono webclient() { + return webClientBuilder + .build() + .get() + .uri("/quickstart/callee/echo") + .retrieve() + .bodyToMono(String.class); + } + + /** + * Get information of caller. + * @return information of caller + */ + @GetMapping("/info") + public String info() { + LOG.info("Lane {} Service [{} - {}:{}] is called.", lane, appName, ip, port); + return String.format("Lane [%s] Service [%s - %s:%s] is called.", lane, appName, ip, port); + } + + /** + * health check. + * @return health check info + */ + @GetMapping("/healthCheck") + public String healthCheck() { + return "ok"; + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml new file mode 100644 index 000000000..259358d55 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml @@ -0,0 +1,42 @@ +server: + port: 48092 +spring: + application: + name: LaneCallerService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + heartbeat: + enabled: true + health-check-url: /lane/caller/healthCheck + contract: + exposure: true + report: + enabled: true + circuitbreaker: + enabled: true + stat: + enabled: true + port: 28082 + # pushgateway: + # enabled: true + # address: 127.0.0.1:9091 + tencent: + rpc-enhancement: + enabled: true + reporter: + enabled: true + ignore-internal-server-error: true + series: server_error + statuses: gateway_timeout, bad_gateway, service_unavailable +management: + endpoints: + web: + exposure: + include: + - polaris-discovery \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml new file mode 100644 index 000000000..efd0edff1 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + com.tencent.polaris + polaris-router-grayrelease-lane-example + ${revision} + ../pom.xml + + + router-grayrelease-lane-gateway + + + + spring-cloud-starter-tencent-polaris-discovery + com.tencent.cloud + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java new file mode 100644 index 000000000..338dd7b01 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/java/com/tencent/cloud/polaris/router/lane/gateway/LaneRouterGatewayApplication.java @@ -0,0 +1,29 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.router.lane.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LaneRouterGatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(LaneRouterGatewayApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml new file mode 100644 index 000000000..5c39a3f50 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml @@ -0,0 +1,37 @@ +server: + port: 48090 +spring: + application: + name: LaneRouterGatewayService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + contract: + exposure: true + report: + enabled: true + stat: + enabled: true + port: 28081 + gateway: + discovery: + locator: + enabled: true + 'predicates[0]': + name: Path + args: + patterns: '''/'' + serviceId + ''/**''' + 'filters[0]': + name: RewritePath + args: + regexp: '''/'' + serviceId + ''/(?.*)''' + replacement: '''/$\{remaining}''' + routes: + - id: LaneRouterCallerService + uri: lb://LaneCallerService + predicates: + - Path=/LaneCallerService/** + filters: + - StripPrefix=1 diff --git a/spring-cloud-tencent-examples/pom.xml b/spring-cloud-tencent-examples/pom.xml index c7e0c5a94..8eccfd444 100644 --- a/spring-cloud-tencent-examples/pom.xml +++ b/spring-cloud-tencent-examples/pom.xml @@ -21,6 +21,9 @@ polaris-router-grayrelease-example polaris-router-featureenv-example quickstart-example + lossless-example + polaris-router-grayrelease-lane-example + tsf-example diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java index bdd60f8ef..8e7177271 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java @@ -38,9 +38,4 @@ public Map getMetadata() { metadata.put("k1", "v1"); return metadata; } - - @Override - public String getZone() { - return "shenzhen-zone-1"; - } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 2370d4c17..88919d5ae 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -123,4 +123,10 @@ public String health() { LOG.info("Quickstart Callee Service [{}:{}] is detected right.", ip, port); return String.format("Quickstart Callee Service [%s:%s] is detected right.", ip, port); } + + @GetMapping("/test/{num}/echo") + public String test(@PathVariable int num) { + LOG.info("Quickstart Callee Service [%s] is detected right.", num); + return String.format("Quickstart Callee Service [%s] is detected right.", num); + } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java index 8257f2cd5..ed4b59b2e 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java @@ -38,9 +38,4 @@ public Map getMetadata() { metadata.put("k1", "v2"); return metadata; } - - @Override - public String getZone() { - return "shenzhen-zone-2"; - } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java index ec939dd17..25764d052 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java @@ -17,16 +17,25 @@ package com.tencent.cloud.quickstart.caller; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -63,6 +72,8 @@ public class QuickstartCallerController { */ @GetMapping("/feign") public String feign(@RequestParam int value1, @RequestParam int value2) { + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Collections.singletonMap("feign-trace", String.format("%d+%d", value1, value2))); return quickstartCalleeService.sum(value1, value2); } @@ -71,8 +82,25 @@ public String feign(@RequestParam int value1, @RequestParam int value2) { * @return information of callee */ @GetMapping("/rest") - public String rest() { - return restTemplate.getForObject("http://QuickstartCalleeService/quickstart/callee/info", String.class); + public ResponseEntity rest(@RequestHeader Map headerMap) { + String url = "http://QuickstartCalleeService/quickstart/callee/info"; + + HttpHeaders headers = new HttpHeaders(); + for (Map.Entry entry : headerMap.entrySet()) { + if (StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue()) + && !entry.getKey().contains("sct-") + && !entry.getKey().contains("SCT-") + && !entry.getKey().contains("polaris-") + && !entry.getKey().contains("POLARIS-")) { + headers.add(entry.getKey(), entry.getValue()); + } + } + + // 创建 HttpEntity 实例并传入 HttpHeaders + HttpEntity entity = new HttpEntity<>(headers); + + // 使用 exchange 方法发送 GET 请求,并获取响应 + return restTemplate.exchange(url, HttpMethod.GET, entity, String.class); } /** diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java index 1dbd829a3..837b5ec0c 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java @@ -17,6 +17,7 @@ package com.tencent.cloud.quickstart.caller.circuitbreaker; +import com.tencent.cloud.common.metadata.MetadataContext; import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +29,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; @@ -110,7 +113,7 @@ public String circuitBreakFeignFallbackFromCodeWildcard(@PathVariable String uid @GetMapping("/rest") public String circuitBreakRestTemplate() { return circuitBreakerFactory - .create("QuickstartCalleeService#/quickstart/callee/circuitBreak") + .create(MetadataContext.LOCAL_NAMESPACE + "#QuickstartCalleeService#/quickstart/callee/circuitBreak#http#GET") .run(() -> defaultRestTemplate.getForObject("/quickstart/callee/circuitBreak", String.class), throwable -> "trigger the refuse for service callee." ); @@ -142,7 +145,12 @@ public ResponseEntity circuitBreakRestTemplateFallbackFromCodeWildcard(@ */ @GetMapping("/rest/fallbackFromPolaris") public ResponseEntity circuitBreakRestTemplateFallbackFromPolaris() { - return restTemplateFallbackFromPolaris.getForEntity("/quickstart/callee/circuitBreak", String.class); + try { + return restTemplateFallbackFromPolaris.getForEntity("/quickstart/callee/circuitBreak", String.class); + } + catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) { + return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode()); + } } /** @@ -151,7 +159,12 @@ public ResponseEntity circuitBreakRestTemplateFallbackFromPolaris() { */ @GetMapping("/rest/fallbackFromCode") public ResponseEntity circuitBreakRestTemplateFallbackFromCode() { - return restTemplateFallbackFromCode.getForEntity("/quickstart/callee/circuitBreak", String.class); + try { + return restTemplateFallbackFromCode.getForEntity("/quickstart/callee/circuitBreak", String.class); + } + catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) { + return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode()); + } } /** @@ -168,7 +181,7 @@ public Mono webclient() { .bodyToMono(String.class) .transform(it -> reactiveCircuitBreakerFactory - .create("QuickstartCalleeService#/quickstart/callee/circuitBreak") + .create(MetadataContext.LOCAL_NAMESPACE + "QuickstartCalleeService#/quickstart/callee/circuitBreak#http#GET") .run(it, throwable -> Mono.just("fallback: trigger the refuse for service callee")) ); } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml index b51cbdec5..38c5079e3 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml @@ -14,10 +14,13 @@ spring: heartbeat: enabled: true health-check-url: /quickstart/caller/healthCheck + zero-protection: + enabled: true + is-need-test-connectivity: true contract: exposure: true report: - enabled: false + enabled: true circuitbreaker: enabled: true stat: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml index 9013c29d4..9bfb76041 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml @@ -28,11 +28,6 @@ org.springframework.cloud spring-cloud-starter-gateway - - - org.springframework.boot - spring-boot-starter-actuator - diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml index c61c418ec..bb5fc7d67 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml @@ -23,7 +23,7 @@ spring: contract: exposure: true report: - enabled: false + enabled: true stat: enabled: true port: 28081 diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml b/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml new file mode 100644 index 000000000..44abeeb31 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + tsf-example + com.tencent.cloud + ${revision} + ../pom.xml + + consumer-demo + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-contract + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-circuitbreaker + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java new file mode 100644 index 000000000..999d198d3 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.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.tsf.demo.consumer; + +import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreaker; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.tsf.annotation.EnableTsf; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@EnableFeignClients // 使用Feign微服务调用时请启用 +@EnableTsf +public class ConsumerApplication { + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + + @LoadBalanced + @Bean + @PolarisCircuitBreaker + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java new file mode 100644 index 000000000..1a7e71983 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java @@ -0,0 +1,102 @@ +/* + * 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.tsf.demo.consumer.controller; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderDemoService; +import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderService; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.tsf.core.context.TsfContext; +import org.springframework.tsf.core.entity.Tag; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +public class ConsumerController { + @Autowired + private RestTemplate restTemplate; + @Autowired + private ProviderService providerService; + @Autowired + private ProviderDemoService providerDemoService; + + @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) + public String restProvider(@PathVariable String str, + @RequestParam(required = false) String tagName, + @RequestParam(required = false) String tagValue) { + if (StringUtils.isNotBlank(tagName)) { + TsfContext.putTag(tagName, tagValue); + } + TsfContext.putTag("operation", "rest"); + Map mTags = new HashMap<>(); + mTags.put("rest-trace-key1", "value1"); + mTags.put("rest-trace-key2", "value2"); + TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE); + try { + return restTemplate.getForObject("http://provider-demo/echo/" + str, String.class); + } + catch (CallAbortedException callAbortedException) { + return callAbortedException.getMessage(); + } + + } + + @RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET) + public String feignProvider(@PathVariable String str, + @RequestParam(required = false) String tagName, + @RequestParam(required = false) String tagValue) { + if (StringUtils.isNotBlank(tagName)) { + TsfContext.putTag(tagName, tagValue); + } + TsfContext.putTag("operation", "feign"); + Map mTags = new HashMap<>(); + mTags.put("feign-trace-key1", "value1"); + mTags.put("feign-trace-key2", "value2"); + TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE); + try { + return providerDemoService.echo(str); + } + catch (CallAbortedException callAbortedException) { + return callAbortedException.getMessage(); + } + } + + @RequestMapping(value = "/echo-feign-url/{str}", method = RequestMethod.GET) + public String feignUrlProvider(@PathVariable String str, + @RequestParam(required = false) String tagName, + @RequestParam(required = false) String tagValue) { + if (StringUtils.isNotBlank(tagName)) { + TsfContext.putTag(tagName, tagValue); + } + TsfContext.putTag("operation", "feignUrl"); + Map mTags = new HashMap<>(); + mTags.put("feignUrl-trace-key1", "value1"); + mTags.put("feignUrl-trace-key2", "value2"); + TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE); + return providerService.echo(str); + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java new file mode 100644 index 000000000..47a38b475 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java @@ -0,0 +1,32 @@ +/* + * 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.tsf.demo.consumer.entity; + +/** + * 用户自定义 Metadata. + */ +public class CustomMetadata { + + private String name; + private String value; + + public CustomMetadata(String name, String value) { + this.name = name; + this.value = value; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java new file mode 100644 index 000000000..c102fc84e --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.tsf.demo.consumer.proxy; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = "provider-demo") +public interface ProviderDemoService { + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); + + @RequestMapping(value = "/echo/error/{str}", method = RequestMethod.GET) + String echoError(@PathVariable("str") String str); + + @RequestMapping(value = "/echo/slow/{str}", method = RequestMethod.GET) + String echoSlow(@PathVariable("str") String str, @RequestParam("delay") int delay); +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.java new file mode 100644 index 000000000..ac540217a --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.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.tsf.demo.consumer.proxy; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * 测试通过URL配置FeignClient + * 使用时修改provider-ip:provider-port配置 + */ +@FeignClient(name = "provider", url = "http://127.0.0.1:18081", fallback = FeignClientFallback.class) +public interface ProviderService { + + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); + +} + +@Component +class FeignClientFallback implements ProviderService { + @Override + public String echo(String str) { + return "tsf-fault-tolerance-" + str; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..b7cd3ee20 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml @@ -0,0 +1,17 @@ +server: + port: 18083 +spring: + application: + name: consumer-demo +feign: + tsf: + enabled: true + +#本地测试时打开 +#tsf_namespace_id: default_namespace + +logging: + file: + name: /tsf-demo-logs/${spring.application.name}/root.log + level: + root: INFO diff --git a/spring-cloud-tencent-examples/tsf-example/pom.xml b/spring-cloud-tencent-examples/tsf-example/pom.xml new file mode 100644 index 000000000..41379d930 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/pom.xml @@ -0,0 +1,41 @@ + + + + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + tsf-example + Spring Cloud Tencent TSF Examples + pom + + + true + + + + provider-demo + consumer-demo + + diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml b/spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml new file mode 100644 index 000000000..e1ccfd1c0 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + tsf-example + com.tencent.cloud + ${revision} + ../pom.xml + + provider-demo + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-contract + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java new file mode 100644 index 000000000..accc1811e --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java @@ -0,0 +1,31 @@ +/* + * 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.tsf.demo.provider; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.tsf.annotation.EnableTsf; + +@SpringBootApplication +@EnableTsf +public class ProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(ProviderApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java new file mode 100644 index 000000000..bfd49ba5f --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.tsf.demo.provider; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RefreshScope +public class ProviderConfigController { + + @Value("${provider.name:default}") + private String name; + + @GetMapping("/config/name") + public String getConfig() { + return name; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java new file mode 100644 index 000000000..370975e42 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java @@ -0,0 +1,156 @@ +/* + * 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.tsf.demo.provider; + + + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + +import javax.servlet.http.HttpServletResponse; + +import com.tencent.cloud.tsf.demo.provider.config.ProviderNameConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + + +/** + * @Author leoziltong@tencent.com + * @Date: 2021/5/11 17:10 + */ +@RestController +public class ProviderController { + + private static final Logger LOG = LoggerFactory.getLogger(ProviderController.class); + + @Value("${spring.application.name:}") + private String applicationName; + + @Autowired + private ProviderNameConfig providerNameConfig; + + // 获取本机ip + public static String getInet4Address() { + Enumeration nis; + String ip = null; + try { + nis = NetworkInterface.getNetworkInterfaces(); + for (; nis.hasMoreElements(); ) { + NetworkInterface ni = nis.nextElement(); + Enumeration ias = ni.getInetAddresses(); + for (; ias.hasMoreElements(); ) { + InetAddress ia = ias.nextElement(); + if (ia instanceof Inet4Address && !ia.getHostAddress().equals("127.0.0.1")) { + ip = ia.getHostAddress(); + } + } + } + } + catch (SocketException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return ip; + } + + @RequestMapping(value = "/hello", method = RequestMethod.GET) + public String hello() { + String echoHello = "say hello"; + LOG.info(echoHello); + return echoHello; + } + + @RequestMapping(value = "/echo/{param}", method = RequestMethod.GET) + public String echo(@PathVariable String param, HttpServletResponse response) throws IOException { + switch (param) { + case "1xx": + response.setStatus(HttpServletResponse.SC_CONTINUE); + response.getWriter().write("mock 1xx return."); + response.getWriter().flush(); + return "mock 1xx return."; + case "3xx": + response.setStatus(HttpServletResponse.SC_FOUND); + response.getWriter().write("mock 3xx return."); + response.getWriter().flush(); + return "mock 3xx return."; + case "4xx": + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + response.getWriter().write("mock 4xx return."); + response.getWriter().flush(); + return "mock 4xx return."; + case "5xx": + response.setStatus(HttpServletResponse.SC_BAD_GATEWAY); + response.getWriter().write("mock 5xx return."); + response.getWriter().flush(); + return "mock 5xx return."; + default: + LOG.info("provider-demo -- request param: [" + param + "]"); + String result = "from host-ip: " + getInet4Address() + ", request param: " + param + ", response from " + providerNameConfig.getName(); + LOG.info("provider-demo -- provider config name: [" + providerNameConfig.getName() + ']'); + LOG.info("provider-demo -- response info: [" + result + "]"); + return result; + } + + } + + @RequestMapping(value = "/echo/error/{param}", method = RequestMethod.GET) + public String echoError(@PathVariable String param) { + LOG.info("Error request param: [" + param + "], throw exception"); + + throw new RuntimeException("mock-ex"); + } + + /** + * 延迟返回. + * @param param 参数 + * @param delay 延时时间,单位毫秒 + * @throws InterruptedException InterruptedException + */ + @RequestMapping(value = "/echo/slow/{param}", method = RequestMethod.GET) + public String echoSlow(@PathVariable String param, @RequestParam(required = false) Integer delay) throws InterruptedException { + int sleepTime = delay == null ? 1000 : delay; + LOG.info("slow request param: [" + param + "], Start sleep: [" + sleepTime + "]ms"); + Thread.sleep(sleepTime); + LOG.info("slow request param: [" + param + "], End sleep: [" + sleepTime + "]ms"); + + String result = "request param: " + param + + ", slow response from " + applicationName + + ", sleep: [" + sleepTime + "]ms"; + return result; + } + + @RequestMapping(value = "/echo/unit/{param}", method = RequestMethod.GET) + public String echoUnit(@PathVariable String param) { + LOG.info("provider-demo -- unit request param: [" + param + "]"); + String result = "request param: " + param + ", response from " + applicationName; + LOG.info("provider-demo -- unit provider config name: [" + applicationName + ']'); + LOG.info("provider-demo -- unit response info: [" + result + "]"); + return result; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java new file mode 100644 index 000000000..45c04f22c --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java @@ -0,0 +1,37 @@ +/* + * 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.tsf.demo.provider.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +@Component +@RefreshScope +@ConfigurationProperties(prefix = "provider.config") +public class ProviderNameConfig { + private String name = "echo-provider-default-name"; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.java new file mode 100644 index 000000000..1493c9105 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.java @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.tsf.demo.provider.config; + +import com.tencent.tsf.consul.config.watch.ConfigChangeCallback; +import com.tencent.tsf.consul.config.watch.ConfigChangeListener; +import com.tencent.tsf.consul.config.watch.ConfigProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.stereotype.Component; + +@Component +@ConfigChangeListener(prefix = "provider.config", value = {"name"}) +public class ProviderNameConfigChangeListener implements ConfigChangeCallback { + + private static final Logger log = LoggerFactory.getLogger(ProviderNameConfigChangeListener.class); + + @Override + public void callback(ConfigProperty lastConfigProperty, ConfigProperty newConfigProperty) { + log.info("[TSF SDK] Configuration Change Listener: key: {}, old value: {}, new value: {}", + lastConfigProperty.getKey(), lastConfigProperty.getValue(), newConfigProperty.getValue()); + } + +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java new file mode 100644 index 000000000..be6cc6cd6 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java @@ -0,0 +1,145 @@ +/* + * 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.tsf.demo.provider.swagger.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.tsf.demo.provider.swagger.model.MessageBox; +import com.tencent.cloud.tsf.demo.provider.swagger.model.MessageModel; +import com.tencent.cloud.tsf.demo.provider.swagger.model.MessageUser; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +import org.springframework.http.MediaType; +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; + +@RestController("/swagger") +@Tag(description = "swagger 测试", name = "swaggerValue1") +public class SwaggerApiController { + + @RequestMapping(value = "/swagger/findMessages", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @Operation(method = "POST", + summary = "根据任务ID查询任务列表", + description = "根据任务ID查询任务列表Note") + public List findMessages(@RequestBody + @Parameter(name = "msgIds", description = "消息ID列表") List msgIds) { + List messageModels = new ArrayList<>(); + MessageModel messageModel = new MessageModel(); + messageModel.setMsgContent("test1"); + messageModel.setMsgId("1"); + messageModel.setSendTime(System.currentTimeMillis()); + MessageUser messageSender = new MessageUser(); + messageSender.setEmail("abc@xxxx.com"); + messageSender.setName("特朗普"); + messageSender.setOfficeAddress("华盛顿白宫"); + messageSender.setPhoneNum("911911911"); + messageModel.setSendUser(messageSender); + MessageUser messageReceiver = new MessageUser(); + messageReceiver.setEmail("abc@xxxx.com"); + messageReceiver.setName("拜登"); + messageReceiver.setOfficeAddress("华盛顿白宫"); + messageReceiver.setPhoneNum("911911911"); + messageModel.setReceiveUsers(Lists.newArrayList(messageReceiver)); + messageModels.add(messageModel); + return messageModels; + } + + //虽然这些@ExampleProperty和@Example属性已经在Swagger中实现,但Springfox还没有支持它们。问题仍然存在: + //https://github.com/springfox/springfox/issues/853 + //https://github.com/springfox/springfox/issues/1536 + + @Operation(summary = "获取消息内容", method = "GET", description = "获取消息内容Note") + @ApiResponse(responseCode = "200", description = "abcdef", content = @Content(schema = @Schema(implementation = String.class))) + @RequestMapping("/swagger/getMessageContent") + public String getMessageContent(@RequestParam(name = "id") + @Parameter(description = "消息ID", name = "id") String msgId) { + return "abcdefg"; + } + + @Operation(summary = "获取消息详情", method = "GET", description = "获取消息内容Note") + @ApiResponses({@ApiResponse(responseCode = "200", description = "abcdef", content = @Content(schema = @Schema(implementation = MessageModel.class)))}) + @RequestMapping(value = "/swagger/getMessageDetail", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public MessageModel getMessageDetail(@RequestParam(name = "id") + @Parameter(description = "消息ID", name = "id") String msgId) { + MessageModel messageModel = new MessageModel(); + messageModel.setMsgContent("test1"); + messageModel.setMsgId("1"); + messageModel.setSendTime(System.currentTimeMillis()); + MessageUser messageSender = new MessageUser(); + messageSender.setEmail("abc@xxxx.com"); + messageSender.setName("特朗普"); + messageSender.setOfficeAddress("华盛顿白宫"); + messageSender.setPhoneNum("911911911"); + messageModel.setSendUser(messageSender); + MessageUser messageReceiver = new MessageUser(); + messageReceiver.setEmail("abc@xxxx.com"); + messageReceiver.setName("拜登"); + messageReceiver.setOfficeAddress("华盛顿白宫"); + messageReceiver.setPhoneNum("911911911"); + messageModel.setReceiveUsers(Lists.newArrayList(messageReceiver)); + return messageModel; + } + + @Operation(summary = "获取投递箱详情", method = "GET", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "获取投递箱成功", content = @Content(schema = @Schema(implementation = MessageBox.class)))}) + @RequestMapping(value = "/swagger/getMessageBox", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public MessageBox getMessageBox(@RequestParam @Parameter(required = true, description = "投递箱ID") String boxId, + @RequestParam @Parameter(name = "sizeLimit", example = "10", description = "投递箱最大投递数") int maxSizeLimit) { + return new MessageBox(); + } + + @Operation(summary = "获取投递箱详情V2", method = "POST", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "获取投递箱成功", content = @Content(schema = @Schema(implementation = MessageBox.class)))}) + @RequestMapping(value = "/swagger/v2/getMessageBox", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public MessageBox getMessageBoxV2(@RequestBody + @Parameter(required = true, name = "messageBox", example = "投递箱信息") MessageBox messageBox) { + return new MessageBox(); + } + + @Operation(summary = "获取投递箱详情V3", method = "POST", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "获取投递箱成功", content = @Content(schema = @Schema(implementation = Map.class)))}) + @RequestMapping(value = "/swagger/v3/getMessageBox", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Map queryMessageBoxV3(@RequestBody + @Parameter(required = true, name = "messageBox", example = "投递箱信息") MessageBox messageBox) { + + return new HashMap<>(); + } + + + @Operation(summary = "获取投递箱地址", method = "GET", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "投递箱地址", content = @Content(schema = @Schema(implementation = String.class)))}) + @RequestMapping(value = "/swagger/getMessageBoxAddress", produces = MediaType.TEXT_PLAIN_VALUE) + public String queryMessageBoxAddress(@RequestParam(name = "boxId") + @Parameter(description = "投递箱ID", name = "boxId", example = "box-qvp9htm5", required = true) String id) { + return "华盛顿白宫"; + + } + +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java new file mode 100644 index 000000000..ec0a4ff05 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java @@ -0,0 +1,102 @@ +/* + * 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.tsf.demo.provider.swagger.model; + + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "消息投递箱") +public class MessageBox { + + @Schema(title = "默认失效天数", required = false) + private int expiredDays; + + @Schema(title = "最大失效天数", required = false) + private Integer maxExpiredDays; + + @Schema(title = "容量大小", required = false) + private Float capacity; + + @Schema(title = "最大容量大小", required = false) + private float maxCapacity; + + @Schema(title = "接受的信息数量", required = false) + private Double size; + + @Schema(title = "最大接受的信息数量", required = false) + private double maxSize; + + @Schema(title = "消息(循环测试嵌套对象)", required = false) + private MessageModel messageModel; + + public int getExpiredDays() { + return expiredDays; + } + + public void setExpiredDays(int expiredDays) { + this.expiredDays = expiredDays; + } + + public Integer getMaxExpiredDays() { + return maxExpiredDays; + } + + public void setMaxExpiredDays(Integer maxExpiredDays) { + this.maxExpiredDays = maxExpiredDays; + } + + public Float getCapacity() { + return capacity; + } + + public void setCapacity(Float capacity) { + this.capacity = capacity; + } + + public float getMaxCapacity() { + return maxCapacity; + } + + public void setMaxCapacity(float maxCapacity) { + this.maxCapacity = maxCapacity; + } + + public Double getSize() { + return size; + } + + public void setSize(Double size) { + this.size = size; + } + + public double getMaxSize() { + return maxSize; + } + + public void setMaxSize(double maxSize) { + this.maxSize = maxSize; + } + + public MessageModel getMessageModel() { + return messageModel; + } + + public void setMessageModel(MessageModel messageModel) { + this.messageModel = messageModel; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java new file mode 100644 index 000000000..08d3a528e --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java @@ -0,0 +1,92 @@ +/* + * 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.tsf.demo.provider.swagger.model; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "消息", title = "messageModel") +public class MessageModel { + + @Schema(name = "id", title = "消息ID", required = true, description = "消息ID notes") + private String msgId; + + @Schema(title = "消息内容", required = false) + private String msgContent; + + @Schema(title = "消息发送者", required = true) + private MessageUser sendUser; + + @Schema(title = "消息接收者", required = true) + private List receiveUsers; + + @Schema(title = "消息发送时间", required = true) + private long sendTime; + + @Schema(title = "消息投递箱", required = false) + private MessageBox messageBox; + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public String getMsgContent() { + return msgContent; + } + + public void setMsgContent(String msgContent) { + this.msgContent = msgContent; + } + + public MessageUser getSendUser() { + return sendUser; + } + + public void setSendUser(MessageUser sendUser) { + this.sendUser = sendUser; + } + + public List getReceiveUsers() { + return receiveUsers; + } + + public void setReceiveUsers(List receiveUsers) { + this.receiveUsers = receiveUsers; + } + + public long getSendTime() { + return sendTime; + } + + public void setSendTime(long sendTime) { + this.sendTime = sendTime; + } + + public MessageBox getMessageBox() { + return messageBox; + } + + public void setMessageBox(MessageBox messageBox) { + this.messageBox = messageBox; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java new file mode 100644 index 000000000..9bd2f06ed --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java @@ -0,0 +1,69 @@ +/* + * 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.tsf.demo.provider.swagger.model; + + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "消息发送/接收者") +public class MessageUser { + + @Schema(title = "用户姓名", name = "name") + private String name; + + @Schema(title = "邮箱地址") + private String email; + + @Schema(title = "电话号码") + private String phoneNum; + + @Schema(title = "办公地址") + private String officeAddress; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhoneNum() { + return phoneNum; + } + + public void setPhoneNum(String phoneNum) { + this.phoneNum = phoneNum; + } + + public String getOfficeAddress() { + return officeAddress; + } + + public void setOfficeAddress(String officeAddress) { + this.officeAddress = officeAddress; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..5e43105a2 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml @@ -0,0 +1,30 @@ +server: + port: 18081 +spring: + application: + name: provider-demo + cloud: + polaris: + namespace: default + enabled: true + stat: + enabled: true + port: 28081 + loadbalancer: + strategy: polarisWeightedRandom + tencent: + rpc-enhancement: + reporter: + enabled: true + +logging: + file: + name: /tsf-demo-logs/${spring.application.name}/root.log + level: + root: INFO +management: + endpoints: + web: + exposure: + include: + - polaris-config diff --git a/spring-cloud-tencent-plugin-starters/pom.xml b/spring-cloud-tencent-plugin-starters/pom.xml index bc2f153b9..702dfeca4 100644 --- a/spring-cloud-tencent-plugin-starters/pom.xml +++ b/spring-cloud-tencent-plugin-starters/pom.xml @@ -18,6 +18,9 @@ spring-cloud-tencent-featureenv-plugin spring-cloud-tencent-gateway-plugin spring-cloud-starter-tencent-discovery-adapter-plugin + spring-cloud-tencent-lossless-plugin + spring-cloud-starter-tencent-threadlocal-plugin + spring-cloud-starter-tencent-trace-plugin diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java index d1332926b..34f930000 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java @@ -19,8 +19,10 @@ package com.tencent.cloud.plugin.discovery.adapter.config; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; +import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosRegistrationTransformer; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerAutoConfiguration; import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -46,4 +48,11 @@ public InstanceTransformer instanceTransformer() { return new NacosInstanceTransformer(); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(name = "com.alibaba.cloud.nacos.registry.NacosRegistration") + public RegistrationTransformer registrationTransformer() { + return new NacosRegistrationTransformer(); + } + } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java new file mode 100644 index 000000000..9d2f44cf6 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java @@ -0,0 +1,48 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.discovery.adapter.transformer; + +import com.alibaba.cloud.nacos.NacosDiscoveryProperties; +import com.alibaba.cloud.nacos.registry.NacosRegistration; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.cloud.client.serviceregistry.Registration; + +public class NacosRegistrationTransformer implements RegistrationTransformer { + + @Override + public String getRegistry() { + return "nacos"; + } + + @Override + public void transformCustom(DefaultInstance instance, Registration registration) { + if (registration instanceof NacosRegistration) { + NacosDiscoveryProperties nacosDiscoveryProperties = ((NacosRegistration) registration).getNacosDiscoveryProperties(); + String namespace = nacosDiscoveryProperties.getNamespace(); + if (StringUtils.isBlank(namespace)) { + namespace = "default"; + } + instance.setNamespace(namespace); + } + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml new file mode 100644 index 000000000..91975c141 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/pom.xml @@ -0,0 +1,35 @@ + + + + spring-cloud-tencent-plugin-starters + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + spring-cloud-starter-tencent-threadlocal-plugin + Spring Cloud Starter Tencent ThreadLocal plugin + + + + + com.tencent.polaris + polaris-threadlocal + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java new file mode 100644 index 000000000..f2f9dc1c4 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/main/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapper.java @@ -0,0 +1,45 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.threadlocal; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import com.tencent.polaris.threadlocal.cross.RunnableWrapper; + +import org.springframework.core.task.TaskExecutor; + +public class TaskExecutorWrapper implements TaskExecutor { + + private final TaskExecutor taskExecutor; + + private final Supplier contextGetter; + + private final Consumer contextSetter; + + public TaskExecutorWrapper(TaskExecutor taskExecutor, Supplier contextGetter, Consumer contextSetter) { + this.taskExecutor = taskExecutor; + this.contextGetter = contextGetter; + this.contextSetter = contextSetter; + } + + @Override + public void execute(Runnable command) { + taskExecutor.execute(new RunnableWrapper<>(command, contextGetter, contextSetter)); + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java new file mode 100644 index 000000000..15dd313c6 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.threadlocal; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.jupiter.api.Test; + +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; + +/** + * Test for {@link TaskExecutorWrapper}. + * + * @author Haotian Zhang + */ +public class TaskExecutorWrapperTest { + + private static final ThreadLocal TEST_THREAD_LOCAL = new ThreadLocal<>(); + + private static final String TEST = "TEST"; + + @Test + public void testExecute() { + TEST_THREAD_LOCAL.set(TEST); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.initialize(); + AtomicReference result = new AtomicReference<>(false); + CountDownLatch latch = new CountDownLatch(1); + TaskExecutorWrapper taskExecutorWrapper = new TaskExecutorWrapper<>( + executor, TEST_THREAD_LOCAL::get, TEST_THREAD_LOCAL::set); + taskExecutorWrapper.execute(() -> { + result.set(TEST.equals(TEST_THREAD_LOCAL.get())); + latch.countDown(); + }); + try { + latch.await(); + assertThat(result.get()).isTrue(); + } + catch (InterruptedException e) { + fail(e.getMessage()); + } + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml new file mode 100644 index 000000000..99fe4f187 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml @@ -0,0 +1,24 @@ + + + spring-cloud-tencent-plugin-starters + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + spring-cloud-starter-tencent-trace-plugin + Spring Cloud Tencent Trace Plugin + + + + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + + com.tencent.polaris + trace-otel + + + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java new file mode 100644 index 000000000..ed7b2d459 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java @@ -0,0 +1,28 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace; + +import java.util.Map; + +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; + +public interface SpanAttributesProvider { + + Map getConsumerSpanAttributes(EnhancedPluginContext context); +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java new file mode 100644 index 000000000..6525ec8e4 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java @@ -0,0 +1,84 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace; + +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.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; +import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; +import com.tencent.polaris.assembly.api.pojo.TraceAttributes; + +public class TraceServerMetadataEnhancedPlugin implements EnhancedPlugin { + + private final PolarisSDKContextManager polarisSDKContextManager; + + private final SpanAttributesProvider spanAttributesProvider; + + public TraceServerMetadataEnhancedPlugin(PolarisSDKContextManager polarisSDKContextManager, SpanAttributesProvider spanAttributesProvider) { + this.polarisSDKContextManager = polarisSDKContextManager; + this.spanAttributesProvider = spanAttributesProvider; + } + + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Server.PRE; + } + + @Override + public void run(EnhancedPluginContext context) throws Throwable { + AssemblyAPI assemblyAPI = polarisSDKContextManager.getAssemblyAPI(); + Map attributes = new HashMap<>(); + if (null != spanAttributesProvider) { + Map additionalAttributes = spanAttributesProvider.getConsumerSpanAttributes(context); + if (CollectionUtils.isNotEmpty(additionalAttributes)) { + attributes.putAll(additionalAttributes); + } + } + MetadataContext metadataContext = MetadataContextHolder.get(); + Map transitiveCustomAttributes = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + if (CollectionUtils.isNotEmpty(transitiveCustomAttributes)) { + for (Map.Entry entry : transitiveCustomAttributes.entrySet()) { + attributes.put("custom." + entry.getKey(), entry.getValue()); + } + } + Map disposableCustomAttributes = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + if (CollectionUtils.isNotEmpty(disposableCustomAttributes)) { + for (Map.Entry entry : disposableCustomAttributes.entrySet()) { + attributes.put("custom." + entry.getKey(), entry.getValue()); + } + } + TraceAttributes traceAttributes = new TraceAttributes(); + traceAttributes.setAttributes(attributes); + traceAttributes.setAttributeLocation(TraceAttributes.AttributeLocation.SPAN); + assemblyAPI.updateTraceAttributes(traceAttributes); + } + + @Override + public int getOrder() { + return PluginOrderConstant.ServerPluginOrder.PROVIDER_TRACE_METADATA_PLUGIN_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java new file mode 100644 index 000000000..72370839a --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java @@ -0,0 +1,41 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.config; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; + +/** + * Spring Cloud Tencent config Override polaris trace config. + * + * @author andrew 2024-06-18 + */ +public class TraceConfigModifier implements PolarisConfigModifier { + + @Override + public void modify(ConfigurationImpl configuration) { + configuration.getGlobal().getTraceReporter().setEnable(true); + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.TRACE_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java new file mode 100644 index 000000000..c9e354048 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.config; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) +public class TraceConfigModifierAutoConfiguration { + + @Bean + public TraceConfigModifier traceConfigModifier() { + return new TraceConfigModifier(); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java new file mode 100644 index 000000000..4f0a87bc7 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java @@ -0,0 +1,30 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(TraceConfigModifierAutoConfiguration.class) +public class TraceConfigModifierBootstrapAutoConfiguration { + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java new file mode 100644 index 000000000..9eb8970a4 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.config; + +import com.tencent.cloud.plugin.trace.SpanAttributesProvider; +import com.tencent.cloud.plugin.trace.TraceServerMetadataEnhancedPlugin; +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) +public class TraceEnhancedPluginAutoConfiguration { + + @Bean + public TraceServerMetadataEnhancedPlugin traceServerMetadataEnhancedPlugin( + PolarisSDKContextManager polarisSDKContextManager, @Autowired(required = false) SpanAttributesProvider spanAttributesProvider) { + return new TraceServerMetadataEnhancedPlugin(polarisSDKContextManager, spanAttributesProvider); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java new file mode 100644 index 000000000..3fe48314c --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java @@ -0,0 +1,52 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.tsf; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.plugin.trace.SpanAttributesProvider; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants; + +import org.springframework.cloud.client.ServiceInstance; + +public class TsfSpanAttributesProvider implements SpanAttributesProvider { + + @Override + public Map getConsumerSpanAttributes(EnhancedPluginContext context) { + Map attributes = new HashMap<>(); + if (null != context.getRequest().getUrl()) { + attributes.put("remoteInterface", context.getRequest().getUrl().getPath()); + } + ServiceInstance targetServiceInstance = context.getTargetServiceInstance(); + if (null != targetServiceInstance && CollectionUtils.isNotEmpty(targetServiceInstance.getMetadata())) { + String nsId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_NAMESPACE_ID); + attributes.put("remote.namespace-id", StringUtils.defaultString(nsId)); + String groupId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_GROUP_ID); + attributes.put("remote.group-id", StringUtils.defaultString(groupId)); + String applicationId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_APPLICATION_ID); + attributes.put("remote.application-id", StringUtils.defaultString(applicationId)); + } + return attributes; + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java new file mode 100644 index 000000000..3b5b102f4 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java @@ -0,0 +1,39 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfEnabled +@ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) +public class TsfTracePropertiesAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfSpanAttributesProvider tsfClientSpanAttributesProvider() { + return new TsfSpanAttributesProvider(); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..eb958b7e9 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.plugin.trace.config.TraceConfigModifierAutoConfiguration,\ + com.tencent.cloud.plugin.trace.config.TraceEnhancedPluginAutoConfiguration,\ + com.tencent.cloud.plugin.trace.tsf.TsfTracePropertiesAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.plugin.trace.config.TraceConfigModifierBootstrapAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml new file mode 100644 index 000000000..416b4130c --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml @@ -0,0 +1,64 @@ + + + + spring-cloud-tencent-plugin-starters + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + spring-cloud-tencent-lossless-plugin + Spring Cloud Tencent Lossless Plugin + + + + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + + + com.tencent.polaris + lossless-register + + + + com.tencent.polaris + lossless-deregister + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-web + test + + + + com.tencent.polaris + polaris-test-mock-discovery + test + + + junit + junit + + + + + + + diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java new file mode 100644 index 000000000..9dab0f243 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java @@ -0,0 +1,107 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless; + +import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; +import com.tencent.polaris.api.pojo.BaseInstance; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; + +/** + * Intercept for of register and deregister. + * + * @author Shedfree Wu + */ +@Aspect +public class LosslessRegistryAspect { + + private ServiceRegistry serviceRegistry; + + private Registration registration; + + private LosslessProperties losslessProperties; + + private PolarisSDKContextManager polarisSDKContextManager; + + private RegistrationTransformer registrationTransformer; + + private PolarisContextProperties properties; + + public LosslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration, + PolarisContextProperties properties, LosslessProperties losslessProperties, + PolarisSDKContextManager polarisSDKContextManager, RegistrationTransformer registrationTransformer) { + this.serviceRegistry = serviceRegistry; + this.registration = registration; + this.losslessProperties = losslessProperties; + this.polarisSDKContextManager = polarisSDKContextManager; + this.registrationTransformer = registrationTransformer; + this.properties = properties; + } + + @Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(..))") + public void registerPointcut() { + + } + + @Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.deregister(..))") + public void deregisterPointcut() { + + } + + @Around("registerPointcut()") + public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { + if (!losslessProperties.isEnabled()) { + return joinPoint.proceed(); + } + + // web started, get port from registration + BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, registrationTransformer); + + Runnable registerAction = () -> executeJoinPoint(joinPoint); + + SpringCloudLosslessActionProvider losslessActionProvider = + new SpringCloudLosslessActionProvider(serviceRegistry, registration, losslessProperties, registerAction); + + polarisSDKContextManager.getLosslessAPI().setLosslessActionProvider(instance, losslessActionProvider); + polarisSDKContextManager.getLosslessAPI().losslessRegister(instance); + // return void + return null; + } + + @Around("deregisterPointcut()") + public Object invokeDeregister(ProceedingJoinPoint joinPoint) throws Throwable { + return joinPoint.proceed(); + } + + public void executeJoinPoint(ProceedingJoinPoint joinPoint) { + try { + joinPoint.proceed(); + } + catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java new file mode 100644 index 000000000..a97df5960 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java @@ -0,0 +1,95 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.util.OkHttpUtil; +import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; +import com.tencent.polaris.api.plugin.lossless.InstanceProperties; +import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider; +import com.tencent.polaris.api.pojo.BaseInstance; +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.http.HttpHeaders; + +/** + * LosslessActionProvider for Spring Cloud. + * + * @author Shedfree Wu + */ +public class SpringCloudLosslessActionProvider implements LosslessActionProvider { + private ServiceRegistry serviceRegistry; + + private LosslessProperties losslessProperties; + + private Runnable originalRegisterAction; + + private Registration registration; + + public SpringCloudLosslessActionProvider(ServiceRegistry serviceRegistry, Registration registration, + LosslessProperties losslessProperties, Runnable originalRegisterAction) { + this.serviceRegistry = serviceRegistry; + this.registration = registration; + this.losslessProperties = losslessProperties; + this.originalRegisterAction = originalRegisterAction; + } + + @Override + public String getName() { + return "spring-cloud"; + } + + @Override + public void doRegister(InstanceProperties instanceProperties) { + // use lambda to do original register + originalRegisterAction.run(); + } + + @Override + public void doDeregister() { + serviceRegistry.deregister(registration); + } + + /** + * Check whether health check is enable. + * @return true: register after passing doHealthCheck, false: register after delayRegisterInterval. + */ + @Override + public boolean isEnableHealthCheck() { + return StringUtils.isNotBlank(losslessProperties.getHealthCheckPath()); + } + + @Override + public boolean doHealthCheck() { + Map headers = new HashMap<>(1); + headers.put(HttpHeaders.USER_AGENT, "polaris"); + + return OkHttpUtil.checkUrl("localhost", registration.getPort(), + losslessProperties.getHealthCheckPath(), headers); + } + + public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { + return registrationTransformer.transform(registration); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java new file mode 100644 index 000000000..8b2cffe49 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessAutoConfiguration.java @@ -0,0 +1,54 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.lossless.config; + +import com.tencent.cloud.plugin.lossless.LosslessRegistryAspect; +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * Autoconfiguration of lossless. + * + * @author Shedfree Wu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@Import(LosslessPropertiesAutoConfiguration.class) +public class LosslessAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public LosslessRegistryAspect losslessRegistryAspect( + ServiceRegistry serviceRegistry, Registration registration, PolarisContextProperties properties, + LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager, + RegistrationTransformer registrationTransformer) { + return new LosslessRegistryAspect(serviceRegistry, registration, properties, losslessProperties, + polarisSDKContextManager, registrationTransformer); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java new file mode 100644 index 000000000..f5049df76 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless.config; + +import java.util.Objects; + +import com.tencent.cloud.common.constant.OrderConstant.Modifier; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.provider.LosslessConfigImpl; + +/** + * Config modifier for lossless. + * + * @author Shedfree Wu + */ +public class LosslessConfigModifier implements PolarisConfigModifier { + + private final LosslessProperties losslessProperties; + + public LosslessConfigModifier(LosslessProperties losslessProperties) { + this.losslessProperties = losslessProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + if (losslessProperties.isEnabled()) { + LosslessConfigImpl losslessConfig = (LosslessConfigImpl) configuration.getProvider().getLossless(); + losslessConfig.setEnable(true); + losslessConfig.setPort(losslessProperties.getPort()); + if (Objects.nonNull(losslessProperties.getDelayRegisterInterval())) { + losslessConfig.setDelayRegisterInterval(losslessProperties.getDelayRegisterInterval()); + } + if (Objects.nonNull(losslessProperties.getHealthCheckInterval())) { + losslessConfig.setHealthCheckInterval(losslessProperties.getHealthCheckInterval()); + } + } + } + + @Override + public int getOrder() { + return Modifier.LOSSLESS_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java new file mode 100644 index 000000000..89398f42a --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java @@ -0,0 +1,75 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.lossless.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("spring.cloud.polaris.lossless") +public class LosslessProperties { + + private boolean enabled = false; + + private int port = 28080; + + private String healthCheckPath; + + private Long delayRegisterInterval; + + private Long healthCheckInterval; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getHealthCheckPath() { + return healthCheckPath; + } + + public void setHealthCheckPath(String healthCheckPath) { + this.healthCheckPath = healthCheckPath; + } + + public Long getDelayRegisterInterval() { + return delayRegisterInterval; + } + + public void setDelayRegisterInterval(Long delayRegisterInterval) { + this.delayRegisterInterval = delayRegisterInterval; + } + + public Long getHealthCheckInterval() { + return healthCheckInterval; + } + + public void setHealthCheckInterval(Long healthCheckInterval) { + this.healthCheckInterval = healthCheckInterval; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java new file mode 100644 index 000000000..23826a37c --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java @@ -0,0 +1,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.plugin.lossless.config; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Autoconfiguration of lossless properties. + * + * @author Shedfree Wu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@EnableConfigurationProperties(LosslessProperties.class) +public class LosslessPropertiesAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public LosslessConfigModifier losslessConfigModifier(LosslessProperties losslessProperties) { + return new LosslessConfigModifier(losslessProperties); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java new file mode 100644 index 000000000..dd047cabc --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesBootstrapConfiguration.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + + +/** + * BootstrapConfiguration of lossless properties. + * + * @author Shedfree Wu + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(LosslessPropertiesAutoConfiguration.class) +public class LosslessPropertiesBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..48a31c1cd --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,10 @@ +{ + "properties": [ + { + "name": "spring.cloud.polaris.lossless.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "the switch for lossless plugin." + } + ] +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..fee2a497c --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.plugin.lossless.config.LosslessPropertiesBootstrapConfiguration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.plugin.lossless.config.LosslessAutoConfiguration diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java new file mode 100644 index 000000000..02e6f4087 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessPropertiesTest.java @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless; + +import com.tencent.cloud.plugin.lossless.config.LosslessProperties; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link LosslessProperties}. + * + * @author Shedfree Wu + */ +public class LosslessPropertiesTest { + + @Test + void testGetAndSet() { + LosslessProperties polarisStatProperties = new LosslessProperties(); + + // healthCheckPath + polarisStatProperties.setHealthCheckPath("/xxx"); + assertThat(polarisStatProperties.getHealthCheckPath()).isEqualTo("/xxx"); + } +} diff --git a/spring-cloud-tencent-polaris-context/pom.xml b/spring-cloud-tencent-polaris-context/pom.xml index 972fe0046..82e881630 100644 --- a/spring-cloud-tencent-polaris-context/pom.xml +++ b/spring-cloud-tencent-polaris-context/pom.xml @@ -34,6 +34,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata @@ -108,6 +112,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata @@ -177,7 +185,16 @@ com.tencent.polaris polaris-router-factory - + + + com.tencent.polaris + polaris-circuitbreaker-factory + + + + com.tencent.polaris + polaris-ratelimit-factory + com.tencent.polaris @@ -193,6 +210,11 @@ com.tencent.polaris polaris-assembly-factory + + + com.tencent.polaris + event-tsf + diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java index 68e9f2c4c..bb830b80d 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.context; +import java.util.ArrayList; import java.util.List; import com.tencent.cloud.common.constant.OrderConstant; @@ -26,6 +27,8 @@ import com.tencent.polaris.factory.config.ConfigurationImpl; import org.apache.commons.lang.StringUtils; +import org.springframework.util.CollectionUtils; + /** * Modify polaris server address. * @@ -48,6 +51,13 @@ public void modify(ConfigurationImpl configuration) { List addresses = AddressUtils.parseAddressList(properties.getAddress()); configuration.getGlobal().getServerConnector().setAddresses(addresses); + if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) { + configuration.getGlobal().setServerConnectors(new ArrayList<>()); + } + if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors()) + && null != configuration.getGlobal().getServerConnector()) { + configuration.getGlobal().getServerConnectors().add(configuration.getGlobal().getServerConnector()); + } } @Override diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java similarity index 80% rename from spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java rename to spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java index 22830fa81..f627d46ed 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java @@ -15,12 +15,12 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.contract.config; +package com.tencent.cloud.polaris.context; /** - * Extend contract properties. + * Config modifier interface for Polaris configuration. * * @author Haotian Zhang */ -public interface ExtendedContractProperties extends ContractProperties { +public interface PolarisConfigurationConfigModifier extends PolarisConfigModifier { } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java index e28a60770..26fe59e6b 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java @@ -17,13 +17,17 @@ package com.tencent.cloud.polaris.context; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.control.Destroyable; import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.core.LosslessAPI; import com.tencent.polaris.api.core.ProviderAPI; +import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.assembly.factory.AssemblyAPIFactory; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; @@ -52,9 +56,11 @@ public class PolarisSDKContextManager { * Constant for checking before destroy SDK context. */ public volatile static boolean isRegistered = false; - private volatile static SDKContext sdkContext; + private volatile static SDKContext configSDKContext; + private volatile static SDKContext serviceSdkContext; private volatile static ProviderAPI providerAPI; private volatile static ConsumerAPI consumerAPI; + private volatile static LosslessAPI losslessAPI; private volatile static RouterAPI routerAPI; private volatile static CircuitBreakAPI circuitBreakAPI; private volatile static LimitAPI limitAPI; @@ -73,7 +79,7 @@ public PolarisSDKContextManager(PolarisContextProperties properties, Environment * Don't call this method directly. */ public static void innerDestroy() { - if (Objects.nonNull(sdkContext)) { + if (Objects.nonNull(serviceSdkContext)) { try { // destroy ProviderAPI if (Objects.nonNull(providerAPI)) { @@ -81,6 +87,12 @@ public static void innerDestroy() { providerAPI = null; } + // destroy LosslessAPI + if (Objects.nonNull(losslessAPI)) { + ((AutoCloseable) losslessAPI).close(); + losslessAPI = null; + } + // destroy ConsumerAPI if (Objects.nonNull(consumerAPI)) { ((AutoCloseable) consumerAPI).close(); @@ -111,9 +123,9 @@ public static void innerDestroy() { assemblyAPI = null; } - if (Objects.nonNull(sdkContext)) { - sdkContext.destroy(); - sdkContext = null; + if (Objects.nonNull(serviceSdkContext)) { + serviceSdkContext.destroy(); + serviceSdkContext = null; } LOG.info("Polaris SDK context is destroyed."); } @@ -123,32 +135,127 @@ public static void innerDestroy() { } } + /** + * Used for config data. + */ + public static SDKContext innerGetConfigSDKContext() { + if (configSDKContext == null) { + throw new IllegalArgumentException("configSDKContext is not initialized."); + } + return configSDKContext; + } + + public static void innerConfigDestroy() { + try { + if (Objects.nonNull(configSDKContext)) { + configSDKContext.destroy(); + configSDKContext = null; + } + LOG.info("Polaris SDK config context is destroyed."); + } + catch (Throwable throwable) { + LOG.info("Polaris SDK config context is destroyed failed.", throwable); + } + } + public void init() { - if (null == sdkContext) { + initService(); + initConfig(); + } + + public SDKContext getSDKContext() { + initService(); + return serviceSdkContext; + } + + public ProviderAPI getProviderAPI() { + initService(); + return providerAPI; + } + + public LosslessAPI getLosslessAPI() { + initService(); + return losslessAPI; + } + + public ConsumerAPI getConsumerAPI() { + initService(); + return consumerAPI; + } + + public RouterAPI getRouterAPI() { + initService(); + return routerAPI; + } + + public CircuitBreakAPI getCircuitBreakAPI() { + initService(); + return circuitBreakAPI; + } + + public LimitAPI getLimitAPI() { + initService(); + return limitAPI; + } + + public AssemblyAPI getAssemblyAPI() { + return assemblyAPI; + } + + public SDKContext getConfigSDKContext() { + initConfig(); + return configSDKContext; + } + + /** + * Used for config data. + */ + public static void setConfigSDKContext(SDKContext context) { + if (configSDKContext == null) { + configSDKContext = context; + // add shutdown hook + Runtime.getRuntime().addShutdownHook(new Thread(PolarisSDKContextManager::innerConfigDestroy)); + LOG.info("create Polaris config SDK context successfully."); + } + } + + public void initService() { + if (null == serviceSdkContext) { try { + // get modifiers for service. + List serviceModifierList = new ArrayList<>(); + for (PolarisConfigModifier modifier : modifierList) { + if (!(modifier instanceof PolarisConfigurationConfigModifier)) { + serviceModifierList.add(modifier); + } + } // init SDKContext - sdkContext = SDKContext.initContextByConfig(properties.configuration(modifierList, + Configuration configuration = properties.configuration(serviceModifierList, () -> environment.getProperty("spring.cloud.client.ip-address"), - () -> environment.getProperty("spring.cloud.polaris.local-port", Integer.class, 0))); - sdkContext.init(); + () -> environment.getProperty("spring.cloud.polaris.local-port", Integer.class, 0)); + serviceSdkContext = SDKContext.initContextByConfig(configuration); + serviceSdkContext.init(); // init ProviderAPI - providerAPI = DiscoveryAPIFactory.createProviderAPIByContext(sdkContext); + providerAPI = DiscoveryAPIFactory.createProviderAPIByContext(serviceSdkContext); + + // init losslessAPI + losslessAPI = DiscoveryAPIFactory.createLosslessAPIByContext(serviceSdkContext); // init ConsumerAPI - consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(sdkContext); + consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(serviceSdkContext); // init RouterAPI - routerAPI = RouterAPIFactory.createRouterAPIByContext(sdkContext); + routerAPI = RouterAPIFactory.createRouterAPIByContext(serviceSdkContext); // init CircuitBreakAPI - circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByContext(sdkContext); + circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByContext(serviceSdkContext); // init LimitAPI - limitAPI = LimitAPIFactory.createLimitAPIByContext(sdkContext); + limitAPI = LimitAPIFactory.createLimitAPIByContext(serviceSdkContext); // init AssemblyAPI - assemblyAPI = AssemblyAPIFactory.createAssemblyAPIByContext(sdkContext); + assemblyAPI = AssemblyAPIFactory.createAssemblyAPIByContext(serviceSdkContext); // add shutdown hook Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -164,46 +271,40 @@ public void init() { } } })); - LOG.info("create Polaris SDK context successfully. properties: {}", properties); + LOG.info("create Polaris SDK context successfully. properties: {}, configuration: {}", properties, configuration); } catch (Throwable throwable) { - LOG.error("create Polaris SDK context failed. properties: {}", properties, throwable); + LOG.error("create Polaris SDK context failed. properties: {}, ", properties, throwable); throw throwable; } } } - public SDKContext getSDKContext() { - init(); - return sdkContext; - } - - public ProviderAPI getProviderAPI() { - init(); - return providerAPI; - } - - public ConsumerAPI getConsumerAPI() { - init(); - return consumerAPI; - } - - public RouterAPI getRouterAPI() { - init(); - return routerAPI; - } - - public CircuitBreakAPI getCircuitBreakAPI() { - init(); - return circuitBreakAPI; - } - - public LimitAPI getLimitAPI() { - init(); - return limitAPI; - } + public void initConfig() { + // get modifiers for configuration. + List configModifierList = new ArrayList<>(); + for (PolarisConfigModifier modifier : modifierList) { + if (modifier instanceof PolarisConfigurationConfigModifier) { + configModifierList.add(modifier); + } + } + if (null == configSDKContext && CollectionUtils.isNotEmpty(configModifierList)) { + try { + // init config SDKContext + Configuration configuration = properties.configuration(configModifierList, + () -> environment.getProperty("spring.cloud.client.ip-address"), + () -> environment.getProperty("spring.cloud.polaris.local-port", Integer.class, 0)); + configSDKContext = SDKContext.initContextByConfig(configuration); + configSDKContext.init(); - public AssemblyAPI getAssemblyAPI() { - return assemblyAPI; + // add shutdown hook + Runtime.getRuntime().addShutdownHook(new Thread(PolarisSDKContextManager::innerConfigDestroy)); + LOG.info("create Polaris config SDK context successfully. properties: {}, configuration: {}", properties, configuration); + } + catch (Throwable throwable) { + LOG.error("create Polaris config SDK context failed. properties: {}, ", properties, throwable); + throw throwable; + } + } } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java index bf41c50bd..132d9e618 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java @@ -20,8 +20,8 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.polaris.api.plugin.common.ValueContext; -import com.tencent.polaris.api.plugin.route.LocationLevel; import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import org.apache.commons.lang.StringUtils; /** @@ -39,13 +39,13 @@ public PostInitPolarisSDKContext(SDKContext sdkContext, StaticMetadataManager st ValueContext valueContext = sdkContext.getValueContext(); if (StringUtils.isNotBlank(region)) { - valueContext.setValue(LocationLevel.region.name(), region); + valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.REGION.name(), region); } if (StringUtils.isNotBlank(zone)) { - valueContext.setValue(LocationLevel.zone.name(), zone); + valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.ZONE.name(), zone); } if (StringUtils.isNotBlank(campus)) { - valueContext.setValue(LocationLevel.campus.name(), campus); + valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.CAMPUS.name(), campus); } } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java index 080b0bf4f..139de40fc 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java @@ -20,11 +20,15 @@ import java.util.List; +import com.tencent.cloud.common.tsf.ConditionalOnTsfEnabled; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ModifyAddress; import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfInstanceMetadataProvider; import com.tencent.cloud.polaris.context.listener.PolarisContextApplicationEventListener; import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.client.api.SDKContext; @@ -64,4 +68,23 @@ public ServiceRuleManager serviceRuleManager(PolarisSDKContextManager polarisSDK public PolarisContextApplicationEventListener contextApplicationEventListener(PolarisSDKContextManager polarisSDKContextManager) { return new PolarisContextApplicationEventListener(polarisSDKContextManager); } + + @Bean + @ConditionalOnMissingBean + public ConsulProperties consulProperties() { + return new ConsulProperties(); + } + + @Bean + @ConditionalOnMissingBean + public TsfCoreProperties tsfCoreProperties() { + return new TsfCoreProperties(); + } + + @Bean + @ConditionalOnTsfEnabled + @ConditionalOnMissingBean + public TsfInstanceMetadataProvider tsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) { + return new TsfInstanceMetadataProvider(tsfCoreProperties); + } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java index 498af60d1..f92d065fb 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java @@ -65,7 +65,7 @@ public class PolarisContextProperties { * If polaris enabled. */ @Value("${spring.cloud.polaris.enabled:#{'true'}}") - private Boolean enabled; + private Boolean enabled = true; /** * polaris namespace. @@ -76,6 +76,7 @@ public class PolarisContextProperties { /** * polaris service name. */ + @Value("${spring.cloud.polaris.service:${spring.application.name:}}") private String service; public Configuration configuration(List modifierList, Supplier ipAddressSupplier, Supplier portSupplier) { diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java new file mode 100644 index 000000000..f5fba1138 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java @@ -0,0 +1,106 @@ +/* + * 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.config.extend.consul; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +/** + * Copy from org.springframework.cloud.consul.ConsulProperties. + * + * @author Spencer Gibb + */ +@ConfigurationProperties(ConsulProperties.PREFIX) +@Validated +public class ConsulProperties { + + /** + * Prefix for configuration properties. + */ + public static final String PREFIX = "spring.cloud.consul"; + + /** Consul agent hostname. Defaults to 'localhost'. */ + private String host = "localhost"; + + /** + * Consul agent scheme (HTTP/HTTPS). If there is no scheme in address - client + * will use HTTP. + */ + private String scheme; + + /** Consul agent port. Defaults to '8500'. */ + private int port = 8500; + + /** Is spring cloud consul enabled. */ + private boolean enabled = false; + + @Value("${consul.token:${CONSUL_TOKEN:${spring.cloud.consul.token:${SPRING_CLOUD_CONSUL_TOKEN:}}}}") + private String aclToken; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getScheme() { + return scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getAclToken() { + return aclToken; + } + + public void setAclToken(String aclToken) { + this.aclToken = aclToken; + } + + @Override + public String toString() { + return "ConsulProperties{" + + "host='" + host + '\'' + + ", scheme='" + scheme + '\'' + + ", port=" + port + + ", enabled=" + enabled + + ", aclToken='" + aclToken + '\'' + + '}'; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.java new file mode 100644 index 000000000..9cfbf9892 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.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.context.config.extend.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * TSF context auto configuration. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(PolarisContextAutoConfiguration.class) +@ConditionalOnTsfConsulEnabled +public class TsfContextAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfContextConfigModifier tsfConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties) { + return new TsfContextConfigModifier(tsfCoreProperties, consulProperties); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java new file mode 100644 index 000000000..2c452f00e --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java @@ -0,0 +1,32 @@ +/* + * 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.config.extend.tsf; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * TSF context bootstrap configuration. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@Import(TsfContextAutoConfiguration.class) +public class TsfContextBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java new file mode 100644 index 000000000..bf681054f --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java @@ -0,0 +1,64 @@ +/* + * 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.config.extend.tsf; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.polaris.api.config.plugin.DefaultPlugins; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.event.tsf.TsfEventReporterConfig; + +/** + * Config modifier for TSF. + * + * @author Haotian Zhang + */ +public class TsfContextConfigModifier implements PolarisConfigModifier { + + private final TsfCoreProperties tsfCoreProperties; + + private final ConsulProperties consulProperties; + + public TsfContextConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties) { + this.tsfCoreProperties = tsfCoreProperties; + this.consulProperties = consulProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + configuration.getGlobal().getEventReporter().getReporters().add(DefaultPlugins.TSF_EVENT_REPORTER_TYPE); + + TsfEventReporterConfig tsfEventReporterConfig = new TsfEventReporterConfig(); + tsfEventReporterConfig.setEventMasterIp(tsfCoreProperties.getEventMasterIp()); + tsfEventReporterConfig.setEventMasterPort(tsfCoreProperties.getEventMasterPort()); + tsfEventReporterConfig.setAppId(tsfCoreProperties.getAppId()); + tsfEventReporterConfig.setRegion(tsfCoreProperties.getTsfRegion()); + tsfEventReporterConfig.setInstanceId(tsfCoreProperties.getInstanceId()); + tsfEventReporterConfig.setTsfNamespaceId(tsfCoreProperties.getTsfNamespaceId()); + tsfEventReporterConfig.setServiceName(tsfCoreProperties.getServiceName()); + tsfEventReporterConfig.setToken(consulProperties.getAclToken()); + configuration.getGlobal().getEventReporter() + .setPluginConfig(DefaultPlugins.TSF_EVENT_REPORTER_TYPE, tsfEventReporterConfig); + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.CIRCUIT_BREAKER_ORDER - 1; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java new file mode 100644 index 000000000..32c51d07d --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java @@ -0,0 +1,174 @@ +/* + * 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.config.extend.tsf; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.polaris.api.utils.StringUtils; +import org.apache.commons.logging.Log; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +/** + * Read TSF env. + * + * @author Haotian Zhang + */ +public final class TsfCoreEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { + + public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 10 - 1; + + private final Logger LOGGER = LoggerFactory.getLogger(TsfCoreEnvironmentPostProcessor.class); + + private TsfCoreEnvironmentPostProcessor() { + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + String tsfAppId = environment.getProperty("tsf_app_id"); + // TSF deploy + if (StringUtils.isNotBlank(tsfAppId)) { + Map defaultProperties = new HashMap<>(); + + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + String tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); + if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("tse_polaris_ip"))) { + tsePolarisAddress = "grpc://" + environment.getProperty("tse_polaris_ip") + ":8091"; + } + + // tsf_prog_version + String tsfProgVersion = environment.getProperty("tsf_prog_version"); + if (StringUtils.isBlank(tsfProgVersion)) { + LOGGER.error("tsf_prog_version is empty"); + } + else { + defaultProperties.put("spring.cloud.polaris.discovery.version", tsfProgVersion); + } + + // lossless + defaultProperties.put("spring.cloud.polaris.lossless.enabled", true); + defaultProperties.put("spring.cloud.polaris.lossless.port", environment.getProperty("tsf_sctt_extensions_port", "11134")); + + // state + defaultProperties.put("spring.cloud.polaris.stat.port", environment.getProperty("tsf_sctt_extensions_port", "11134")); + + boolean tsfConsulEnable = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); + if (tsfConsulEnable) { + // tsf_consul_port + String tsfConsulPort = environment.getProperty("tsf_consul_port"); + if (StringUtils.isBlank(tsfConsulPort)) { + LOGGER.error("tsf_consul_port is empty"); + } + // tsf_token + String tsfConsulToken = environment.getProperty("tsf_token"); + if (StringUtils.isBlank(tsfConsulToken)) { + LOGGER.error("tsf_token is empty"); + } + // tsf_instance_id + String tsfInstanceId = environment.getProperty("tsf_instance_id"); + if (StringUtils.isBlank(tsfInstanceId)) { + LOGGER.error("tsf_instance_id is empty"); + } + // tsf_application_id + String tsfApplicationId = environment.getProperty("tsf_application_id"); + if (StringUtils.isBlank(tsfApplicationId)) { + LOGGER.error("tsf_application_id is empty"); + } + + // tsf_group_id + String tsfGroupId = environment.getProperty("tsf_group_id"); + if (StringUtils.isBlank(tsfGroupId)) { + LOGGER.error("tsf_group_id is empty"); + } + + // tsf_namespace_id + String tsfNamespaceId = environment.getProperty("tsf_namespace_id"); + if (StringUtils.isBlank(tsfNamespaceId)) { + LOGGER.error("tsf_namespace_id is empty"); + } + else { + defaultProperties.put("spring.cloud.polaris.namespace", tsfNamespaceId); + } + + // context + defaultProperties.put("spring.cloud.polaris.enabled", "true"); + defaultProperties.put("spring.cloud.polaris.discovery.enabled", "false"); + defaultProperties.put("spring.cloud.polaris.discovery.register", "false"); + defaultProperties.put("spring.cloud.consul.enabled", "true"); + defaultProperties.put("spring.cloud.consul.host", tsfConsulIp); + defaultProperties.put("spring.cloud.consul.port", tsfConsulPort); + defaultProperties.put("spring.cloud.consul.token", tsfConsulToken); + + // discovery + defaultProperties.put("spring.cloud.consul.discovery.enabled", "true"); + defaultProperties.put("spring.cloud.consul.discovery.register", "true"); + defaultProperties.put("spring.cloud.consul.discovery.instance-id", tsfInstanceId); + defaultProperties.put("spring.cloud.polaris.discovery.instance-id", tsfInstanceId); + defaultProperties.put("spring.cloud.polaris.discovery.zero-protection.enabled", "true"); + defaultProperties.put("spring.cloud.polaris.discovery.zero-protection.is-need-test-connectivity", "true"); + defaultProperties.put("spring.cloud.discovery.client.health-indicator.enabled", "false"); + + // contract + defaultProperties.put("spring.cloud.polaris.contract.enabled", environment.getProperty("tsf.swagger.enabled", "true")); + if (StringUtils.isNotBlank(environment.getProperty("tsf.swagger.basePackage"))) { + defaultProperties.put("spring.cloud.polaris.contract.base-package", environment.getProperty("tsf.swagger.basePackage")); + } + if (StringUtils.isNotBlank(environment.getProperty("tsf.swagger.excludePath"))) { + defaultProperties.put("spring.cloud.polaris.contract.exclude-path", environment.getProperty("tsf.swagger.excludePath")); + } + defaultProperties.put("spring.cloud.polaris.contract.group", environment.getProperty("tsf.swagger.group", "polaris")); + defaultProperties.put("spring.cloud.polaris.contract.base-path", environment.getProperty("tsf.swagger.basePath", "/**")); + defaultProperties.put("spring.cloud.polaris.contract.exposure", environment.getProperty("tsf.swagger.doc.auto-startup", "true")); + defaultProperties.put("spring.cloud.polaris.contract.report.enabled", environment.getProperty("tsf.swagger.enabled", "true")); + defaultProperties.put("spring.cloud.polaris.contract.name", tsfApplicationId); + + // configuration + defaultProperties.put("spring.cloud.polaris.config.enabled", "true"); + defaultProperties.put("spring.cloud.polaris.config.internal-enabled", "false"); + defaultProperties.put("spring.cloud.polaris.config.data-source", "consul"); + defaultProperties.put("spring.cloud.polaris.config.address", "http://" + tsfConsulIp + ":" + tsfConsulPort); + defaultProperties.put("spring.cloud.polaris.config.port", tsfConsulPort); + defaultProperties.put("spring.cloud.polaris.config.token", tsfConsulToken); + defaultProperties.put("spring.cloud.polaris.config.groups[0].namespace", "config"); + defaultProperties.put("spring.cloud.polaris.config.groups[0].name", "application"); + defaultProperties.put("spring.cloud.polaris.config.groups[0].files[0]", tsfApplicationId + "/" + tsfGroupId + "/"); + defaultProperties.put("spring.cloud.polaris.config.groups[0].files[1]", tsfNamespaceId + "/"); + defaultProperties.put("spring.cloud.polaris.config.refresh-type", "refresh_context"); + + // router + defaultProperties.put("spring.cloud.polaris.router.rule-router.fail-over", "none"); + defaultProperties.put("spring.cloud.polaris.router.namespace-router.enabled", "true"); + } + + MapPropertySource propertySource = new MapPropertySource("tsf-polaris-properties", defaultProperties); + environment.getPropertySources().addFirst(propertySource); + } + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java new file mode 100644 index 000000000..c60220a9f --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java @@ -0,0 +1,294 @@ +/* + * 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.config.extend.tsf; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Core properties. + * + * @author Haotian Zhang + */ +@ConfigurationProperties("tsf") +public class TsfCoreProperties { + + @Value("${tsf_app_id:}") + private String appId; + + /** + * Unique service instance id. + */ + @Value("${tsf_instance_id:${spring.cloud.consul.discovery.instanceId:${SPRING_CLOUD_CONSUL_DISCOVERY_INSTANCEID:}}}") + private String instanceId; + + /** + * tsf service consul registration tags. + *

+ * applicationId 应用Id + */ + @Value("${tsf_application_id:}") + private String tsfApplicationId; + + /** + * tsf service consul registration tags. + *

+ * groupId 部署组Id + */ + @Value("${tsf_group_id:}") + private String tsfGroupId; + + /** + * tsf service consul registration tags. + * + * progVersion 包版本 + */ + @Value("${tsf_prog_version:}") + private String tsfProgVersion; + + /** + * 仅本地测试时使用. + */ + @Value("${tsf_namespace_id:}") + private String tsfNamespaceId; + + @Value("${spring.application.name:}") + private String serviceName; + + /** + * tsf service consul registration tags. + * + * 地域信息 + */ + @Value("${tsf_region:}") + private String tsfRegion; + + /** + * tsf service consul registration tags. + * + * 可用区信息 + */ + @Value("${tsf_zone:}") + private String tsfZone; + + /** + * Tags to use when registering service. + */ + @Value("${tsf.discovery.tags:}") + private List tags = new ArrayList<>(); + + /** + * Service instance zone. + */ + @Value("${tsf.discovery.instanceZone:}") + private String instanceZone; + + /** + * Service instance group. + */ + @Value("${tsf.discovery.instanceGroup:}") + private String instanceGroup; + + /** + * Service instance zone comes from metadata. + * This allows changing the metadata tag name. + */ + @Value("${tsf.discovery.defaultZoneMetadataName:zone}") + private String defaultZoneMetadataName = "zone"; + + /** + * Whether to register an http or https service. + */ + @Value("${tsf.discovery.scheme:http}") + private String scheme = "http"; + + @Value("${tsf_event_master_ip:}") + private String eventMasterIp; + + @Value("${tsf_event_master_port:15200}") + private Integer eventMasterPort; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getTsfApplicationId() { + return tsfApplicationId; + } + + public void setTsfApplicationId(final String tsfApplicationId) { + this.tsfApplicationId = tsfApplicationId; + } + + public String getTsfGroupId() { + return tsfGroupId; + } + + public void setTsfGroupId(final String tsfGroupId) { + this.tsfGroupId = tsfGroupId; + } + + public String getTsfProgVersion() { + return tsfProgVersion; + } + + public void setTsfProgVersion(final String tsfProgVersion) { + this.tsfProgVersion = tsfProgVersion; + } + + public String getTsfNamespaceId() { + return tsfNamespaceId; + } + + public void setTsfNamespaceId(String tsfNamespaceId) { + this.tsfNamespaceId = tsfNamespaceId; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getTsfRegion() { + return tsfRegion; + } + + public void setTsfRegion(String tsfRegion) { + this.tsfRegion = tsfRegion; + } + + public String getTsfZone() { + return tsfZone; + } + + public void setTsfZone(String tsfZone) { + this.tsfZone = tsfZone; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public List getTsfTags() { + List tags = new LinkedList<>(getTags()); + if (StringUtils.isNotBlank(getInstanceZone())) { + tags.add(getDefaultZoneMetadataName() + "=" + getInstanceZone()); + } + if (StringUtils.isNotBlank(getInstanceGroup())) { + tags.add("group=" + getInstanceGroup()); + } + //store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically + tags.add("secure=" + getScheme().equalsIgnoreCase("https")); + return tags; + } + + public String getInstanceZone() { + return instanceZone; + } + + public void setInstanceZone(String instanceZone) { + this.instanceZone = instanceZone; + } + + public String getInstanceGroup() { + return instanceGroup; + } + + public void setInstanceGroup(String instanceGroup) { + this.instanceGroup = instanceGroup; + } + + public String getDefaultZoneMetadataName() { + return defaultZoneMetadataName; + } + + public void setDefaultZoneMetadataName(String defaultZoneMetadataName) { + this.defaultZoneMetadataName = defaultZoneMetadataName; + } + + public String getScheme() { + return scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getEventMasterIp() { + return eventMasterIp; + } + + public void setEventMasterIp(String eventMasterIp) { + this.eventMasterIp = eventMasterIp; + } + + public Integer getEventMasterPort() { + return eventMasterPort; + } + + public void setEventMasterPort(Integer eventMasterPort) { + this.eventMasterPort = eventMasterPort; + } + + @Override + public String toString() { + return "TsfCoreProperties{" + + "appId='" + appId + '\'' + + ", instanceId='" + instanceId + '\'' + + ", tsfApplicationId='" + tsfApplicationId + '\'' + + ", tsfGroupId='" + tsfGroupId + '\'' + + ", tsfProgVersion='" + tsfProgVersion + '\'' + + ", tsfNamespaceId='" + tsfNamespaceId + '\'' + + ", serviceName='" + serviceName + '\'' + + ", tsfRegion='" + tsfRegion + '\'' + + ", tsfZone='" + tsfZone + '\'' + + ", tags=" + tags + + ", instanceZone='" + instanceZone + '\'' + + ", instanceGroup='" + instanceGroup + '\'' + + ", defaultZoneMetadataName='" + defaultZoneMetadataName + '\'' + + ", scheme='" + scheme + '\'' + + ", eventMasterIp='" + eventMasterIp + '\'' + + ", eventMasterPort=" + eventMasterPort + + '}'; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java new file mode 100644 index 000000000..340fe393a --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java @@ -0,0 +1,82 @@ +/* + * 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.config.extend.tsf; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.constant.SdkVersion; +import com.tencent.cloud.common.constant.WarmupCons; +import com.tencent.cloud.common.spi.InstanceMetadataProvider; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.inet.PolarisInetUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants; + + +/** + * InstanceMetadataProvider for TSF. + * + * @author Hoatian Zhang + */ +public class TsfInstanceMetadataProvider implements InstanceMetadataProvider { + + private final TsfCoreProperties tsfCoreProperties; + + public TsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) { + this.tsfCoreProperties = tsfCoreProperties; + } + + @Override + public Map getMetadata() { + return new HashMap() {{ + put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion()); + put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId()); + put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId()); + put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId()); + put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion()); + put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId()); + put(TsfMetadataConstants.TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId()); + put(TsfMetadataConstants.TSF_INSTNACE_ID, tsfCoreProperties.getInstanceId()); + put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion()); + put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone()); + // 处理预热相关的参数 + put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis())); + put(TsfMetadataConstants.TSF_SDK_VERSION, SdkVersion.get()); + put(TsfMetadataConstants.TSF_TAGS, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags())); + String ipv4Address = PolarisInetUtils.getIpString(false); + if (StringUtils.isNotBlank(ipv4Address)) { + put(TsfMetadataConstants.TSF_ADDRESS_IPV4, ipv4Address); + } + String ipv6Address = PolarisInetUtils.getIpString(true); + if (StringUtils.isNotBlank(ipv6Address)) { + put(TsfMetadataConstants.TSF_ADDRESS_IPV6, ipv6Address); + } + }}; + } + + @Override + public String getRegion() { + return tsfCoreProperties.getTsfRegion(); + } + + @Override + public String getZone() { + return tsfCoreProperties.getTsfZone(); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java index d01ef8a7f..67ad30a8b 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java @@ -23,6 +23,7 @@ import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.logging.LoggingApplicationListener; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.GenericApplicationListener; import org.springframework.core.ResolvableType; @@ -45,7 +46,8 @@ public boolean supportsEventType(ResolvableType resolvableType) { return false; } return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type) - || ApplicationFailedEvent.class.isAssignableFrom(type); + || ApplicationFailedEvent.class.isAssignableFrom(type) + || EnvironmentChangeEvent.class.isAssignableFrom(type); } @Override diff --git a/spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.java b/spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.java new file mode 100644 index 000000000..364695e73 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.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 org.springframework.tsf.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * Compatible with old versions TSF SDK. + * + * @author Haotian Zhang + */ + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@EnableAutoConfiguration +@EnableDiscoveryClient // 服务注册发现 +@EnableConfigurationProperties // 分布式配置 +public @interface EnableTsf { +} diff --git a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories index a121e3c26..913208449 100644 --- a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories @@ -1,7 +1,11 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration,\ - com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration + com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration,\ + com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration + com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration,\ + com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextBootstrapConfiguration org.springframework.context.ApplicationListener=\ com.tencent.cloud.polaris.context.logging.PolarisLoggingApplicationListener +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreEnvironmentPostProcessor diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java index e2d33f049..b6fd8a8d2 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java @@ -20,6 +20,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.client.api.SDKContext; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.platform.commons.util.StringUtils; @@ -38,8 +39,8 @@ */ @ExtendWith(SpringExtension.class) @SpringBootTest(classes = PolarisContextApplication.class, - properties = { "spring.config.location = classpath:bootstrap.yml" }) -@ImportAutoConfiguration({ PolarisContextAutoConfiguration.class }) + properties = {"spring.config.location = classpath:bootstrap.yml"}) +@ImportAutoConfiguration({PolarisContextAutoConfiguration.class}) public class PolarisContextGetHostTest { @Autowired @@ -48,6 +49,11 @@ public class PolarisContextGetHostTest { @Autowired private PolarisContextProperties polarisContextProperties; + @BeforeEach + public void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + @Test public void testGetConfigHost() { String bindIP = polarisSDKContextManager.getSDKContext().getConfig().getGlobal().getAPI().getBindIP(); @@ -58,5 +64,6 @@ public void testGetConfigHost() { assertThat(polarisContextProperties.getEnabled()).isTrue(); assertThat(polarisContextProperties.getNamespace()).isEqualTo("dev"); assertThat(polarisContextProperties.getService()).isEqualTo("TestApp"); + assertThat(polarisContextProperties.getLocalPort()).isEqualTo(9090); } } diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java index a5567c764..c6d06f8a5 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java @@ -19,8 +19,8 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.polaris.api.plugin.common.ValueContext; -import com.tencent.polaris.api.plugin.route.LocationLevel; import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -55,9 +55,9 @@ public void testConstructor() { when(staticMetadataManager.getCampus()).thenReturn(CAMPUS); new PostInitPolarisSDKContext(sdkContext, staticMetadataManager); - String regionName = valueContext.getValue(LocationLevel.region.name()); - String zoneName = valueContext.getValue(LocationLevel.zone.name()); - String campusName = valueContext.getValue(LocationLevel.campus.name()); + String regionName = valueContext.getValue(RoutingProto.NearbyRoutingConfig.LocationLevel.REGION.name()); + String zoneName = valueContext.getValue(RoutingProto.NearbyRoutingConfig.LocationLevel.ZONE.name()); + String campusName = valueContext.getValue(RoutingProto.NearbyRoutingConfig.LocationLevel.CAMPUS.name()); Assertions.assertThat(regionName).isEqualTo(REGION); Assertions.assertThat(zoneName).isEqualTo(ZONE); diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java index 43c61d3b3..f26e93869 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java @@ -35,7 +35,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; - import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.when; diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java index e5d05b6a3..328d7a7e6 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java @@ -35,8 +35,7 @@ public class PolarisContextAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(UtilAutoConfiguration.class)) - .withConfiguration( - AutoConfigurations.of(PolarisContextAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:8083"); @Test diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.java new file mode 100644 index 000000000..77ef87b5d --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.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.context.config.extend.consul; + +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link ConsulPropertiesTest}. + * + * @author Haotian Zhang + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = ConsulPropertiesTest.TestApplication.class) +@ActiveProfiles("test") +public class ConsulPropertiesTest { + + @Autowired + private ConsulProperties consulProperties; + + @BeforeEach + public void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @AfterEach + public void tearDown() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + public void testDefaultInitialization() { + assertThat(consulProperties).isNotNull(); + assertThat(consulProperties.isEnabled()).isFalse(); + assertThat(consulProperties.getHost()).isEqualTo("localhost"); + assertThat(consulProperties.getPort()).isEqualTo(8500); + } + + @SpringBootApplication + protected static class TestApplication { + + static { + PolarisSDKContextManager.innerDestroy(); + } + } +} diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java index 235610bd7..039c5c661 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java @@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisLoggingApplicationListener}. + * Test for {@link PolarisLoggingApplicationListener} * * @author wenxuan70 */ diff --git a/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml b/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml index 843279bfb..3339e6934 100644 --- a/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml +++ b/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml @@ -6,5 +6,6 @@ spring: namespace: dev service: TestApp enabled: true + local-port: 9090 logging: - path: /tmp/polaris/logs + path: /tmp/polaris/logs \ No newline at end of file diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 9235e861d..92251c916 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,47 +1,69 @@ { "properties": [ { - "name": "spring.cloud.polaris.loadbalancer.enabled", + "name": "spring.cloud.polaris.router.metadata-router.enabled", "type": "java.lang.Boolean", - "defaultValue": "true", - "description": "polaris loadbalancer." + "defaultValue": true, + "description": "the switch for metadata router." }, { - "name": "spring.cloud.polaris.loadbalancer.discoveryType", + "name": "spring.cloud.polaris.router.nearby-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "the switch for nearby router." + }, + { + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", "type": "java.lang.String", - "defaultValue": "POLARIS", - "description": "Type of discovery server." + "defaultValue": "ZONE", + "description": "the match level for nearby router, options can be REGION/ZONE/CAMPUS." }, { - "name": "spring.cloud.polaris.loadbalancer.strategy", + "name": "spring.cloud.polaris.router.rule-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "the switch for rule based router." + }, + { + "name": "spring.cloud.polaris.router.rule-router.failOver", "type": "java.lang.String", - "defaultValue": "roundRobin", - "description": "loadbalancer strategy." + "defaultValue": "all", + "description": "the fail over type for rule based router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "the switch for namespace router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.failOver", + "type": "java.lang.String", + "defaultValue": "all", + "description": "the fail over type for namespace router." + }, + { + "name": "spring.cloud.polaris.router.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "the switch for router module." } ], "hints": [ { - "name": "spring.cloud.polaris.loadbalancer.strategy", + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", "values": [ { - "value": "roundRobin", - "description": "round robin load balancer." - }, - { - "value": "random", - "description": "random load balancer." + "value": "CAMPUS" }, { - "value": "polarisWeightedRandom", - "description": "polaris weighted random load balancer." + "value": "ZONE" }, { - "value": "polarisWeightedRoundRobin", - "description": "polaris weighted round robin load balancer." + "value": "REGION" }, { - "value": "polarisRingHash", - "description": "polaris ring hash load balancer." + "value": "ALL" } ] } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java index 102f931c6..ea0825a44 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java @@ -35,6 +35,10 @@ import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer; import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter; +import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisRegistrationTransformer; +import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import com.tencent.cloud.rpc.enhancement.webclient.EnhancedWebClientExchangeFilterFunction; import com.tencent.cloud.rpc.enhancement.webclient.PolarisLoadBalancerClientRequestTransformer; import com.tencent.cloud.rpc.enhancement.webclient.RibbonLoadBalancerClientAspect; @@ -84,6 +88,20 @@ @AutoConfigureAfter(PolarisContextAutoConfiguration.class) public class RpcEnhancementAutoConfiguration { + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(name = "com.tencent.cloud.common.pojo.PolarisServiceInstance") + public InstanceTransformer instanceTransformer() { + return new PolarisInstanceTransformer(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(name = "com.tencent.cloud.polaris.registry.PolarisRegistration") + public RegistrationTransformer registrationTransformer() { + return new PolarisRegistrationTransformer(); + } + @Bean @Lazy public EnhancedPluginRunner enhancedFeignPluginRunner( diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java index f50e5df59..0735a90df 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java @@ -67,10 +67,13 @@ public Response execute(Request request, Options options) throws IOException { .url(url) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); - DefaultServiceInstance serviceInstance = new DefaultServiceInstance(request.requestTemplate().feignTarget() - .name(), url.getHost(), url.getPort(), url.getScheme().equals("https")); + String svcName = request.requestTemplate().feignTarget().name(); + DefaultServiceInstance serviceInstance = new DefaultServiceInstance( + String.format("%s-%s-%d", svcName, url.getHost(), url.getPort()), + svcName, url.getHost(), url.getPort(), url.getScheme().equals("https")); // -1 means access directly by url if (serviceInstance.getPort() == -1) { enhancedPluginContext.setTargetServiceInstance(null, url); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java index 7eb14ae89..e9ef0cc67 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/EnhancedPluginContext.java @@ -36,6 +36,8 @@ public class EnhancedPluginContext { private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedPluginContext.class); + private Object originRequest; + private EnhancedRequestContext request; private EnhancedResponseContext response; @@ -51,6 +53,14 @@ public class EnhancedPluginContext { */ private ServiceInstance targetServiceInstance; + public Object getOriginRequest() { + return originRequest; + } + + public void setOriginRequest(Object originRequest) { + this.originRequest = originRequest; + } + public EnhancedRequestContext getRequest() { return request; } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java index 6677dac0a..f839e1dc5 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java @@ -20,6 +20,7 @@ import org.springframework.core.Ordered; + /** * PluginOrderConstant. * @@ -44,5 +45,35 @@ public static class ClientPluginOrder { * {@link com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter}. */ public static final int CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 2; + + /** + * order for + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataZuulEnhancedPlugin} + * and + * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin}. + */ + public static final int CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; + + /** + * order for + * {@link com.tencent.cloud.plugin.trace.TraceClientMetadataEnhancedPlugin}. + */ + public static final int CONSUMER_TRACE_METADATA_PLUGIN_ORDER = CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER - 1; + } + + public static class ServerPluginOrder { + + /** + * order for + * {@link com.tencent.cloud.plugin.trace.TraceServerMetadataEnhancedPlugin}. + */ + public static final int PROVIDER_TRACE_METADATA_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 1; } + } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java index c50cbb907..6241ac598 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateInterceptor.java @@ -58,6 +58,7 @@ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttp .url(request.getURI()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); enhancedPluginContext.setTargetServiceInstance((ServiceInstance) MetadataContextHolder.get() diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java index f42aff2bb..7b65f2e81 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/scg/EnhancedGatewayGlobalFilter.java @@ -51,19 +51,21 @@ public EnhancedGatewayGlobalFilter(EnhancedPluginRunner pluginRunner) { } @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + public Mono filter(ServerWebExchange originExchange, GatewayFilterChain chain) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() - .httpHeaders(exchange.getRequest().getHeaders()) - .httpMethod(exchange.getRequest().getMethod()) - .url(exchange.getRequest().getURI()) + .httpHeaders(originExchange.getRequest().getHeaders()) + .httpMethod(originExchange.getRequest().getMethod()) + .url(originExchange.getRequest().getURI()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(originExchange); // Run pre enhanced plugins. pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext); - + // Exchange may be changed in plugin + ServerWebExchange exchange = (ServerWebExchange) enhancedPluginContext.getOriginRequest(); long startTime = System.currentTimeMillis(); return chain.filter(exchange) .doOnSubscribe(v -> { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java index abaac1c93..0a8ff8f15 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java @@ -62,7 +62,7 @@ public void modify(ConfigurationImpl configuration) { // pull metrics prometheusHandlerConfig.setType("pull"); if (!StringUtils.hasText(polarisStatProperties.getHost())) { - polarisStatProperties.setHost(environment.getProperty("spring.cloud.client.ip-address")); + polarisStatProperties.setHost("0.0.0.0"); } prometheusHandlerConfig.setHost(polarisStatProperties.getHost()); prometheusHandlerConfig.setPort(polarisStatProperties.getPort()); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java new file mode 100644 index 000000000..13c19dfb0 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/InstanceTransformer.java @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.rpc.enhancement.transformer; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; + +import org.springframework.cloud.client.ServiceInstance; + +/** + * InstanceTransformer. + * + * @author sean yu + */ +public interface InstanceTransformer { + + default Instance transform(ServiceInstance serviceInstance) { + DefaultInstance instance = new DefaultInstance(); + transformDefault(instance, serviceInstance); + transformCustom(instance, serviceInstance); + return instance; + } + + default void transformDefault(DefaultInstance instance, ServiceInstance serviceInstance) { + instance.setNamespace(MetadataContext.LOCAL_NAMESPACE); + instance.setService(serviceInstance.getServiceId()); + instance.setProtocol(serviceInstance.getScheme()); + instance.setId(serviceInstance.getInstanceId()); + instance.setHost(serviceInstance.getHost()); + instance.setPort(serviceInstance.getPort()); + instance.setMetadata(serviceInstance.getMetadata()); + } + + void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance); + +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java new file mode 100644 index 000000000..81e8beb23 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.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.rpc.enhancement.transformer; + +import com.tencent.cloud.common.pojo.PolarisServiceInstance; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.utils.CollectionUtils; + +import org.springframework.cloud.client.ServiceInstance; + +/** + * PolarisInstanceTransformer. + * + * @author sean yu + */ +public class PolarisInstanceTransformer implements InstanceTransformer { + + @Override + public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) { + if (serviceInstance instanceof PolarisServiceInstance) { + PolarisServiceInstance polarisServiceInstance = (PolarisServiceInstance) serviceInstance; + instance.setRegion(polarisServiceInstance.getPolarisInstance().getRegion()); + instance.setZone(polarisServiceInstance.getPolarisInstance().getZone()); + instance.setCampus(polarisServiceInstance.getPolarisInstance().getCampus()); + instance.setWeight(polarisServiceInstance.getPolarisInstance().getWeight()); + if (CollectionUtils.isNotEmpty(polarisServiceInstance.getServiceMetadata())) { + instance.setServiceMetadata(polarisServiceInstance.getServiceMetadata()); + } + } + } + +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java new file mode 100644 index 000000000..20df4f183 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisRegistrationTransformer.java @@ -0,0 +1,27 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.rpc.enhancement.transformer; + +public class PolarisRegistrationTransformer implements RegistrationTransformer { + + @Override + public String getRegistry() { + return "polaris"; + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java new file mode 100644 index 000000000..7996ebd78 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/RegistrationTransformer.java @@ -0,0 +1,58 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.rpc.enhancement.transformer; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; + +import org.springframework.cloud.client.serviceregistry.Registration; + + +/** + * RegistrationTransformer extensions to adapt 3rd registration to polaris instance. + * + * @author andrew shan + */ +public interface RegistrationTransformer { + + String getRegistry(); + + default Instance transform(Registration registration) { + DefaultInstance instance = new DefaultInstance(); + transformDefault(instance, registration); + transformCustom(instance, registration); + return instance; + } + + default void transformDefault(DefaultInstance instance, Registration registration) { + instance.setRegistry(getRegistry()); + instance.setNamespace(MetadataContext.LOCAL_NAMESPACE); + instance.setService(registration.getServiceId()); + instance.setProtocol(registration.getScheme()); + instance.setId(registration.getInstanceId()); + instance.setHost(registration.getHost()); + instance.setPort(registration.getPort()); + instance.setMetadata(registration.getMetadata()); + } + + default void transformCustom(DefaultInstance instance, Registration registration) { + + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java index 673cac3da..a215cfe8a 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/webclient/EnhancedWebClientExchangeFilterFunction.java @@ -46,23 +46,25 @@ public EnhancedWebClientExchangeFilterFunction(EnhancedPluginRunner pluginRunner } @Override - public Mono filter(ClientRequest request, ExchangeFunction next) { + public Mono filter(ClientRequest originRequest, ExchangeFunction next) { EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() - .httpHeaders(request.headers()) - .httpMethod(request.method()) - .url(request.url()) + .httpHeaders(originRequest.headers()) + .httpMethod(originRequest.method()) + .url(originRequest.url()) .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(originRequest); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); enhancedPluginContext.setTargetServiceInstance((ServiceInstance) MetadataContextHolder.get() - .getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE), request.url()); + .getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE), originRequest.url()); // Run post enhanced plugins. pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext); - + // request may be changed by plugin + ClientRequest request = (ClientRequest) enhancedPluginContext.getOriginRequest(); long startTime = System.currentTimeMillis(); return next.exchange(request) .doOnSuccess(response -> { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java index 1254209c7..094f24f79 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/zuul/EnhancedPreZuulFilter.java @@ -99,6 +99,7 @@ public Object run() throws ZuulException { .build(); enhancedPluginContext.setRequest(enhancedRequestContext); + enhancedPluginContext.setOriginRequest(context); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); // Run pre enhanced plugins. From 2aa88adaeff522be22e1ee828f00c72a7cbe354d Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Wed, 9 Oct 2024 23:48:24 +0800 Subject: [PATCH 11/19] fix --- .../cloud/quickstart/caller/CustomMetadataProvider.java | 4 ---- .../cloud/polaris/loadbalancer/PolarisLoadBalancer.java | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java index 948296578..9cbdcd18d 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java @@ -27,8 +27,4 @@ @Component public class CustomMetadataProvider implements InstanceMetadataProvider { - @Override - public String getRegion() { - return "huadong"; - } } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java index 07335adf5..d18bca83b 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 @@ -77,7 +77,7 @@ public void addServers(List servers) { @Override public List getReachableServers() { // Get servers first from the thread context - if (!CollectionUtils.isEmpty(THREAD_CACHE_SERVERS.get())) { + if (THREAD_CACHE_SERVERS.get() != null) { return THREAD_CACHE_SERVERS.get(); } return getReachableServersWithoutCache(); From 3b4522dffd89a7214a732768b5eb2e533a2d8493 Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Thu, 7 Nov 2024 16:00:14 +0800 Subject: [PATCH 12/19] feat: support lossless config from console & support warmup (#1435) feat:add admin http handler. (#1448) feat:support concurrency rate limit. (#1454) --- .../MetadataTransferAutoConfiguration.java | 8 +- .../DecodeTransferMetadataReactiveFilter.java | 5 - .../DecodeTransferMetadataServletFilter.java | 6 - ...odeTransferMetadataReactiveFilterTest.java | 3 +- .../PolarisCircuitBreakerMockServerTest.java | 32 ++-- ...cuitBreakerBootstrapConfigurationTest.java | 7 + ...risCircuitBreakerFeignIntegrationTest.java | 118 ++++---------- ...sCircuitBreakerGatewayIntegrationTest.java | 125 ++++----------- ...uitBreakerRestTemplateIntegrationTest.java | 122 ++++----------- .../resources/application-test-gateway.yml | 17 +-- .../polaris/config/ConfigurationModifier.java | 1 + .../lossless/LosslessRegistryAspectTest.java | 4 +- .../config/LosslessConfigModifierTest.java | 34 ++++- .../config/WarmupConfigModifierTest.java | 86 +++++++++++ .../AutoServiceRegistrationUtils.java | 6 +- .../ratelimit/RateLimitRuleLabelResolver.java | 73 --------- .../PolarisRateLimitAutoConfiguration.java | 29 +--- .../filter/QuotaCheckReactiveFilter.java | 47 +++--- .../filter/QuotaCheckServletFilter.java | 44 +++--- ...RateLimitRuleArgumentReactiveResolver.java | 122 --------------- .../RateLimitRuleArgumentServletResolver.java | 123 --------------- .../tsf/TsfRateLimitAutoConfiguration.java | 44 ++++++ .../TsfRateLimitBootstrapConfiguration.java} | 25 ++- .../tsf/TsfRateLimitConfigModifier.java | 68 +++++++++ .../ratelimit/utils/QuotaCheckUtils.java | 30 +--- .../ratelimit/utils/RateLimitUtils.java | 38 +++++ .../main/resources/META-INF/spring.factories | 3 +- .../context/CalleeControllerTests.java | 16 +- .../RateLimitRuleLabelResolverTest.java | 99 ------------ ...PolarisRateLimitAutoConfigurationTest.java | 23 +-- .../PolarisRateLimitRuleEndpointTests.java | 2 +- .../filter/QuotaCheckReactiveFilterTest.java | 21 +-- .../filter/QuotaCheckServletFilterTest.java | 33 ++-- ...LimitRuleArgumentReactiveResolverTest.java | 144 ------------------ ...eLimitRuleArgumentServletResolverTest.java | 135 ---------------- .../ratelimit/utils/QuotaCheckUtilsTest.java | 42 +---- .../cloud/common/constant/OrderConstant.java | 5 + .../metadata/MetadataContextHolder.java | 14 +- .../tsf/ConditionalOnTsfConsulEnabled.java | 8 +- .../common/tsf/ConditionalOnTsfEnabled.java | 50 ------ .../tsf/core/context/TsfContext.java | 2 +- .../src/main/resources/bootstrap.yml | 4 +- .../src/main/resources/bootstrap.yml | 3 +- .../src/main/resources/application.yml | 3 +- .../src/main/resources/application.yml | 3 +- .../src/main/resources/application.yml | 3 +- .../quickstart/callee/CustomMetadata.java | 1 + .../callee/ratelimit/CustomLabelResolver.java | 63 -------- .../src/main/resources/bootstrap.yml | 7 +- .../quickstart/callee/CustomMetadata.java | 1 + .../callee/QuickstartCalleeController.java | 2 +- .../CustomLabelResolverReactive.java | 60 -------- .../src/main/resources/bootstrap.yml | 7 +- .../caller/CustomMetadataProvider.java | 10 ++ .../caller/QuickstartCallerController.java | 45 +++--- .../src/main/resources/bootstrap.yml | 3 +- .../src/main/resources/bootstrap.yml | 3 +- .../tsf/demo/provider/ProviderController.java | 46 +++--- .../src/main/resources/bootstrap.yml | 1 - .../trace/tsf/TsfSpanAttributesProvider.java | 18 ++- .../TsfTracePropertiesAutoConfiguration.java | 3 - .../pom.xml | 5 + .../lossless/LosslessRegistryAspect.java | 14 +- .../SpringCloudLosslessActionProvider.java | 95 ------------ .../config/LosslessConfigModifier.java | 20 ++- .../lossless/config/LosslessProperties.java | 10 -- .../LosslessPropertiesAutoConfiguration.java | 7 +- .../lossless/config/WarmupConfigModifier.java | 66 ++++++++ .../lossless/config/WarmupProperties.java | 27 ++-- ...itional-spring-configuration-metadata.json | 2 +- .../admin/PolarisAdminConfigModifier.java | 47 ++++++ .../context/admin/PolarisAdminProperties.java | 63 ++++++++ .../PolarisContextAutoConfiguration.java | 16 +- ...olarisContextEnvironmentPostProcessor.java | 102 +++++++++++++ .../extend/tsf/TsfContextConfigModifier.java | 1 + .../config/extend/tsf/TsfContextUtils.java | 58 +++++++ .../tsf/TsfCoreEnvironmentPostProcessor.java | 35 ++--- .../config/extend/tsf/TsfCoreProperties.java | 24 +++ .../tsf/TsfInstanceMetadataProvider.java | 71 +++++---- .../main/resources/META-INF/spring.factories | 1 + .../context/ServiceRuleManagerTest.java | 1 + .../PolarisContextAutoConfigurationTest.java | 3 +- .../PolarisLoggingPathSystemPropertyTest.java | 2 +- .../src/test/resources/bootstrap.yml | 2 +- .../PolarisRibbonClientConfiguration.java | 4 +- .../stat/config/PolarisStatProperties.java | 40 ++--- ...olarisStatPropertiesAutoConfiguration.java | 4 +- .../stat/config/StatConfigModifier.java | 26 +--- ...itional-spring-configuration-metadata.json | 14 +- .../config/PolarisStatPropertiesTest.java | 4 - .../stat/config/StatConfigModifierTest.java | 12 +- 91 files changed, 1164 insertions(+), 1712 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java delete mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java delete mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java delete mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java create mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.java rename spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/{spi/PolarisRateLimiterLabelReactiveResolver.java => tsf/TsfRateLimitBootstrapConfiguration.java} (61%) create mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.java delete mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java delete mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java delete mode 100644 spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java delete mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java delete mode 100644 spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java delete mode 100644 spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java delete mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java create mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java rename spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java => spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java (61%) create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.java diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index 003bc062b..0dd6313da 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -68,8 +68,8 @@ public FilterRegistrationBean metadataServl } @Bean - public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextProperties polarisContextProperties) { - return new DecodeTransferMetadataServletFilter(polarisContextProperties); + public DecodeTransferMetadataServletFilter metadataServletFilter() { + return new DecodeTransferMetadataServletFilter(); } } @@ -81,8 +81,8 @@ public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextP protected static class MetadataReactiveFilterConfig { @Bean - public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisContextProperties polarisContextProperties) { - return new DecodeTransferMetadataReactiveFilter(polarisContextProperties); + public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() { + return new DecodeTransferMetadataReactiveFilter(); } } 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 d279aa0c5..85cf40e0f 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 @@ -54,11 +54,6 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class); - private PolarisContextProperties polarisContextProperties; - - public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) { - this.polarisContextProperties = polarisContextProperties; - } @Override public int getOrder() { 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 ec060a4ff..bd31a3f4e 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 @@ -57,12 +57,6 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); - private PolarisContextProperties polarisContextProperties; - - public DecodeTransferMetadataServletFilter(PolarisContextProperties polarisContextProperties) { - this.polarisContextProperties = polarisContextProperties; - } - @Override protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java index ff27c0c4d..bbee696c9 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java @@ -20,7 +20,6 @@ import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -55,7 +54,7 @@ public class DecodeTransferMetadataReactiveFilterTest { @BeforeEach public void setUp() { - this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(new PolarisContextProperties()); + this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(); } @Test diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java index dc720bd4a..7b4a80d74 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java @@ -37,6 +37,7 @@ import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; +import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.util.Utils; import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; @@ -71,6 +72,8 @@ public class PolarisCircuitBreakerMockServerTest { private static MockedStatic mockedApplicationContextAwareUtils; private static NamingServer namingServer; + private static SDKContext context; + @BeforeAll public static void beforeAll() throws IOException { mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); @@ -79,18 +82,23 @@ public static void beforeAll() throws IOException { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service")) .thenReturn(SERVICE_CIRCUIT_BREAKER); PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(-1); System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_CIRCUIT_BREAKER); - - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerMockServerTest.class.getClassLoader().getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerMockServerTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder().addRules(circuitBreakerRule).build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + + Configuration configuration = TestUtils.configWithEnvAddress(); + context = SDKContext.initContextByConfig(configuration); } @AfterAll @@ -101,14 +109,15 @@ public static void afterAll() { if (null != mockedApplicationContextAwareUtils) { mockedApplicationContextAwareUtils.close(); } + if (null != context) { + context.close(); + } } @Test public void testCircuitBreaker() { - Configuration configuration = TestUtils.configWithEnvAddress(); - CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - - ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); + CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByContext(context); + ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(context); PolarisCircuitBreakerProperties polarisCircuitBreakerProperties = new PolarisCircuitBreakerProperties(); PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); @@ -140,7 +149,8 @@ public void testCircuitBreaker() { assertThat(Mono.error(new RuntimeException("boom")).transform(it -> rcb.run(it, t -> Mono.just("fallback"))) .block()).isEqualTo("fallback"); - assertThat(Flux.just("foobar", "hello world").transform(it -> rcb.run(it, t -> Flux.just("fallback", "fallback"))) + assertThat(Flux.just("foobar", "hello world") + .transform(it -> rcb.run(it, t -> Flux.just("fallback", "fallback"))) .collectList().block()) .isEqualTo(Arrays.asList("fallback", "fallback")); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java index 653ba8ffe..747282ca5 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java @@ -17,8 +17,10 @@ package com.tencent.cloud.polaris.circuitbreaker.config; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -42,6 +44,11 @@ public class PolarisCircuitBreakerBootstrapConfigurationTest { .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + @BeforeAll + static void beforeAll() { + PolarisSDKContextManager.innerDestroy(); + } + @Test public void testDefaultInitialization() { this.contextRunner.run(context -> { diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index 0f0c6ec1d..a38fec459 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -34,6 +34,7 @@ import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.ServiceKey; @@ -44,6 +45,8 @@ import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -83,6 +86,7 @@ properties = { "feign.hystrix.enabled=true", "spring.cloud.gateway.enabled=false", + "spring.cloud.polaris.address=grpc://127.0.0.1:10081", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, "spring.cloud.polaris.service=test" @@ -91,6 +95,8 @@ public class PolarisCircuitBreakerFeignIntegrationTest { private static final String TEST_SERVICE_NAME = "test-service-callee"; + private static NamingServer namingServer; + @Autowired private EchoService echoService; @@ -103,6 +109,31 @@ public class PolarisCircuitBreakerFeignIntegrationTest { @Autowired private BazService bazService; + @BeforeAll + static void beforeAll() throws Exception { + PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(10081); + ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); + + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerFeignIntegrationTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); + JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); + CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); + namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } + @Test public void contextLoads() { assertThat(echoService).isNotNull(); @@ -171,9 +202,6 @@ public interface BazClient extends BazService { @EnableFeignClients public static class TestConfig { - @Autowired(required = false) - private List> customizers = new ArrayList<>(); - @Bean public EchoServiceFallback echoServiceFallback() { return new EchoServiceFallback(); @@ -183,75 +211,6 @@ public EchoServiceFallback echoServiceFallback() { public CustomFallbackFactory customFallbackFactory() { return new CustomFallbackFactory(); } - - @Bean - public PreDestroy preDestroy(NamingServer namingServer) { - return new PreDestroy(namingServer); - } - - @Bean - public NamingServer namingServer() throws IOException { - NamingServer namingServer = NamingServer.startNamingServer(-1); - System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); - - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerFeignIntegrationTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); - CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); - namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); - return namingServer; - } - - @Bean - public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - } - - @Bean - public ConsumerAPI consumerAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - } - - @Bean - public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, - PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); - customizers.forEach(customizer -> customizer.customize(factory)); - return factory; - } - - @Bean - public PolarisCircuitBreakerNameResolver polarisCircuitBreakerNameResolver() { - return new PolarisCircuitBreakerNameResolver(); - } - - @Bean - @Primary - @ConditionalOnBean(CircuitBreakerFactory.class) - @ConditionalOnProperty(value = "feign.hystrix.enabled", havingValue = "true") - public PolarisFeignCircuitBreakerTargeter polarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { - return new PolarisFeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerNameResolver); - } } public static class EchoServiceFallback implements EchoService { @@ -286,19 +245,4 @@ public FooService create(Throwable throwable) { } } - - public static class PreDestroy implements DisposableBean { - - private final NamingServer namingServer; - - public PreDestroy(NamingServer namingServer) { - this.namingServer = namingServer; - } - - @Override - public void destroy() throws Exception { - namingServer.terminate(); - } - } - } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java index 2d4f9bbf0..294d1014c 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java @@ -19,44 +19,30 @@ import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.stream.Collectors; import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; -import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; -import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; -import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; -import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; -import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; -import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; import com.tencent.polaris.client.util.Utils; -import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; -import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Mono; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; -import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; @@ -70,7 +56,6 @@ import org.springframework.web.bind.annotation.RestController; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; @@ -94,12 +79,39 @@ public class PolarisCircuitBreakerGatewayIntegrationTest { private static final String TEST_SERVICE_NAME = "test-service-callee"; + private static NamingServer namingServer; + @Autowired private WebTestClient webClient; @Autowired private ApplicationContext applicationContext; + @BeforeAll + static void beforeAll() throws Exception { + PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(10081); + ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); + + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerGatewayIntegrationTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); + JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); + CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); + namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } + @Test public void fallback() throws Exception { SpringCloudCircuitBreakerFilterFactory.Config config = new SpringCloudCircuitBreakerFilterFactory.Config(); @@ -161,68 +173,6 @@ public void fallback() throws Exception { @EnableAutoConfiguration public static class TestApplication { - @Autowired(required = false) - private List> customizers = new ArrayList<>(); - - @Bean - public PreDestroy preDestroy(NamingServer namingServer) { - return new PreDestroy(namingServer); - } - - @Bean - public NamingServer namingServer() throws IOException { - NamingServer namingServer = NamingServer.startNamingServer(-1); - System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); - - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerGatewayIntegrationTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); - CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); - namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); - return namingServer; - } - - @Bean - public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) throws IOException { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - } - - @Bean - public ConsumerAPI consumerAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - } - - @Bean - @ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class) - public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - @ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class) - public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, - PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); - customizers.forEach(customizer -> customizer.customize(factory)); - return factory; - } - @Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { Set codeSets = new HashSet<>(); @@ -265,19 +215,4 @@ public Mono fallback() { } } - - public static class PreDestroy implements DisposableBean { - - private final NamingServer namingServer; - - public PreDestroy(NamingServer namingServer) { - this.namingServer = namingServer; - } - - @Override - public void destroy() throws Exception { - namingServer.terminate(); - } - } - } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java index 14e41ae8b..d486ac3f5 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java @@ -18,44 +18,31 @@ package com.tencent.cloud.polaris.circuitbreaker.resttemplate; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.stream.Collectors; import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; -import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; -import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; -import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; -import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; import com.tencent.polaris.client.util.Utils; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; -import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; -import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ApplicationContext; @@ -74,7 +61,6 @@ import org.springframework.web.util.DefaultUriBuilderFactory; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -90,6 +76,7 @@ classes = PolarisCircuitBreakerRestTemplateIntegrationTest.TestConfig.class, properties = { "spring.cloud.gateway.enabled=false", + "spring.cloud.polaris.address=grpc://127.0.0.1:10081", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, "spring.cloud.polaris.service=test" @@ -98,6 +85,8 @@ public class PolarisCircuitBreakerRestTemplateIntegrationTest { private static final String TEST_SERVICE_NAME = "test-service-callee"; + private static NamingServer namingServer; + @Autowired @Qualifier("defaultRestTemplate") private RestTemplate defaultRestTemplate; @@ -125,6 +114,29 @@ public class PolarisCircuitBreakerRestTemplateIntegrationTest { @Autowired private ApplicationContext applicationContext; + @BeforeAll + static void beforeAll() throws Exception { + PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(10081); + ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerRestTemplateIntegrationTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); + JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); + CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); + namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } @Test public void testRestTemplate() throws URISyntaxException { @@ -151,7 +163,8 @@ public void testRestTemplate() throws URISyntaxException { Utils.sleepUninterrupted(2000); assertThat(restTemplateFallbackFromCode2.getForObject("/example/service/b/info", String.class)).isEqualTo("\"this is a fallback class\""); Utils.sleepUninterrupted(2000); - assertThat(restTemplateFallbackFromCode3.getForEntity("/example/service/b/info", String.class).getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(restTemplateFallbackFromCode3.getForEntity("/example/service/b/info", String.class) + .getStatusCode()).isEqualTo(HttpStatus.OK); Utils.sleepUninterrupted(2000); assertThat(restTemplateFallbackFromCode4.getForObject("/example/service/b/info", String.class)).isEqualTo("fallback"); Utils.sleepUninterrupted(2000); @@ -168,13 +181,6 @@ public void testRestTemplate() throws URISyntaxException { @EnableFeignClients public static class TestConfig { - @Autowired(required = false) - private List> customizers = new ArrayList<>(); - - { - PolarisSDKContextManager.innerDestroy(); - } - @Bean @com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreaker(fallback = "fallback") public RestTemplate defaultRestTemplate() { @@ -246,59 +252,6 @@ public CustomPolarisCircuitBreakerFallback3 customPolarisCircuitBreakerFallback3 return new CustomPolarisCircuitBreakerFallback3(); } - @Bean - public NamingServer namingServer() throws IOException { - NamingServer namingServer = NamingServer.startNamingServer(-1); - System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerRestTemplateIntegrationTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); - CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); - namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); - return namingServer; - } - - @Bean - public PreDestroy preDestroy(NamingServer namingServer) { - return new PreDestroy(namingServer); - } - - @Bean - public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - } - - @Bean - @ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class) - public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - @ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class) - public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, - PolarisSDKContextManager polarisSDKContextManager, PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( - circuitBreakAPI, polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); - customizers.forEach(customizer -> customizer.customize(factory)); - return factory; - } - @RestController @RequestMapping("/example/service/b") public class ServiceBController { @@ -347,19 +300,4 @@ public PolarisCircuitBreakerHttpResponse fallback() { ); } } - - public static class PreDestroy implements DisposableBean { - - private final NamingServer namingServer; - - public PreDestroy(NamingServer namingServer) { - this.namingServer = namingServer; - } - - @Override - public void destroy() throws Exception { - namingServer.terminate(); - } - } - } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml index 6094b46e5..d484da8aa 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml @@ -1,22 +1,15 @@ spring: + main: + web-application-type: reactive application: name: GatewayScgService cloud: - tencent: - plugin: - scg: - staining: - enabled: true - rule-staining: - enabled: true - router: - feature-env: - enabled: true polaris: - address: grpc://127.0.0.1:8091 - namespace: default + address: grpc://127.0.0.1:10081 + namespace: Test enabled: true gateway: + enabled: true routes: - id: cb-test uri: http://localhost:${server.port}/hello/1 diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java index 993b3f978..69025b48e 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java @@ -63,6 +63,7 @@ public ConfigurationModifier(PolarisConfigProperties polarisConfigProperties, @Override public void modify(ConfigurationImpl configuration) { configuration.getGlobal().getAPI().setReportEnable(false); + configuration.getGlobal().getStatReporter().setEnable(false); if (!polarisContextProperties.getEnabled() || !polarisConfigProperties.isEnabled()) { return; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java index ba05d6619..126f7228a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java @@ -76,7 +76,7 @@ public class LosslessRegistryAspectTest { .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") - .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) + .withPropertyValues("spring.cloud.polaris.admin.port=" + LOSSLESS_PORT_1) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + APPLICATION_PORT) .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) @@ -97,7 +97,7 @@ public class LosslessRegistryAspectTest { .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=1000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/test") - .withPropertyValues("spring.cloud.polaris.lossless.port=28082") + .withPropertyValues("spring.cloud.polaris.admin.port=28082") .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + APPLICATION_PORT) .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java index 9152f04f2..ef4f9bb81 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java @@ -19,6 +19,7 @@ import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.config.provider.LosslessConfig; +import com.tencent.polaris.specification.api.v1.traffic.manage.LosslessProto; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,14 +36,23 @@ */ public class LosslessConfigModifierTest { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private final ApplicationContextRunner delayRegisterContextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(TestApplication.class)) .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") - .withPropertyValues("spring.cloud.polaris.lossless.port=20000") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") + .withPropertyValues("spring.cloud.polaris.admin.port=20000") .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=10") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + + private final ApplicationContextRunner healthCheckContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") + .withPropertyValues("spring.cloud.polaris.admin.port=20000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=5") .withPropertyValues("spring.application.name=test") .withPropertyValues("spring.cloud.gateway.enabled=false"); @@ -60,15 +70,25 @@ void setUp() { } @Test - void testModify() { - contextRunner.run(context -> { + void testDelayRegister() { + delayRegisterContextRunner.run(context -> { PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). getConfig().getProvider().getLossless(); - assertThat(losslessConfig.getHost()).isEqualTo("0.0.0.0"); - assertThat(losslessConfig.getPort()).isEqualTo(20000); assertThat(losslessConfig.getDelayRegisterInterval()).isEqualTo(10); + assertThat(losslessConfig.getStrategy()).isEqualTo(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_TIME); + }); + } + + @Test + void testHealthCheck() { + healthCheckContextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getProvider().getLossless(); + assertThat(losslessConfig.getHealthCheckPath()).isEqualTo("/xxx"); assertThat(losslessConfig.getHealthCheckInterval()).isEqualTo(5); + assertThat(losslessConfig.getStrategy()).isEqualTo(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_HEALTH_CHECK); }); } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java new file mode 100644 index 000000000..c097a04a4 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java @@ -0,0 +1,86 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless.config; + +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.config.consumer.WeightAdjustConfig; +import com.tencent.polaris.plugin.lossless.warmup.WarmupWeightAdjuster; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link WarmupConfigModifier}. + * + * @author Shedfree Wu + */ +public class WarmupConfigModifierTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.warmup.enabled=true") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + private final ApplicationContextRunner disabledContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.warmup.enabled=false") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + + @BeforeEach + void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + void testModify() { + contextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + WeightAdjustConfig weightAdjustConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getConsumer().getWeightAdjust(); + assertThat(weightAdjustConfig.isEnable()).isTrue(); + assertThat(weightAdjustConfig.getChain().contains(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME)).isTrue(); + }); + } + + + @Test + void testDisabled() { + disabledContextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + WeightAdjustConfig weightAdjustConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getConsumer().getWeightAdjust(); + assertThat(weightAdjustConfig.isEnable()).isTrue(); + assertThat(weightAdjustConfig.getChain().contains(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME)).isFalse(); + }); + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java index 1c8e09f91..4c9d481ed 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java @@ -17,7 +17,11 @@ package org.springframework.cloud.client.serviceregistry; -public class AutoServiceRegistrationUtils { +public final class AutoServiceRegistrationUtils { + + private AutoServiceRegistrationUtils() { + + } public static void register(AbstractAutoServiceRegistration autoServiceRegistration) { autoServiceRegistration.register(); 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 deleted file mode 100644 index f51b6f0b8..000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java +++ /dev/null @@ -1,73 +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.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.expresstion.ExpressionLabelUtils; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.polaris.specification.api.v1.model.ModelProto; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; - -import org.springframework.util.CollectionUtils; - -/** - * resolve labels from rate limit rule. - * - *@author lepdou 2022-05-13 - */ -@Deprecated -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/PolarisRateLimitAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java index 72d46d23a..a034e4049 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java @@ -20,14 +20,9 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import org.springframework.beans.factory.annotation.Autowired; @@ -63,20 +58,13 @@ public class PolarisRateLimitAutoConfiguration { @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) protected static class QuotaCheckFilterConfig { - @Bean - public RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver(ServiceRuleManager serviceRuleManager, - @Autowired(required = false) PolarisRateLimiterLabelServletResolver labelResolver) { - return new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver); - } - @Bean @ConditionalOnMissingBean public QuotaCheckServletFilter quotaCheckFilter(PolarisSDKContextManager polarisSDKContextManager, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver, @Autowired(required = false) PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { - return new QuotaCheckServletFilter(polarisSDKContextManager.getLimitAPI(), polarisRateLimitProperties, - rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback); + return new QuotaCheckServletFilter(polarisSDKContextManager.getLimitAPI(), polarisSDKContextManager.getAssemblyAPI(), + polarisRateLimitProperties, polarisRateLimiterLimitedFallback); } @Bean @@ -97,21 +85,14 @@ public FilterRegistrationBean quotaFilterRegistrationBe */ @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) - protected static class MetadataReactiveFilterConfig { - - @Bean - public RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver(ServiceRuleManager serviceRuleManager, - @Autowired(required = false) PolarisRateLimiterLabelReactiveResolver labelResolver) { - return new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver); - } + protected static class QuotaCheckReactiveFilterConfig { @Bean public QuotaCheckReactiveFilter quotaCheckReactiveFilter(PolarisSDKContextManager polarisSDKContextManager, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver, @Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { - return new QuotaCheckReactiveFilter(polarisSDKContextManager.getLimitAPI(), polarisRateLimitProperties, - rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback); + return new QuotaCheckReactiveFilter(polarisSDKContextManager.getLimitAPI(), polarisSDKContextManager.getAssemblyAPI(), + polarisRateLimitProperties, polarisRateLimiterLimitedFallback); } } } 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 f6bf04706..d68a765a8 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 @@ -23,7 +23,6 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Objects; -import java.util.Set; import javax.annotation.PostConstruct; @@ -31,13 +30,13 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils; import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils; import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.ratelimit.api.core.LimitAPI; -import com.tencent.polaris.ratelimit.api.rpc.Argument; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import org.slf4j.Logger; @@ -54,11 +53,12 @@ import org.springframework.web.server.WebFilterChain; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static org.springframework.core.io.buffer.DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY; /** * Reactive filter to check quota. * - * @author Haotian Zhang, lepdou, cheese8, kaiy + * @author Haotian Zhang, lepdou, kaiy, cheese8 */ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { @@ -66,22 +66,20 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { private final LimitAPI limitAPI; - private final PolarisRateLimitProperties polarisRateLimitProperties; + private final AssemblyAPI assemblyAPI; - private final RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver; + private final PolarisRateLimitProperties polarisRateLimitProperties; private final PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback; - private String rejectTips; - public QuotaCheckReactiveFilter(LimitAPI limitAPI, + public QuotaCheckReactiveFilter(LimitAPI limitAPI, AssemblyAPI assemblyAPI, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver, @Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { this.limitAPI = limitAPI; + this.assemblyAPI = assemblyAPI; this.polarisRateLimitProperties = polarisRateLimitProperties; - this.rateLimitRuleArgumentResolver = rateLimitRuleArgumentResolver; this.polarisRateLimiterLimitedFallback = polarisRateLimiterLimitedFallback; } @@ -100,31 +98,41 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; - Set arguments = rateLimitRuleArgumentResolver.getArguments(exchange, localNamespace, localService); long waitMs = -1; + QuotaResponse quotaResponse = null; try { String path = exchange.getRequest().getURI().getPath(); - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota( - limitAPI, localNamespace, localService, 1, arguments, path); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, path); if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { ServerHttpResponse response = exchange.getResponse(); DataBuffer dataBuffer; - if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { + if (Objects.nonNull(quotaResponse.getActiveRule()) + && StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) { + response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode()); + response.getHeaders().setContentType(MediaType.TEXT_PLAIN); + dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY) + .write(quotaResponse.getActiveRule().getCustomResponse().getBody() + .getBytes(StandardCharsets.UTF_8)); + } + else if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { response.setRawStatusCode(polarisRateLimiterLimitedFallback.rejectHttpCode()); response.getHeaders().setContentType(polarisRateLimiterLimitedFallback.mediaType()); - dataBuffer = response.bufferFactory().allocateBuffer() + dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY) .write(polarisRateLimiterLimitedFallback.rejectTips() .getBytes(polarisRateLimiterLimitedFallback.charset())); } else { response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode()); response.getHeaders().setContentType(MediaType.TEXT_HTML); - dataBuffer = response.bufferFactory().allocateBuffer() + dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY) .write(rejectTips.getBytes(StandardCharsets.UTF_8)); } + // set flow control to header response.getHeaders() .add(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); + // set trace span + RateLimitUtils.reportTrace(assemblyAPI, quotaResponse.getActiveRule().getId().getValue()); if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( @@ -136,6 +144,7 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { quotaResponse.getActiveRuleName(), e); } } + RateLimitUtils.release(quotaResponse); return response.writeWith(Mono.just(dataBuffer)); } // Unirate @@ -150,11 +159,13 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { LOG.error("fail to invoke getQuota, service is " + localService, t); } + QuotaResponse finalQuotaResponse = quotaResponse; if (waitMs > 0) { - return Mono.delay(Duration.ofMillis(waitMs)).flatMap(e -> chain.filter(exchange)); + return Mono.delay(Duration.ofMillis(waitMs)) + .flatMap(e -> chain.filter(exchange).doFinally((v) -> RateLimitUtils.release(finalQuotaResponse))); } else { - return chain.filter(exchange); + return chain.filter(exchange).doFinally((v) -> RateLimitUtils.release(finalQuotaResponse)); } } 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 7266e5b54..74282fc08 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 @@ -22,7 +22,6 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Objects; -import java.util.Set; import javax.annotation.PostConstruct; import javax.servlet.FilterChain; @@ -34,13 +33,13 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils; import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils; import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.ratelimit.api.core.LimitAPI; -import com.tencent.polaris.ratelimit.api.rpc.Argument; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import org.slf4j.Logger; @@ -69,21 +68,20 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class); private final LimitAPI limitAPI; - private final PolarisRateLimitProperties polarisRateLimitProperties; + private final AssemblyAPI assemblyAPI; - private final RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver; + private final PolarisRateLimitProperties polarisRateLimitProperties; private final PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback; private String rejectTips; - public QuotaCheckServletFilter(LimitAPI limitAPI, + public QuotaCheckServletFilter(LimitAPI limitAPI, AssemblyAPI assemblyAPI, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver, @Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { this.limitAPI = limitAPI; + this.assemblyAPI = assemblyAPI; this.polarisRateLimitProperties = polarisRateLimitProperties; - this.rateLimitRuleArgumentResolver = rateLimitRuleArgumentResolver; this.polarisRateLimiterLimitedFallback = polarisRateLimiterLimitedFallback; } @@ -94,19 +92,20 @@ public void init() { @Override protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain) - throws ServletException, IOException { + @NonNull FilterChain filterChain) throws ServletException, IOException { String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; - - Set arguments = rateLimitRuleArgumentResolver.getArguments(request, localNamespace, localService); - + QuotaResponse quotaResponse = null; try { - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, - localNamespace, localService, 1, arguments, request.getRequestURI()); - + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, request.getRequestURI()); if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { - if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { + if (Objects.nonNull(quotaResponse.getActiveRule()) + && StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) { + response.setStatus(polarisRateLimitProperties.getRejectHttpCode()); + response.setContentType("text/plain;charset=UTF-8"); + response.getWriter().write(quotaResponse.getActiveRule().getCustomResponse().getBody()); + } + else if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { response.setStatus(polarisRateLimiterLimitedFallback.rejectHttpCode()); String contentType = new MediaType(polarisRateLimiterLimitedFallback.mediaType(), polarisRateLimiterLimitedFallback.charset()).toString(); response.setContentType(contentType); @@ -117,7 +116,10 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht response.setContentType("text/html;charset=UTF-8"); response.getWriter().write(rejectTips); } + // set flow control to header response.addHeader(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); + // set trace span + RateLimitUtils.reportTrace(assemblyAPI, quotaResponse.getActiveRule().getId().getValue()); if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( @@ -129,6 +131,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht quotaResponse.getActiveRuleName(), e); } } + RateLimitUtils.release(quotaResponse); return; } // Unirate @@ -144,7 +147,12 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht LOG.error("fail to invoke getQuota, service is " + localService, t); } - filterChain.doFilter(request, response); + try { + filterChain.doFilter(request, response); + } + finally { + RateLimitUtils.release(quotaResponse); + } } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java deleted file mode 100644 index 43d9b7209..000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java +++ /dev/null @@ -1,122 +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.polaris.ratelimit.resolver; - -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.CollectionUtils; -import org.springframework.web.server.ServerWebExchange; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; - -/** - * resolve arguments from rate limit rule for Reactive. - * - * @author seansyyu 2023-03-09 - */ -public class RateLimitRuleArgumentReactiveResolver { - - private static final Logger LOG = LoggerFactory.getLogger(RateLimitRuleArgumentReactiveResolver.class); - - private final ServiceRuleManager serviceRuleManager; - - private final PolarisRateLimiterLabelReactiveResolver labelResolver; - - public RateLimitRuleArgumentReactiveResolver(ServiceRuleManager serviceRuleManager, PolarisRateLimiterLabelReactiveResolver labelResolver) { - this.serviceRuleManager = serviceRuleManager; - this.labelResolver = labelResolver; - } - - public Set getArguments(ServerWebExchange request, 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(); - } - return rules.stream() - .flatMap(rule -> rule.getArgumentsList().stream()) - .map(matchArgument -> { - String matchKey = matchArgument.getKey(); - Argument argument = null; - switch (matchArgument.getType()) { - case CUSTOM: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)).orElse(StringUtils.EMPTY)); - break; - case METHOD: - argument = Argument.buildMethod(request.getRequest().getMethodValue()); - break; - case HEADER: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildHeader(matchKey, Optional.ofNullable(request.getRequest().getHeaders().getFirst(matchKey)).orElse(StringUtils.EMPTY)); - break; - case QUERY: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildQuery(matchKey, Optional.ofNullable(request.getRequest().getQueryParams().getFirst(matchKey)).orElse(StringUtils.EMPTY)); - break; - case CALLER_SERVICE: - String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true).orElse(StringUtils.EMPTY); - String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true).orElse(StringUtils.EMPTY); - if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) { - argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName); - } - break; - case CALLER_IP: - InetSocketAddress remoteAddress = request.getRequest().getRemoteAddress(); - argument = Argument.buildCallerIP(remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : StringUtils.EMPTY); - break; - default: - break; - } - return argument; - }).filter(Objects::nonNull).collect(Collectors.toSet()); - } - - private Map getCustomResolvedLabels(ServerWebExchange request) { - if (labelResolver != null) { - try { - return labelResolver.resolve(request); - } - catch (Throwable e) { - LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e); - } - } - return Collections.emptyMap(); - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java deleted file mode 100644 index e384d0333..000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java +++ /dev/null @@ -1,123 +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.polaris.ratelimit.resolver; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; - -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.CollectionUtils; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; - -/** - * resolve arguments from rate limit rule for Servlet. - * - * @author seansyyu 2023-03-09 - */ -public class RateLimitRuleArgumentServletResolver { - - private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class); - - private final ServiceRuleManager serviceRuleManager; - - private final PolarisRateLimiterLabelServletResolver labelResolver; - - public RateLimitRuleArgumentServletResolver(ServiceRuleManager serviceRuleManager, PolarisRateLimiterLabelServletResolver labelResolver) { - this.serviceRuleManager = serviceRuleManager; - this.labelResolver = labelResolver; - } - - public Set getArguments(HttpServletRequest request, 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(); - } - return rules.stream() - .flatMap(rule -> rule.getArgumentsList().stream()) - .map(matchArgument -> { - String matchKey = matchArgument.getKey(); - Argument argument = null; - switch (matchArgument.getType()) { - case CUSTOM: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)).orElse(StringUtils.EMPTY)); - break; - case METHOD: - argument = Argument.buildMethod(request.getMethod()); - break; - case HEADER: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildHeader(matchKey, Optional.ofNullable(request.getHeader(matchKey)).orElse(StringUtils.EMPTY)); - break; - case QUERY: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildQuery(matchKey, Optional.ofNullable(request.getParameter(matchKey)).orElse(StringUtils.EMPTY)); - break; - case CALLER_SERVICE: - String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true).orElse(StringUtils.EMPTY); - String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true).orElse(StringUtils.EMPTY); - if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) { - argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName); - } - break; - case CALLER_IP: - argument = Argument.buildCallerIP(Optional.ofNullable(request.getRemoteAddr()).orElse(StringUtils.EMPTY)); - break; - default: - break; - } - return argument; - }).filter(Objects::nonNull).collect(Collectors.toSet()); - } - - private Map getCustomResolvedLabels(HttpServletRequest request) { - if (labelResolver != null) { - try { - return labelResolver.resolve(request); - } - catch (Throwable e) { - LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e); - } - } - return Collections.emptyMap(); - } - -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.java new file mode 100644 index 000000000..c4a4aaebe --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.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.ratelimit.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +/** + * Auto configuration of TSF rate limit. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +public class TsfRateLimitAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfRateLimitConfigModifier tsfRateLimitConfigModifier(TsfCoreProperties tsfCoreProperties, + ConsulProperties consulProperties, Environment environment) { + return new TsfRateLimitConfigModifier(tsfCoreProperties, consulProperties, environment); + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitBootstrapConfiguration.java similarity index 61% rename from spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java rename to spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitBootstrapConfiguration.java index 818769bfd..f71c1d0e4 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitBootstrapConfiguration.java @@ -13,27 +13,22 @@ * 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.spi; +package com.tencent.cloud.polaris.ratelimit.tsf; -import java.util.Map; +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; -import org.springframework.web.server.ServerWebExchange; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; /** - * Resolve custom label from request. The label used for rate limit params. + * Bootstrap configuration for TSF rate limit. * - * @author lepdou 2022-03-31 + * @author Haotian Zhang */ -public interface PolarisRateLimiterLabelReactiveResolver { - - /** - * Resolve custom label from request. - * - * @param exchange the http request - * @return resolved labels - */ - Map resolve(ServerWebExchange exchange); +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +@Import(TsfRateLimitAutoConfiguration.class) +public class TsfRateLimitBootstrapConfiguration { } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.java new file mode 100644 index 000000000..682559c23 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.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.ratelimit.tsf; + +import java.util.Map; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextUtils; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.ratelimit.client.sync.tsf.TsfRateLimitConstants; + +import org.springframework.core.env.Environment; + +/** + * Config modifier for TSF rate limit. + * + * @author Haotian Zhang + */ +public class TsfRateLimitConfigModifier implements PolarisConfigModifier { + + private final TsfCoreProperties tsfCoreProperties; + + private final ConsulProperties consulProperties; + + private final Environment environment; + + public TsfRateLimitConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties, + Environment environment) { + this.tsfCoreProperties = tsfCoreProperties; + this.consulProperties = consulProperties; + this.environment = environment; + } + + @Override + public void modify(ConfigurationImpl configuration) { + if (TsfContextUtils.isTsfConsulEnabled(environment)) { + Map metadata = configuration.getProvider().getRateLimit().getMetadata(); + metadata.put(TsfRateLimitConstants.RATE_LIMIT_MASTER_IP_KEY, tsfCoreProperties.getRatelimitMasterIp()); + metadata.put(TsfRateLimitConstants.RATE_LIMIT_MASTER_PORT_KEY, String.valueOf(tsfCoreProperties.getRatelimitMasterPort())); + metadata.put(TsfRateLimitConstants.SERVICE_NAME_KEY, tsfCoreProperties.getServiceName()); + metadata.put(TsfRateLimitConstants.INSTANCE_ID_KEY, tsfCoreProperties.getInstanceId()); + metadata.put(TsfRateLimitConstants.TOKEN_KEY, consulProperties.getAclToken()); + } + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.RATE_LIMIT_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java index 3adcee5e4..a3ea94446 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java @@ -17,12 +17,9 @@ package com.tencent.cloud.polaris.ratelimit.utils; -import java.util.Map; -import java.util.Set; - +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; -import com.tencent.polaris.ratelimit.api.rpc.Argument; import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import org.slf4j.Logger; @@ -40,34 +37,13 @@ public final class QuotaCheckUtils { private QuotaCheckUtils() { } - @Deprecated - public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, - Map labels, String method) { - // build quota request - QuotaRequest quotaRequest = new QuotaRequest(); - quotaRequest.setNamespace(namespace); - quotaRequest.setService(service); - quotaRequest.setCount(count); - quotaRequest.setLabels(labels); - quotaRequest.setMethod(method); - - try { - return limitAPI.getQuota(quotaRequest); - } - catch (Throwable throwable) { - LOG.error("fail to invoke getQuota of LimitAPI with QuotaRequest[{}].", quotaRequest, throwable); - return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "get quota failed")); - } - } - - public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, - Set arguments, String method) { + public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, String method) { // build quota request QuotaRequest quotaRequest = new QuotaRequest(); quotaRequest.setNamespace(namespace); quotaRequest.setService(service); quotaRequest.setCount(count); - quotaRequest.setArguments(arguments); + quotaRequest.setMetadataContext(MetadataContextHolder.get()); quotaRequest.setMethod(method); try { diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java index f55cea3a6..1b90b1beb 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java @@ -18,9 +18,17 @@ package com.tencent.cloud.polaris.ratelimit.utils; +import java.util.HashMap; +import java.util.Map; + import com.tencent.cloud.common.util.ResourceFileUtils; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; +import com.tencent.polaris.api.plugin.stat.TraceConstants; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; +import com.tencent.polaris.assembly.api.pojo.TraceAttributes; +import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +44,7 @@ public final class RateLimitUtils { private static final Logger LOG = LoggerFactory.getLogger(RateLimitUtils.class); private RateLimitUtils() { + } public static String getRejectTips(PolarisRateLimitProperties polarisRateLimitProperties) { @@ -62,4 +71,33 @@ public static String getRejectTips(PolarisRateLimitProperties polarisRateLimitPr return RateLimitConstant.QUOTA_LIMITED_INFO; } + + public static void reportTrace(AssemblyAPI assemblyAPI, String ruleId) { + try { + if (assemblyAPI != null) { + Map attributes = new HashMap<>(); + attributes.put(TraceConstants.RateLimitRuleId, ruleId); + TraceAttributes traceAttributes = new TraceAttributes(); + traceAttributes.setAttributes(attributes); + traceAttributes.setAttributeLocation(TraceAttributes.AttributeLocation.SPAN); + assemblyAPI.updateTraceAttributes(traceAttributes); + } + } + catch (Throwable throwable) { + LOG.warn("[RateLimit] Report rule id {} to trace error.", ruleId, throwable); + } + } + + public static void release(QuotaResponse quotaResponse) { + if (quotaResponse != null && CollectionUtils.isNotEmpty(quotaResponse.getReleaseList())) { + for (Runnable release : quotaResponse.getReleaseList()) { + try { + release.run(); + } + catch (Throwable throwable) { + LOG.warn("[RateLimit] Release error.", throwable); + } + } + } + } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories index 563704410..7a4abe837 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories @@ -3,4 +3,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesAutoConfiguration,\ com.tencent.cloud.polaris.ratelimit.endpoint.PolarisRateLimitRuleEndpointAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesBootstrapConfiguration + com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesBootstrapConfiguration,\ + com.tencent.cloud.polaris.ratelimit.tsf.TsfRateLimitBootstrapConfiguration diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java index cf157182a..660611c18 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java @@ -17,15 +17,16 @@ package com.tencent.cloud.polaris.context; +import com.google.protobuf.StringValue; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import com.tencent.polaris.ratelimit.factory.LimitAPIFactory; +import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; import com.tencent.polaris.test.mock.discovery.NamingServer; import com.tencent.polaris.test.mock.discovery.NamingService; import org.junit.jupiter.api.AfterAll; @@ -118,6 +119,13 @@ public void test1() { QuotaResponse quotaResponse = mock(QuotaResponse.class); when(quotaResponse.getCode()).thenReturn(QuotaResultCode.QuotaResultLimited); when(quotaResponse.getInfo()).thenReturn("Testing rate limit after 10 times success."); + RateLimitProto.Rule rule = mock(RateLimitProto.Rule.class); + when(rule.getId()).thenReturn(StringValue.of("rate-test")); + RateLimitProto.CustomResponse customResponse = mock(RateLimitProto.CustomResponse.class); + when(customResponse.getBody()).thenReturn("limited"); + when(rule.getCustomResponse()).thenReturn(customResponse); + when(quotaResponse.getActiveRule()).thenReturn(rule); + when(quotaResponse.getActiveRuleName()).thenReturn("rate-test"); when(limitAPI.getQuota(any())).thenReturn(quotaResponse); } String result = restTemplate.getForObject(url, String.class); @@ -126,7 +134,7 @@ public void test1() { } catch (RestClientException e) { if (e instanceof TooManyRequests) { - System.out.println(((TooManyRequests) e).getResponseBodyAsString()); + assertThat(((TooManyRequests) e).getResponseBodyAsString()).isEqualTo("limited"); hasLimited = true; } else { @@ -157,10 +165,8 @@ public LimitAPI limitAPI(PolarisSDKContextManager polarisSDKContextManager) { @Primary public QuotaCheckServletFilter quotaCheckFilter(LimitAPI limitAPI, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver, @Autowired(required = false) PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { - return new QuotaCheckServletFilter(limitAPI, polarisRateLimitProperties, - rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback); + return new QuotaCheckServletFilter(limitAPI, null, polarisRateLimitProperties, polarisRateLimiterLimitedFallback); } } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java deleted file mode 100644 index 4d39e0c39..000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java +++ /dev/null @@ -1,99 +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.polaris.ratelimit; - -import java.util.Set; - -import com.google.protobuf.StringValue; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.polaris.specification.api.v1.model.ModelProto; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Test for {@link RateLimitRuleLabelResolver}. - * - * @author Haotian Zhang - */ -@ExtendWith(MockitoExtension.class) -public class RateLimitRuleLabelResolverTest { - - private RateLimitRuleLabelResolver rateLimitRuleLabelResolver; - - @BeforeEach - void setUp() { - ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - when(serviceRuleManager.getServiceRateLimitRule(any(), anyString())).thenAnswer(invocationOnMock -> { - String serviceName = invocationOnMock.getArgument(1).toString(); - if (serviceName.equals("TestApp1")) { - return null; - } - else if (serviceName.equals("TestApp2")) { - return RateLimitProto.RateLimit.newBuilder().build(); - } - else if (serviceName.equals("TestApp3")) { - RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder().build(); - return RateLimitProto.RateLimit.newBuilder().addRules(rule).build(); - } - else { - ModelProto.MatchString matchString = ModelProto.MatchString.newBuilder() - .setType(ModelProto.MatchString.MatchStringType.EXACT) - .setValue(StringValue.of("value")) - .setValueType(ModelProto.MatchString.ValueType.TEXT).build(); - RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder() - .putLabels("${http.method}", matchString).build(); - return RateLimitProto.RateLimit.newBuilder().addRules(rule).build(); - } - }); - - rateLimitRuleLabelResolver = new RateLimitRuleLabelResolver(serviceRuleManager); - } - - @Test - public void testGetExpressionLabelKeys() { - // rateLimitRule == null - String serviceName = "TestApp1"; - Set labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isEmpty(); - - // CollectionUtils.isEmpty(rules) - serviceName = "TestApp2"; - labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isEmpty(); - - // CollectionUtils.isEmpty(labels) - serviceName = "TestApp3"; - labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isEmpty(); - - // Has labels - serviceName = "TestApp4"; - labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isNotEmpty(); - assertThat(labelKeys).contains("${http.method}"); - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java index 9a959e511..668df07b3 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java @@ -20,8 +20,6 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -43,8 +41,7 @@ public class PolarisRateLimitAutoConfigurationTest { private final WebApplicationContextRunner webApplicationContextRunner = new WebApplicationContextRunner(); - private final ReactiveWebApplicationContextRunner reactiveWebApplicationContextRunner = - new ReactiveWebApplicationContextRunner(); + private final ReactiveWebApplicationContextRunner reactiveWebApplicationContextRunner = new ReactiveWebApplicationContextRunner(); @Test public void testNoWebApplication() { @@ -54,12 +51,10 @@ public void testNoWebApplication() { PolarisRateLimitProperties.class, PolarisRateLimitAutoConfiguration.class)) .run(context -> { - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentServletResolver.class); - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentReactiveResolver.class); assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class); assertThat(context).doesNotHaveBean(FilterRegistrationBean.class); - assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class); + assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class); }); } @@ -67,33 +62,31 @@ public void testNoWebApplication() { @Test public void testServletWebApplication() { this.webApplicationContextRunner - .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of( + PolarisContextAutoConfiguration.class, PolarisRateLimitProperties.class, PolarisRateLimitAutoConfiguration.class)) .run(context -> { - assertThat(context).hasSingleBean(RateLimitRuleArgumentServletResolver.class); assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class); assertThat(context).hasSingleBean(QuotaCheckServletFilter.class); assertThat(context).hasSingleBean(FilterRegistrationBean.class); - assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class); + assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class); - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentReactiveResolver.class); }); } @Test public void testReactiveWebApplication() { this.reactiveWebApplicationContextRunner - .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of( + PolarisContextAutoConfiguration.class, PolarisRateLimitProperties.class, PolarisRateLimitAutoConfiguration.class)) .run(context -> { - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentServletResolver.class); - assertThat(context).hasSingleBean(RateLimitRuleArgumentReactiveResolver.class); assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class); assertThat(context).doesNotHaveBean(FilterRegistrationBean.class); - assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class); + assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class); assertThat(context).hasSingleBean(QuotaCheckReactiveFilter.class); }); } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java index 9b1cbafc8..acc1438aa 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java @@ -53,7 +53,7 @@ public class PolarisRateLimitRuleEndpointTests { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - PolarisRateLimitAutoConfiguration.class, + PolarisRateLimitRuleEndpointTests.PolarisRateLimitAutoConfiguration.class, PolarisRateLimitRuleEndpointAutoConfiguration.class, PolarisRateLimitAutoConfiguration.class, PolarisRateLimitAutoConfiguration.class)) diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java index 812ebb1e8..f99e5d0af 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java @@ -27,13 +27,13 @@ import java.util.stream.Collectors; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.StringValue; import com.google.protobuf.util.JsonFormat; +import com.tencent.cloud.common.constant.HeaderConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; @@ -67,15 +67,13 @@ /** * Test for {@link QuotaCheckReactiveFilter}. * - * @author Haotian Zhang, cheese8, kaiy + * @author Haotian Zhang, kaiy */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @SpringBootTest(classes = QuotaCheckReactiveFilterTest.TestApplication.class, properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"}) public class QuotaCheckReactiveFilterTest { - private final PolarisRateLimiterLabelReactiveResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); private QuotaCheckReactiveFilter quotaCheckReactiveFilter; private QuotaCheckReactiveFilter quotaCheckWithRateLimiterLimitedFallbackReactiveFilter; private PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback; @@ -95,11 +93,12 @@ else if (serviceName.equals("TestApp2")) { } else if (serviceName.equals("TestApp3")) { QuotaResponse response = new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited")); - response.setActiveRule(RateLimitProto.Rule.newBuilder().build()); + response.setActiveRule(RateLimitProto.Rule.newBuilder() + .setName(StringValue.newBuilder().setValue("MOCK_RULE").build()).build()); return response; } else { - return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, null)); + return new QuotaResponse(new QuotaResult(null, 0, null)); } }); @@ -123,10 +122,10 @@ else if (serviceName.equals("TestApp3")) { RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver); - this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, polarisRateLimitProperties, rateLimitRuleArgumentReactiveResolver, null); + this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, null, polarisRateLimitProperties, null); this.polarisRateLimiterLimitedFallback = new JsonPolarisRateLimiterLimitedFallback(); - this.quotaCheckWithRateLimiterLimitedFallbackReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentReactiveResolver, polarisRateLimiterLimitedFallback); + this.quotaCheckWithRateLimiterLimitedFallbackReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, null, + polarisRateLimitWithHtmlRejectTipsProperties, polarisRateLimiterLimitedFallback); } @Test @@ -185,6 +184,8 @@ public void testFilter() { ServerHttpResponse response = testApp3Exchange.getResponse(); assertThat(response.getRawStatusCode()).isEqualTo(419); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INSUFFICIENT_SPACE_ON_RESOURCE); + assertThat(response.getHeaders() + .get(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)).isEqualTo(Collections.singletonList("MOCK_RULE")); // Exception MetadataContext.LOCAL_SERVICE = "TestApp4"; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java index 13065c92b..d6a760ad6 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java @@ -23,19 +23,18 @@ import java.io.InputStreamReader; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; -import java.util.Collections; import java.util.stream.Collectors; import javax.servlet.FilterChain; import javax.servlet.ServletException; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.StringValue; import com.google.protobuf.util.JsonFormat; +import com.tencent.cloud.common.constant.HeaderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; @@ -69,12 +68,10 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = QuotaCheckServletFilterTest.TestApplication.class, properties = { - "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" -}) + "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" + }) public class QuotaCheckServletFilterTest { - private final PolarisRateLimiterLabelServletResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); private QuotaCheckServletFilter quotaCheckServletFilter; private QuotaCheckServletFilter quotaCheckWithHtmlRejectTipsServletFilter; private QuotaCheckServletFilter quotaCheckWithRateLimiterLimitedFallbackFilter; @@ -95,7 +92,8 @@ else if (serviceName.equals("TestApp2")) { } else if (serviceName.equals("TestApp3")) { QuotaResponse response = new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited")); - response.setActiveRule(RateLimitProto.Rule.newBuilder().build()); + response.setActiveRule(RateLimitProto.Rule.newBuilder() + .setName(StringValue.newBuilder().setValue("MOCK_RULE").build()).build()); return response; } else { @@ -113,19 +111,22 @@ else if (serviceName.equals("TestApp3")) { ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); - InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); + RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); + InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader() + .getResourceAsStream("ratelimit.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder); RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build(); RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver); - this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitProperties, rateLimitRuleArgumentServletResolver, null); - this.quotaCheckWithHtmlRejectTipsServletFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentServletResolver, null); + this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, null, polarisRateLimitProperties, null); + this.quotaCheckWithHtmlRejectTipsServletFilter = new QuotaCheckServletFilter(limitAPI, null, + polarisRateLimitWithHtmlRejectTipsProperties, null); this.polarisRateLimiterLimitedFallback = new JsonPolarisRateLimiterLimitedFallback(); - this.quotaCheckWithRateLimiterLimitedFallbackFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentServletResolver, polarisRateLimiterLimitedFallback); + this.quotaCheckWithRateLimiterLimitedFallbackFilter = new QuotaCheckServletFilter(limitAPI, null, + polarisRateLimitWithHtmlRejectTipsProperties, polarisRateLimiterLimitedFallback); } @Test @@ -182,13 +183,13 @@ public void testDoFilterInternal() { quotaCheckServletFilter.doFilterInternal(request, testApp3Response, filterChain); assertThat(testApp3Response.getStatus()).isEqualTo(419); assertThat(testApp3Response.getContentAsString()).isEqualTo("RejectRequestTips提示消息"); + assertThat(testApp3Response.getHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)).isEqualTo("MOCK_RULE"); MockHttpServletResponse testApp3Response2 = new MockHttpServletResponse(); quotaCheckWithHtmlRejectTipsServletFilter.doFilterInternal(request, testApp3Response2, filterChain); assertThat(testApp3Response2.getStatus()).isEqualTo(419); assertThat(testApp3Response2.getContentAsString()).isEqualTo("

RejectRequestTips提示消息

"); - // Exception MockHttpServletResponse testApp4Response = new MockHttpServletResponse(); MetadataContext.LOCAL_SERVICE = "TestApp4"; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java deleted file mode 100644 index 1648a9618..000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java +++ /dev/null @@ -1,144 +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.polaris.ratelimit.resolver; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilterTest; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.http.server.reactive.MockServerHttpRequest; -import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.web.server.ServerWebExchange; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = RateLimitRuleArgumentReactiveResolverTest.TestApplication.class, - properties = { - "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" - }) -public class RateLimitRuleArgumentReactiveResolverTest { - - private final PolarisRateLimiterLabelReactiveResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); - - private final PolarisRateLimiterLabelReactiveResolver labelResolverEx = - exchange -> { - throw new RuntimeException(); - }; - - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver1; - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver2; - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver3; - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver4; - - @BeforeEach - void setUp() throws InvalidProtocolBufferException { - MetadataContext.LOCAL_NAMESPACE = "TEST"; - - ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - - RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); - InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder); - RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build(); - RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); - when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - - // normal - this.rateLimitRuleArgumentReactiveResolver1 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver); - // ex - this.rateLimitRuleArgumentReactiveResolver2 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolverEx); - // null - ServiceRuleManager serviceRuleManager1 = mock(ServiceRuleManager.class); - when(serviceRuleManager1.getServiceRateLimitRule(anyString(), anyString())).thenReturn(null); - this.rateLimitRuleArgumentReactiveResolver3 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager1, labelResolver); - // null 2 - ServiceRuleManager serviceRuleManager2 = mock(ServiceRuleManager.class); - RateLimitProto.RateLimit rateLimit2 = RateLimitProto.RateLimit.newBuilder().build(); - when(serviceRuleManager2.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit2); - this.rateLimitRuleArgumentReactiveResolver4 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager2, labelResolver); - } - - @Test - public void testGetRuleArguments() { - // Mock request - MetadataContext.LOCAL_SERVICE = "Test"; - // Mock request - MockServerHttpRequest request = MockServerHttpRequest.get("http://127.0.0.1:8080/test") - .remoteAddress(new InetSocketAddress("127.0.0.1", 8080)) - .header("xxx", "xxx") - .queryParam("yyy", "yyy") - .build(); - ServerWebExchange exchange = MockServerWebExchange.from(request); - MetadataContext metadataContext = new MetadataContext(); - metadataContext.setUpstreamDisposableMetadata(new HashMap() {{ - put(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, MetadataContext.LOCAL_NAMESPACE); - put(DEFAULT_METADATA_SOURCE_SERVICE_NAME, MetadataContext.LOCAL_SERVICE); - }}); - MetadataContextHolder.set(metadataContext); - Set arguments = rateLimitRuleArgumentReactiveResolver1.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - Set exceptRes = new HashSet<>(); - exceptRes.add(Argument.buildMethod("GET")); - exceptRes.add(Argument.buildHeader("xxx", "xxx")); - exceptRes.add(Argument.buildQuery("yyy", "yyy")); - exceptRes.add(Argument.buildCallerIP("127.0.0.1")); - exceptRes.add(Argument.buildCustom("xxx", "xxx")); - exceptRes.add(Argument.buildCallerService(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); - assertThat(arguments).isEqualTo(exceptRes); - - rateLimitRuleArgumentReactiveResolver2.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentReactiveResolver3.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentReactiveResolver4.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - } - - @SpringBootApplication - protected static class TestApplication { - } - -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java deleted file mode 100644 index 1a8b49ed7..000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java +++ /dev/null @@ -1,135 +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.polaris.ratelimit.resolver; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilterTest; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = RateLimitRuleArgumentServletResolverTest.TestApplication.class, - properties = { - "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" - }) -public class RateLimitRuleArgumentServletResolverTest { - - private final PolarisRateLimiterLabelServletResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); - private final PolarisRateLimiterLabelServletResolver labelResolverEx = - exchange -> { - throw new RuntimeException(); - }; - - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver1; - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver2; - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver3; - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver4; - - @BeforeEach - void setUp() throws InvalidProtocolBufferException { - MetadataContext.LOCAL_NAMESPACE = "TEST"; - - ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - - RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); - InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder); - RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build(); - RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); - when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - - // normal - this.rateLimitRuleArgumentServletResolver1 = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver); - // ex - this.rateLimitRuleArgumentServletResolver2 = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolverEx); - // null - ServiceRuleManager serviceRuleManager1 = mock(ServiceRuleManager.class); - when(serviceRuleManager1.getServiceRateLimitRule(anyString(), anyString())).thenReturn(null); - this.rateLimitRuleArgumentServletResolver3 = new RateLimitRuleArgumentServletResolver(serviceRuleManager1, labelResolver); - // null 2 - ServiceRuleManager serviceRuleManager2 = mock(ServiceRuleManager.class); - RateLimitProto.RateLimit rateLimit2 = RateLimitProto.RateLimit.newBuilder().build(); - when(serviceRuleManager2.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit2); - this.rateLimitRuleArgumentServletResolver4 = new RateLimitRuleArgumentServletResolver(serviceRuleManager2, labelResolver); - } - - @Test - public void testGetRuleArguments() { - // Mock request - MetadataContext.LOCAL_SERVICE = "Test"; - MockHttpServletRequest request = new MockHttpServletRequest(null, "GET", "/xxx"); - request.setParameter("yyy", "yyy"); - request.addHeader("xxx", "xxx"); - MetadataContext metadataContext = new MetadataContext(); - metadataContext.setUpstreamDisposableMetadata(new HashMap() {{ - put(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, MetadataContext.LOCAL_NAMESPACE); - put(DEFAULT_METADATA_SOURCE_SERVICE_NAME, MetadataContext.LOCAL_SERVICE); - }}); - MetadataContextHolder.set(metadataContext); - Set arguments = rateLimitRuleArgumentServletResolver1.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - Set exceptRes = new HashSet<>(); - exceptRes.add(Argument.buildMethod("GET")); - exceptRes.add(Argument.buildHeader("xxx", "xxx")); - exceptRes.add(Argument.buildQuery("yyy", "yyy")); - exceptRes.add(Argument.buildCallerIP("127.0.0.1")); - exceptRes.add(Argument.buildCustom("xxx", "xxx")); - exceptRes.add(Argument.buildCallerService(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); - assertThat(arguments).isEqualTo(exceptRes); - - rateLimitRuleArgumentServletResolver2.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentServletResolver3.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentServletResolver4.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - } - - @SpringBootApplication - protected static class TestApplication { - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java index ad2691f4d..792948c88 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java @@ -17,9 +17,6 @@ package com.tencent.cloud.polaris.ratelimit.utils; -import java.util.HashMap; -import java.util.HashSet; - import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest; @@ -69,59 +66,28 @@ else if (serviceName.equals("TestApp3")) { public void testGetQuota() { // Pass String serviceName = "TestApp1"; - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); - assertThat(quotaResponse.getWaitMs()).isEqualTo(0); - assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); - - // Unirate waiting 1000ms - serviceName = "TestApp2"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); - assertThat(quotaResponse.getWaitMs()).isEqualTo(1000); - assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); - - // Rate limited - serviceName = "TestApp3"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited); - assertThat(quotaResponse.getWaitMs()).isEqualTo(0); - assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited"); - - // Exception - serviceName = "TestApp4"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); - assertThat(quotaResponse.getWaitMs()).isEqualTo(0); - assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed"); - } - - @Test - public void testGetQuota2() { - // Pass - String serviceName = "TestApp1"; - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); assertThat(quotaResponse.getWaitMs()).isEqualTo(0); assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); // Unirate waiting 1000ms serviceName = "TestApp2"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); assertThat(quotaResponse.getWaitMs()).isEqualTo(1000); assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); // Rate limited serviceName = "TestApp3"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited); assertThat(quotaResponse.getWaitMs()).isEqualTo(0); assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited"); // Exception serviceName = "TestApp4"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); assertThat(quotaResponse.getWaitMs()).isEqualTo(0); assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed"); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java index 98a9cd422..35df6cb7f 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java @@ -217,6 +217,11 @@ public static final class Modifier { */ public static Integer LOSSLESS_ORDER = 2; + /** + * Order of admin configuration modifier. + */ + public static Integer ADMIN_ORDER = 2; + /** * Order of service contract configuration modifier. */ 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 2a1ec1e3e..1f220769d 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 @@ -28,6 +28,8 @@ import com.tencent.polaris.metadata.core.MetadataProvider; import com.tencent.polaris.metadata.core.MetadataType; import com.tencent.polaris.metadata.core.TransitiveType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -42,6 +44,8 @@ */ public final class MetadataContextHolder { + private static final Logger LOG = LoggerFactory.getLogger(MetadataContextHolder.class); + private static StaticMetadataManager staticMetadataManager; static { @@ -58,8 +62,14 @@ public static MetadataContext get() { private static MetadataContext createMetadataManager() { MetadataContext metadataManager = new MetadataContext(); if (staticMetadataManager == null) { - staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() - .getBean(StaticMetadataManager.class); + if (ApplicationContextAwareUtils.getApplicationContext() != null) { + staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() + .getBean(StaticMetadataManager.class); + } + else { + // for junit test. + return metadataManager; + } } // local custom metadata MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java index 2044bcb01..559867419 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java @@ -47,12 +47,12 @@ public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata Environment environment = conditionContext.getEnvironment(); boolean tsfConsulEnable = false; - String tsfAppId = environment.getProperty("tsf_app_id", ""); + String tsfAppId = environment.getProperty("tsf_app_id"); if (StringUtils.isNotBlank(tsfAppId)) { String tsfConsulIp = environment.getProperty("tsf_consul_ip"); - String tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); - if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("tse_polaris_ip"))) { - tsePolarisAddress = "grpc://" + environment.getProperty("tse_polaris_ip") + ":8091"; + String tsePolarisAddress = environment.getProperty("polaris_address"); + if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("spring.cloud.polaris.address"))) { + tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); } tsfConsulEnable = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java deleted file mode 100644 index dee92deb0..000000000 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfEnabled.java +++ /dev/null @@ -1,50 +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.tsf; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.tencent.polaris.api.utils.StringUtils; - -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.context.annotation.Conditional; -import org.springframework.core.type.AnnotatedTypeMetadata; - -/** - * Condition that if Polaris enabled. - * - * @author Haotian Zhang - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.METHOD}) -@Conditional(ConditionalOnTsfEnabled.OnTsfEnabledCondition.class) -public @interface ConditionalOnTsfEnabled { - - class OnTsfEnabledCondition implements Condition { - - @Override - public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { - String tsfAppId = conditionContext.getEnvironment().getProperty("tsf_app_id", ""); - return StringUtils.isNotBlank(tsfAppId); - } - } -} diff --git a/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java index 0e7c98a8f..a97f2635c 100644 --- a/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java +++ b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java @@ -43,7 +43,7 @@ public static void putTags(Map tagMap, Tag.ControlFlag... flags) return; } MetadataContext tsfCoreContext = MetadataContextHolder.get(); - TransitiveType transitive = TransitiveType.NONE; + TransitiveType transitive = TransitiveType.DISPOSABLE; if (null != flags) { for (Tag.ControlFlag flag : flags) { if (flag == Tag.ControlFlag.TRANSITIVE) { diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml index 4e8c2a8ce..a42bb9e9d 100644 --- a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml @@ -15,12 +15,12 @@ spring: exposure: true report: enabled: true + admin: + port: 28084 stat: enabled: true - port: 28084 lossless: enabled: true - port: 28084 #healthCheckPath: /actuator/health #healthCheckInterval: 5000 lossless: diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml index 39d7f2c51..8e2a7b94c 100644 --- a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml @@ -9,9 +9,10 @@ spring: server-addr: 127.0.0.1:8848 enabled: true polaris: + admin: + port: 28085 lossless: enabled: true - port: 28085 healthCheckPath: /actuator/health healthCheckInterval: 5000 lossless: diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml index 29d9d9c96..c5c4c4072 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml @@ -15,9 +15,10 @@ spring: exposure: true report: enabled: true + admin: + port: 28083 stat: enabled: true - port: 28083 # pushgateway: # enabled: true # address: 127.0.0.1:9091 diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml index 259358d55..ee0cb3c2e 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml @@ -20,9 +20,10 @@ spring: enabled: true circuitbreaker: enabled: true + admin: + port: 28082 stat: enabled: true - port: 28082 # pushgateway: # enabled: true # address: 127.0.0.1:9091 diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml index 5c39a3f50..044956f09 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml @@ -12,9 +12,10 @@ spring: exposure: true report: enabled: true + admin: + port: 28081 stat: enabled: true - port: 28081 gateway: discovery: locator: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java index 8e7177271..a5090dbf0 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java @@ -36,6 +36,7 @@ public class CustomMetadata implements InstanceMetadataProvider { public Map getMetadata() { Map metadata = new HashMap<>(); metadata.put("k1", "v1"); + metadata.put("lane", "lane1"); return metadata; } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java deleted file mode 100644 index cdd4b97e0..000000000 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java +++ /dev/null @@ -1,63 +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.quickstart.callee.ratelimit; - -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * resolver custom label from request. - * - * @author lepdou 2022-03-31 - */ -@Component -public class CustomLabelResolver implements PolarisRateLimiterLabelServletResolver { - private static final Logger LOG = LoggerFactory.getLogger(CustomLabelResolver.class); - - @Value("${label.key-value:}") - private String[] keyValues; - - @Override - public Map resolve(HttpServletRequest request) { - // rate limit by some request params. such as query params, headers .. - - return getLabels(keyValues); - } - - private Map getLabels(String[] keyValues) { - Map labels = new HashMap<>(); - for (String kv : keyValues) { - String key = kv.substring(0, kv.indexOf(":")); - String value = kv.substring(kv.indexOf(":") + 1); - labels.put(key, value); - } - - LOG.info("Current labels:{}", labels); - return labels; - } -} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml index bf4d56b8f..d9f0131b2 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml @@ -14,10 +14,11 @@ spring: contract: exposure: true report: - enabled: false + enabled: true + admin: + port: 28083 stat: enabled: true - port: 28083 # pushgateway: # enabled: true # address: 127.0.0.1:9091 @@ -35,7 +36,7 @@ spring: metadata: content: label1: value1 - region: huanan +# region: huanan management: endpoints: web: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java index ed4b59b2e..7b4b9edef 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java @@ -36,6 +36,7 @@ public class CustomMetadata implements InstanceMetadataProvider { public Map getMetadata() { Map metadata = new HashMap<>(); metadata.put("k1", "v2"); + metadata.put("lane", "lane2"); return metadata; } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 9f923950a..a3dac5adb 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -61,7 +61,7 @@ public class QuickstartCalleeController { @Autowired private DataSourceProperties dataSourceProperties; private boolean ifBadGateway = true; - private boolean ifDelay = true; + private boolean ifDelay = false; /** * Get sum of two value. diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java deleted file mode 100644 index 4a270fc62..000000000 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java +++ /dev/null @@ -1,60 +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.quickstart.callee.ratelimit; - -import java.util.HashMap; -import java.util.Map; - -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; - -/** - * resolver custom label from request. - * - * @author sean yu - */ -@Component -public class CustomLabelResolverReactive implements PolarisRateLimiterLabelReactiveResolver { - private static final Logger LOG = LoggerFactory.getLogger(CustomLabelResolverReactive.class); - - @Value("${label.key-value:}") - private String[] keyValues; - - @Override - public Map resolve(ServerWebExchange exchange) { - // rate limit by some request params. such as query params, headers .. - return getLabels(keyValues); - } - - private Map getLabels(String[] keyValues) { - Map labels = new HashMap<>(); - for (String kv : keyValues) { - String key = kv.substring(0, kv.indexOf(":")); - String value = kv.substring(kv.indexOf(":") + 1); - labels.put(key, value); - } - - LOG.info("Current labels:{}", labels); - return labels; - } -} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml index b5c7ec0bf..19e7e5d5f 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml @@ -14,10 +14,11 @@ spring: contract: exposure: true report: - enabled: false + enabled: true + admin: + port: 28084 stat: enabled: true - port: 28084 # pushgateway: # enabled: true # address: 127.0.0.1:9091 @@ -34,7 +35,7 @@ spring: metadata: content: label1: value2 - region: huanan +# region: huanan management: endpoints: web: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java index 9cbdcd18d..c936bef0b 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java @@ -17,6 +17,9 @@ package com.tencent.cloud.quickstart.caller; +import java.util.HashMap; +import java.util.Map; + import com.tencent.cloud.common.spi.InstanceMetadataProvider; import org.springframework.stereotype.Component; @@ -27,4 +30,11 @@ @Component public class CustomMetadataProvider implements InstanceMetadataProvider { + @Override + public Map getMetadata() { + Map metadata = new HashMap<>(); + metadata.put("k1", "v1"); + return metadata; + } + } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java index 25764d052..7ec58858a 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java @@ -40,6 +40,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; @@ -100,7 +101,12 @@ public ResponseEntity rest(@RequestHeader Map headerMap) HttpEntity entity = new HttpEntity<>(headers); // 使用 exchange 方法发送 GET 请求,并获取响应 - return restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + try { + return restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + } + catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) { + return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode()); + } } /** @@ -121,32 +127,33 @@ public Mono webclient() { * Get information 30 times per 1 second. * * @return result of 30 calls. - * @throws InterruptedException exception */ @GetMapping("/ratelimit") - public String invokeInfo() throws InterruptedException { - StringBuffer builder = new StringBuffer(); - CountDownLatch count = new CountDownLatch(30); + public String invokeInfo() { + StringBuilder builder = new StringBuilder(); AtomicInteger index = new AtomicInteger(0); for (int i = 0; i < 30; i++) { - new Thread(() -> { + try { + ResponseEntity entity = restTemplate.getForEntity( + "http://QuickstartCalleeService/quickstart/callee/info", String.class); + builder.append(entity.getBody() + "\n"); try { - ResponseEntity entity = restTemplate.getForEntity( - "http://QuickstartCalleeService/quickstart/callee/info", String.class); - builder.append(entity.getBody() + "\n"); + Thread.sleep(30); } - catch (RestClientException e) { - if (e instanceof HttpClientErrorException.TooManyRequests) { - builder.append("TooManyRequests " + index.incrementAndGet() + "\n"); - } - else { - throw e; - } + catch (InterruptedException e) { + throw new RuntimeException(e); } - count.countDown(); - }).start(); + } + catch (RestClientException e) { + if (e instanceof HttpClientErrorException.TooManyRequests) { + builder.append("TooManyRequests " + index.incrementAndGet() + "\n"); + } + else { + throw e; + } + } } - count.await(); + return builder.toString(); } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml index 38c5079e3..89f73c3c5 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml @@ -23,9 +23,10 @@ spring: enabled: true circuitbreaker: enabled: true + admin: + port: 28082 stat: enabled: true - port: 28082 # pushgateway: # enabled: true # address: 127.0.0.1:9091 diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml index bb5fc7d67..b30f39da4 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml @@ -24,9 +24,10 @@ spring: exposure: true report: enabled: true + admin: + port: 28081 stat: enabled: true - port: 28081 gateway: discovery: locator: diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java index 370975e42..b2f80e1b4 100644 --- a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java @@ -17,8 +17,6 @@ package com.tencent.cloud.tsf.demo.provider; - -import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; @@ -33,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -87,36 +86,35 @@ public String hello() { } @RequestMapping(value = "/echo/{param}", method = RequestMethod.GET) - public String echo(@PathVariable String param, HttpServletResponse response) throws IOException { + public ResponseEntity echo(@PathVariable String param) { + int status; + String responseBody; + switch (param) { case "1xx": - response.setStatus(HttpServletResponse.SC_CONTINUE); - response.getWriter().write("mock 1xx return."); - response.getWriter().flush(); - return "mock 1xx return."; + status = HttpServletResponse.SC_CONTINUE; + responseBody = "mock 1xx return."; + break; case "3xx": - response.setStatus(HttpServletResponse.SC_FOUND); - response.getWriter().write("mock 3xx return."); - response.getWriter().flush(); - return "mock 3xx return."; + status = HttpServletResponse.SC_FOUND; + responseBody = "mock 3xx return."; + break; case "4xx": - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - response.getWriter().write("mock 4xx return."); - response.getWriter().flush(); - return "mock 4xx return."; + status = HttpServletResponse.SC_NOT_FOUND; + responseBody = "mock 4xx return."; + break; case "5xx": - response.setStatus(HttpServletResponse.SC_BAD_GATEWAY); - response.getWriter().write("mock 5xx return."); - response.getWriter().flush(); - return "mock 5xx return."; + status = HttpServletResponse.SC_BAD_GATEWAY; + responseBody = "mock 5xx return."; + break; default: - LOG.info("provider-demo -- request param: [" + param + "]"); - String result = "from host-ip: " + getInet4Address() + ", request param: " + param + ", response from " + providerNameConfig.getName(); - LOG.info("provider-demo -- provider config name: [" + providerNameConfig.getName() + ']'); - LOG.info("provider-demo -- response info: [" + result + "]"); - return result; + responseBody = String.format("from host-ip: %s, request param: %s, response from %s", + getInet4Address(), param, providerNameConfig.getName()); + status = HttpServletResponse.SC_OK; + break; } + return ResponseEntity.status(status).body(responseBody); } @RequestMapping(value = "/echo/error/{param}", method = RequestMethod.GET) diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml index 5e43105a2..018fc9510 100644 --- a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml @@ -9,7 +9,6 @@ spring: enabled: true stat: enabled: true - port: 28081 loadbalancer: strategy: polarisWeightedRandom tencent: diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java index 3fe48314c..311fbc65a 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java @@ -39,12 +39,18 @@ public Map getConsumerSpanAttributes(EnhancedPluginContext conte } ServiceInstance targetServiceInstance = context.getTargetServiceInstance(); if (null != targetServiceInstance && CollectionUtils.isNotEmpty(targetServiceInstance.getMetadata())) { - String nsId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_NAMESPACE_ID); - attributes.put("remote.namespace-id", StringUtils.defaultString(nsId)); - String groupId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_GROUP_ID); - attributes.put("remote.group-id", StringUtils.defaultString(groupId)); - String applicationId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_APPLICATION_ID); - attributes.put("remote.application-id", StringUtils.defaultString(applicationId)); + if (targetServiceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_NAMESPACE_ID)) { + attributes.put("remote.namespace-id", StringUtils.defaultString( + targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_NAMESPACE_ID))); + } + if (targetServiceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_GROUP_ID)) { + attributes.put("remote.group-id", StringUtils.defaultString( + targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_GROUP_ID))); + } + if (targetServiceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_APPLICATION_ID)) { + attributes.put("remote.application-id", StringUtils.defaultString( + targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_APPLICATION_ID))); + } } return attributes; } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java index 3b5b102f4..6bfed4541 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java @@ -18,15 +18,12 @@ package com.tencent.cloud.plugin.trace.tsf; -import com.tencent.cloud.common.tsf.ConditionalOnTsfEnabled; - import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) -@ConditionalOnTsfEnabled @ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) public class TsfTracePropertiesAutoConfiguration { diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml index 416b4130c..2cd286421 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml @@ -30,6 +30,11 @@ lossless-deregister
+ + com.tencent.polaris + lossless-warmup + + org.springframework.boot spring-boot-starter-aop diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java index 9dab0f243..37cfca588 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java @@ -22,6 +22,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import com.tencent.polaris.api.pojo.BaseInstance; +import com.tencent.polaris.plugin.lossless.common.HttpLosslessActionProvider; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -78,12 +79,13 @@ public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { } // web started, get port from registration - BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, registrationTransformer); + BaseInstance instance = getBaseInstance(registration, registrationTransformer); Runnable registerAction = () -> executeJoinPoint(joinPoint); - - SpringCloudLosslessActionProvider losslessActionProvider = - new SpringCloudLosslessActionProvider(serviceRegistry, registration, losslessProperties, registerAction); + Runnable deregisterAction = () -> serviceRegistry.deregister(registration); + HttpLosslessActionProvider losslessActionProvider = + new HttpLosslessActionProvider(registerAction, deregisterAction, registration.getPort(), + instance, polarisSDKContextManager.getSDKContext().getExtensions()); polarisSDKContextManager.getLosslessAPI().setLosslessActionProvider(instance, losslessActionProvider); polarisSDKContextManager.getLosslessAPI().losslessRegister(instance); @@ -104,4 +106,8 @@ public void executeJoinPoint(ProceedingJoinPoint joinPoint) { throw new RuntimeException(e); } } + + public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { + return registrationTransformer.transform(registration); + } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java deleted file mode 100644 index a97df5960..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.plugin.lossless; - -import java.util.HashMap; -import java.util.Map; - -import com.tencent.cloud.common.util.OkHttpUtil; -import com.tencent.cloud.plugin.lossless.config.LosslessProperties; -import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; -import com.tencent.polaris.api.plugin.lossless.InstanceProperties; -import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider; -import com.tencent.polaris.api.pojo.BaseInstance; -import com.tencent.polaris.api.utils.StringUtils; - -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.http.HttpHeaders; - -/** - * LosslessActionProvider for Spring Cloud. - * - * @author Shedfree Wu - */ -public class SpringCloudLosslessActionProvider implements LosslessActionProvider { - private ServiceRegistry serviceRegistry; - - private LosslessProperties losslessProperties; - - private Runnable originalRegisterAction; - - private Registration registration; - - public SpringCloudLosslessActionProvider(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, Runnable originalRegisterAction) { - this.serviceRegistry = serviceRegistry; - this.registration = registration; - this.losslessProperties = losslessProperties; - this.originalRegisterAction = originalRegisterAction; - } - - @Override - public String getName() { - return "spring-cloud"; - } - - @Override - public void doRegister(InstanceProperties instanceProperties) { - // use lambda to do original register - originalRegisterAction.run(); - } - - @Override - public void doDeregister() { - serviceRegistry.deregister(registration); - } - - /** - * Check whether health check is enable. - * @return true: register after passing doHealthCheck, false: register after delayRegisterInterval. - */ - @Override - public boolean isEnableHealthCheck() { - return StringUtils.isNotBlank(losslessProperties.getHealthCheckPath()); - } - - @Override - public boolean doHealthCheck() { - Map headers = new HashMap<>(1); - headers.put(HttpHeaders.USER_AGENT, "polaris"); - - return OkHttpUtil.checkUrl("localhost", registration.getPort(), - losslessProperties.getHealthCheckPath(), headers); - } - - public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { - return registrationTransformer.transform(registration); - } - -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java index f5049df76..56a06c27f 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java @@ -21,8 +21,10 @@ import com.tencent.cloud.common.constant.OrderConstant.Modifier; import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.factory.config.provider.LosslessConfigImpl; +import com.tencent.polaris.specification.api.v1.traffic.manage.LosslessProto; /** * Config modifier for lossless. @@ -39,17 +41,27 @@ public LosslessConfigModifier(LosslessProperties losslessProperties) { @Override public void modify(ConfigurationImpl configuration) { + LosslessConfigImpl losslessConfig = (LosslessConfigImpl) configuration.getProvider().getLossless(); if (losslessProperties.isEnabled()) { - LosslessConfigImpl losslessConfig = (LosslessConfigImpl) configuration.getProvider().getLossless(); losslessConfig.setEnable(true); - losslessConfig.setPort(losslessProperties.getPort()); if (Objects.nonNull(losslessProperties.getDelayRegisterInterval())) { losslessConfig.setDelayRegisterInterval(losslessProperties.getDelayRegisterInterval()); } - if (Objects.nonNull(losslessProperties.getHealthCheckInterval())) { - losslessConfig.setHealthCheckInterval(losslessProperties.getHealthCheckInterval()); + if (StringUtils.isNotEmpty(losslessProperties.getHealthCheckPath())) { + losslessConfig.setHealthCheckPath(losslessProperties.getHealthCheckPath()); + losslessConfig.setStrategy(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_HEALTH_CHECK); + + if (Objects.nonNull(losslessProperties.getHealthCheckInterval())) { + losslessConfig.setHealthCheckInterval(losslessProperties.getHealthCheckInterval()); + } + } + else { + losslessConfig.setStrategy(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_TIME); } } + else { + losslessConfig.setEnable(false); + } } @Override diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java index 89398f42a..288e0bf96 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java @@ -25,8 +25,6 @@ public class LosslessProperties { private boolean enabled = false; - private int port = 28080; - private String healthCheckPath; private Long delayRegisterInterval; @@ -41,14 +39,6 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - public String getHealthCheckPath() { return healthCheckPath; } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java index 23826a37c..96e3fbee1 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java @@ -32,7 +32,7 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisEnabled -@EnableConfigurationProperties(LosslessProperties.class) +@EnableConfigurationProperties({LosslessProperties.class, WarmupProperties.class}) public class LosslessPropertiesAutoConfiguration { @Bean @@ -41,4 +41,9 @@ public LosslessConfigModifier losslessConfigModifier(LosslessProperties lossless return new LosslessConfigModifier(losslessProperties); } + @Bean + @ConditionalOnMissingBean + public WarmupConfigModifier warmupConfigModifier(WarmupProperties warmupProperties) { + return new WarmupConfigModifier(warmupProperties); + } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java new file mode 100644 index 000000000..4547ffd0e --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.plugin.lossless.config; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + +import com.tencent.cloud.common.constant.OrderConstant.Modifier; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.consumer.WeightAdjustConfigImpl; +import com.tencent.polaris.plugin.lossless.warmup.WarmupWeightAdjuster; + +/** + * Config modifier for warmup. + * + * @author Shedfree Wu + */ +public class WarmupConfigModifier implements PolarisConfigModifier { + + private final WarmupProperties warmupProperties; + + public WarmupConfigModifier(WarmupProperties warmupProperties) { + this.warmupProperties = warmupProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + WeightAdjustConfigImpl weightAdjustConfig = (WeightAdjustConfigImpl) configuration.getConsumer().getWeightAdjust(); + if (warmupProperties.isEnabled()) { + Set chainSet = new TreeSet<>( + Optional.ofNullable(weightAdjustConfig.getChain()).orElse(Collections.emptyList())); + chainSet.add(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME); + weightAdjustConfig.setChain(new ArrayList<>(chainSet)); + } + else { + Set chainSet = new TreeSet<>( + Optional.ofNullable(weightAdjustConfig.getChain()).orElse(Collections.emptyList())); + chainSet.remove(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME); + weightAdjustConfig.setChain(new ArrayList<>(chainSet)); + } + } + + @Override + public int getOrder() { + return Modifier.LOSSLESS_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java similarity index 61% rename from spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java rename to spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java index 8fe859092..1b8d8d4f9 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java @@ -16,25 +16,20 @@ * */ -package com.tencent.cloud.polaris.ratelimit.spi; +package com.tencent.cloud.plugin.lossless.config; -import java.util.Map; +import org.springframework.boot.context.properties.ConfigurationProperties; -import javax.servlet.http.HttpServletRequest; +@ConfigurationProperties("spring.cloud.polaris.warmup") +public class WarmupProperties { -/** - * Resolve custom label from request. The label used for rate limit params. - * - * @author lepdou 2022-03-31 - */ -public interface PolarisRateLimiterLabelServletResolver { + private boolean enabled = false; - /** - * Resolve custom label from request. - * - * @param request the http request - * @return resolved labels - */ - Map resolve(HttpServletRequest request); + public boolean isEnabled() { + return enabled; + } + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 48a31c1cd..c4e339832 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -3,7 +3,7 @@ { "name": "spring.cloud.polaris.lossless.enabled", "type": "java.lang.Boolean", - "defaultValue": true, + "defaultValue": false, "description": "the switch for lossless plugin." } ] diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java new file mode 100644 index 000000000..6929db5c5 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java @@ -0,0 +1,47 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.admin; + +import com.tencent.cloud.common.constant.OrderConstant.Modifier; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; + +/** + * Config modifier for admin. + * + * @author Haotian Zhang + */ +public class PolarisAdminConfigModifier implements PolarisConfigModifier { + + private final PolarisAdminProperties polarisAdminProperties; + + public PolarisAdminConfigModifier(PolarisAdminProperties polarisAdminProperties) { + this.polarisAdminProperties = polarisAdminProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + configuration.getGlobal().getAdmin().setHost(this.polarisAdminProperties.getHost()); + configuration.getGlobal().getAdmin().setPort(this.polarisAdminProperties.getPort()); + } + + @Override + public int getOrder() { + return Modifier.ADMIN_ORDER; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.java new file mode 100644 index 000000000..6d7c5f58d --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.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.context.admin; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties for Polaris Admin. + * + * @author Haotian Zhang + */ +@ConfigurationProperties(prefix = "spring.cloud.polaris.admin") +public class PolarisAdminProperties { + + /** + * Admin host. + */ + private String host = "0.0.0.0"; + + /** + * Admin port. + */ + private int port = 28080; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + @Override + public String toString() { + return "PolarisAdminProperties{" + + "host='" + host + '\'' + + ", port=" + port + + '}'; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java index 139de40fc..30ef485f0 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java @@ -20,12 +20,13 @@ import java.util.List; -import com.tencent.cloud.common.tsf.ConditionalOnTsfEnabled; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ModifyAddress; import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.context.admin.PolarisAdminConfigModifier; +import com.tencent.cloud.polaris.context.admin.PolarisAdminProperties; import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; import com.tencent.cloud.polaris.context.config.extend.tsf.TsfInstanceMetadataProvider; @@ -69,6 +70,18 @@ public PolarisContextApplicationEventListener contextApplicationEventListener(Po return new PolarisContextApplicationEventListener(polarisSDKContextManager); } + @Bean + @ConditionalOnMissingBean + public PolarisAdminProperties polarisAdminProperties() { + return new PolarisAdminProperties(); + } + + @Bean + @ConditionalOnMissingBean + public PolarisAdminConfigModifier polarisAdminConfigModifier(PolarisAdminProperties polarisAdminProperties) { + return new PolarisAdminConfigModifier(polarisAdminProperties); + } + @Bean @ConditionalOnMissingBean public ConsulProperties consulProperties() { @@ -82,7 +95,6 @@ public TsfCoreProperties tsfCoreProperties() { } @Bean - @ConditionalOnTsfEnabled @ConditionalOnMissingBean public TsfInstanceMetadataProvider tsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) { return new TsfInstanceMetadataProvider(tsfCoreProperties); diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java new file mode 100644 index 000000000..84830f9d2 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java @@ -0,0 +1,102 @@ +/* + * 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.config; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +/** + * Read Polaris env. + * + * @author Haotian Zhang + */ +public final class PolarisContextEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { + + public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 10 - 2; + + private final Logger LOGGER = LoggerFactory.getLogger(PolarisContextEnvironmentPostProcessor.class); + + private PolarisContextEnvironmentPostProcessor() { + + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + Map polarisEnvProperties = new HashMap<>(); + + // polaris_address + String polarisAddress = environment.getProperty("polaris_address"); + if (StringUtils.isNotBlank(polarisAddress)) { + polarisEnvProperties.put("spring.cloud.polaris.address", polarisAddress); + } + + // polaris_address + String polarisNamespace = environment.getProperty("polaris_namespace"); + if (StringUtils.isNotBlank(polarisNamespace)) { + polarisEnvProperties.put("spring.cloud.polaris.namespace", polarisNamespace); + } + + // polaris_config_address + String polarisConfigAddress = environment.getProperty("polaris_config_address"); + if (StringUtils.isNotBlank(polarisConfigAddress)) { + polarisEnvProperties.put("spring.cloud.polaris.config.address", polarisConfigAddress); + } + + // polaris_admin_port + String polarisAdminPort = environment.getProperty("polaris_admin_port"); + if (StringUtils.isNotBlank(polarisAdminPort)) { + polarisEnvProperties.put("spring.cloud.polaris.admin.port", polarisAdminPort); + } + + // application_version + String applicationVersion = environment.getProperty("tsf_prog_version"); + if (StringUtils.isNotBlank(applicationVersion)) { + polarisEnvProperties.put("spring.cloud.polaris.discovery.version", applicationVersion); + } + + // region + String region = environment.getProperty("tsf_region"); + if (StringUtils.isNotBlank(region)) { + polarisEnvProperties.put("spring.cloud.tencent.metadata.content.region", region); + } + + // zone + String zone = environment.getProperty("tsf_zone"); + if (StringUtils.isNotBlank(zone)) { + polarisEnvProperties.put("spring.cloud.tencent.metadata.content.zone", zone); + } + + MapPropertySource propertySource = new MapPropertySource("polaris-env-properties", polarisEnvProperties); + environment.getPropertySources().addFirst(propertySource); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java index bf681054f..18c55bcb7 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java @@ -53,6 +53,7 @@ public void modify(ConfigurationImpl configuration) { tsfEventReporterConfig.setTsfNamespaceId(tsfCoreProperties.getTsfNamespaceId()); tsfEventReporterConfig.setServiceName(tsfCoreProperties.getServiceName()); tsfEventReporterConfig.setToken(consulProperties.getAclToken()); + tsfEventReporterConfig.setApplicationId(tsfCoreProperties.getTsfApplicationId()); configuration.getGlobal().getEventReporter() .setPluginConfig(DefaultPlugins.TSF_EVENT_REPORTER_TYPE, tsfEventReporterConfig); } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.java new file mode 100644 index 000000000..b940cfd74 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.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.context.config.extend.tsf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.core.env.Environment; + +/** + * Utils for TSF. + * + * @author Haotian Zhang + */ +public final class TsfContextUtils { + + private static final Logger LOG = LoggerFactory.getLogger(TsfContextUtils.class); + + private static final AtomicBoolean isFirstConfiguration = new AtomicBoolean(true); + + private static boolean tsfConsulEnabled = false; + + private TsfContextUtils() { + } + + public static boolean isTsfConsulEnabled(Environment environment) { + if (environment != null && isFirstConfiguration.compareAndSet(true, false)) { + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + String tsePolarisAddress = environment.getProperty("polaris_address"); + if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("spring.cloud.polaris.address"))) { + tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); + } + tsfConsulEnabled = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); + if (tsfConsulEnabled) { + LOG.info("Tsf Consul is enabled: {}", tsfConsulIp); + } + } + return tsfConsulEnabled; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java index 32c51d07d..874c2c90c 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java @@ -57,30 +57,18 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp if (StringUtils.isNotBlank(tsfAppId)) { Map defaultProperties = new HashMap<>(); - String tsfConsulIp = environment.getProperty("tsf_consul_ip"); - String tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); - if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("tse_polaris_ip"))) { - tsePolarisAddress = "grpc://" + environment.getProperty("tse_polaris_ip") + ":8091"; - } - - // tsf_prog_version - String tsfProgVersion = environment.getProperty("tsf_prog_version"); - if (StringUtils.isBlank(tsfProgVersion)) { - LOGGER.error("tsf_prog_version is empty"); - } - else { - defaultProperties.put("spring.cloud.polaris.discovery.version", tsfProgVersion); - } - // lossless - defaultProperties.put("spring.cloud.polaris.lossless.enabled", true); - defaultProperties.put("spring.cloud.polaris.lossless.port", environment.getProperty("tsf_sctt_extensions_port", "11134")); - - // state - defaultProperties.put("spring.cloud.polaris.stat.port", environment.getProperty("tsf_sctt_extensions_port", "11134")); + String polarisAdminPort = environment.getProperty("polaris_admin_port"); + if (StringUtils.isNotBlank(polarisAdminPort)) { + defaultProperties.put("spring.cloud.polaris.lossless.enabled", true); + } - boolean tsfConsulEnable = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); - if (tsfConsulEnable) { + if (TsfContextUtils.isTsfConsulEnabled(environment)) { + // tsf_consul_ip + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + if (StringUtils.isBlank(tsfConsulIp)) { + LOGGER.error("tsf_consul_ip is empty"); + } // tsf_consul_port String tsfConsulPort = environment.getProperty("tsf_consul_port"); if (StringUtils.isBlank(tsfConsulPort)) { @@ -113,9 +101,6 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp if (StringUtils.isBlank(tsfNamespaceId)) { LOGGER.error("tsf_namespace_id is empty"); } - else { - defaultProperties.put("spring.cloud.polaris.namespace", tsfNamespaceId); - } // context defaultProperties.put("spring.cloud.polaris.enabled", "true"); diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java index c60220a9f..39c29baaf 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java @@ -129,6 +129,12 @@ public class TsfCoreProperties { @Value("${tsf_event_master_port:15200}") private Integer eventMasterPort; + @Value("${tsf_ratelimit_master_ip:}") + private String ratelimitMasterIp; + + @Value("${tsf_ratelimit_master_port:7000}") + private Integer ratelimitMasterPort; + public String getAppId() { return appId; } @@ -270,6 +276,22 @@ public void setEventMasterPort(Integer eventMasterPort) { this.eventMasterPort = eventMasterPort; } + public String getRatelimitMasterIp() { + return ratelimitMasterIp; + } + + public void setRatelimitMasterIp(String ratelimitMasterIp) { + this.ratelimitMasterIp = ratelimitMasterIp; + } + + public Integer getRatelimitMasterPort() { + return ratelimitMasterPort; + } + + public void setRatelimitMasterPort(Integer ratelimitMasterPort) { + this.ratelimitMasterPort = ratelimitMasterPort; + } + @Override public String toString() { return "TsfCoreProperties{" + @@ -289,6 +311,8 @@ public String toString() { ", scheme='" + scheme + '\'' + ", eventMasterIp='" + eventMasterIp + '\'' + ", eventMasterPort=" + eventMasterPort + + ", ratelimitMasterIp='" + ratelimitMasterIp + '\'' + + ", ratelimitMasterPort=" + ratelimitMasterPort + '}'; } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java index 340fe393a..e30ade6a1 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java @@ -44,39 +44,46 @@ public TsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) { @Override public Map getMetadata() { - return new HashMap() {{ - put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion()); - put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId()); - put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId()); - put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId()); - put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion()); - put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId()); - put(TsfMetadataConstants.TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId()); - put(TsfMetadataConstants.TSF_INSTNACE_ID, tsfCoreProperties.getInstanceId()); - put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion()); - put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone()); - // 处理预热相关的参数 - put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis())); - put(TsfMetadataConstants.TSF_SDK_VERSION, SdkVersion.get()); - put(TsfMetadataConstants.TSF_TAGS, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags())); - String ipv4Address = PolarisInetUtils.getIpString(false); - if (StringUtils.isNotBlank(ipv4Address)) { - put(TsfMetadataConstants.TSF_ADDRESS_IPV4, ipv4Address); - } - String ipv6Address = PolarisInetUtils.getIpString(true); - if (StringUtils.isNotBlank(ipv6Address)) { - put(TsfMetadataConstants.TSF_ADDRESS_IPV6, ipv6Address); - } - }}; - } + HashMap tsfMetadata = new HashMap<>(); + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfApplicationId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId()); + } - @Override - public String getRegion() { - return tsfCoreProperties.getTsfRegion(); - } + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfProgVersion())) { + tsfMetadata.put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion()); + } - @Override - public String getZone() { - return tsfCoreProperties.getTsfZone(); + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfGroupId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfNamespaceId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getInstanceId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_INSTNACE_ID, tsfCoreProperties.getInstanceId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfRegion())) { + tsfMetadata.put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfZone())) { + tsfMetadata.put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone()); + } + + tsfMetadata.put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis())); + tsfMetadata.put(TsfMetadataConstants.TSF_SDK_VERSION, SdkVersion.get()); + tsfMetadata.put(TsfMetadataConstants.TSF_TAGS, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags())); + String ipv4Address = PolarisInetUtils.getIpString(false); + if (StringUtils.isNotBlank(ipv4Address)) { + tsfMetadata.put(TsfMetadataConstants.TSF_ADDRESS_IPV4, ipv4Address); + } + String ipv6Address = PolarisInetUtils.getIpString(true); + if (StringUtils.isNotBlank(ipv6Address)) { + tsfMetadata.put(TsfMetadataConstants.TSF_ADDRESS_IPV6, ipv6Address); + } + return tsfMetadata; } } diff --git a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories index 913208449..ac093c297 100644 --- a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories @@ -8,4 +8,5 @@ org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.context.ApplicationListener=\ com.tencent.cloud.polaris.context.logging.PolarisLoggingApplicationListener org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tencent.cloud.polaris.context.config.PolarisContextEnvironmentPostProcessor,\ com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreEnvironmentPostProcessor diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java index f26e93869..43c61d3b3 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/ServiceRuleManagerTest.java @@ -35,6 +35,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.when; diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java index 328d7a7e6..e5d05b6a3 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfigurationTest.java @@ -35,7 +35,8 @@ public class PolarisContextAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(UtilAutoConfiguration.class)) - .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class)) + .withConfiguration( + AutoConfigurations.of(PolarisContextAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:8083"); @Test diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java index 039c5c661..235610bd7 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingPathSystemPropertyTest.java @@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisLoggingApplicationListener} + * Test for {@link PolarisLoggingApplicationListener}. * * @author wenxuan70 */ diff --git a/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml b/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml index 3339e6934..de73a15d7 100644 --- a/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml +++ b/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml @@ -8,4 +8,4 @@ spring: enabled: true local-port: 9090 logging: - path: /tmp/polaris/logs \ No newline at end of file + path: /tmp/polaris/logs 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 8156b6c73..bb8f021d2 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 @@ -56,7 +56,7 @@ public ILoadBalancer polarisLoadBalancer(IClientConfig iClientConfig, IRule iRul @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "roundRobin", matchIfMissing = true) + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "roundRobin") public IRule roundRobinRule() { return new RoundRobinRule(); } @@ -77,7 +77,7 @@ public IRule polarisWeightedRandomRule(PolarisSDKContextManager polarisSDKContex @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRoundRobin") + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRoundRobin", matchIfMissing = true) public IRule polarisWeightedRoundRobinRule(PolarisSDKContextManager polarisSDKContextManager) { return new PolarisWeightedRoundRobinRule(polarisSDKContextManager.getRouterAPI()); } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java index 2ad8e5de0..41865379a 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java @@ -33,16 +33,6 @@ public class PolarisStatProperties { */ private boolean enabled = true; - /** - * Local host for prometheus to pull. - */ - private String host; - - /** - * Port for prometheus to pull. 0 for random from 20000 to 65535. - */ - private int port = 0; - /** * Path for prometheus to pull. */ @@ -67,6 +57,12 @@ public class PolarisStatProperties { @Value("${spring.cloud.polaris.stat.pushgateway.push-interval:#{30000}}") private Long pushGatewayPushInterval = 30 * 1000L; + /** + * If push gateway gzip open. default false. + */ + @Value("${spring.cloud.polaris.stat.pushgateway.open-gzip:#{false}}") + private Boolean openGzip = false; + public boolean isEnabled() { return enabled; } @@ -75,22 +71,6 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - public String getPath() { return path; } @@ -122,4 +102,12 @@ public Long getPushGatewayPushInterval() { public void setPushGatewayPushInterval(Long pushGatewayPushInterval) { this.pushGatewayPushInterval = pushGatewayPushInterval; } + + public Boolean getOpenGzip() { + return openGzip; + } + + public void setOpenGzip(Boolean openGzip) { + this.openGzip = openGzip; + } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java index 36c21680b..4ba48aba3 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java @@ -37,7 +37,7 @@ public class PolarisStatPropertiesAutoConfiguration { @Bean @ConditionalOnMissingBean - public StatConfigModifier statReporterConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) { - return new StatConfigModifier(polarisStatProperties, environment); + public StatConfigModifier statReporterConfigModifier(PolarisStatProperties polarisStatProperties) { + return new StatConfigModifier(polarisStatProperties); } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java index 0a8ff8f15..6d166fd6a 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java @@ -20,11 +20,9 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.global.StatReporterConfigImpl; import com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandlerConfig; -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - import static com.tencent.polaris.api.config.global.StatReporterConfig.DEFAULT_REPORTER_PROMETHEUS; /** @@ -36,43 +34,31 @@ public class StatConfigModifier implements PolarisConfigModifier { private final PolarisStatProperties polarisStatProperties; - private final Environment environment; - - public StatConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) { + public StatConfigModifier(PolarisStatProperties polarisStatProperties) { this.polarisStatProperties = polarisStatProperties; - this.environment = environment; } @Override public void modify(ConfigurationImpl configuration) { // Turn on stat reporter configuration. configuration.getGlobal().getStatReporter().setEnable(polarisStatProperties.isEnabled()); - PrometheusHandlerConfig prometheusHandlerConfig = configuration.getGlobal().getStatReporter() - .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); + StatReporterConfigImpl statReporterConfig = configuration.getGlobal().getStatReporter(); + statReporterConfig.setEnable(polarisStatProperties.isEnabled()); + PrometheusHandlerConfig prometheusHandlerConfig = statReporterConfig.getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); // Set prometheus plugin. if (polarisStatProperties.isEnabled()) { - if (polarisStatProperties.isPushGatewayEnabled()) { // push gateway prometheusHandlerConfig.setType("push"); prometheusHandlerConfig.setAddress(polarisStatProperties.getPushGatewayAddress()); prometheusHandlerConfig.setPushInterval(polarisStatProperties.getPushGatewayPushInterval()); + prometheusHandlerConfig.setOpenGzip(polarisStatProperties.getOpenGzip()); } else { // pull metrics prometheusHandlerConfig.setType("pull"); - if (!StringUtils.hasText(polarisStatProperties.getHost())) { - polarisStatProperties.setHost("0.0.0.0"); - } - prometheusHandlerConfig.setHost(polarisStatProperties.getHost()); - prometheusHandlerConfig.setPort(polarisStatProperties.getPort()); prometheusHandlerConfig.setPath(polarisStatProperties.getPath()); } - - } - else { - // Set port to -1 to disable stat plugin. - prometheusHandlerConfig.setPort(-1); } configuration.getGlobal().getStatReporter() .setPluginConfig(DEFAULT_REPORTER_PROMETHEUS, prometheusHandlerConfig); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json index a2a449b33..7c6745ba8 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -57,20 +57,28 @@ "name": "spring.cloud.polaris.stat.pushgateway.address", "type": "java.lang.String", "description": "PushGateway address.", - "sourceType": "com.tencent.cloud.plugin.pushgateway.PolarisStatPushGatewayProperties" + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties" }, { "name": "spring.cloud.polaris.stat.pushgateway.enabled", "type": "java.lang.Boolean", "description": "If state pushGateway reporter enabled.", - "sourceType": "com.tencent.cloud.plugin.pushgateway.PolarisStatPushGatewayProperties", + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties", "defaultValue": false }, { "name": "spring.cloud.polaris.stat.pushgateway.push-interval", "type": "java.lang.Long", "description": "Push metrics interval. unit: milliseconds default 30s.", - "sourceType": "com.tencent.cloud.plugin.pushgateway.PolarisStatPushGatewayProperties" + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties", + "defaultValue": 30000 + }, + { + "name": "spring.cloud.polaris.stat.pushgateway.open-gzip", + "type": "java.lang.Boolean", + "description": "If push gateway gzip open. default false.", + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties", + "defaultValue": false } ] } diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java index 86c0c74a7..2244b10ab 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java @@ -35,8 +35,6 @@ public class PolarisStatPropertiesTest { .withConfiguration(AutoConfigurations.of(PolarisStatPropertiesAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.stat.enabled=true") - .withPropertyValues("spring.cloud.polaris.stat.host=127.0.0.1") - .withPropertyValues("spring.cloud.polaris.stat.port=20000") .withPropertyValues("spring.cloud.polaris.stat.path=/xxx") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.enabled=true") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.address=127.0.0.1:9091") @@ -50,8 +48,6 @@ public void testDefaultInitialization() { assertThat(polarisStatProperties).isNotNull(); assertThat(polarisStatProperties.isEnabled()).isTrue(); - assertThat(polarisStatProperties.getHost()).isNotBlank(); - assertThat(polarisStatProperties.getPort()).isEqualTo(20000); assertThat(polarisStatProperties.getPath()).isEqualTo("/xxx"); assertThat(polarisStatProperties.isPushGatewayEnabled()).isTrue(); assertThat(polarisStatProperties.getPushGatewayAddress()).isEqualTo("127.0.0.1:9091"); diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java index 52c125ebf..032127157 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java @@ -18,6 +18,7 @@ package com.tencent.cloud.rpc.enhancement.stat.config; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.config.global.StatReporterConfig; import com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandlerConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,6 +54,7 @@ public class StatConfigModifierTest { .withPropertyValues("spring.cloud.polaris.stat.pushgateway.enabled=true") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.address=127.0.0.1:9091") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.push-interval=1000") + .withPropertyValues("spring.cloud.polaris.stat.pushgateway.open-gzip=true") .withPropertyValues("spring.application.name=test") .withPropertyValues("spring.cloud.gateway.enabled=false"); @@ -76,8 +78,6 @@ void testPull() { .getGlobal().getStatReporter() .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); assertThat(prometheusHandlerConfig.getType()).isEqualTo("pull"); - assertThat(prometheusHandlerConfig.getHost()).isEqualTo("127.0.0.1"); - assertThat(prometheusHandlerConfig.getPort()).isEqualTo(20000); assertThat(prometheusHandlerConfig.getPath()).isEqualTo("/xxx"); }); } @@ -92,6 +92,7 @@ void testPush() { assertThat(prometheusHandlerConfig.getType()).isEqualTo("push"); assertThat(prometheusHandlerConfig.getAddress()).isEqualTo("127.0.0.1:9091"); assertThat(prometheusHandlerConfig.getPushInterval()).isEqualTo(1000); + assertThat(prometheusHandlerConfig.isOpenGzip()).isTrue(); }); } @@ -99,10 +100,9 @@ void testPush() { void testDisabled() { disabledContextRunner.run(context -> { PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); - PrometheusHandlerConfig prometheusHandlerConfig = polarisSDKContextManager.getSDKContext().getConfig() - .getGlobal().getStatReporter() - .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); - assertThat(prometheusHandlerConfig.getPort()).isEqualTo(-1); + StatReporterConfig statReporterConfig = polarisSDKContextManager.getSDKContext().getConfig() + .getGlobal().getStatReporter(); + assertThat(statReporterConfig.isEnable()).isFalse(); }); } From aa11401883ce346b6816915cab2bb89f72d6485c Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Thu, 7 Nov 2024 19:42:08 +0800 Subject: [PATCH 13/19] fix --- pom.xml | 8 +- ...odeTransferMetadataReactiveFilterTest.java | 3 +- ...RouterConfigModifierAutoConfiguration.java | 4 +- .../PolarisNearByRouterProperties.java | 2 - .../RouterBootstrapAutoConfiguration.java | 36 ---- ...RouterConfigModifierAutoConfiguration.java | 46 ----- ...itional-spring-configuration-metadata.json | 6 - .../main/resources/META-INF/spring.factories | 2 +- .../RouterBootstrapAutoConfigurationTest.java | 2 +- .../transformer/NacosInstanceTransformer.java | 27 +-- .../config/NacosInstanceTransformerTest.java | 21 +- .../SpringCloudLosslessActionProvider.java | 95 --------- .../lossless/LosslessConfigModifierTest.java | 91 --------- .../lossless/LosslessRegistryAspectTest.java | 191 ------------------ .../AutoServiceRegistrationUtils.java | 29 --- 15 files changed, 29 insertions(+), 534 deletions(-) delete mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java delete mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java delete mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java delete mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java delete mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java delete mode 100644 spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java diff --git a/pom.xml b/pom.xml index 070e126a8..603886b54 100644 --- a/pom.xml +++ b/pom.xml @@ -171,10 +171,10 @@ - - org.apache.maven.plugins - maven-checkstyle-plugin - + + + + org.apache.maven.plugins maven-compiler-plugin diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java index ff27c0c4d..bbee696c9 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java @@ -20,7 +20,6 @@ import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -55,7 +54,7 @@ public class DecodeTransferMetadataReactiveFilterTest { @BeforeEach public void setUp() { - this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(new PolarisContextProperties()); + this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(); } @Test diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java index e1de4a37f..c3669ab80 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java @@ -20,6 +20,7 @@ import com.tencent.cloud.polaris.router.RouterConfigModifier; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNamespaceRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; @@ -35,7 +36,8 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisRouterEnabled -@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class}) +@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class, + PolarisNamespaceRouterProperties.class}) public class RouterConfigModifierAutoConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java index ac3e6f27b..226195a13 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java @@ -31,8 +31,6 @@ public class PolarisNearByRouterProperties { private String matchLevel; - private String matchLevel; - public boolean isEnabled() { return enabled; } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java deleted file mode 100644 index 3b3934caa..000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterBootstrapAutoConfiguration.java +++ /dev/null @@ -1,36 +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.polaris.router.config.properties; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * RouterBootstrapAutoConfiguration. - * - * @author sean yu - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnProperty("spring.cloud.polaris.enabled") -@Import(RouterConfigModifierAutoConfiguration.class) -public class RouterBootstrapAutoConfiguration { - - -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java deleted file mode 100644 index 354b237b2..000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/RouterConfigModifierAutoConfiguration.java +++ /dev/null @@ -1,46 +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.polaris.router.config.properties; - -import com.tencent.cloud.polaris.router.RouterConfigModifier; -import com.tencent.cloud.polaris.router.config.ConditionalOnPolarisRouterEnabled; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * RouterConfigModifierAutoConfiguration. - * - * @author sean yu - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnPolarisRouterEnabled -@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class, - PolarisNamespaceRouterProperties.class}) -public class RouterConfigModifierAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - public RouterConfigModifier routerConfigModifier(PolarisNearByRouterProperties polarisNearByRouterProperties) { - return new RouterConfigModifier(polarisNearByRouterProperties); - } - -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json index b3ee9a2d1..92251c916 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -18,12 +18,6 @@ "defaultValue": "ZONE", "description": "the match level for nearby router, options can be REGION/ZONE/CAMPUS." }, - { - "name": "spring.cloud.polaris.router.nearby-router.matchLevel", - "type": "java.lang.String", - "defaultValue": "zone", - "description": "the match level for nearby router, options can be region/zone/campus." - }, { "name": "spring.cloud.polaris.router.rule-router.enabled", "type": "java.lang.Boolean", diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories index 5170ed04b..c350e3ff9 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories @@ -1,5 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.tencent.cloud.polaris.router.config.properties.RouterConfigModifierAutoConfiguration,\ + com.tencent.cloud.polaris.router.config.RouterConfigModifierAutoConfiguration,\ com.tencent.cloud.polaris.router.config.RouterAutoConfiguration,\ com.tencent.cloud.polaris.router.config.FeignAutoConfiguration,\ com.tencent.cloud.polaris.router.endpoint.PolarisRouterEndpointAutoConfiguration diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java index f10d9ada4..6d3323a56 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java @@ -61,7 +61,7 @@ public void testDefaultInitialization() { routerConfigModifier.modify((ConfigurationImpl) configuration); NearbyRouterConfig nearbyRouterConfig = configuration.getConsumer().getServiceRouter().getPluginConfig( ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, NearbyRouterConfig.class); - Assertions.assertEquals("campus", nearbyRouterConfig.getMatchLevel().name()); + Assertions.assertEquals("CAMPUS", nearbyRouterConfig.getMatchLevel().name()); }); } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java index dbcc1c8bc..db1047296 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java @@ -18,11 +18,10 @@ package com.tencent.cloud.plugin.discovery.adapter.transformer; -import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; +import com.alibaba.cloud.nacos.ribbon.NacosServer; +import com.netflix.loadbalancer.Server; +import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; import com.tencent.polaris.api.pojo.DefaultInstance; -import org.apache.commons.lang.StringUtils; - -import org.springframework.cloud.client.ServiceInstance; /** * NacosInstanceTransformer. @@ -32,20 +31,12 @@ public class NacosInstanceTransformer implements InstanceTransformer { @Override - public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) { - if ("com.alibaba.cloud.nacos.NacosServiceInstance".equals(serviceInstance.getClass().getName())) { - String nacosWeight = serviceInstance.getMetadata().get("nacos.weight"); - instance.setWeight( - StringUtils.isBlank(nacosWeight) ? 100 : (int) Double.parseDouble(nacosWeight) * 100 - ); - String nacosHealthy = serviceInstance.getMetadata().get("nacos.healthy"); - instance.setHealthy( - !StringUtils.isBlank(nacosHealthy) && Boolean.parseBoolean(nacosHealthy) - ); - String nacosInstanceId = serviceInstance.getMetadata().get("nacos.instanceId"); - instance.setId(nacosInstanceId); - + public void transformCustom(DefaultInstance instance, Server server) { + if ("com.alibaba.cloud.nacos.ribbon.NacosServer".equals(server.getClass().getName())) { + NacosServer nacosServer = (NacosServer) server; + instance.setWeight((int) (nacosServer.getInstance().getWeight() * 100)); + instance.setHealthy(nacosServer.getInstance().isHealthy()); + instance.setMetadata(nacosServer.getMetadata()); } } - } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java index 8320d6d90..00dd8be77 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java @@ -18,12 +18,10 @@ package com.tencent.cloud.plugin.discovery.adapter.config; -import java.util.HashMap; - -import com.alibaba.cloud.nacos.NacosServiceInstance; +import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; -import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.pojo.DefaultInstance; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -53,13 +51,14 @@ public static void beforeAll() { @Test public void test() { NacosInstanceTransformer nacosInstanceTransformer = new NacosInstanceTransformer(); - NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); - nacosServiceInstance.setMetadata(new HashMap() {{ - put("nacos.weight", "0.01"); - put("nacos.healthy", "true"); - put("nacos.instanceId", "xxx"); - }}); - Instance instance = nacosInstanceTransformer.transform(nacosServiceInstance); + + com.alibaba.nacos.api.naming.pojo.Instance nacosInstance = new com.alibaba.nacos.api.naming.pojo.Instance(); + nacosInstance.setHealthy(true); + NacosServer nacosServer = new NacosServer(nacosInstance); + + + DefaultInstance instance = new DefaultInstance(); + nacosInstanceTransformer.transformCustom(instance, nacosServer); assertThat(instance.isHealthy()).isEqualTo(true); } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java deleted file mode 100644 index a97df5960..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.plugin.lossless; - -import java.util.HashMap; -import java.util.Map; - -import com.tencent.cloud.common.util.OkHttpUtil; -import com.tencent.cloud.plugin.lossless.config.LosslessProperties; -import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; -import com.tencent.polaris.api.plugin.lossless.InstanceProperties; -import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider; -import com.tencent.polaris.api.pojo.BaseInstance; -import com.tencent.polaris.api.utils.StringUtils; - -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.http.HttpHeaders; - -/** - * LosslessActionProvider for Spring Cloud. - * - * @author Shedfree Wu - */ -public class SpringCloudLosslessActionProvider implements LosslessActionProvider { - private ServiceRegistry serviceRegistry; - - private LosslessProperties losslessProperties; - - private Runnable originalRegisterAction; - - private Registration registration; - - public SpringCloudLosslessActionProvider(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, Runnable originalRegisterAction) { - this.serviceRegistry = serviceRegistry; - this.registration = registration; - this.losslessProperties = losslessProperties; - this.originalRegisterAction = originalRegisterAction; - } - - @Override - public String getName() { - return "spring-cloud"; - } - - @Override - public void doRegister(InstanceProperties instanceProperties) { - // use lambda to do original register - originalRegisterAction.run(); - } - - @Override - public void doDeregister() { - serviceRegistry.deregister(registration); - } - - /** - * Check whether health check is enable. - * @return true: register after passing doHealthCheck, false: register after delayRegisterInterval. - */ - @Override - public boolean isEnableHealthCheck() { - return StringUtils.isNotBlank(losslessProperties.getHealthCheckPath()); - } - - @Override - public boolean doHealthCheck() { - Map headers = new HashMap<>(1); - headers.put(HttpHeaders.USER_AGENT, "polaris"); - - return OkHttpUtil.checkUrl("localhost", registration.getPort(), - losslessProperties.getHealthCheckPath(), headers); - } - - public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { - return registrationTransformer.transform(registration); - } - -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java deleted file mode 100644 index 0b0d847ff..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.plugin.lossless; - -import com.tencent.cloud.plugin.lossless.config.LosslessConfigModifier; -import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.polaris.api.config.provider.LosslessConfig; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test for {@link LosslessConfigModifier}. - * - * @author Shedfree Wu - */ -public class LosslessConfigModifierTest { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(TestApplication.class)) - .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") - .withPropertyValues("spring.cloud.polaris.enabled=true") - .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") - .withPropertyValues("spring.cloud.polaris.lossless.port=20000") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") - .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=10") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=5") - .withPropertyValues("spring.application.name=test") - .withPropertyValues("spring.cloud.gateway.enabled=false"); - private final ApplicationContextRunner disabledContextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(TestApplication.class)) - .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") - .withPropertyValues("spring.cloud.polaris.enabled=true") - .withPropertyValues("spring.cloud.polaris.lossless.enabled=false") - .withPropertyValues("spring.application.name=test") - .withPropertyValues("spring.cloud.gateway.enabled=false"); - - @BeforeEach - void setUp() { - PolarisSDKContextManager.innerDestroy(); - } - - @Test - void testModify() { - contextRunner.run(context -> { - PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); - LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). - getConfig().getProvider().getLossless(); - assertThat(losslessConfig.getHost()).isEqualTo("0.0.0.0"); - assertThat(losslessConfig.getPort()).isEqualTo(20000); - assertThat(losslessConfig.getDelayRegisterInterval()).isEqualTo(10); - assertThat(losslessConfig.getHealthCheckInterval()).isEqualTo(5); - }); - } - - - @Test - void testDisabled() { - disabledContextRunner.run(context -> { - PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); - LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). - getConfig().getProvider().getLossless(); - assertThat(losslessConfig.isEnable()).isFalse(); - }); - } - - @SpringBootApplication - protected static class TestApplication { - - } -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java deleted file mode 100644 index 687041540..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.plugin.lossless; - -import java.util.Collections; - -import com.tencent.cloud.common.util.OkHttpUtil; -import com.tencent.cloud.plugin.lossless.config.LosslessAutoConfiguration; -import com.tencent.cloud.plugin.lossless.config.LosslessPropertiesBootstrapConfiguration; -import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; -import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration; -import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration; -import com.tencent.cloud.polaris.registry.PolarisRegistration; -import com.tencent.cloud.polaris.registry.PolarisServiceRegistry; -import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.test.mock.discovery.NamingServer; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.test.context.runner.WebApplicationContextRunner; -import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; -import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationUtils; -import org.springframework.context.annotation.Configuration; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -/** - * Test for {@link LosslessRegistryAspect}. - * - * @author Shedfree Wu - */ -public class LosslessRegistryAspectTest { - - private static String NAMESPACE_TEST = "Test"; - - private static String SERVICE_PROVIDER = "java_provider_test"; - - private static String HOST = "127.0.0.1"; - - private static int APPLICATION_PORT = 19091; - - private static int LOSSLESS_PORT_1 = 28083; - - private static NamingServer namingServer; - - private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - LosslessAutoConfiguration.class, - LosslessPropertiesBootstrapConfiguration.class, - PolarisContextAutoConfiguration.class, - PolarisPropertiesConfiguration.class, - PolarisDiscoveryClientConfiguration.class, - PolarisDiscoveryAutoConfiguration.class)) - .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") - .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") - .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) - .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) - .withPropertyValues("server.port=" + APPLICATION_PORT) - .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) - .withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT) - .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") - .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) - .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); - - private final WebApplicationContextRunner contextRunner2 = new WebApplicationContextRunner() - .withConfiguration(AutoConfigurations.of( - LosslessAutoConfiguration.class, - LosslessPropertiesBootstrapConfiguration.class, - PolarisContextAutoConfiguration.class, - PolarisPropertiesConfiguration.class, - PolarisDiscoveryClientConfiguration.class, - PolarisDiscoveryAutoConfiguration.class)) - .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=1000") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/test") - .withPropertyValues("spring.cloud.polaris.lossless.port=28082") - .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) - .withPropertyValues("server.port=" + APPLICATION_PORT) - .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) - .withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT) - .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") - .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) - .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); - - @BeforeAll - static void beforeAll() throws Exception { - namingServer = NamingServer.startNamingServer(10081); - - // add service - namingServer.getNamingService().addService(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER)); - } - - @AfterAll - static void afterAll() { - if (null != namingServer) { - namingServer.terminate(); - } - } - - @BeforeEach - void setUp() { - PolarisSDKContextManager.innerDestroy(); - } - - @Test - public void testRegister() { - this.contextRunner.run(context -> { - - AbstractAutoServiceRegistration autoServiceRegistration = context.getBean(AbstractAutoServiceRegistration.class); - - assertThatCode(() -> { - AutoServiceRegistrationUtils.register(autoServiceRegistration); - }).doesNotThrowAnyException(); - Thread.sleep(1000); - // before register online status is false - assertThatCode(() -> { - assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isFalse(); - }).doesNotThrowAnyException(); - // delay register after 5s - Thread.sleep(10000); - PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); - PolarisRegistration registration = context.getBean(PolarisRegistration.class); - - assertThatCode(() -> { - assertThat(registry.getStatus(registration)).isEqualTo("DOWN"); - }).doesNotThrowAnyException(); - - assertThatCode(() -> { - assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isTrue(); - }).doesNotThrowAnyException(); - - assertThatCode(() -> { - assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/offline", Collections.EMPTY_MAP)).isTrue(); - }).doesNotThrowAnyException(); - - assertThatCode(() -> { - AutoServiceRegistrationUtils.deRegister(autoServiceRegistration); - }).doesNotThrowAnyException(); - - assertThatCode(() -> { - assertThat(registry.getStatus(registration)).isEqualTo("DOWN"); - }).doesNotThrowAnyException(); - }); - } - - @Test - public void testRegister2() { - this.contextRunner2.run(context -> { - - AbstractAutoServiceRegistration autoServiceRegistration = context.getBean(AbstractAutoServiceRegistration.class); - - assertThatCode(() -> { - AutoServiceRegistrationUtils.register(autoServiceRegistration); - }).doesNotThrowAnyException(); - - Thread.sleep(2000); - - assertThatCode(() -> { - AutoServiceRegistrationUtils.deRegister(autoServiceRegistration); - }).doesNotThrowAnyException(); - }); - } - - @Configuration - @EnableAutoConfiguration - static class PolarisPropertiesConfiguration { - - } -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java deleted file mode 100644 index 1c8e09f91..000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java +++ /dev/null @@ -1,29 +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 org.springframework.cloud.client.serviceregistry; - -public class AutoServiceRegistrationUtils { - - public static void register(AbstractAutoServiceRegistration autoServiceRegistration) { - autoServiceRegistration.register(); - } - - public static void deRegister(AbstractAutoServiceRegistration autoServiceRegistration) { - autoServiceRegistration.deregister(); - } -} From 0ec5e0249e51bfec47008853fedc00552e69ac58 Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Thu, 7 Nov 2024 20:25:56 +0800 Subject: [PATCH 14/19] add changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 864bc5f5e..6b3e01593 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,4 +24,5 @@ - fix:fix NullPointerException when properties contain kv with null value. - [fix: memory not released while using wildcard api call with circuitbreaker](https://github.com/Tencent/spring-cloud-tencent/pull/1361) - [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1392) -- [fix: fix npe when feign.hystrix.enabled=false](https://github.com/Tencent/spring-cloud-tencent/pull/1436) \ No newline at end of file +- [fix: fix npe when feign.hystrix.enabled=false](https://github.com/Tencent/spring-cloud-tencent/pull/1436) +- [feat: support 2.0.0](https://github.com/Tencent/spring-cloud-tencent/pull/1458) \ No newline at end of file From 4fc0bb991bdb143590392bcff93288a7acd8943a Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Thu, 7 Nov 2024 20:32:04 +0800 Subject: [PATCH 15/19] fix --- .../polaris/router/MockApplicationContext.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java index 5d771e012..f9405886b 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java @@ -1,3 +1,21 @@ +/* + * 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.io.IOException; From c74d90e8861f4542f1127daab48cfa0eab5b4dd9 Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Fri, 8 Nov 2024 10:23:11 +0800 Subject: [PATCH 16/19] fix changelog --- CHANGELOG.md | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b3e01593..6f8a4057d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,28 +1,19 @@ # Change Log --- -- [feat: fix the logging problem open at #1189](https://github.com/Tencent/spring-cloud-tencent/pull/1197) -- [fix:the polaris config relation non-daemon thread should stop when application fails to start.](https://github.com/Tencent/spring-cloud-tencent/pull/1110) -- [Refactoring:remove invalid @AutoConfigureAfter and @AutoConfigureBefore from discovery client automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1118) -- [fix:fix feign url bug when using sleuth.](https://github.com/Tencent/spring-cloud-tencent/pull/1119) -- [refactor:optimize the order and condition matching of service registration automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1133) -- [feat:support service contract reporting.](https://github.com/Tencent/spring-cloud-tencent/pull/1135) -- [feat: support log path configuration parameters.](https://github.com/Tencent/spring-cloud-tencent/pull/1143) -- [feat:add swagger exposure filters.](https://github.com/Tencent/spring-cloud-tencent/pull/1144) -- [feat:add swagger report switch.](https://github.com/Tencent/spring-cloud-tencent/pull/1147) -- [fix: dynamic routing using cookies.](https://github.com/Tencent/spring-cloud-tencent/pull/1152) -- [fix:fix retry loadbalancer not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1157) -- [fix:fix header validation when using Chinese char.](https://github.com/Tencent/spring-cloud-tencent/pull/1167) -- [feat: add circuit breaker actuator.](https://github.com/Tencent/spring-cloud-tencent/pull/1172) -- [feat: add metadata transfer for http header via spring.cloud.tencent.metadata.headers.](https://github.com/Tencent/spring-cloud-tencent/pull/1174) -- [fix:remove bcprov-jdk15on dependency.](https://github.com/Tencent/spring-cloud-tencent/pull/1178) -- [feat:support configuration encryption.](https://github.com/Tencent/spring-cloud-tencent/pull/1182) -- [feat:optimize examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1186) -- [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1191) -- [fix:fix sct-all wrong spring boot version obtain.](https://github.com/Tencent/spring-cloud-tencent/pull/1204) -- fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. -- fix:fix NullPointerException when properties contain kv with null value. -- [fix: memory not released while using wildcard api call with circuitbreaker](https://github.com/Tencent/spring-cloud-tencent/pull/1361) -- [fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis](https://github.com/Tencent/spring-cloud-tencent/pull/1392) -- [fix: fix npe when feign.hystrix.enabled=false](https://github.com/Tencent/spring-cloud-tencent/pull/1436) +- [feat: support lossless register and deregister at #977](https://github.com/Tencent/spring-cloud-tencent/pull/1242) +- [feat: PolarisServiceRegistry#deregister support idempotency.](https://github.com/Tencent/spring-cloud-tencent/pull/1243) +- [feat: SCT元数据管理能力与polaris-java元数据管理能力进行下沉及整合](https://github.com/Tencent/spring-cloud-tencent/pull/1249) +- [feat: support lane router](https://github.com/Tencent/spring-cloud-tencent/pull/1250) +- [feat: lane router rule support caller ip](https://github.com/Tencent/spring-cloud-tencent/pull/1253) +- [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255) +- [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257) +- [fix:fix wrong report when using Zuul with instance not found exception.](https://github.com/Tencent/spring-cloud-tencent/pull/1283) +- [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288) +- [fix: fix npe when add circuitbreak module without feign.hystrix.enable=true](https://github.com/Tencent/spring-cloud-tencent/pull/1292) +- [fix:fix ApplicationContextAwareUtils NPE bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1295) +- [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) +- [feat:upgrade jacoco version.](https://github.com/Tencent/spring-cloud-tencent/pull/1306) +- [fix:fix no registry when lossless is disabled.](https://github.com/Tencent/spring-cloud-tencent/pull/1313) +- [fix: memory not released while using wildcard api call with circuitbreaker enabled](https://github.com/Tencent/spring-cloud-tencent/pull/1335) - [feat: support 2.0.0](https://github.com/Tencent/spring-cloud-tencent/pull/1458) \ No newline at end of file From 97fb657dfab98d47f928fa962b20d4b81df2dfcd Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Mon, 18 Nov 2024 22:17:41 +0800 Subject: [PATCH 17/19] fix --- pom.xml | 8 ++++---- .../router/config/FeignLoadBalancerConfiguration.java | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 603886b54..070e126a8 100644 --- a/pom.xml +++ b/pom.xml @@ -171,10 +171,10 @@ - - - - + + org.apache.maven.plugins + maven-checkstyle-plugin + org.apache.maven.plugins maven-compiler-plugin diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java index 17222e23c..9e783a217 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java @@ -23,6 +23,7 @@ import com.tencent.cloud.polaris.router.feign.PolarisFeignLoadBalancer; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.context.annotation.Bean; @@ -40,6 +41,7 @@ public class FeignLoadBalancerConfiguration { @Bean + @ConditionalOnMissingClass("com.netflix.zuul.http.ZuulServlet") @ConditionalOnMissingBean public PolarisFeignLoadBalancer polarisFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) { From aee15cab9911b311baccd5596f4c094e82247fa8 Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Mon, 18 Nov 2024 22:45:22 +0800 Subject: [PATCH 18/19] fix checkstyle --- .../MetadataTransferAutoConfiguration.java | 2 -- .../DecodeTransferMetadataReactiveFilter.java | 1 - .../DecodeTransferMetadataServletFilter.java | 1 - ...ignIntegrationDisableFeignHystrixTest.java | 2 +- ...risCircuitBreakerFeignIntegrationTest.java | 20 ------------------- .../PolarisConfigPropertyAutoRefresher.java | 1 + ...arisAdaptorTsfConfigAutoConfiguration.java | 1 + .../PolarisAdaptorTsfConfigController.java | 1 + .../config/tsf/encrypt/EncryptConfig.java | 1 + .../extend/consul/ConsulDiscoveryUtil.java | 7 +++++++ .../config/RouterAutoConfiguration.java | 1 - .../feign/PolarisFeignLoadBalancer.java | 1 - .../router/MockApplicationContext.java | 2 +- .../RouterContextFactoryTest.java | 2 +- .../tencent/cloud/common/util/GzipUtil.java | 4 +++- .../context/PolarisSDKContextManager.java | 2 ++ ...olarisContextEnvironmentPostProcessor.java | 7 +++++-- .../tsf/TsfCoreEnvironmentPostProcessor.java | 7 ++++--- ...olarisStatPropertiesAutoConfiguration.java | 1 - 19 files changed, 28 insertions(+), 36 deletions(-) diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index 0dd6313da..5ea82792a 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -18,7 +18,6 @@ package com.tencent.cloud.metadata.config; -import com.netflix.zuul.ZuulFilter; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter; @@ -27,7 +26,6 @@ import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulEnhancedPlugin; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 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 85cf40e0f..f462f67fe 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -27,7 +27,6 @@ import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 bd31a3f4e..bea520eb1 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -32,7 +32,6 @@ import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.metadata.provider.ServletMetadataProvider; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java index 689eed2e4..23a6c9342 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java @@ -36,7 +36,7 @@ @SpringBootTest(webEnvironment = RANDOM_PORT, classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class, properties = { - "feign.hystrix.enabled=false", + "feign.hystrix.enabled=false", "spring.cloud.gateway.enabled=false", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index a38fec459..999ec16fd 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -19,51 +19,32 @@ import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; import java.util.stream.Collectors; import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; -import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; -import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; -import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; -import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; -import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; import com.tencent.polaris.client.util.Utils; -import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; -import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; -import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.cloud.openfeign.PolarisFeignCircuitBreakerTargeter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -72,7 +53,6 @@ import org.springframework.web.bind.annotation.RequestParam; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java index dc6989066..1d983c1b3 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java @@ -158,6 +158,7 @@ private void customRegisterPolarisConfigPublishChangeListener(PolarisPropertySou /** * Just for junit test. + * @param registered if the polaris config property auto refresh is registered */ public void setRegistered(boolean registered) { this.registered.set(registered); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java index 6270836ca..4a1507a62 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java @@ -48,6 +48,7 @@ public TsfConsulConfigRefreshEventListener polarisAdaptorTsfConsulRefreshEventLi * 1、关闭Spring Cloud Consul Config配置开关(如果开启Consul Config配置开关,那么初始化的是tsf自身的类ConfigController) * 2、开启北极星配置(本类通过注解@ConditionalOnPolarisConfigEnabled开启) * 3、tsf.config.instance.released-config.lookup.enabled的开关是打开的(默认不配置就是打开的). + * @return polarisAdaptorTsfConfigController */ @Bean @ConditionalOnMissingBean diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java index bf9a044a2..0c4760c0c 100755 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java @@ -53,6 +53,7 @@ public PolarisAdaptorTsfConfigController() { /** * 兼容目前TSF控制台的用法,提供北极星查询当前SDK配置接口. + * @return config map */ @RequestMapping("/tsf/innerApi/config/findAllConfig") public Map findAllConfig() { diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java index 125fb46a9..9cd08140f 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java @@ -56,6 +56,7 @@ private EncryptConfig() { /** * 是否开启配置,判断 password 是否为空. + * @return true:开启;false:关闭 */ public static Boolean getEnabled() { return !StringUtils.isEmpty(password); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java index f7b1bee92..27f07d95a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java @@ -157,6 +157,10 @@ public static NewService.Check createCheck(Integer port, ConsulHeartbeatProperti } /** + * + * @param autoServiceRegistrationProperties auto service registration properties + * @param properties consul discovery properties + * @param context application context * @return if the management service should be registered with the {@link ServiceRegistry} */ public static boolean shouldRegisterManagement(AutoServiceRegistrationProperties autoServiceRegistrationProperties, @@ -167,6 +171,9 @@ && getManagementPort(properties, context) != null } /** + * + * @param properties consul discovery properties + * @param context application context * @return the port of the Management Service */ public static Integer getManagementPort(ConsulDiscoveryProperties properties, ApplicationContext context) { 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 60a4e3f51..69238fbf7 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 @@ -49,7 +49,6 @@ import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.netflix.ribbon.RibbonClients; 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 b40792170..731390810 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 @@ -37,7 +37,6 @@ import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer; -import org.springframework.util.CollectionUtils; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java index f9405886b..7c835c8a6 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java @@ -39,7 +39,7 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; -public class MockApplicationContext implements org.springframework.context.ApplicationContext{ +public class MockApplicationContext implements org.springframework.context.ApplicationContext { @Override public String getId() { return null; diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java index 37da92570..4fc3808d9 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java @@ -51,7 +51,7 @@ import static org.mockito.Mockito.when; /** - * Test for {@link RouterContextFactory} + * Test for {@link RouterContextFactory}. * * @author lepdou 2022-10-09 */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java index 89b1d37f3..a8631d112 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java @@ -61,7 +61,9 @@ public static String compressBase64Encode(byte[] byteData, String charsetName) t public static byte[] decompress(byte[] zipData) throws IOException { - try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData); GZIPInputStream gzip = new GZIPInputStream(bis); ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData); + GZIPInputStream gzip = new GZIPInputStream(bis); + ByteArrayOutputStream bos = new ByteArrayOutputStream()) { byte[] buf = new byte[256]; int num; while ((num = gzip.read(buf)) != -1) { diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java index 26fe59e6b..8138aeb5c 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java @@ -137,6 +137,7 @@ public static void innerDestroy() { /** * Used for config data. + * @return configSDKContext */ public static SDKContext innerGetConfigSDKContext() { if (configSDKContext == null) { @@ -209,6 +210,7 @@ public SDKContext getConfigSDKContext() { /** * Used for config data. + * @param context sdk context */ public static void setConfigSDKContext(SDKContext context) { if (configSDKContext == null) { diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java index 84830f9d2..dfe166113 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java @@ -36,8 +36,10 @@ * @author Haotian Zhang */ public final class PolarisContextEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { - - public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 10 - 2; + /** + * order before TsfCoreEnvironmentPostProcessor. + */ + public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 8; private final Logger LOGGER = LoggerFactory.getLogger(PolarisContextEnvironmentPostProcessor.class); @@ -96,6 +98,7 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp polarisEnvProperties.put("spring.cloud.tencent.metadata.content.zone", zone); } + LOGGER.debug("polaris-env-properties:{}", polarisEnvProperties); MapPropertySource propertySource = new MapPropertySource("polaris-env-properties", polarisEnvProperties); environment.getPropertySources().addFirst(propertySource); } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java index 874c2c90c..558a9e31e 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java @@ -21,7 +21,6 @@ import java.util.Map; import com.tencent.polaris.api.utils.StringUtils; -import org.apache.commons.logging.Log; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,8 +36,10 @@ * @author Haotian Zhang */ public final class TsfCoreEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { - - public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 10 - 1; + /** + * order after PolarisContextEnvironmentPostProcessor. + */ + public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 9; private final Logger LOGGER = LoggerFactory.getLogger(TsfCoreEnvironmentPostProcessor.class); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java index 4ba48aba3..53db6a75d 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java @@ -23,7 +23,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; /** * Autoconfiguration of stat reporter. From 0b375cb9fe8ae9c41ca5b587da32869664ddcc5b Mon Sep 17 00:00:00 2001 From: shedfreewu Date: Tue, 19 Nov 2024 15:35:49 +0800 Subject: [PATCH 19/19] fix ut --- .../circuitbreaker/ReactivePolarisCircuitBreakerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java index 7507ae43c..6af1975ad 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java @@ -110,10 +110,10 @@ public void run() { ReflectionUtils.makeAccessible(getConfigurationsMethod); Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); Assertions.assertNotNull(values); - Assertions.assertEquals(1, values.size()); + Assertions.assertTrue(values.size() >= 0); Utils.sleepUninterrupted(10 * 1000); - + // clear by cleanupService in ReactivePolarisCircuitBreakerFactory Assertions.assertEquals(0, values.size()); }); }