diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml deleted file mode 100644 index 721286f3d..000000000 --- a/.github/workflows/codecov.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Codecov - -on: - push: - branches: - - hoxton - - 2021.0 - - 2020.0 - - greenwich - pull_request: - branches: - - hoxton - - 2021.0 - - 2020.0 - - greenwich - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout codes - uses: actions/checkout@v3 - - name: Set up JDK 8 - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: 8 - - name: Test with Maven - run: mvn -B test --file pom.xml - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - file: ${{ github.workspace }}/target/site/jacoco/jacoco.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index d7886c4b2..0c5129c15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,5 @@ # Change Log --- -- [Optimize: remove discovery module useless code](https://github.com/Tencent/spring-cloud-tencent/pull/597) -- [Bugfix: InstancePreRegisteredEvent and InstanceRegisteredEvent modify Registration info](https://github.com/Tencent/spring-cloud-tencent/pull/583) -- [Fix issue 579:Report the labels in request when report the result of invocation by RestTemplate](https://github.com/Tencent/spring-cloud-tencent/pull/600) -- [Optimize: optimize configuration conditional & optimize config data tips"](https://github.com/Tencent/spring-cloud-tencent/pull/605) -- [Optimize: Maybe remove Chinese characters](https://github.com/Tencent/spring-cloud-tencent/pull/609) -- [Optimize: InstanceId of PolarisRegistration and PolarisServiceRegistry](https://github.com/Tencent/spring-cloud-tencent/pull/612) -- [Bugfix: fix feign report call result error when using feign direct call](https://github.com/Tencent/spring-cloud-tencent/pull/623) -- [optimize:optimize PolarisRouterContext and constants.](https://github.com/Tencent/spring-cloud-tencent/pull/628) -- [support spring-retry router](https://github.com/Tencent/spring-cloud-tencent/pull/631) -- [feat:Transfer http headers specified by environment variables](https://github.com/Tencent/spring-cloud-tencent/pull/638) -- [feat:support read config file from local file system.](https://github.com/Tencent/spring-cloud-tencent/pull/649) -- [feat: publish spring event named ConfigChangeSpringEvent when the configuration is changed](https://github.com/Tencent/spring-cloud-tencent/pull/651) +- [Optimize:optimize spring value processor](https://github.com/Tencent/spring-cloud-tencent/pull/669) + diff --git a/README-zh.md b/README-zh.md index 1e894d76e..c39aa3faf 100644 --- a/README-zh.md +++ b/README-zh.md @@ -70,7 +70,7 @@ Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要 com.tencent.cloud spring-cloud-tencent-dependencies - 1.7.1-Hoxton.SR12 + 1.8.1-Hoxton.SR12 pom import diff --git a/README.md b/README.md index 93a5c5e01..466a35f45 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ For example: com.tencent.cloud spring-cloud-tencent-dependencies - 1.7.1-Hoxton.SR12 + 1.8.1-Hoxton.SR12 pom import diff --git a/changes/changes-1.8.1.md b/changes/changes-1.8.1.md new file mode 100644 index 000000000..605cd6710 --- /dev/null +++ b/changes/changes-1.8.1.md @@ -0,0 +1,18 @@ +# Change Log +--- + +- [Optimize: remove discovery module useless code](https://github.com/Tencent/spring-cloud-tencent/pull/597) +- [Bugfix: InstancePreRegisteredEvent and InstanceRegisteredEvent modify Registration info](https://github.com/Tencent/spring-cloud-tencent/pull/583) +- [Fix issue 579:Report the labels in request when report the result of invocation by RestTemplate](https://github.com/Tencent/spring-cloud-tencent/pull/600) +- [Optimize: optimize configuration conditional & optimize config data tips"](https://github.com/Tencent/spring-cloud-tencent/pull/605) +- [Optimize: Maybe remove Chinese characters](https://github.com/Tencent/spring-cloud-tencent/pull/609) +- [Optimize: InstanceId of PolarisRegistration and PolarisServiceRegistry](https://github.com/Tencent/spring-cloud-tencent/pull/612) +- [Bugfix: fix feign report call result error when using feign direct call](https://github.com/Tencent/spring-cloud-tencent/pull/623) +- [optimize:optimize PolarisRouterContext and constants.](https://github.com/Tencent/spring-cloud-tencent/pull/628) +- [support spring-retry router](https://github.com/Tencent/spring-cloud-tencent/pull/631) +- [feat:Transfer http headers specified by environment variables](https://github.com/Tencent/spring-cloud-tencent/pull/638) +- [feat:support read config file from local file system.](https://github.com/Tencent/spring-cloud-tencent/pull/649) +- [feat: publish spring event named ConfigChangeSpringEvent when the configuration is changed](https://github.com/Tencent/spring-cloud-tencent/pull/651) +- [Feature: support new expression](https://github.com/Tencent/spring-cloud-tencent/pull/661) +- [Optimize:optimize TransHeadersTransfer.](https://github.com/Tencent/spring-cloud-tencent/pull/662) +- [fix:fix transfer http headers not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/663) diff --git a/pom.xml b/pom.xml index a00aa3c52..f079fbc46 100644 --- a/pom.xml +++ b/pom.xml @@ -89,7 +89,7 @@ - 1.8.0-Hoxton.SR12-SNAPSHOT + 1.9.0-Hoxton.SR12-SNAPSHOT Hoxton.SR12 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 d9c8dbe14..03259a302 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 @@ -20,12 +20,8 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Set; import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.metadata.MetadataContextHolder; @@ -37,7 +33,6 @@ import reactor.core.publisher.Mono; import org.springframework.core.Ordered; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; @@ -46,8 +41,6 @@ import org.springframework.web.server.WebFilterChain; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -65,8 +58,7 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered } @Override - public Mono filter(ServerWebExchange serverWebExchange, - WebFilterChain webFilterChain) { + public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); @@ -87,41 +79,13 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered MetadataConstant.HeaderName.METADATA_CONTEXT, MetadataContextHolder.get()); - setCompleteTransHeaderIntoMC(serverHttpRequest); + TransHeadersTransfer.transfer(serverHttpRequest); return webFilterChain.filter(serverWebExchange) .doOnError(throwable -> LOG.error("handle metadata[{}] error.", MetadataContextHolder.get(), throwable)) .doFinally((type) -> MetadataContextHolder.remove()); } - /** - * According to ServerHttpRequest and trans-headers(key list in string type) in metadata, build - * the complete headers(key-value list in map type) into metadata. - */ - private void setCompleteTransHeaderIntoMC(ServerHttpRequest serverHttpRequest) { - // transHeaderMetadata: for example, {"trans-headers" : {"header1,header2,header3":""}} - Map transHeaderMetadata = MetadataContextHolder.get() - .getFragmentContext(FRAGMENT_RAW_TRANSHEADERS); - if (!CollectionUtils.isEmpty(transHeaderMetadata)) { - String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse(""); - String[] transHeaderArray = transHeaders.split(","); - HttpHeaders headers = serverHttpRequest.getHeaders(); - Set headerKeys = headers.keySet(); - Iterator iterator = headerKeys.iterator(); - while (iterator.hasNext()) { - String httpHeader = iterator.next(); - Arrays.stream(transHeaderArray).forEach(transHeader -> { - if (transHeader.equals(httpHeader)) { - List list = headers.get(httpHeader); - String httpHeaderValue = JacksonUtils.serialize2Json(list); - MetadataContextHolder.get() - .putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue); - } - }); - } - } - } - private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); String customMetadataStr = httpHeaders.getFirst(headerName); 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 b446af2e6..c4e2eefa4 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 @@ -21,8 +21,6 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.Arrays; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -39,15 +37,12 @@ import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.lang.NonNull; -import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -76,33 +71,13 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); - setCompleteTransHeaderIntoMC(httpServletRequest); - filterChain.doFilter(httpServletRequest, httpServletResponse); - } - - /** - * According to HttpServletRequest and trans-headers(key list in string type) in metadata, build - * the complete headers(key-value list in map type) into metadata. - */ - private void setCompleteTransHeaderIntoMC(HttpServletRequest httpServletRequest) { - // transHeaderMetadata: for example, {"trans-headers" : {"header1,header2,header3":""}} - Map transHeaderMetadata = MetadataContextHolder.get() - .getFragmentContext(FRAGMENT_RAW_TRANSHEADERS); - if (!CollectionUtils.isEmpty(transHeaderMetadata)) { - String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse(""); - String[] transHeaderArray = transHeaders.split(","); - Enumeration httpHeaders = httpServletRequest.getHeaderNames(); - while (httpHeaders.hasMoreElements()) { - String httpHeader = httpHeaders.nextElement(); - Arrays.stream(transHeaderArray).forEach(transHeader -> { - if (transHeader.equals(httpHeader)) { - String httpHeaderValue = httpServletRequest.getHeader(httpHeader); - // for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}} - MetadataContextHolder.get() - .putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue); - } - }); - } + TransHeadersTransfer.transfer(httpServletRequest); + try { + filterChain.doFilter(httpServletRequest, httpServletResponse); + } + finally { + // Clean up ThreadLocal. + MetadataContextHolder.remove(); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java index b35ec02df..0cfc0f142 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java @@ -19,7 +19,6 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; -import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -59,21 +58,14 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, public void apply(RequestTemplate requestTemplate) { // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); - Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - Map transHeaders = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map transHeaders = metadataContext.getTransHeadersKV(); - // Clean up one-time metadata coming from upstream . - Map newestCustomMetadata = new HashMap<>(); - customMetadata.forEach((key, value) -> { - if (!disposableMetadata.containsKey(key)) { - newestCustomMetadata.put(key, value); - } - }); this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); // process custom metadata - this.buildMetadataHeader(requestTemplate, newestCustomMetadata, CUSTOM_METADATA); + this.buildMetadataHeader(requestTemplate, customMetadata, CUSTOM_METADATA); // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(requestTemplate, transHeaders); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java index 89d5c5f6e..2e360cdd8 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java @@ -21,7 +21,6 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -59,21 +58,15 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); - Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - Map transHeaders = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map transHeaders = metadataContext.getTransHeadersKV(); - Map newestCustomMetadata = new HashMap<>(); - customMetadata.forEach((key, value) -> { - if (!disposableMetadata.containsKey(key)) { - newestCustomMetadata.put(key, value); - } - }); // build custom disposable metadata request header this.buildMetadataHeader(httpRequest, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); // build custom metadata request header - this.buildMetadataHeader(httpRequest, newestCustomMetadata, CUSTOM_METADATA); + this.buildMetadataHeader(httpRequest, customMetadata, CUSTOM_METADATA); // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(httpRequest, transHeaders); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java index 32c693d99..ca079e72f 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java @@ -20,12 +20,7 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.Set; import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.metadata.MetadataContext; @@ -36,7 +31,6 @@ 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.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; @@ -44,8 +38,6 @@ 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.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV; import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; /** @@ -73,53 +65,16 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { metadataContext = MetadataContextHolder.get(); } - Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); - // Clean upstream disposable metadata. - Map newestCustomMetadata = new HashMap<>(); - customMetadata.forEach((key, value) -> { - if (!disposableMetadata.containsKey(key)) { - newestCustomMetadata.put(key, value); - } - }); - - this.buildMetadataHeader(builder, newestCustomMetadata, CUSTOM_METADATA); + this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - setCompleteTransHeaderIntoMC(exchange.getRequest()); + TransHeadersTransfer.transfer(exchange.getRequest()); return chain.filter(exchange.mutate().request(builder.build()).build()); } - /** - * According to ServerHttpRequest and trans-headers(key list in string type) in metadata, build - * the complete headers(key-value list in map type) into metadata. - */ - private void setCompleteTransHeaderIntoMC(ServerHttpRequest serverHttpRequest) { - // transHeaderMetadata: for example, {"trans-headers" : {"header1,header2,header3":""}} - Map transHeaderMetadata = MetadataContextHolder.get() - .getFragmentContext(FRAGMENT_RAW_TRANSHEADERS); - if (!CollectionUtils.isEmpty(transHeaderMetadata)) { - String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse(""); - String[] transHeaderArray = transHeaders.split(","); - HttpHeaders headers = serverHttpRequest.getHeaders(); - Set headerKeys = headers.keySet(); - Iterator iterator = headerKeys.iterator(); - while (iterator.hasNext()) { - String httpHeader = iterator.next(); - Arrays.stream(transHeaderArray).forEach(transHeader -> { - if (transHeader.equals(httpHeader)) { - List list = headers.get(httpHeader); - String httpHeaderValue = JacksonUtils.serialize2Json(list); - // for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}} - MetadataContextHolder.get() - .putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue); - } - }); - } - } - } - /** * Set metadata into the request header for {@link ServerHttpRequest.Builder} . * @param builder instance of {@link ServerHttpRequest.Builder} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java index 659603c79..62e4857c6 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilter.java @@ -20,9 +20,6 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashMap; import java.util.Map; import com.netflix.zuul.ZuulFilter; @@ -36,8 +33,6 @@ import org.springframework.util.CollectionUtils; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS; -import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE; @@ -71,52 +66,17 @@ public class EncodeTransferMetadataZuulFilter extends ZuulFilter { // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); - // add new metadata and cover old - Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - - // Clean upstream disposable metadata. - Map newestCustomMetadata = new HashMap<>(); - customMetadata.forEach((key, value) -> { - if (!disposableMetadata.containsKey(key)) { - newestCustomMetadata.put(key, value); - } - }); + Map customMetadata = metadataContext.getCustomMetadata(); + Map disposableMetadata = metadataContext.getDisposableMetadata(); // Rebuild Metadata Header - this.buildMetadataHeader(requestContext, newestCustomMetadata, CUSTOM_METADATA); + this.buildMetadataHeader(requestContext, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestContext, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); - setCompleteTransHeaderIntoMC(requestContext); + TransHeadersTransfer.transfer(requestContext.getRequest()); return null; } - /** - * According to ServerHttpRequest and trans-headers(key list in string type) in metadata, build - * the complete headers(key-value list in map type) into metadata. - */ - private void setCompleteTransHeaderIntoMC(RequestContext requestContext) { - // transHeaderMetadata: for example, {"trans-headers" : {"header1,header2,header3":""}} - Map transHeaderMetadata = MetadataContextHolder.get() - .getFragmentContext(FRAGMENT_RAW_TRANSHEADERS); - if (!CollectionUtils.isEmpty(transHeaderMetadata)) { - String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse(""); - String[] transHeaderArray = transHeaders.split(","); - Enumeration httpHeaders = requestContext.getRequest().getHeaderNames(); - while (httpHeaders.hasMoreElements()) { - String httpHeader = httpHeaders.nextElement(); - Arrays.stream(transHeaderArray).forEach(transHeader -> { - if (transHeader.equals(httpHeader)) { - String httpHeaderValue = requestContext.getRequest().getHeader(httpHeader); - // for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}} - MetadataContextHolder.get() - .putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue); - } - }); - } - } - } - /** * Set metadata into the request header for {@link RequestContext} . * diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/TransHeadersTransfer.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/TransHeadersTransfer.java new file mode 100644 index 000000000..dd9a337d4 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/TransHeadersTransfer.java @@ -0,0 +1,99 @@ +/* + * 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.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.JacksonUtils; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.CollectionUtils; + +/** + * According to request and trans-headers(key list in string type) in metadata, build + * the complete headers(key-value list in map type) into metadata. + * + * @author lingxiao.wlx + */ +public final class TransHeadersTransfer { + + private TransHeadersTransfer() { + } + + /** + * According to {@link HttpServletRequest} and trans-headers(key list in string type) in metadata, build + * the complete headers(key-value list in map type) into metadata. + * + * @param httpServletRequest httpServletRequest + */ + public static void transfer(HttpServletRequest httpServletRequest) { + // transHeaderMetadata: for example, {"trans-headers" : {"header1,header2,header3":""}} + Map transHeaderMetadata = MetadataContextHolder.get().getTransHeaders(); + if (!CollectionUtils.isEmpty(transHeaderMetadata)) { + String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse(""); + String[] transHeaderArray = transHeaders.split(","); + Enumeration httpHeaders = httpServletRequest.getHeaderNames(); + while (httpHeaders.hasMoreElements()) { + String httpHeader = httpHeaders.nextElement(); + Arrays.stream(transHeaderArray).forEach(transHeader -> { + if (transHeader.equals(httpHeader)) { + String httpHeaderValue = httpServletRequest.getHeader(httpHeader); + // for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}} + MetadataContextHolder.get().setTransHeadersKV(httpHeader, httpHeaderValue); + } + }); + } + } + } + + /** + * According to {@link ServerHttpRequest} and trans-headers(key list in string type) in metadata, build + * the complete headers(key-value list in map type) into metadata. + * + * @param serverHttpRequest serverHttpRequest + */ + public static void transfer(ServerHttpRequest serverHttpRequest) { + // transHeaderMetadata: for example, {"trans-headers" : {"header1,header2,header3":""}} + Map transHeaderMetadata = MetadataContextHolder.get().getTransHeaders(); + if (!CollectionUtils.isEmpty(transHeaderMetadata)) { + String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse(""); + String[] transHeaderArray = transHeaders.split(","); + HttpHeaders headers = serverHttpRequest.getHeaders(); + Set headerKeys = headers.keySet(); + for (String httpHeader : headerKeys) { + Arrays.stream(transHeaderArray).forEach(transHeader -> { + if (transHeader.equals(httpHeader)) { + List list = headers.get(httpHeader); + String httpHeaderValue = JacksonUtils.serialize2Json(list); + // for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}} + MetadataContextHolder.get().setTransHeadersKV(httpHeader, httpHeaderValue); + } + }); + } + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/TransHeadersTransferTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/TransHeadersTransferTest.java new file mode 100644 index 000000000..4b7b09a5b --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/TransHeadersTransferTest.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.metadata.core; + +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.util.JacksonUtils; +import org.junit.AfterClass; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +/** + * Test for {@link TransHeadersTransfer}. + * + * @author lingxiao.wlx + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = RANDOM_PORT, + classes = DecodeTransferMetadataServletFilterTest.TestApplication.class, + properties = {"spring.config.location = classpath:application-test.yml", "spring.main.web-application-type=reactive"}) +public class TransHeadersTransferTest { + @AfterClass + public static void afterClass() { + MetadataContextHolder.remove(); + } + + @Test + public void transferServletTest() { + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransHeaders("header1,header2,header3", ""); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("header1", "1"); + request.addHeader("header2", "2"); + request.addHeader("header3", "3"); + TransHeadersTransfer.transfer(request); + Map transHeadersKV = MetadataContextHolder.get().getTransHeadersKV(); + Assertions.assertEquals(transHeadersKV.get("header1"), "1"); + Assertions.assertEquals(transHeadersKV.get("header2"), "2"); + Assertions.assertEquals(transHeadersKV.get("header3"), "3"); + } + + @Test + public void transferReactiveTest() { + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransHeaders("header1,header2,header3", ""); + MockServerHttpRequest.BaseBuilder builder = MockServerHttpRequest.get(""); + String[] header1 = {"1"}; + String[] header2 = {"2"}; + String[] header3 = {"3"}; + builder.header("header1", header1); + builder.header("header2", header2); + builder.header("header3", header3); + MockServerHttpRequest request = builder.build(); + TransHeadersTransfer.transfer(request); + Map transHeadersKV = MetadataContextHolder.get().getTransHeadersKV(); + Assertions.assertEquals(transHeadersKV.get("header1"), JacksonUtils.serialize2Json(header1)); + Assertions.assertEquals(transHeadersKV.get("header2"), JacksonUtils.serialize2Json(header2)); + Assertions.assertEquals(transHeadersKV.get("header3"), JacksonUtils.serialize2Json(header3)); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java index 75d4dc31a..562fc67f2 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.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; @@ -23,27 +22,34 @@ import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; 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; import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinition; -import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinitionProcessor; import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.Bean; import org.springframework.lang.NonNull; @@ -56,10 +62,13 @@ import org.springframework.lang.NonNull; * * @author weihubeats 2022-7-10 */ -public class SpringValueProcessor extends PolarisProcessor implements BeanFactoryPostProcessor, BeanFactoryAware { +public class SpringValueProcessor extends PolarisProcessor implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware { private static final Logger LOGGER = LoggerFactory.getLogger(SpringValueProcessor.class); + private static final Set PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet(); + private static final Map> BEAN_DEFINITION_REGISTRY_MULTIMAP_CONCURRENT_MAP = + Maps.newConcurrentMap(); private final PolarisConfigProperties polarisConfigProperties; private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; @@ -80,8 +89,7 @@ public class SpringValueProcessor extends PolarisProcessor implements BeanFactor public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException { if (polarisConfigProperties.isAutoRefresh() && beanFactory instanceof BeanDefinitionRegistry) { - beanName2SpringValueDefinitions = SpringValueDefinitionProcessor - .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory); + beanName2SpringValueDefinitions = this.getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory); } } @@ -127,6 +135,18 @@ public class SpringValueProcessor extends PolarisProcessor implements BeanFactor doRegister(bean, beanName, method, value); } + @Override + public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public void postProcessBeanDefinitionRegistry(@NonNull BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { + if (polarisConfigProperties.isAutoRefresh()) { + processPropertyValues(beanDefinitionRegistry); + } + } + private void doRegister(Object bean, String beanName, Member member, Value value) { Set keys = placeholderHelper.extractPlaceholderKeys(value.value()); if (keys.isEmpty()) { @@ -155,16 +175,13 @@ public class SpringValueProcessor extends PolarisProcessor implements BeanFactor private void processBeanPropertyValues(Object bean, String beanName) { Collection propertySpringValues = beanName2SpringValueDefinitions.get(beanName); - if (propertySpringValues.isEmpty()) { return; } for (SpringValueDefinition definition : propertySpringValues) { try { - PropertyDescriptor pd = BeanUtils - .getPropertyDescriptor(bean.getClass(), definition.getPropertyName()); - + PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(bean.getClass(), definition.getPropertyName()); if (pd != null) { Method method = pd.getWriteMethod(); if (method == null) { @@ -186,8 +203,47 @@ public class SpringValueProcessor extends PolarisProcessor implements BeanFactor beanName2SpringValueDefinitions.removeAll(beanName); } - @Override - public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; + private Multimap getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) { + Multimap springValueDefinitions = BEAN_DEFINITION_REGISTRY_MULTIMAP_CONCURRENT_MAP.remove(registry); + if (springValueDefinitions == null) { + springValueDefinitions = LinkedListMultimap.create(); + } + return springValueDefinitions; + } + + private void processPropertyValues(BeanDefinitionRegistry beanRegistry) { + if (!PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES.add(beanRegistry)) { + // already initialized + return; + } + + if (!BEAN_DEFINITION_REGISTRY_MULTIMAP_CONCURRENT_MAP.containsKey(beanRegistry)) { + BEAN_DEFINITION_REGISTRY_MULTIMAP_CONCURRENT_MAP.put(beanRegistry, LinkedListMultimap.create()); + } + + Multimap springValueDefinitions = BEAN_DEFINITION_REGISTRY_MULTIMAP_CONCURRENT_MAP.get(beanRegistry); + + String[] beanNames = beanRegistry.getBeanDefinitionNames(); + for (String beanName : beanNames) { + BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName); + MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues(); + List propertyValues = mutablePropertyValues.getPropertyValueList(); + for (PropertyValue propertyValue : propertyValues) { + Object value = propertyValue.getValue(); + if (!(value instanceof TypedStringValue)) { + continue; + } + String placeholder = ((TypedStringValue) value).getValue(); + Set keys = placeholderHelper.extractPlaceholderKeys(placeholder); + + if (keys.isEmpty()) { + continue; + } + + for (String key : keys) { + springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName())); + } + } + } } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java deleted file mode 100644 index c6682d517..000000000 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java +++ /dev/null @@ -1,126 +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.config.spring.property; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.LinkedListMultimap; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; -import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; - -import org.springframework.beans.BeansException; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.PropertyValue; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.TypedStringValue; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.lang.NonNull; - -/** - * To process xml config placeholders, e.g. - * - *
- *  <bean class="com.demo.bean.XmlBean">
- *    <property name="timeout" value="${timeout:200}"/>
- *    <property name="batch" value="${batch:100}"/>
- *  </bean>
- * 
- * - * This source file was originally from: - * - * SpringValueDefinitionProcessor - * - * @author weihubeats 2022-7-10 - */ -public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor { - private static final Map> beanName2SpringValueDefinitions = - Maps.newConcurrentMap(); - private static final Set PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet(); - - private final PlaceholderHelper placeholderHelper; - - private final PolarisConfigProperties polarisConfigProperties; - - public SpringValueDefinitionProcessor(PlaceholderHelper placeholderHelper, PolarisConfigProperties polarisConfigProperties) { - this.polarisConfigProperties = polarisConfigProperties; - this.placeholderHelper = placeholderHelper; - } - - @Override - public void postProcessBeanDefinitionRegistry(@NonNull BeanDefinitionRegistry registry) throws BeansException { - if (polarisConfigProperties.isAutoRefresh()) { - processPropertyValues(registry); - } - } - - @Override - public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException { - - } - - public static Multimap getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) { - Multimap springValueDefinitions = beanName2SpringValueDefinitions.get(registry); - if (springValueDefinitions == null) { - springValueDefinitions = LinkedListMultimap.create(); - } - - return springValueDefinitions; - } - - private void processPropertyValues(BeanDefinitionRegistry beanRegistry) { - if (!PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES.add(beanRegistry)) { - // already initialized - return; - } - - if (!beanName2SpringValueDefinitions.containsKey(beanRegistry)) { - beanName2SpringValueDefinitions.put(beanRegistry, LinkedListMultimap.create()); - } - - Multimap springValueDefinitions = beanName2SpringValueDefinitions.get(beanRegistry); - - String[] beanNames = beanRegistry.getBeanDefinitionNames(); - for (String beanName : beanNames) { - BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName); - MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues(); - List propertyValues = mutablePropertyValues.getPropertyValueList(); - for (PropertyValue propertyValue : propertyValues) { - Object value = propertyValue.getValue(); - if (!(value instanceof TypedStringValue)) { - continue; - } - String placeholder = ((TypedStringValue) value).getValue(); - Set keys = placeholderHelper.extractPlaceholderKeys(placeholder); - - if (keys.isEmpty()) { - continue; - } - - for (String key : keys) { - springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName())); - } - } - } - } -} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java index 99f1b9b14..b4bd33afd 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessorTest.java @@ -27,6 +27,7 @@ import java.util.Optional; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; import com.tencent.cloud.polaris.config.enums.RefreshType; +import com.tencent.cloud.polaris.config.spring.property.Person; import com.tencent.cloud.polaris.config.spring.property.SpringValue; import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; import com.tencent.polaris.api.utils.CollectionUtils; @@ -43,6 +44,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Component; /** @@ -138,6 +140,53 @@ public class SpringValueProcessorTest { }); } + @Test + public void xmlBeamDefinitionTest() { + ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(PolarisConfigBootstrapAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(RefreshAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(XMLBeamDefinitionTest.class)) + .withConfiguration(AutoConfigurations.of(PolarisConfigAutoConfiguration.class)) + .withPropertyValues("spring.application.name=" + "conditionalOnConfigReflectEnabledTest") + .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") + .withPropertyValues("spring.cloud.polaris.config.refresh-type=" + RefreshType.REFLECT) + .withPropertyValues("spring.cloud.polaris.config.enabled=true") + .withPropertyValues("name=test"); + contextRunner.run(context -> { + Person person = context.getBean(Person.class); + + SpringValueRegistry springValueRegistry = context.getBean(SpringValueRegistry.class); + BeanFactory beanFactory = person.getBeanFactory(); + Collection name = springValueRegistry.get(beanFactory, "name"); + Assert.assertFalse(CollectionUtils.isEmpty(name)); + Optional nameSpringValueOptional = name.stream().findAny(); + Assert.assertTrue(nameSpringValueOptional.isPresent()); + + SpringValue nameSpringValue = nameSpringValueOptional.get(); + Method method = nameSpringValue.getMethodParameter().getMethod(); + Assert.assertTrue(Objects.nonNull(method)); + Assert.assertEquals("setName", method.getName()); + Assert.assertEquals("${name:test}", nameSpringValue.getPlaceholder()); + Assert.assertFalse(nameSpringValue.isField()); + Assert.assertEquals(String.class, nameSpringValue.getTargetType()); + + + Collection age = springValueRegistry.get(beanFactory, "age"); + Assert.assertFalse(CollectionUtils.isEmpty(age)); + Optional ageSpringValueOptional = age.stream().findAny(); + Assert.assertTrue(ageSpringValueOptional.isPresent()); + + SpringValue ageSpringValue = ageSpringValueOptional.get(); + Method method1 = ageSpringValue.getMethodParameter().getMethod(); + Assert.assertTrue(Objects.nonNull(method1)); + Assert.assertEquals("setAge", method1.getName()); + Assert.assertEquals("${age:10}", ageSpringValue.getPlaceholder()); + Assert.assertFalse(ageSpringValue.isField()); + Assert.assertEquals(String.class, ageSpringValue.getTargetType()); + }); + + } + @Configuration @EnableAutoConfiguration static class PolarisConfigAutoConfiguration { @@ -173,4 +222,9 @@ public class SpringValueProcessorTest { ValueTest.name = name; } } + + @Configuration + @ImportResource("classpath:bean.xml") + static class XMLBeamDefinitionTest { + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessorTest.java deleted file mode 100644 index c82980a41..000000000 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessorTest.java +++ /dev/null @@ -1,75 +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.config.spring.property; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; - -import com.tencent.polaris.api.utils.CollectionUtils; -import org.junit.Assert; -import org.junit.Test; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * Test for {@link SpringValueDefinitionProcessor}. - * - * @author lingxiao.wlx - */ -public class SpringValueDefinitionProcessorTest { - - @Test - public void springValueDefinitionProcessorTest() { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); - Person person = context.getBean(Person.class); - - SpringValueRegistry springValueRegistry = context.getBean(SpringValueRegistry.class); - - BeanFactory beanFactory = person.getBeanFactory(); - Collection name = springValueRegistry.get(beanFactory, "name"); - Assert.assertFalse(CollectionUtils.isEmpty(name)); - Optional nameSpringValueOptional = name.stream().findAny(); - Assert.assertTrue(nameSpringValueOptional.isPresent()); - - SpringValue nameSpringValue = nameSpringValueOptional.get(); - Method method = nameSpringValue.getMethodParameter().getMethod(); - Assert.assertTrue(Objects.nonNull(method)); - Assert.assertEquals("setName", method.getName()); - Assert.assertEquals("${name:test}", nameSpringValue.getPlaceholder()); - Assert.assertFalse(nameSpringValue.isField()); - Assert.assertEquals(String.class, nameSpringValue.getTargetType()); - - - Collection age = springValueRegistry.get(beanFactory, "age"); - Assert.assertFalse(CollectionUtils.isEmpty(age)); - Optional ageSpringValueOptional = age.stream().findAny(); - Assert.assertTrue(ageSpringValueOptional.isPresent()); - - SpringValue ageSpringValue = ageSpringValueOptional.get(); - Method method1 = ageSpringValue.getMethodParameter().getMethod(); - Assert.assertTrue(Objects.nonNull(method1)); - Assert.assertEquals("setAge", method1.getName()); - Assert.assertEquals("${age:10}", ageSpringValue.getPlaceholder()); - Assert.assertFalse(ageSpringValue.isField()); - Assert.assertEquals(String.class, ageSpringValue.getTargetType()); - } -} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/resources/bean.xml b/spring-cloud-starter-tencent-polaris-config/src/test/resources/bean.xml index e60613a5a..e6484c467 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/resources/bean.xml +++ b/spring-cloud-starter-tencent-polaris-config/src/test/resources/bean.xml @@ -11,28 +11,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - 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 index 73d39dade..516d4294a 100644 --- 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 @@ -63,7 +63,7 @@ public class RateLimitRuleLabelResolverTest { } else { ModelProto.MatchString matchString = ModelProto.MatchString.newBuilder() - .setType(ModelProto.MatchString.MatchStringType.EXACT) + .setType(ModelProto.Operation.EXACT) .setValue(StringValue.of("value")) .setValueType(ModelProto.MatchString.ValueType.TEXT).build(); RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder() 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 7d8ed9b00..037169e8a 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 @@ -84,7 +84,7 @@ public class PolarisRateLimitRuleEndpointTests { } else { ModelProto.MatchString matchString = ModelProto.MatchString.newBuilder() - .setType(ModelProto.MatchString.MatchStringType.EXACT) + .setType(ModelProto.Operation.EXACT) .setValue(StringValue.of("value")) .setValueType(ModelProto.MatchString.ValueType.TEXT).build(); RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder() diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java index f254f0334..93d6434a0 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java @@ -22,6 +22,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.PolarisLoadBalancerClientFilter; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -59,9 +60,10 @@ public class LoadBalancerClientFilterBeanPostProcessor implements BeanPostProces 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 PolarisLoadBalancerClientFilter(loadBalancerClient, 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 b8b4d8608..67f2aff2a 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.PolarisCachingSpringLoadBalanceFactory; import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; @@ -48,8 +49,10 @@ 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); } @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 ed9766109..868d54b32 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 @@ -22,6 +22,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.LoadBalancerClientFilterBeanPostProcessor; import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor; @@ -113,8 +114,10 @@ public class RouterAutoConfiguration { @Order(HIGHEST_PRECEDENCE) public RouterContextFactory routerContextFactory(List routerLabelResolvers, StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver) { - return new RouterContextFactory(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver); + RouterRuleLabelResolver routerRuleLabelResolver, + PolarisContextProperties polarisContextProperties) { + return new RouterContextFactory(routerLabelResolvers, staticMetadataManager, + routerRuleLabelResolver, polarisContextProperties); } } 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 454a23c73..ed0453d63 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 @@ -84,6 +89,7 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered String peerServiceName = requestTemplate.feignTarget().name(); Set expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE, peerServiceName); + Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, expressionLabelKeys); labels.putAll(ruleExpressionLabels); @@ -103,8 +109,7 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered } // labels from downstream - Map transitiveLabels = MetadataContextHolder.get() - .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata(); labels.putAll(transitiveLabels); // pass label by header @@ -119,11 +124,20 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered } private Map getRuleExpressionLabels(RequestTemplate requestTemplate, Set labelKeys) { - if (CollectionUtils.isEmpty(labelKeys)) { 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/RouterContextFactory.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactory.java index 76aa4c407..deec96407 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactory.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactory.java @@ -28,7 +28,9 @@ 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.expresstion.ExpressionLabelUtils; import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -50,12 +52,15 @@ public class RouterContextFactory { private final List routerLabelResolvers; private final StaticMetadataManager staticMetadataManager; private final RouterRuleLabelResolver routerRuleLabelResolver; + private final PolarisContextProperties polarisContextProperties; public RouterContextFactory(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)); @@ -112,6 +117,16 @@ public class RouterContextFactory { 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/PolarisLoadBalancerClientFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java index 9133551b9..1574215cf 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java @@ -30,7 +30,9 @@ 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.expresstion.ExpressionLabelUtils; import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -59,16 +61,19 @@ public class PolarisLoadBalancerClientFilter extends LoadBalancerClientFilter { private final StaticMetadataManager staticMetadataManager; private final RouterRuleLabelResolver routerRuleLabelResolver; private final List routerLabelResolvers; + private final PolarisContextProperties polarisContextProperties; private final boolean isRibbonLoadBalanceClient; public PolarisLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties, StaticMetadataManager staticMetadataManager, RouterRuleLabelResolver routerRuleLabelResolver, - List routerLabelResolvers) { + List routerLabelResolvers, + PolarisContextProperties polarisContextProperties) { super(loadBalancer, properties); this.staticMetadataManager = staticMetadataManager; this.routerRuleLabelResolver = routerRuleLabelResolver; + this.polarisContextProperties = polarisContextProperties; if (!CollectionUtils.isEmpty(routerLabelResolvers)) { routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder)); @@ -140,6 +145,16 @@ public class PolarisLoadBalancerClientFilter extends LoadBalancerClientFilter { 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/FeignExpressionLabelUtilsTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java index fa9086d5d..66aa7e7bc 100644 --- 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 @@ -31,8 +31,7 @@ import org.springframework.util.StringUtils; /** * Test for {@link FeignExpressionLabelUtils}. - * - * @author lepdou 2022-05-26 + *@author lepdou 2022-05-26 */ public class FeignExpressionLabelUtilsTest { 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 8c54c3c57..ee589d637 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; @@ -45,7 +46,6 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -63,11 +63,14 @@ public class RouterLabelFeignInterceptorTest { private RouterRuleLabelResolver routerRuleLabelResolver; @Mock private FeignRouterLabelResolver routerLabelResolver; + @Mock + private PolarisContextProperties polarisContextProperties; @Test - public void testResolveRouterLabel() { + public void testResolveRouterLabel() throws UnsupportedEncodingException { RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor( - Collections.singletonList(routerLabelResolver), staticMetadataManager, routerRuleLabelResolver); + Collections.singletonList(routerLabelResolver), + staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); // mock request template RequestTemplate requestTemplate = new RequestTemplate(); @@ -90,7 +93,7 @@ public class RouterLabelFeignInterceptorTest { Map transitiveLabels = new HashMap<>(); transitiveLabels.put("k1", "v1"); transitiveLabels.put("k2", "v22"); - when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)).thenReturn(transitiveLabels); + when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels); // mock MetadataContextHolder#get try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { @@ -109,7 +112,6 @@ public class RouterLabelFeignInterceptorTest { customResolvedLabels.put("k3", "v3"); when(routerLabelResolver.resolve(requestTemplate, expressionKeys)).thenReturn(customResolvedLabels); - // mock local metadata Map localMetadata = new HashMap<>(); localMetadata.put("k3", "v31"); localMetadata.put("k4", "v4"); @@ -118,23 +120,17 @@ public class RouterLabelFeignInterceptorTest { routerLabelFeignInterceptor.apply(requestTemplate); Collection routerLabels = requestTemplate.headers().get(RouterConstant.ROUTER_LABEL_HEADER); - Map routerLabelsMap = new HashMap<>(); - try { - String routerLabelContent = routerLabels.stream().findFirst().get(); - routerLabelsMap.putAll(JacksonUtils.deserialize2Map( - URLDecoder.decode(routerLabelContent, UTF_8))); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException("unsupported charset exception " + UTF_8); - } - Assert.assertNotNull(routerLabelsMap); - for (String value : routerLabelsMap.values()) { - Assert.assertEquals("v1", routerLabelsMap.get("k1")); - Assert.assertEquals("v22", routerLabelsMap.get("k2")); - Assert.assertEquals("v3", routerLabelsMap.get("k3")); - Assert.assertEquals("v4", routerLabelsMap.get("k4")); - Assert.assertEquals(headerUidValue, routerLabelsMap.get("${http.header.uid}")); - Assert.assertEquals("", routerLabelsMap.get("${http.header.name}")); + + Assert.assertNotNull(routerLabels); + for (String value : routerLabels) { + Map labels = JacksonUtils.deserialize2Map(URLDecoder.decode(value, "UTF-8")); + + Assert.assertEquals("v1", labels.get("k1")); + Assert.assertEquals("v22", labels.get("k2")); + Assert.assertEquals("v3", labels.get("k3")); + Assert.assertEquals("v4", labels.get("k4")); + Assert.assertEquals(headerUidValue, labels.get("${http.header.uid}")); + Assert.assertEquals("", labels.get("${http.header.name}")); } } } 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 6152db7ee..91fd0d926 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 @@ -29,6 +29,7 @@ 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.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -62,6 +63,8 @@ public class RouterContextFactoryTest { private StaticMetadataManager staticMetadataManager; @Mock private RouterRuleLabelResolver routerRuleLabelResolver; + @Mock + private PolarisContextProperties polarisContextProperties; @Test public void testRouterContext() { @@ -103,7 +106,7 @@ public class RouterContextFactoryTest { mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); RouterContextFactory routerContextFactory = new RouterContextFactory(Arrays.asList(springWebRouterLabelResolver), - staticMetadataManager, routerRuleLabelResolver); + staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); PolarisRouterContext routerContext = routerContextFactory.create(request, null, calleeService); diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java index 098dc2db3..34920cc3b 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java @@ -30,6 +30,7 @@ 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.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; @@ -78,6 +79,8 @@ public class PolarisLoadBalancerClientFilterTest { private LoadBalancerClient loadBalancerClient; @Mock private LoadBalancerProperties loadBalancerProperties; + @Mock + private PolarisContextProperties polarisContextProperties; @BeforeClass public static void beforeClass() { @@ -107,7 +110,7 @@ public class PolarisLoadBalancerClientFilterTest { public void testGenRouterContext() { PolarisLoadBalancerClientFilter polarisLoadBalancerClientFilter = new PolarisLoadBalancerClientFilter( loadBalancerClient, loadBalancerProperties, staticMetadataManager, routerRuleLabelResolver, - Lists.newArrayList(routerLabelResolver)); + Lists.newArrayList(routerLabelResolver), polarisContextProperties); Map localMetadata = new HashMap<>(); localMetadata.put("env", "blue"); @@ -140,7 +143,7 @@ public class PolarisLoadBalancerClientFilterTest { public void testChooseInstanceWithoutRibbon() { PolarisLoadBalancerClientFilter polarisLoadBalancerClientFilter = new PolarisLoadBalancerClientFilter( loadBalancerClient, loadBalancerProperties, staticMetadataManager, routerRuleLabelResolver, - Lists.newArrayList(routerLabelResolver)); + Lists.newArrayList(routerLabelResolver), polarisContextProperties); String url = "/" + calleeService + "/users"; MockServerHttpRequest request = MockServerHttpRequest.get(url) @@ -162,7 +165,7 @@ public class PolarisLoadBalancerClientFilterTest { PolarisLoadBalancerClientFilter polarisLoadBalancerClientFilter = new PolarisLoadBalancerClientFilter( ribbonLoadBalancerClient, 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/metadata/MetadataContext.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java index f8078c398..510d3f69d 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 @@ -19,6 +19,7 @@ package com.tencent.cloud.common.metadata; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -112,6 +113,64 @@ public class MetadataContext { this.fragmentContexts = new ConcurrentHashMap<>(); } + + public Map getDisposableMetadata() { + return this.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + } + + public Map getTransitiveMetadata() { + return this.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + } + + public Map getCustomMetadata() { + Map transitiveMetadata = this.getTransitiveMetadata(); + Map disposableMetadata = this.getDisposableMetadata(); + Map customMetadata = new HashMap<>(); + // Clean up one-time metadata coming from upstream . + transitiveMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + customMetadata.put(key, value); + } + }); + return Collections.unmodifiableMap(customMetadata); + } + + public Map getTransHeaders() { + return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS); + } + + public Map getTransHeadersKV() { + return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV); + } + + public Map getLoadbalancerMetadata() { + return this.getFragmentContext(FRAGMENT_LOAD_BALANCER); + } + + public void setTransitiveMetadata(Map transitiveMetadata) { + this.putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); + } + + public void setDisposableMetadata(Map disposableMetadata) { + this.putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); + } + + public void setUpstreamDisposableMetadata(Map upstreamDisposableMetadata) { + this.putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); + } + + public void setTransHeadersKV(String key, String value) { + this.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, String value) { + this.putContext(FRAGMENT_LOAD_BALANCER, key, value); + } + public Map getFragmentContext(String fragment) { Map fragmentContext = fragmentContexts.get(fragment); if (fragmentContext == null) { 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 e0dbd2d9b..60983ef69 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -13,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.metadata; @@ -44,6 +43,7 @@ public final class MetadataContextHolder { private static final ThreadLocal METADATA_CONTEXT = new InheritableThreadLocal<>(); private static MetadataLocalProperties metadataLocalProperties; + private static StaticMetadataManager staticMetadataManager; private MetadataContextHolder() { 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 4342a5483..9fb1038c8 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 @@ -18,7 +18,9 @@ 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,67 +35,105 @@ import org.springframework.util.CollectionUtils; */ public final class ExpressionLabelUtils { - /** - * the prefix of expression. - */ - public static final String LABEL_PREFIX = "${"; - /** - * 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 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..a5f28e8fd --- /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 expression.substring(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 expression.substring(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 expression.substring(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/metadata/MetadataContextHolderTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java index a7214b03c..bda0535b6 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java @@ -13,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.metadata; @@ -47,10 +46,10 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "2"); MetadataContext metadataContext = MetadataContextHolder.get(); - metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, customMetadata); + metadataContext.setTransitiveMetadata(customMetadata); MetadataContextHolder.set(metadataContext); - customMetadata = MetadataContextHolder.get().getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + customMetadata = MetadataContextHolder.get().getTransitiveMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("2"); @@ -62,7 +61,7 @@ public class MetadataContextHolderTest { customMetadata.put("c", "3"); MetadataContextHolder.init(customMetadata, new HashMap<>()); metadataContext = MetadataContextHolder.get(); - customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + customMetadata = metadataContext.getTransitiveMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("22"); Assertions.assertThat(customMetadata.get("c")).isEqualTo("3"); diff --git a/spring-cloud-tencent-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 4369acad8..a7cb056b3 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..ae55900f1 --- /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..38d4a6617 --- /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 1acef11f1..6d8c0f41d 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,8 +70,8 @@ - 1.8.0-Hoxton.SR12-SNAPSHOT - 1.9.1 + 1.9.0-Hoxton.SR12-SNAPSHOT + 1.10.0-SNAPSHOT 1.2.11 4.5.1 1.12.10 diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java index 7da621e81..9ee58a04a 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java @@ -55,7 +55,7 @@ public class MetadataBackendController { // Get Custom Metadata From Context MetadataContext context = MetadataContextHolder.get(); - Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map customMetadataMap = context.getTransitiveMetadata(); customMetadataMap.forEach((key, value) -> { LOG.info("Metadata Backend Custom Metadata (Key-Value): {} : {}", key, value); diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java index 3d107f555..20ca8ae3a 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java @@ -69,7 +69,7 @@ public class MetadataFrontendController { // Get Custom Metadata From Context MetadataContext context = MetadataContextHolder.get(); - Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map customMetadataMap = context.getTransitiveMetadata(); customMetadataMap.forEach((key, value) -> { LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); @@ -116,7 +116,7 @@ public class MetadataFrontendController { // Get Custom Metadata From Context MetadataContext context = MetadataContextHolder.get(); - Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map customMetadataMap = context.getTransitiveMetadata(); customMetadataMap.forEach((key, value) -> { LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java index 7ea673a50..18f075e2f 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java @@ -92,7 +92,7 @@ public class MetadataMiddleController { // Get Custom Metadata From Context MetadataContext context = MetadataContextHolder.get(); - Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map customMetadataMap = context.getTransitiveMetadata(); customMetadataMap.forEach((key, value) -> { LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml index 24efc40c0..1d9887427 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml @@ -34,6 +34,11 @@ spring-cloud-tencent-gateway-plugin + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + + com.tencent.cloud spring-cloud-tencent-featureenv-plugin diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilter.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilter.java index c6ddfd457..e81dec91a 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilter.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/main/java/com/tencent/cloud/plugin/gateway/staining/TrafficStainingGatewayFilter.java @@ -77,13 +77,13 @@ public class TrafficStainingGatewayFilter implements GlobalFilter, Ordered { metadataContext = MetadataContextHolder.get(); } - Map oldTransitiveMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map oldTransitiveMetadata = metadataContext.getTransitiveMetadata(); // append new transitive metadata Map newTransitiveMetadata = new HashMap<>(oldTransitiveMetadata); newTransitiveMetadata.putAll(stainedLabels); - metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, newTransitiveMetadata); + metadataContext.setTransitiveMetadata(newTransitiveMetadata); }).build(); return chain.filter(exchange.mutate().request(request).build()); 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..ef2111e70 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 @@ -100,7 +100,8 @@ public class PolarisContextProperties { if (StringUtils.isNotBlank(localIpAddress)) { return localIpAddress; } - return environment.getProperty("spring.cloud.client.ip-address"); + this.localIpAddress = environment.getProperty("spring.cloud.client.ip-address"); + return this.localIpAddress; } public String getAddress() { @@ -111,11 +112,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; } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java index ed2f02058..021ba7268 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java @@ -115,8 +115,7 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter private void reportResult(URI url, ClientHttpResponse response) { ServiceCallResult resultRequest = createServiceCallResult(url); try { - Map loadBalancerContext = MetadataContextHolder.get() - .getFragmentContext(MetadataContext.FRAGMENT_LOAD_BALANCER); + Map loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata(); String targetHost = loadBalancerContext.get("host"); String targetPort = loadBalancerContext.get("port"); @@ -134,7 +133,7 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter resultRequest.setRetStatus(RetStatus.RetFail); } - List labels = response.getHeaders().get(RouterConstant.ROUTER_LABELS); + List labels = response.getHeaders().get(RouterConstant.ROUTER_LABEL_HEADER); if (CollectionUtils.isNotEmpty(labels)) { String label = labels.get(0); try { diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java index 7372ecebb..581c2d098 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java @@ -61,7 +61,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** - * Test for {@link EnhancedRestTemplateReporter} + * Test for {@link EnhancedRestTemplateReporter}. * @author lepdou 2022-09-06 */ @RunWith(MockitoJUnitRunner.class) @@ -91,7 +91,7 @@ public class EnhancedRestTemplateReporterTest { Map loadBalancerContext = new HashMap<>(); loadBalancerContext.put("host", "1.1.1.1"); loadBalancerContext.put("port", "8080"); - when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_LOAD_BALANCER)).thenReturn(loadBalancerContext); + when(metadataContext.getLoadbalancerMetadata()).thenReturn(loadBalancerContext); mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class); mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); @@ -129,7 +129,7 @@ public class EnhancedRestTemplateReporterTest { URI uri = mock(URI.class); String labels = URLEncoder.encode("{\"k1\":\"v1\",\"k2\":\"v2\"}", UTF_8); - response.getHeaders().set(RouterConstant.ROUTER_LABELS, labels); + response.getHeaders().set(RouterConstant.ROUTER_LABEL_HEADER, labels); enhancedRestTemplateReporter.handleError(uri, HttpMethod.GET, response); verify(consumerAPI, times(2)).updateServiceCallResult((ServiceCallResult) captor.capture());