From af0845f01fb96d2b55faab4bec4c93859ae29014 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Fri, 14 Oct 2022 15:41:13 +0800 Subject: [PATCH] feat:support new label expression. (#641) * feat:support new label expression. * feat:support new label expression. --- CHANGELOG.md | 1 + ...BalancerClientFilterBeanPostProcessor.java | 4 +- .../router/config/FeignAutoConfiguration.java | 6 +- .../config/RouterAutoConfiguration.java | 7 +- .../feign/FeignExpressionLabelUtils.java | 8 +- .../feign/RouterLabelFeignInterceptor.java | 19 ++- .../RouterLabelRestTemplateInterceptor.java | 19 ++- ...larisReactiveLoadBalancerClientFilter.java | 19 ++- .../router/RouterRuleLabelResolverTest.java | 4 +- .../RouterLabelFeignInterceptorTest.java | 5 +- ...outerLabelRestTemplateInterceptorTest.java | 5 +- ...sReactiveLoadBalancerClientFilterTest.java | 5 +- .../expresstion/ExpressionLabelUtils.java | 137 +++++++++++------- .../util/expresstion/ExpressionParser.java | 95 ++++++++++++ .../util/expresstion/ExpressionParserV1.java | 93 ++++++++++++ .../util/expresstion/ExpressionParserV2.java | 88 +++++++++++ .../ServletExpressionLabelUtils.java | 10 +- .../SpringWebExpressionLabelUtils.java | 18 +-- .../common/util/ExpressionLabelUtilsTest.java | 6 +- .../common/util/ExpressionParserV1Test.java | 70 +++++++++ .../common/util/ExpressionParserV2Test.java | 74 ++++++++++ spring-cloud-tencent-dependencies/pom.xml | 2 +- .../src/main/resources/bootstrap.yml | 2 +- .../PolarisContextAutoConfiguration.java | 10 +- .../config/PolarisContextProperties.java | 30 ++-- 25 files changed, 626 insertions(+), 111 deletions(-) create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParser.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV2.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV1Test.java create mode 100644 spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV2Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8870e64ae..60a1af3c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,4 @@ - [Feature: support spring-retry router](https://github.com/Tencent/spring-cloud-tencent/pull/633) - [Bugfix: fix throw npe when router context is null](https://github.com/Tencent/spring-cloud-tencent/pull/634) - [feat:Transfer http headers specified by environment variables](https://github.com/Tencent/spring-cloud-tencent/pull/637) +- [feat:support new label expression](https://github.com/Tencent/spring-cloud-tencent/pull/641) diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/ReactiveLoadBalancerClientFilterBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/ReactiveLoadBalancerClientFilterBeanPostProcessor.java index d383901b5..eb2b9d66f 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/ReactiveLoadBalancerClientFilterBeanPostProcessor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/ReactiveLoadBalancerClientFilterBeanPostProcessor.java @@ -21,6 +21,7 @@ import java.util.List; import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.common.util.BeanFactoryUtils; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.scg.PolarisReactiveLoadBalancerClientFilter; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -60,10 +61,11 @@ public class ReactiveLoadBalancerClientFilterBeanPostProcessor implements BeanPo List routerLabelResolvers = BeanFactoryUtils.getBeans(factory, SpringWebRouterLabelResolver.class); StaticMetadataManager staticMetadataManager = this.factory.getBean(StaticMetadataManager.class); RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class); + PolarisContextProperties polarisContextProperties = this.factory.getBean(PolarisContextProperties.class); return new PolarisReactiveLoadBalancerClientFilter( loadBalancerClientFactory, gatewayLoadBalancerProperties, loadBalancerProperties, - staticMetadataManager, routerRuleLabelResolver, routerLabelResolvers); + staticMetadataManager, routerRuleLabelResolver, routerLabelResolvers, polarisContextProperties); } return bean; } 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 8a90289df..fef47e170 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 @@ -21,6 +21,7 @@ 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.RouterLabelFeignInterceptor; import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; @@ -38,7 +39,8 @@ public class FeignAutoConfiguration { @Bean public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List routerLabelResolvers, StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver) { - return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver); + RouterRuleLabelResolver routerRuleLabelResolver, + PolarisContextProperties polarisContextProperties) { + return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); } } 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 19dd7b419..90e711806 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 @@ -24,6 +24,7 @@ import java.util.List; import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.beanprocessor.ReactiveLoadBalancerClientFilterBeanPostProcessor; @@ -114,8 +115,10 @@ public class RouterAutoConfiguration { public RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor( List routerLabelResolvers, StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver) { - return new RouterLabelRestTemplateInterceptor(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver); + RouterRuleLabelResolver routerRuleLabelResolver, + PolarisContextProperties polarisContextProperties) { + return new RouterLabelRestTemplateInterceptor(routerLabelResolvers, staticMetadataManager, + routerRuleLabelResolver, polarisContextProperties); } @Bean 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 index b040a6f7c..320aff3be 100644 --- 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 @@ -49,24 +49,24 @@ public final class FeignExpressionLabelUtils { Map labels = new HashMap<>(); for (String labelKey : labelKeys) { - if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_HEADER_PREFIX)) { + if (ExpressionLabelUtils.isHeaderLabel(labelKey)) { String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { continue; } labels.put(labelKey, getHeaderValue(request, headerKey)); } - else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_QUERY_PREFIX)) { + else if (ExpressionLabelUtils.isQueryLabel(labelKey)) { String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); if (StringUtils.isBlank(queryKey)) { continue; } labels.put(labelKey, getQueryValue(request, queryKey)); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_METHOD, labelKey)) { + else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { labels.put(labelKey, request.method()); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) { + else if (ExpressionLabelUtils.isUriLabel(labelKey)) { URI uri = URI.create(request.request().url()); labels.put(labelKey, uri.getPath()); } 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 f2322dbea..829333fc1 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 @@ -32,6 +32,8 @@ 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 feign.RequestInterceptor; @@ -55,10 +57,12 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered private final List routerLabelResolvers; private final StaticMetadataManager staticMetadataManager; private final RouterRuleLabelResolver routerRuleLabelResolver; + private final PolarisContextProperties polarisContextProperties; public RouterLabelFeignInterceptor(List routerLabelResolvers, StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver) { + RouterRuleLabelResolver routerRuleLabelResolver, + PolarisContextProperties polarisContextProperties) { if (!CollectionUtils.isEmpty(routerLabelResolvers)) { routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder)); this.routerLabelResolvers = routerLabelResolvers; @@ -68,6 +72,7 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered } this.staticMetadataManager = staticMetadataManager; this.routerRuleLabelResolver = routerRuleLabelResolver; + this.polarisContextProperties = polarisContextProperties; } @Override @@ -124,6 +129,16 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered return Collections.emptyMap(); } - return FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys); + //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; } } 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 index 1d6ef7c00..641774810 100644 --- 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 @@ -33,7 +33,9 @@ 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.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; import org.slf4j.Logger; @@ -62,12 +64,15 @@ public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInte private final List routerLabelResolvers; private final StaticMetadataManager staticMetadataManager; private final RouterRuleLabelResolver routerRuleLabelResolver; + private final PolarisContextProperties polarisContextProperties; public RouterLabelRestTemplateInterceptor(List routerLabelResolvers, StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver) { + RouterRuleLabelResolver routerRuleLabelResolver, + PolarisContextProperties polarisContextProperties) { this.staticMetadataManager = staticMetadataManager; this.routerRuleLabelResolver = routerRuleLabelResolver; + this.polarisContextProperties = polarisContextProperties; if (!CollectionUtils.isEmpty(routerLabelResolvers)) { routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder)); @@ -145,6 +150,16 @@ public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInte return Collections.emptyMap(); } - return SpringWebExpressionLabelUtils.resolve(request, labelKeys); + //enrich labels from request + Map labels = SpringWebExpressionLabelUtils.resolve(request, labelKeys); + + //enrich caller ip label + for (String labelKey : labelKeys) { + if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) { + labels.put(labelKey, polarisContextProperties.getLocalIpAddress()); + } + } + + return labels; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilter.java index cc69049cd..a75c432ec 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilter.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilter.java @@ -32,7 +32,9 @@ 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.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.PolarisRouterServiceInstanceListSupplier; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -87,13 +89,15 @@ public class PolarisReactiveLoadBalancerClientFilter extends ReactiveLoadBalance private final StaticMetadataManager staticMetadataManager; private final RouterRuleLabelResolver routerRuleLabelResolver; private final List routerLabelResolvers; + private final PolarisContextProperties polarisContextProperties; public PolarisReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, GatewayLoadBalancerProperties gatewayLoadBalancerProperties, LoadBalancerProperties loadBalancerProperties, StaticMetadataManager staticMetadataManager, RouterRuleLabelResolver routerRuleLabelResolver, - List routerLabelResolvers) { + List routerLabelResolvers, + PolarisContextProperties polarisContextProperties) { super(clientFactory, gatewayLoadBalancerProperties, loadBalancerProperties); this.clientFactory = clientFactory; @@ -102,6 +106,7 @@ public class PolarisReactiveLoadBalancerClientFilter extends ReactiveLoadBalance this.staticMetadataManager = staticMetadataManager; this.routerRuleLabelResolver = routerRuleLabelResolver; this.routerLabelResolvers = routerLabelResolvers; + this.polarisContextProperties = polarisContextProperties; } /** @@ -262,6 +267,16 @@ public class PolarisReactiveLoadBalancerClientFilter extends ReactiveLoadBalance return Collections.emptyMap(); } - return SpringWebExpressionLabelUtils.resolve(exchange, labelKeys); + //enrich labels from request + Map labels = SpringWebExpressionLabelUtils.resolve(exchange, labelKeys); + + //enrich caller ip label + for (String labelKey : labelKeys) { + if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) { + labels.put(labelKey, polarisContextProperties.getLocalIpAddress()); + } + } + + return labels; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java index 3ae3261f7..b08426b7d 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/RouterRuleLabelResolverTest.java @@ -84,12 +84,12 @@ public class RouterRuleLabelResolverTest { Set resolvedExpressionLabelKeys = resolver.getExpressionLabelKeys(testNamespace, testSourceService, testDstService); Assert.assertNotNull(resolvedExpressionLabelKeys); - Assert.assertEquals(5, resolvedExpressionLabelKeys.size()); + Assert.assertEquals(6, resolvedExpressionLabelKeys.size()); Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey1)); Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey2)); Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey3)); Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey4)); Assert.assertTrue(resolvedExpressionLabelKeys.contains(validKey5)); - Assert.assertFalse(resolvedExpressionLabelKeys.contains(invalidKey)); + Assert.assertTrue(resolvedExpressionLabelKeys.contains(invalidKey)); } } 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 16d4bec35..e5d592b1a 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 @@ -33,6 +33,7 @@ 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 feign.RequestTemplate; @@ -63,12 +64,14 @@ public class RouterLabelFeignInterceptorTest { private RouterRuleLabelResolver routerRuleLabelResolver; @Mock private FeignRouterLabelResolver routerLabelResolver; + @Mock + private PolarisContextProperties polarisContextProperties; @Test public void testResolveRouterLabel() { RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor( Collections.singletonList(routerLabelResolver), - staticMetadataManager, routerRuleLabelResolver); + staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); // mock request template RequestTemplate requestTemplate = new RequestTemplate(); 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 index 056cfb0ed..7847bb4f8 100644 --- 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 @@ -32,6 +32,7 @@ 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.SpringWebRouterLabelResolver; import org.assertj.core.api.Assertions; @@ -67,6 +68,8 @@ public class RouterLabelRestTemplateInterceptorTest { private StaticMetadataManager staticMetadataManager; @Mock private RouterRuleLabelResolver routerRuleLabelResolver; + @Mock + private PolarisContextProperties polarisContextProperties; @BeforeClass public static void beforeClass() { @@ -119,7 +122,7 @@ public class RouterLabelRestTemplateInterceptorTest { mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor = new RouterLabelRestTemplateInterceptor( - Collections.singletonList(routerLabelResolver), staticMetadataManager, routerRuleLabelResolver); + Collections.singletonList(routerLabelResolver), staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); routerLabelRestTemplateInterceptor.setLabelsToHeaders(request, null, calleeService); diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilterTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilterTest.java index a21e9a844..3ff8216ee 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisReactiveLoadBalancerClientFilterTest.java @@ -33,6 +33,7 @@ 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.SpringWebRouterLabelResolver; import org.junit.AfterClass; @@ -82,6 +83,8 @@ public class PolarisReactiveLoadBalancerClientFilterTest { private GatewayLoadBalancerProperties gatewayLoadBalancerProperties; @Mock private LoadBalancerProperties loadBalancerProperties; + @Mock + private PolarisContextProperties polarisContextProperties; @BeforeClass public static void beforeClass() { @@ -111,7 +114,7 @@ public class PolarisReactiveLoadBalancerClientFilterTest { public void testGenRouterHttpHeaders() throws UnsupportedEncodingException { PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory, gatewayLoadBalancerProperties, loadBalancerProperties, staticMetadataManager, routerRuleLabelResolver, - Lists.newArrayList(routerLabelResolver)); + Lists.newArrayList(routerLabelResolver), polarisContextProperties); Map localMetadata = new HashMap<>(); localMetadata.put("env", "blue"); 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 2b85b9538..627bf2b45 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,12 +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.common.util.expresstion; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; @@ -33,69 +34,105 @@ import org.springframework.util.CollectionUtils; */ public final class ExpressionLabelUtils { - /** - * the expression prefix of header label. - */ - public static final String LABEL_HEADER_PREFIX = "${http.header."; - /** - * the length of expression header label prefix. - */ - public static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length(); - /** - * the expression prefix of query. - */ - public static final String LABEL_QUERY_PREFIX = "${http.query."; - /** - * the length of expression query label prefix. - */ - public static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length(); - /** - * the expression prefix of cookie. - */ - public static final String LABEL_COOKIE_PREFIX = "${http.cookie."; - /** - * the length of expression cookie label prefix. - */ - public static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length(); - /** - * the expression of method. - */ - public static final String LABEL_METHOD = "${http.method}"; - /** - * the expression of uri. - */ - public static final String LABEL_URI = "${http.uri}"; - - /** - * the prefix of expression. - */ - public static final String LABEL_PREFIX = "${"; - - /** - * the suffix of expression. - */ - public static final String LABEL_SUFFIX = "}"; + private static final List EXPRESSION_PARSERS; + + static { + EXPRESSION_PARSERS = new ArrayList<>(2); + EXPRESSION_PARSERS.add(new ExpressionParserV1()); + EXPRESSION_PARSERS.add(new ExpressionParserV2()); + } private ExpressionLabelUtils() { } - public static boolean isExpressionLabel(String labelKey) { - if (StringUtils.isEmpty(labelKey)) { - return false; + public static boolean isExpressionLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isExpressionLabel(expression)) { + return true; + } } - return StringUtils.startsWith(labelKey, LABEL_PREFIX) && StringUtils.endsWith(labelKey, LABEL_SUFFIX); + return false; + } + + public static boolean isHeaderLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isHeaderLabel(expression)) { + return true; + } + } + return false; } public static String parseHeaderKey(String expression) { - return expression.substring(LABEL_HEADER_PREFIX_LEN, expression.length() - 1); + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isHeaderLabel(expression)) { + return parser.parseHeaderKey(expression); + } + } + return ""; + } + + public static boolean isQueryLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isQueryLabel(expression)) { + return true; + } + } + return false; } public static String parseQueryKey(String expression) { - return expression.substring(LABEL_QUERY_PREFIX_LEN, expression.length() - 1); + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isQueryLabel(expression)) { + return parser.parseQueryKey(expression); + } + } + return ""; + } + + public static boolean isCookieLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isCookieLabel(expression)) { + return true; + } + } + return false; } public static String parseCookieKey(String expression) { - return expression.substring(LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isCookieLabel(expression)) { + return parser.parseCookieKey(expression); + } + } + return ""; + } + + public static boolean isMethodLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isMethodLabel(expression)) { + return true; + } + } + return false; + } + + public static boolean isUriLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isUriLabel(expression)) { + return true; + } + } + return false; + } + + public static boolean isCallerIPLabel(String expression) { + for (ExpressionParser parser : EXPRESSION_PARSERS) { + if (parser.isCallerIPLabel(expression)) { + return true; + } + } + return false; } public static String getQueryValue(String queryString, String queryKey) { diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParser.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParser.java new file mode 100644 index 000000000..3ff203f31 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParser.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.common.util.expresstion; + +/** + * Expression parser for rate limit rule and router rule. + * @author lepdou 2022-10-08 + */ +public interface ExpressionParser { + + /** + * whether is valid expression. + * @param expression the expression + * @return true if is valid + */ + boolean isExpressionLabel(String expression); + + /** + * whether is header expression. + * @param expression the expression + * @return true if is header expression + */ + boolean isHeaderLabel(String expression); + + /** + * parse label from header expression. + * @param expression the expression + * @return parsed key from expression + */ + String parseHeaderKey(String expression); + + /** + * whether is query expression. + * @param expression the expression + * @return true if is query expression + */ + boolean isQueryLabel(String expression); + + /** + * parse label from query expression. + * @param expression the expression + * @return parsed key from expression + */ + String parseQueryKey(String expression); + + /** + * whether is cookie expression. + * @param expression the expression + * @return true if is cookie expression + */ + boolean isCookieLabel(String expression); + + /** + * parse label from cookie expression. + * @param expression the expression + * @return parsed cookie key from expression + */ + String parseCookieKey(String expression); + + /** + * whether is method expression. + * @param expression the expression + * @return true if is method expression + */ + boolean isMethodLabel(String expression); + + /** + * whether is uri/path expression. + * @param expression the expression + * @return true if is uri/path expression + */ + boolean isUriLabel(String expression); + + /** + * whether is caller ip expression. + * @param expression the expression + * @return true if is caller ip expression + */ + boolean isCallerIPLabel(String expression); +} 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 new file mode 100644 index 000000000..dff35783a --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java @@ -0,0 +1,93 @@ +/* + * 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.expresstion; + +import org.apache.commons.lang.StringUtils; + +/** + * Old custom expression resolver like ${http.query.key}、${http.header.key}. + * New expression like $query.key、$header.key + * @author lepdou 2022-10-08 + */ +public class ExpressionParserV1 implements ExpressionParser { + + private static final String LABEL_HEADER_PREFIX = "${http.header."; + private static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length(); + private static final String LABEL_QUERY_PREFIX = "${http.query."; + private static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length(); + private static final String LABEL_COOKIE_PREFIX = "${http.cookie."; + private static final int LABEL_COOKIE_PREFIX_LEN = LABEL_COOKIE_PREFIX.length(); + private static final String LABEL_METHOD = "${http.method}"; + private static final String LABEL_URI = "${http.uri}"; + private static final String LABEL_CALLER_IP = "${http.caller.ip}"; + private static final String LABEL_PREFIX = "${"; + private static final String LABEL_SUFFIX = "}"; + + @Override + public boolean isExpressionLabel(String labelKey) { + if (StringUtils.isEmpty(labelKey)) { + return false; + } + return StringUtils.startsWith(labelKey, LABEL_PREFIX) && StringUtils.endsWith(labelKey, LABEL_SUFFIX); + } + + @Override + public boolean isHeaderLabel(String expression) { + return StringUtils.startsWith(expression, LABEL_HEADER_PREFIX) && StringUtils.endsWith(expression, LABEL_SUFFIX); + } + + @Override + public String parseHeaderKey(String expression) { + return StringUtils.substring(expression, LABEL_HEADER_PREFIX_LEN, expression.length() - 1); + } + + @Override + public boolean isQueryLabel(String expression) { + return StringUtils.startsWith(expression, LABEL_QUERY_PREFIX) && StringUtils.endsWith(expression, LABEL_SUFFIX); + } + + @Override + public String parseQueryKey(String expression) { + return StringUtils.substring(expression, LABEL_QUERY_PREFIX_LEN, expression.length() - 1); + } + + @Override + public boolean isCookieLabel(String expression) { + return StringUtils.startsWith(expression, LABEL_COOKIE_PREFIX) && StringUtils.endsWith(expression, LABEL_SUFFIX); + } + + @Override + public String parseCookieKey(String expression) { + return StringUtils.substring(expression, LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); + } + + @Override + public boolean isMethodLabel(String expression) { + return StringUtils.equalsIgnoreCase(expression, LABEL_METHOD); + } + + @Override + public boolean isUriLabel(String expression) { + return StringUtils.equalsIgnoreCase(expression, LABEL_URI); + } + + @Override + public boolean isCallerIPLabel(String expression) { + return StringUtils.equalsIgnoreCase(expression, LABEL_CALLER_IP); + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV2.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV2.java new file mode 100644 index 000000000..ad23a3d8d --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV2.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.expresstion; + +import org.apache.commons.lang.StringUtils; + +/** + * New custom expression resolver like $query.key、$header.key. + * Old expression like ${http.query.key}、${http.header.key} + * @author lepdou 2022-10-08 + */ +public class ExpressionParserV2 implements ExpressionParser { + + private static final String LABEL_HEADER_PREFIX = "$header."; + private static final int LABEL_HEADER_PREFIX_LEN = LABEL_HEADER_PREFIX.length(); + private static final String LABEL_QUERY_PREFIX = "$query."; + private static final int LABEL_QUERY_PREFIX_LEN = LABEL_QUERY_PREFIX.length(); + private static final String LABEL_METHOD = "$method"; + private static final String LABEL_PATH = "$path"; + private static final String LABEL_CALLER_IP = "$caller_ip"; + private static final String LABEL_PREFIX = "$"; + + + @Override + public boolean isExpressionLabel(String expression) { + return StringUtils.startsWith(expression, LABEL_PREFIX); + } + + @Override + public boolean isHeaderLabel(String expression) { + return StringUtils.startsWith(expression, LABEL_HEADER_PREFIX); + } + + @Override + public String parseHeaderKey(String expression) { + return StringUtils.substring(expression, LABEL_HEADER_PREFIX_LEN); + } + + @Override + public boolean isQueryLabel(String expression) { + return StringUtils.startsWith(expression, LABEL_QUERY_PREFIX); + } + + @Override + public String parseQueryKey(String expression) { + return StringUtils.substring(expression, LABEL_QUERY_PREFIX_LEN); + } + + @Override + public boolean isCookieLabel(String expression) { + return false; + } + + @Override + public String parseCookieKey(String expression) { + return null; + } + + @Override + public boolean isMethodLabel(String expression) { + return StringUtils.equalsIgnoreCase(expression, LABEL_METHOD); + } + + @Override + public boolean isUriLabel(String expression) { + return StringUtils.equalsIgnoreCase(expression, LABEL_PATH); + } + + @Override + public boolean isCallerIPLabel(String expression) { + return StringUtils.equalsIgnoreCase(expression, LABEL_CALLER_IP); + } +} 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 cf504fffb..a054c8f65 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 @@ -50,31 +50,31 @@ public final class ServletExpressionLabelUtils { if (!ExpressionLabelUtils.isExpressionLabel(labelKey)) { continue; } - if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_HEADER_PREFIX)) { + if (ExpressionLabelUtils.isHeaderLabel(labelKey)) { String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { continue; } labels.put(labelKey, request.getHeader(headerKey)); } - else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_QUERY_PREFIX)) { + else if (ExpressionLabelUtils.isQueryLabel(labelKey)) { String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); if (StringUtils.isBlank(queryKey)) { continue; } labels.put(labelKey, ExpressionLabelUtils.getQueryValue(request.getQueryString(), queryKey)); } - else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_COOKIE_PREFIX)) { + else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { String cookieKey = ExpressionLabelUtils.parseCookieKey(labelKey); if (StringUtils.isBlank(cookieKey)) { continue; } labels.put(labelKey, getCookieValue(request.getCookies(), cookieKey)); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_METHOD, labelKey)) { + else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { labels.put(labelKey, request.getMethod()); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) { + else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, request.getRequestURI()); } } 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 ebf27607b..b1bf54536 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 @@ -53,31 +53,31 @@ public final class SpringWebExpressionLabelUtils { if (!ExpressionLabelUtils.isExpressionLabel(labelKey)) { continue; } - if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_HEADER_PREFIX)) { + if (ExpressionLabelUtils.isHeaderLabel(labelKey)) { String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { continue; } labels.put(labelKey, getHeaderValue(exchange.getRequest(), headerKey)); } - else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_QUERY_PREFIX)) { + else if (ExpressionLabelUtils.isQueryLabel(labelKey)) { String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); if (StringUtils.isBlank(queryKey)) { continue; } labels.put(labelKey, getQueryValue(exchange.getRequest(), queryKey)); } - else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_COOKIE_PREFIX)) { + else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { String cookieKey = ExpressionLabelUtils.parseCookieKey(labelKey); if (StringUtils.isBlank(cookieKey)) { continue; } labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey)); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_METHOD, labelKey)) { + else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { labels.put(labelKey, exchange.getRequest().getMethodValue()); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) { + else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, exchange.getRequest().getURI().getPath()); } } @@ -96,24 +96,24 @@ public final class SpringWebExpressionLabelUtils { if (!ExpressionLabelUtils.isExpressionLabel(labelKey)) { continue; } - if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_HEADER_PREFIX)) { + if (ExpressionLabelUtils.isHeaderLabel(labelKey)) { String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); if (StringUtils.isBlank(headerKey)) { continue; } labels.put(labelKey, getHeaderValue(request, headerKey)); } - else if (StringUtils.startsWithIgnoreCase(labelKey, ExpressionLabelUtils.LABEL_QUERY_PREFIX)) { + else if (ExpressionLabelUtils.isQueryLabel(labelKey)) { String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); if (StringUtils.isBlank(queryKey)) { continue; } labels.put(labelKey, getQueryValue(request, queryKey)); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_METHOD, labelKey)) { + else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { labels.put(labelKey, request.getMethodValue()); } - else if (StringUtils.equalsIgnoreCase(ExpressionLabelUtils.LABEL_URI, labelKey)) { + else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, request.getURI().getPath()); } } 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 0757d2da2..e15fd1ae8 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 @@ -71,12 +71,12 @@ public class ExpressionLabelUtilsTest { Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(validLabel5)); Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(invalidLabel1)); Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel2)); - Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel3)); - Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel4)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(invalidLabel3)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(invalidLabel4)); Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(invalidLabel5)); Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(invalidLabel6)); Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel7)); - Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel8)); + Assert.assertTrue(ExpressionLabelUtils.isExpressionLabel(invalidLabel8)); Assert.assertFalse(ExpressionLabelUtils.isExpressionLabel(invalidLabel9)); } diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV1Test.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV1Test.java new file mode 100644 index 000000000..2f6e5b64e --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV1Test.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.common.util; + +import com.tencent.cloud.common.util.expresstion.ExpressionParserV1; +import org.junit.Assert; +import org.junit.Test; + +/** + * Test for {@link ExpressionParserV1} + * @author lepdou 2022-10-08 + */ +public class ExpressionParserV1Test { + + @Test + public void testExpressionLabel() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + ExpressionParserV1 parser = new ExpressionParserV1(); + + Assert.assertTrue(parser.isExpressionLabel(validLabel1)); + Assert.assertTrue(parser.isExpressionLabel(validLabel2)); + Assert.assertTrue(parser.isExpressionLabel(validLabel3)); + Assert.assertTrue(parser.isExpressionLabel(validLabel4)); + Assert.assertTrue(parser.isExpressionLabel(validLabel5)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel1)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel2)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel3)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel4)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel5)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel6)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel7)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel8)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel9)); + + Assert.assertTrue(parser.isQueryLabel(validLabel1)); + Assert.assertTrue(parser.isHeaderLabel(validLabel2)); + Assert.assertTrue(parser.isCookieLabel(validLabel3)); + Assert.assertTrue(parser.isMethodLabel(validLabel4)); + Assert.assertTrue(parser.isUriLabel(validLabel5)); + } +} diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV2Test.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV2Test.java new file mode 100644 index 000000000..a97b64ba5 --- /dev/null +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionParserV2Test.java @@ -0,0 +1,74 @@ +/* + * 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 com.tencent.cloud.common.util.expresstion.ExpressionParserV2; +import org.junit.Assert; +import org.junit.Test; + +/** + * Test for {@link ExpressionParserV2} + * @author lepdou 2022-10-08 + */ +public class ExpressionParserV2Test { + + @Test + public void testExpressionLabel() { + String validLabel1 = "${http.query.uid}"; + String validLabel2 = "${http.header.uid}"; + String validLabel3 = "${http.cookie.uid}"; + String validLabel4 = "${http.method}"; + String validLabel5 = "${http.uri}"; + String invalidLabel1 = "${http.queryuid}"; + String invalidLabel2 = "{http.query.uid}"; + String invalidLabel3 = "${http.query.uid"; + String invalidLabel4 = "$ {http.query.uid}"; + String invalidLabel5 = "${ http.query.uid}"; + String invalidLabel6 = "${query.uid}"; + String invalidLabel7 = "http.query.uid"; + String invalidLabel8 = "$${http.uri}"; + String invalidLabel9 = "#{http.uri}"; + + ExpressionParserV2 parser = new ExpressionParserV2(); + + Assert.assertTrue(parser.isExpressionLabel(validLabel1)); + Assert.assertTrue(parser.isExpressionLabel(validLabel2)); + Assert.assertTrue(parser.isExpressionLabel(validLabel3)); + Assert.assertTrue(parser.isExpressionLabel(validLabel4)); + Assert.assertTrue(parser.isExpressionLabel(validLabel5)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel1)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel2)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel3)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel4)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel5)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel6)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel7)); + Assert.assertTrue(parser.isExpressionLabel(invalidLabel8)); + Assert.assertFalse(parser.isExpressionLabel(invalidLabel9)); + + Assert.assertFalse(parser.isQueryLabel(validLabel1)); + Assert.assertFalse(parser.isHeaderLabel(validLabel2)); + Assert.assertFalse(parser.isCookieLabel(validLabel3)); + Assert.assertFalse(parser.isMethodLabel(validLabel4)); + Assert.assertFalse(parser.isUriLabel(validLabel5)); + + Assert.assertTrue(parser.isHeaderLabel("$header.userId")); + Assert.assertTrue(parser.isMethodLabel("$method")); + Assert.assertTrue(parser.isQueryLabel("$query.userId")); + } +} diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index f3f6a8d02..038166f96 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.8.0-2020.0.5-SNAPSHOT - 1.8.0 + 1.9.1 1.2.11 4.5.1 1.12.10 diff --git a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml index 22c330986..4ca108aba 100644 --- a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml @@ -11,7 +11,7 @@ spring: region: shanghai rpc-enhancement: reporter: - enabled: true + enabled: false polaris: address: grpc://183.47.111.80:8091 namespace: default 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 eab0ad5e6..eec34bf78 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 @@ -18,8 +18,11 @@ package com.tencent.cloud.polaris.context.config; +import java.util.List; + 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.ServiceRuleManager; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ProviderAPI; @@ -31,6 +34,7 @@ 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; +import org.springframework.core.env.Environment; /** * Autoconfiguration for Polaris {@link SDKContext}. @@ -44,9 +48,11 @@ public class PolarisContextAutoConfiguration { @Bean(name = "polarisContext", initMethod = "init", destroyMethod = "destroy") @ConditionalOnMissingBean - public SDKContext polarisContext(PolarisContextProperties properties) + public SDKContext polarisContext(PolarisContextProperties properties, Environment environment, + List modifierList) throws PolarisException { - return SDKContext.initContextByConfig(properties.configuration()); + return SDKContext.initContextByConfig(properties.configuration(modifierList, + () -> environment.getProperty("spring.cloud.client.ip-address"))); } @Bean 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 87a076e21..696218a28 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 @@ -21,6 +21,7 @@ package com.tencent.cloud.polaris.context.config; import java.util.Collection; import java.util.Comparator; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; import com.tencent.cloud.polaris.context.PolarisConfigModifier; @@ -30,9 +31,7 @@ import com.tencent.polaris.factory.ConfigAPIFactory; import com.tencent.polaris.factory.config.ConfigurationImpl; import org.apache.commons.lang.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.core.env.Environment; import org.springframework.util.CollectionUtils; /** @@ -68,19 +67,18 @@ public class PolarisContextProperties { */ private String service; - @Autowired - private Environment environment; - - @Autowired - private List modifierList; - - protected Configuration configuration() { + public Configuration configuration(List modifierList, Supplier ipAddressSupplier) { // 1. Read user-defined polaris.yml configuration ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory .defaultConfig(ConfigProvider.DEFAULT_CONFIG); // 2. Override user-defined polaris.yml configuration with SCT configuration - String defaultHost = getHost(); + String defaultHost = this.localIpAddress; + if (StringUtils.isBlank(localIpAddress)) { + defaultHost = ipAddressSupplier.get(); + this.localIpAddress = defaultHost; + } + configuration.getGlobal().getAPI().setBindIP(defaultHost); Collection modifiers = modifierList; @@ -96,13 +94,6 @@ public class PolarisContextProperties { return configuration; } - private String getHost() { - if (StringUtils.isNotBlank(localIpAddress)) { - return localIpAddress; - } - return environment.getProperty("spring.cloud.client.ip-address"); - } - public String getAddress() { return address; } @@ -111,11 +102,11 @@ public class PolarisContextProperties { this.address = address; } - String getLocalIpAddress() { + public String getLocalIpAddress() { return localIpAddress; } - void setLocalIpAddress(String localIpAddress) { + public void setLocalIpAddress(String localIpAddress) { this.localIpAddress = localIpAddress; } @@ -142,5 +133,4 @@ public class PolarisContextProperties { public void setService(String service) { this.service = service; } - }