Merge branch 'Tencent:hoxton' into hoxton

pull/687/head
DerekYRC 3 years ago committed by GitHub
commit 32fa5864f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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

@ -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)

@ -70,7 +70,7 @@ Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId>
<!--version number-->
<version>1.7.1-Hoxton.SR12</version>
<version>1.8.1-Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>

@ -72,7 +72,7 @@ For example:
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId>
<!--version number-->
<version>1.7.1-Hoxton.SR12</version>
<version>1.8.1-Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>

@ -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)

@ -89,7 +89,7 @@
<properties>
<!-- Project revision -->
<revision>1.8.0-Hoxton.SR12-SNAPSHOT</revision>
<revision>1.9.0-Hoxton.SR12-SNAPSHOT</revision>
<!-- Spring Cloud -->
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>

@ -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<Void> filter(ServerWebExchange serverWebExchange,
WebFilterChain webFilterChain) {
public Mono<Void> 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<String, String> 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<String> headerKeys = headers.keySet();
Iterator<String> iterator = headerKeys.iterator();
while (iterator.hasNext()) {
String httpHeader = iterator.next();
Arrays.stream(transHeaderArray).forEach(transHeader -> {
if (transHeader.equals(httpHeader)) {
List<String> list = headers.get(httpHeader);
String httpHeaderValue = JacksonUtils.serialize2Json(list);
MetadataContextHolder.get()
.putContext(FRAGMENT_RAW_TRANSHEADERS_KV, httpHeader, httpHeaderValue);
}
});
}
}
}
private Map<String, String> getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) {
HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
String customMetadataStr = httpHeaders.getFirst(headerName);

@ -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<String, String> transHeaderMetadata = MetadataContextHolder.get()
.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS);
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse("");
String[] transHeaderArray = transHeaders.split(",");
Enumeration<String> 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();
}
}

@ -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<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
Map<String, String> transHeaders = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV);
Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
Map<String, String> transHeaders = metadataContext.getTransHeadersKV();
// Clean up one-time metadata coming from upstream .
Map<String, String> 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);

@ -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<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
Map<String, String> transHeaders = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV);
Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
Map<String, String> transHeaders = metadataContext.getTransHeadersKV();
Map<String, String> 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);

@ -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<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
// Clean upstream disposable metadata.
Map<String, String> 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<String, String> 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<String> headerKeys = headers.keySet();
Iterator<String> iterator = headerKeys.iterator();
while (iterator.hasNext()) {
String httpHeader = iterator.next();
Arrays.stream(transHeaderArray).forEach(transHeader -> {
if (transHeader.equals(httpHeader)) {
List<String> 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}

@ -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<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
// Clean upstream disposable metadata.
Map<String, String> newestCustomMetadata = new HashMap<>();
customMetadata.forEach((key, value) -> {
if (!disposableMetadata.containsKey(key)) {
newestCustomMetadata.put(key, value);
}
});
Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> 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<String, String> transHeaderMetadata = MetadataContextHolder.get()
.getFragmentContext(FRAGMENT_RAW_TRANSHEADERS);
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse("");
String[] transHeaderArray = transHeaders.split(",");
Enumeration<String> 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} .
*

@ -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<String, String> transHeaderMetadata = MetadataContextHolder.get().getTransHeaders();
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse("");
String[] transHeaderArray = transHeaders.split(",");
Enumeration<String> 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<String, String> transHeaderMetadata = MetadataContextHolder.get().getTransHeaders();
if (!CollectionUtils.isEmpty(transHeaderMetadata)) {
String transHeaders = transHeaderMetadata.keySet().stream().findFirst().orElse("");
String[] transHeaderArray = transHeaders.split(",");
HttpHeaders headers = serverHttpRequest.getHeaders();
Set<String> headerKeys = headers.keySet();
for (String httpHeader : headerKeys) {
Arrays.stream(transHeaderArray).forEach(transHeader -> {
if (transHeader.equals(httpHeader)) {
List<String> list = headers.get(httpHeader);
String httpHeaderValue = JacksonUtils.serialize2Json(list);
// for example, {"trans-headers-kv" : {"header1":"v1","header2":"v2"...}}
MetadataContextHolder.get().setTransHeadersKV(httpHeader, httpHeaderValue);
}
});
}
}
}
}

@ -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<String, String> 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<String, String> 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));
}
}

@ -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<BeanDefinitionRegistry> PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet();
private static final Map<BeanDefinitionRegistry, Multimap<String, SpringValueDefinition>> 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<String> 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<SpringValueDefinition> 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<String, SpringValueDefinition> getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) {
Multimap<String, SpringValueDefinition> 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<String, SpringValueDefinition> 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<PropertyValue> propertyValues = mutablePropertyValues.getPropertyValueList();
for (PropertyValue propertyValue : propertyValues) {
Object value = propertyValue.getValue();
if (!(value instanceof TypedStringValue)) {
continue;
}
String placeholder = ((TypedStringValue) value).getValue();
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
if (keys.isEmpty()) {
continue;
}
for (String key : keys) {
springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName()));
}
}
}
}
}

@ -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.
*
* <pre>
* &lt;bean class=&quot;com.demo.bean.XmlBean&quot;&gt;
* &lt;property name=&quot;timeout&quot; value=&quot;${timeout:200}&quot;/&gt;
* &lt;property name=&quot;batch&quot; value=&quot;${batch:100}&quot;/&gt;
* &lt;/bean&gt;
* </pre>
*
* This source file was originally from:
* <code><a href=https://github.com/apolloconfig/apollo/blob/master/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueDefinitionProcessor.java>
* SpringValueDefinitionProcessor</a></code>
*
* @author weihubeats 2022-7-10
*/
public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {
private static final Map<BeanDefinitionRegistry, Multimap<String, SpringValueDefinition>> beanName2SpringValueDefinitions =
Maps.newConcurrentMap();
private static final Set<BeanDefinitionRegistry> 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<String, SpringValueDefinition> getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) {
Multimap<String, SpringValueDefinition> 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<String, SpringValueDefinition> springValueDefinitions = beanName2SpringValueDefinitions.get(beanRegistry);
String[] beanNames = beanRegistry.getBeanDefinitionNames();
for (String beanName : beanNames) {
BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName);
MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues();
List<PropertyValue> propertyValues = mutablePropertyValues.getPropertyValueList();
for (PropertyValue propertyValue : propertyValues) {
Object value = propertyValue.getValue();
if (!(value instanceof TypedStringValue)) {
continue;
}
String placeholder = ((TypedStringValue) value).getValue();
Set<String> keys = placeholderHelper.extractPlaceholderKeys(placeholder);
if (keys.isEmpty()) {
continue;
}
for (String key : keys) {
springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName()));
}
}
}
}
}

@ -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<SpringValue> name = springValueRegistry.get(beanFactory, "name");
Assert.assertFalse(CollectionUtils.isEmpty(name));
Optional<SpringValue> 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<SpringValue> age = springValueRegistry.get(beanFactory, "age");
Assert.assertFalse(CollectionUtils.isEmpty(age));
Optional<SpringValue> 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 {
}
}

@ -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<SpringValue> name = springValueRegistry.get(beanFactory, "name");
Assert.assertFalse(CollectionUtils.isEmpty(name));
Optional<SpringValue> 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<SpringValue> age = springValueRegistry.get(beanFactory, "age");
Assert.assertFalse(CollectionUtils.isEmpty(age));
Optional<SpringValue> 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());
}
}

@ -11,28 +11,4 @@
<property name="name" value="${name:test}"/>
<property name="age" value="${age:10}"/>
</bean>
<!--SpringValueDefinitionProcessor to process xml config placeholders -->
<bean class="com.tencent.cloud.polaris.config.spring.property.SpringValueDefinitionProcessor">
<constructor-arg index="0" ref="helper"/>
<constructor-arg index="1" ref="polarisConfigProperties"/>
</bean>
<!--Placeholder helper functions -->
<bean id="helper" class="com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper"/>
<!--PolarisConfigProperties -->
<bean id="polarisConfigProperties" class="com.tencent.cloud.polaris.config.config.PolarisConfigProperties">
<property name="autoRefresh" value="true"/>
</bean>
<!--springValueRegistry -->
<bean id="springValueRegistry" class="com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry"/>
<!--Spring value processor of method -->
<bean class="com.tencent.cloud.polaris.config.spring.annotation.SpringValueProcessor">
<constructor-arg index="0" ref="helper"/>
<constructor-arg index="1" ref="springValueRegistry"/>
<constructor-arg index="2" ref="polarisConfigProperties"/>
</bean>
</beans>

@ -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()

@ -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()

@ -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<SpringWebRouterLabelResolver> 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;
}

@ -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<FeignRouterLabelResolver> routerLabelResolvers,
StaticMetadataManager staticMetadataManager,
RouterRuleLabelResolver routerRuleLabelResolver) {
return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver);
RouterRuleLabelResolver routerRuleLabelResolver,
PolarisContextProperties polarisContextProperties) {
return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager,
routerRuleLabelResolver, polarisContextProperties);
}
@Bean

@ -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<SpringWebRouterLabelResolver> routerLabelResolvers,
StaticMetadataManager staticMetadataManager,
RouterRuleLabelResolver routerRuleLabelResolver) {
return new RouterContextFactory(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver);
RouterRuleLabelResolver routerRuleLabelResolver,
PolarisContextProperties polarisContextProperties) {
return new RouterContextFactory(routerLabelResolvers, staticMetadataManager,
routerRuleLabelResolver, polarisContextProperties);
}
}

@ -49,24 +49,24 @@ public final class FeignExpressionLabelUtils {
Map<String, String> 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());
}

@ -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<FeignRouterLabelResolver> routerLabelResolvers;
private final StaticMetadataManager staticMetadataManager;
private final RouterRuleLabelResolver routerRuleLabelResolver;
private final PolarisContextProperties polarisContextProperties;
public RouterLabelFeignInterceptor(List<FeignRouterLabelResolver> 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<String> expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE, peerServiceName);
Map<String, String> ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, expressionLabelKeys);
labels.putAll(ruleExpressionLabels);
@ -103,8 +109,7 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered
}
// labels from downstream
Map<String, String> transitiveLabels = MetadataContextHolder.get()
.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata();
labels.putAll(transitiveLabels);
// pass label by header
@ -119,11 +124,20 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered
}
private Map<String, String> getRuleExpressionLabels(RequestTemplate requestTemplate, Set<String> labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
}
return FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys);
//enrich labels from request
Map<String, String> labels = FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys);
//enrich caller ip label
for (String labelKey : labelKeys) {
if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) {
labels.put(labelKey, polarisContextProperties.getLocalIpAddress());
}
}
return labels;
}
}

@ -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<SpringWebRouterLabelResolver> routerLabelResolvers;
private final StaticMetadataManager staticMetadataManager;
private final RouterRuleLabelResolver routerRuleLabelResolver;
private final PolarisContextProperties polarisContextProperties;
public RouterContextFactory(List<SpringWebRouterLabelResolver> 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<String, String> labels = SpringWebExpressionLabelUtils.resolve(request, labelKeys);
//enrich caller ip label
for (String labelKey : labelKeys) {
if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) {
labels.put(labelKey, polarisContextProperties.getLocalIpAddress());
}
}
return labels;
}
}

@ -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<SpringWebRouterLabelResolver> routerLabelResolvers;
private final PolarisContextProperties polarisContextProperties;
private final boolean isRibbonLoadBalanceClient;
public PolarisLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties,
StaticMetadataManager staticMetadataManager,
RouterRuleLabelResolver routerRuleLabelResolver,
List<SpringWebRouterLabelResolver> routerLabelResolvers) {
List<SpringWebRouterLabelResolver> 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<String, String> labels = SpringWebExpressionLabelUtils.resolve(exchange, labelKeys);
//enrich caller ip label
for (String labelKey : labelKeys) {
if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) {
labels.put(labelKey, polarisContextProperties.getLocalIpAddress());
}
}
return labels;
}
}

@ -84,12 +84,12 @@ public class RouterRuleLabelResolverTest {
Set<String> 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));
}
}

@ -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 {

@ -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<String, String> 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<MetadataContextHolder> 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<String, String> localMetadata = new HashMap<>();
localMetadata.put("k3", "v31");
localMetadata.put("k4", "v4");
@ -118,23 +120,17 @@ public class RouterLabelFeignInterceptorTest {
routerLabelFeignInterceptor.apply(requestTemplate);
Collection<String> routerLabels = requestTemplate.headers().get(RouterConstant.ROUTER_LABEL_HEADER);
Map<String, String> 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<String, String> 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}"));
}
}
}

@ -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);

@ -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<String, String> 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<String, String> localMetadata = new HashMap<>();
localMetadata.put("env", "blue");

@ -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<String, String> getDisposableMetadata() {
return this.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE);
}
public Map<String, String> getTransitiveMetadata() {
return this.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
}
public Map<String, String> getCustomMetadata() {
Map<String, String> transitiveMetadata = this.getTransitiveMetadata();
Map<String, String> disposableMetadata = this.getDisposableMetadata();
Map<String, String> 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<String, String> getTransHeaders() {
return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS);
}
public Map<String, String> getTransHeadersKV() {
return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV);
}
public Map<String, String> getLoadbalancerMetadata() {
return this.getFragmentContext(FRAGMENT_LOAD_BALANCER);
}
public void setTransitiveMetadata(Map<String, String> transitiveMetadata) {
this.putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata));
}
public void setDisposableMetadata(Map<String, String> disposableMetadata) {
this.putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata));
}
public void setUpstreamDisposableMetadata(Map<String, String> 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<String, String> getFragmentContext(String fragment) {
Map<String, String> fragmentContext = fragmentContexts.get(fragment);
if (fragmentContext == null) {

@ -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<MetadataContext> METADATA_CONTEXT = new InheritableThreadLocal<>();
private static MetadataLocalProperties metadataLocalProperties;
private static StaticMetadataManager staticMetadataManager;
private MetadataContextHolder() {

@ -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<ExpressionParser> 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) {

@ -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);
}

@ -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);
}
}

@ -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);
}
}

@ -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());
}
}

@ -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());
}
}

@ -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");

@ -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));
}

@ -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));
}
}

@ -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"));
}
}

@ -70,8 +70,8 @@
</developers>
<properties>
<revision>1.8.0-Hoxton.SR12-SNAPSHOT</revision>
<polaris.version>1.9.1</polaris.version>
<revision>1.9.0-Hoxton.SR12-SNAPSHOT</revision>
<polaris.version>1.10.0-SNAPSHOT</polaris.version>
<logback.version>1.2.11</logback.version>
<mocktio.version>4.5.1</mocktio.version>
<byte-buddy.version>1.12.10</byte-buddy.version>

@ -55,7 +55,7 @@ public class MetadataBackendController {
// Get Custom Metadata From Context
MetadataContext context = MetadataContextHolder.get();
Map<String, String> customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> customMetadataMap = context.getTransitiveMetadata();
customMetadataMap.forEach((key, value) -> {
LOG.info("Metadata Backend Custom Metadata (Key-Value): {} : {}", key, value);

@ -69,7 +69,7 @@ public class MetadataFrontendController {
// Get Custom Metadata From Context
MetadataContext context = MetadataContextHolder.get();
Map<String, String> customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> 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<String, String> customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> customMetadataMap = context.getTransitiveMetadata();
customMetadataMap.forEach((key, value) -> {
LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value);

@ -92,7 +92,7 @@ public class MetadataMiddleController {
// Get Custom Metadata From Context
MetadataContext context = MetadataContextHolder.get();
Map<String, String> customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> customMetadataMap = context.getTransitiveMetadata();
customMetadataMap.forEach((key, value) -> {
LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value);

@ -34,6 +34,11 @@
<artifactId>spring-cloud-tencent-gateway-plugin</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-featureenv-plugin</artifactId>

@ -77,13 +77,13 @@ public class TrafficStainingGatewayFilter implements GlobalFilter, Ordered {
metadataContext = MetadataContextHolder.get();
}
Map<String, String> oldTransitiveMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> oldTransitiveMetadata = metadataContext.getTransitiveMetadata();
// append new transitive metadata
Map<String, String> 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());

@ -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;
}

@ -115,8 +115,7 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter
private void reportResult(URI url, ClientHttpResponse response) {
ServiceCallResult resultRequest = createServiceCallResult(url);
try {
Map<String, String> loadBalancerContext = MetadataContextHolder.get()
.getFragmentContext(MetadataContext.FRAGMENT_LOAD_BALANCER);
Map<String, String> 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<String> labels = response.getHeaders().get(RouterConstant.ROUTER_LABELS);
List<String> labels = response.getHeaders().get(RouterConstant.ROUTER_LABEL_HEADER);
if (CollectionUtils.isNotEmpty(labels)) {
String label = labels.get(0);
try {

@ -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<String, String> 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());

Loading…
Cancel
Save