feat:support TSF router. (#1403)

Co-authored-by: Haotian Zhang <skyebefreeman@qq.com>
pull/1404/head
Fishtail 3 months ago committed by GitHub
parent 775b66cecb
commit 4487317354
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -24,3 +24,4 @@
- [fix: memory cost too many when using wildcard feign calls](https://github.com/Tencent/spring-cloud-tencent/pull/1400) - [fix: memory cost too many when using wildcard feign calls](https://github.com/Tencent/spring-cloud-tencent/pull/1400)
- [feat:support consul config data.](https://github.com/Tencent/spring-cloud-tencent/pull/1401) - [feat:support consul config data.](https://github.com/Tencent/spring-cloud-tencent/pull/1401)
- [feat: support otel trace](https://github.com/Tencent/spring-cloud-tencent/pull/1402) - [feat: support otel trace](https://github.com/Tencent/spring-cloud-tencent/pull/1402)
- [feat:support TSF router.](https://github.com/Tencent/spring-cloud-tencent/pull/1403)

@ -28,6 +28,7 @@ import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -39,8 +40,10 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL_IP;
/** /**
* Filter used for storing the metadata from upstream temporarily when web application is * Filter used for storing the metadata from upstream temporarily when web application is
@ -50,9 +53,8 @@ import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUST
*/ */
public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered { public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered {
private PolarisContextProperties polarisContextProperties;
private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class); private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class);
private PolarisContextProperties polarisContextProperties;
public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) { public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) {
this.polarisContextProperties = polarisContextProperties; this.polarisContextProperties = polarisContextProperties;
@ -67,16 +69,34 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
// Get metadata string from http header. // Get metadata string from http header.
ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest();
Map<String, String> internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA);
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange);
// transitive metadata
// from specific header
Map<String, String> internalTransitiveMetadata = getInternalMetadata(serverHttpRequest, CUSTOM_METADATA);
// from header with specific prefix
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange);
Map<String, String> mergedTransitiveMetadata = new HashMap<>(); Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(internalTransitiveMetadata);
mergedTransitiveMetadata.putAll(customTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata);
Map<String, String> internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA);
// disposable metadata
// from specific header
Map<String, String> internalDisposableMetadata = getInternalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA);
Map<String, String> mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); Map<String, String> mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata);
ReactiveMetadataProvider metadataProvider = new ReactiveMetadataProvider(serverHttpRequest, polarisContextProperties.getLocalIpAddress());
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); // application metadata
Map<String, String> internalApplicationMetadata = getInternalMetadata(serverHttpRequest, APPLICATION_METADATA);
Map<String, String> mergedApplicationMetadata = new HashMap<>(internalApplicationMetadata);
String callerIp = "";
if (StringUtils.isNotBlank(mergedApplicationMetadata.get(LOCAL_IP))) {
callerIp = mergedApplicationMetadata.get(LOCAL_IP);
}
// message metadata
ReactiveMetadataProvider callerMessageMetadataProvider = new ReactiveMetadataProvider(serverHttpRequest, callerIp);
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider);
// Save to ServerWebExchange. // Save to ServerWebExchange.
serverWebExchange.getAttributes().put( serverWebExchange.getAttributes().put(
MetadataConstant.HeaderName.METADATA_CONTEXT, MetadataConstant.HeaderName.METADATA_CONTEXT,
@ -90,7 +110,7 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
.doFinally((type) -> MetadataContextHolder.remove()); .doFinally((type) -> MetadataContextHolder.remove());
} }
private Map<String, String> getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { private Map<String, String> getInternalMetadata(ServerHttpRequest serverHttpRequest, String headerName) {
HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
String customMetadataStr = UrlUtils.decode(httpHeaders.getFirst(headerName)); String customMetadataStr = UrlUtils.decode(httpHeaders.getFirst(headerName));
LOG.debug("Get upstream metadata string: {}", customMetadataStr); LOG.debug("Get upstream metadata string: {}", customMetadataStr);

@ -33,6 +33,7 @@ import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.metadata.provider.ServletMetadataProvider; import com.tencent.cloud.metadata.provider.ServletMetadataProvider;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -40,8 +41,10 @@ import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL_IP;
/** /**
* Filter used for storing the metadata from upstream temporarily when web application is * Filter used for storing the metadata from upstream temporarily when web application is
@ -64,16 +67,32 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest,
@NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
// transitive metadata
// from specific header
Map<String, String> internalTransitiveMetadata = getInternalMetadata(httpServletRequest, CUSTOM_METADATA); Map<String, String> internalTransitiveMetadata = getInternalMetadata(httpServletRequest, CUSTOM_METADATA);
// from header with specific prefix
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest); Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest);
Map<String, String> mergedTransitiveMetadata = new HashMap<>(); Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(internalTransitiveMetadata);
mergedTransitiveMetadata.putAll(customTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata);
// disposable metadata
// from specific header
Map<String, String> internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); Map<String, String> internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA);
Map<String, String> mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); Map<String, String> mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata);
ServletMetadataProvider metadataProvider = new ServletMetadataProvider(httpServletRequest, polarisContextProperties.getLocalIpAddress());
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); // application metadata
Map<String, String> internalApplicationMetadata = getInternalMetadata(httpServletRequest, APPLICATION_METADATA);
Map<String, String> mergedApplicationMetadata = new HashMap<>(internalApplicationMetadata);
String callerIp = "";
if (StringUtils.isNotBlank(mergedApplicationMetadata.get(LOCAL_IP))) {
callerIp = mergedApplicationMetadata.get(LOCAL_IP);
}
// message metadata
ServletMetadataProvider callerMessageMetadataProvider = new ServletMetadataProvider(httpServletRequest, callerIp);
MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider);
TransHeadersTransfer.transfer(httpServletRequest); TransHeadersTransfer.transfer(httpServletRequest);

@ -39,6 +39,7 @@ import feign.Request;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
@ -64,6 +65,7 @@ public class EncodeTransferMedataFeignEnhancedPlugin implements EnhancedPlugin {
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> customMetadata = metadataContext.getCustomMetadata(); Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata(); Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
Map<String, String> applicationMetadata = metadataContext.getApplicationMetadata();
Map<String, String> transHeaders = metadataContext.getTransHeadersKV(); Map<String, String> transHeaders = metadataContext.getTransHeadersKV();
MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false);
@ -77,6 +79,9 @@ public class EncodeTransferMedataFeignEnhancedPlugin implements EnhancedPlugin {
// process custom metadata // process custom metadata
this.buildMetadataHeader(request, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(request, customMetadata, CUSTOM_METADATA);
// add application metadata
this.buildMetadataHeader(request, applicationMetadata, APPLICATION_METADATA);
// set headers that need to be transmitted from the upstream // set headers that need to be transmitted from the upstream
this.buildTransmittedHeader(request, transHeaders); this.buildTransmittedHeader(request, transHeaders);
} }

@ -35,6 +35,7 @@ import com.tencent.polaris.metadata.core.MetadataType;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
@ -60,6 +61,7 @@ public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedP
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> customMetadata = metadataContext.getCustomMetadata(); Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata(); Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
Map<String, String> applicationMetadata = metadataContext.getApplicationMetadata();
Map<String, String> transHeaders = metadataContext.getTransHeadersKV(); Map<String, String> transHeaders = metadataContext.getTransHeadersKV();
MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false);
Map<String, String> calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); Map<String, String> calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders();
@ -72,6 +74,9 @@ public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedP
// build custom metadata request header // build custom metadata request header
this.buildMetadataHeader(httpRequest, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(httpRequest, customMetadata, CUSTOM_METADATA);
// build application metadata request header
this.buildMetadataHeader(httpRequest, applicationMetadata, APPLICATION_METADATA);
// set headers that need to be transmitted from the upstream // set headers that need to be transmitted from the upstream
this.buildTransmittedHeader(httpRequest, transHeaders); this.buildTransmittedHeader(httpRequest, transHeaders);
} }

@ -37,6 +37,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
@ -69,6 +70,7 @@ public class EncodeTransferMedataScgEnhancedPlugin implements EnhancedPlugin {
Map<String, String> customMetadata = metadataContext.getCustomMetadata(); Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata(); Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
Map<String, String> applicationMetadata = metadataContext.getApplicationMetadata();
MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false);
Map<String, String> calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); Map<String, String> calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders();
@ -77,6 +79,7 @@ public class EncodeTransferMedataScgEnhancedPlugin implements EnhancedPlugin {
this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA);
this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA);
this.buildMetadataHeader(builder, applicationMetadata, APPLICATION_METADATA);
TransHeadersTransfer.transfer(exchange.getRequest()); TransHeadersTransfer.transfer(exchange.getRequest());
context.setOriginRequest(exchange.mutate().request(builder.build()).build()); context.setOriginRequest(exchange.mutate().request(builder.build()).build());

@ -35,6 +35,7 @@ import com.tencent.polaris.metadata.core.MetadataType;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientRequest;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA;
import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA;
@ -59,6 +60,7 @@ public class EncodeTransferMedataWebClientEnhancedPlugin implements EnhancedPlug
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
Map<String, String> customMetadata = metadataContext.getCustomMetadata(); Map<String, String> customMetadata = metadataContext.getCustomMetadata();
Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata(); Map<String, String> disposableMetadata = metadataContext.getDisposableMetadata();
Map<String, String> applicationMetadata = metadataContext.getApplicationMetadata();
Map<String, String> transHeaders = metadataContext.getTransHeadersKV(); Map<String, String> transHeaders = metadataContext.getTransHeadersKV();
MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false);
Map<String, String> calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); Map<String, String> calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders();
@ -70,6 +72,7 @@ public class EncodeTransferMedataWebClientEnhancedPlugin implements EnhancedPlug
this.buildMetadataHeader(requestBuilder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestBuilder, customMetadata, CUSTOM_METADATA);
this.buildMetadataHeader(requestBuilder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); this.buildMetadataHeader(requestBuilder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA);
this.buildMetadataHeader(requestBuilder, applicationMetadata, APPLICATION_METADATA);
this.buildTransmittedHeader(requestBuilder, transHeaders); this.buildTransmittedHeader(requestBuilder, transHeaders);
context.setOriginRequest(requestBuilder.build()); context.setOriginRequest(requestBuilder.build());

@ -0,0 +1,75 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.metadata.provider;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataProvider;
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
import feign.RequestTemplate;
/**
* MetadataProvider used for Feign RequestTemplate.
*
* @author Haotian Zhang
*/
public class FeignRequestTemplateMetadataProvider implements MetadataProvider {
private final RequestTemplate requestTemplate;
public FeignRequestTemplateMetadataProvider(RequestTemplate requestTemplate) {
this.requestTemplate = requestTemplate;
}
@Override
public String getRawMetadataStringValue(String key) {
switch (key) {
case MessageMetadataContainer.LABEL_KEY_METHOD:
return requestTemplate.method();
case MessageMetadataContainer.LABEL_KEY_PATH:
URI uri = URI.create(requestTemplate.request().url());
return UrlUtils.decode(uri.getPath());
case MessageMetadataContainer.LABEL_KEY_CALLER_IP:
return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.getRawMetadataStringValue(MetadataConstants.LOCAL_IP);
default:
return null;
}
}
@Override
public String getRawMetadataMapValue(String key, String mapKey) {
Map<String, Collection<String>> headers = requestTemplate.headers();
switch (key) {
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(headers, mapKey));
case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE:
return UrlUtils.decode(ExpressionLabelUtils.getCookieFirstValue(headers, mapKey));
case MessageMetadataContainer.LABEL_MAP_KEY_QUERY:
return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(requestTemplate.queries(), mapKey));
default:
return null;
}
}
}

@ -0,0 +1,70 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.metadata.provider;
import com.tencent.cloud.common.util.UrlUtils;
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils;
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataProvider;
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
import org.springframework.http.HttpRequest;
/**
* MetadataProvider used for RestTemplate HttpRequest.
*
* @author Haotian Zhang
*/
public class RestTemplateMetadataProvider implements MetadataProvider {
private final HttpRequest request;
public RestTemplateMetadataProvider(HttpRequest request) {
this.request = request;
}
@Override
public String getRawMetadataStringValue(String key) {
switch (key) {
case MessageMetadataContainer.LABEL_KEY_METHOD:
return request.getMethod().toString();
case MessageMetadataContainer.LABEL_KEY_PATH:
return UrlUtils.decode(request.getURI().getPath());
case MessageMetadataContainer.LABEL_KEY_CALLER_IP:
return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.getRawMetadataStringValue(MetadataConstants.LOCAL_IP);
default:
return null;
}
}
@Override
public String getRawMetadataMapValue(String key, String mapKey) {
switch (key) {
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(request, mapKey));
case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(request, mapKey));
case MessageMetadataContainer.LABEL_MAP_KEY_QUERY:
return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(request, mapKey));
default:
return null;
}
}
}

@ -69,7 +69,7 @@ public class PolarisServiceDiscovery {
InstancesResponse filteredInstances = polarisDiscoveryHandler.getHealthyInstances(serviceId); InstancesResponse filteredInstances = polarisDiscoveryHandler.getHealthyInstances(serviceId);
ServiceInstances serviceInstances = filteredInstances.toServiceInstances(); ServiceInstances serviceInstances = filteredInstances.toServiceInstances();
for (Instance instance : serviceInstances.getInstances()) { for (Instance instance : serviceInstances.getInstances()) {
instances.add(new PolarisServiceInstance(instance)); instances.add(new PolarisServiceInstance(instance, filteredInstances.getMetadata()));
} }
return instances; return instances;
} }

@ -48,8 +48,6 @@ import static com.tencent.cloud.polaris.extend.nacos.NacosContextProperties.DEFA
*/ */
public class PolarisRegistration implements Registration { public class PolarisRegistration implements Registration {
private static final String METADATA_KEY_IP = "internal-ip";
private static final String METADATA_KEY_ADDRESS = "internal-address";
private static final String GROUP_SERVER_ID_FORMAT = "%s__%s"; private static final String GROUP_SERVER_ID_FORMAT = "%s__%s";
private static final String NACOS_CLUSTER = "nacos.cluster"; private static final String NACOS_CLUSTER = "nacos.cluster";
@ -116,10 +114,6 @@ public class PolarisRegistration implements Registration {
if (CollectionUtils.isEmpty(metadata)) { if (CollectionUtils.isEmpty(metadata)) {
Map<String, String> instanceMetadata = new HashMap<>(); Map<String, String> instanceMetadata = new HashMap<>();
// put internal metadata
instanceMetadata.put(METADATA_KEY_IP, host);
instanceMetadata.put(METADATA_KEY_ADDRESS, host + ":" + port);
// put internal-nacos-cluster if necessary // put internal-nacos-cluster if necessary
if (Objects.nonNull(nacosContextProperties)) { if (Objects.nonNull(nacosContextProperties)) {
String clusterName = nacosContextProperties.getClusterName(); String clusterName = nacosContextProperties.getClusterName();

@ -44,6 +44,9 @@ import com.tencent.polaris.api.rpc.InstanceRegisterResponse;
import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.api.rpc.InstancesResponse;
import com.tencent.polaris.client.util.NamedThreadFactory; import com.tencent.polaris.client.util.NamedThreadFactory;
import com.tencent.polaris.factory.config.provider.ServiceConfigImpl; import com.tencent.polaris.factory.config.provider.ServiceConfigImpl;
import com.tencent.polaris.metadata.core.TransitiveType;
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -121,6 +124,14 @@ public class PolarisServiceRegistry implements ServiceRegistry<PolarisRegistrati
instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol()); instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol());
instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion()); instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion());
instanceRegisterRequest.setInstanceId(polarisDiscoveryProperties.getInstanceId()); instanceRegisterRequest.setInstanceId(polarisDiscoveryProperties.getInstanceId());
CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.putMetadataStringValue(MetadataConstants.LOCAL_NAMESPACE, polarisDiscoveryProperties.getNamespace(), TransitiveType.DISPOSABLE);
CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.putMetadataStringValue(MetadataConstants.LOCAL_SERVICE, serviceId, TransitiveType.DISPOSABLE);
CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.putMetadataStringValue(MetadataConstants.LOCAL_IP, registration.getHost(), TransitiveType.DISPOSABLE);
CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.putMetadataStringValue(MetadataConstants.LOCAL_PORT, String.valueOf(registration.getPort()), TransitiveType.DISPOSABLE);
try { try {
ProviderAPI providerClient = polarisSDKContextManager.getProviderAPI(); ProviderAPI providerClient = polarisSDKContextManager.getProviderAPI();
InstanceRegisterResponse instanceRegisterResponse; InstanceRegisterResponse instanceRegisterResponse;

@ -26,6 +26,7 @@ import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.context.tsf.TsfUtils;
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties; import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import com.tencent.cloud.polaris.context.tsf.consul.TsfConsulProperties; import com.tencent.cloud.polaris.context.tsf.consul.TsfConsulProperties;
import com.tencent.cloud.polaris.tsf.util.RegistrationUtil; import com.tencent.cloud.polaris.tsf.util.RegistrationUtil;
@ -84,10 +85,10 @@ public class TsfDiscoveryConfigModifier implements PolarisConfigModifier {
System.setProperty("spring.cloud.polaris.namespace", tsfCoreProperties.getTsfNamespaceId()); System.setProperty("spring.cloud.polaris.namespace", tsfCoreProperties.getTsfNamespaceId());
// application id // application id
polarisDiscoveryProperties.setVersion(tsfDiscoveryProperties.getTsfProgVersion()); polarisDiscoveryProperties.setVersion(tsfCoreProperties.getTsfProgVersion());
// instance id // instance id
polarisDiscoveryProperties.setInstanceId(tsfDiscoveryProperties.getInstanceId()); polarisDiscoveryProperties.setInstanceId(tsfCoreProperties.getInstanceId());
boolean consulEnable = tsfCoreProperties.isTsfConsulEnable(); boolean consulEnable = tsfCoreProperties.isTsfConsulEnable();
boolean polarisEnable = tsfCoreProperties.isTsePolarisEnable(); boolean polarisEnable = tsfCoreProperties.isTsePolarisEnable();
@ -133,11 +134,11 @@ public class TsfDiscoveryConfigModifier implements PolarisConfigModifier {
Map<String, String> metadata = serverConnectorConfig.getMetadata(); Map<String, String> metadata = serverConnectorConfig.getMetadata();
String appName = RegistrationUtil.getAppName(tsfDiscoveryProperties, context.getEnvironment()); String appName = RegistrationUtil.getAppName(tsfDiscoveryProperties, context.getEnvironment());
metadata.put(ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY, RegistrationUtil.normalizeForDns(appName)); metadata.put(ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY, RegistrationUtil.normalizeForDns(appName));
metadata.put(ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY, RegistrationUtil.getInstanceId(tsfDiscoveryProperties, context)); metadata.put(ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY, RegistrationUtil.getInstanceId(tsfCoreProperties, context));
if (StringUtils.isNotBlank(tsfConsulProperties.getAclToken())) { if (StringUtils.isNotBlank(tsfConsulProperties.getAclToken())) {
serverConnectorConfig.setToken(tsfConsulProperties.getAclToken()); serverConnectorConfig.setToken(tsfConsulProperties.getAclToken());
} }
metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(RegistrationUtil.createTags(tsfDiscoveryProperties))); metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(TsfUtils.createTags(tsfCoreProperties)));
if (StringUtils.isNotBlank(tsfDiscoveryProperties.getDefaultQueryTag())) { if (StringUtils.isNotBlank(tsfDiscoveryProperties.getDefaultQueryTag())) {
metadata.put(ConsulConstant.MetadataMapKey.QUERY_TAG_KEY, tsfDiscoveryProperties.getDefaultQueryTag()); metadata.put(ConsulConstant.MetadataMapKey.QUERY_TAG_KEY, tsfDiscoveryProperties.getDefaultQueryTag());
} }

@ -24,7 +24,6 @@ import java.util.Map;
import com.tencent.cloud.common.util.inet.PolarisInetUtils; import com.tencent.cloud.common.util.inet.PolarisInetUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.commons.util.InetUtils;
@ -43,11 +42,6 @@ public class TsfDiscoveryProperties {
private InetUtils.HostInfo hostInfo; private InetUtils.HostInfo hostInfo;
/**
* Tags to use when registering service.
*/
private List<String> tags = new ArrayList<>();
/** /**
* If service discovery enabled. * If service discovery enabled.
*/ */
@ -132,33 +126,6 @@ public class TsfDiscoveryProperties {
*/ */
private String serviceName; private String serviceName;
/**
* Unique service instance id.
*/
@Value("${tsf_instance_id:${spring.cloud.consul.discovery.instanceId:${SPRING_CLOUD_CONSUL_DISCOVERY_INSTANCEID:}}}")
private String instanceId;
/**
* Service instance zone.
*/
private String instanceZone;
/**
* Service instance group.
*/
private String instanceGroup;
/**
* Service instance zone comes from metadata.
* This allows changing the metadata tag name.
*/
private String defaultZoneMetadataName = "zone";
/**
* Whether to register an http or https service.
*/
private String scheme = "http";
/** /**
* Suffix to use when registering management service. * Suffix to use when registering management service.
*/ */
@ -214,30 +181,6 @@ public class TsfDiscoveryProperties {
*/ */
private Boolean healthCheckTlsSkipVerify; private Boolean healthCheckTlsSkipVerify;
/**
* tsf service consul registration tags.
*
* progVersion
*/
@Value("${tsf_prog_version:}")
private String tsfProgVersion;
/**
* tsf service consul registration tags.
*
*
*/
@Value("${tsf_region:}")
private String tsfRegion;
/**
* tsf service consul registration tags.
*
*
*/
@Value("${tsf_zone:}")
private String tsfZone;
/** /**
* 线. * 线.
*/ */
@ -247,7 +190,6 @@ public class TsfDiscoveryProperties {
private long callbackErrorDelay = 30 * 1000L; private long callbackErrorDelay = 30 * 1000L;
/** /**
* consul 线0线provider线. * consul 线0线provider线.
* provider线 consul . * provider线 consul .
@ -296,14 +238,6 @@ public class TsfDiscoveryProperties {
this.hostInfo = hostInfo; this.hostInfo = hostInfo;
} }
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
@ -433,46 +367,6 @@ public class TsfDiscoveryProperties {
this.serviceName = serviceName; this.serviceName = serviceName;
} }
public String getInstanceId() {
return instanceId;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
public String getInstanceZone() {
return instanceZone;
}
public void setInstanceZone(String instanceZone) {
this.instanceZone = instanceZone;
}
public String getInstanceGroup() {
return instanceGroup;
}
public void setInstanceGroup(String instanceGroup) {
this.instanceGroup = instanceGroup;
}
public String getDefaultZoneMetadataName() {
return defaultZoneMetadataName;
}
public void setDefaultZoneMetadataName(String defaultZoneMetadataName) {
this.defaultZoneMetadataName = defaultZoneMetadataName;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
public String getManagementSuffix() { public String getManagementSuffix() {
return managementSuffix; return managementSuffix;
} }
@ -553,30 +447,6 @@ public class TsfDiscoveryProperties {
this.healthCheckTlsSkipVerify = healthCheckTlsSkipVerify; this.healthCheckTlsSkipVerify = healthCheckTlsSkipVerify;
} }
public String getTsfProgVersion() {
return tsfProgVersion;
}
public void setTsfProgVersion(final String tsfProgVersion) {
this.tsfProgVersion = tsfProgVersion;
}
public String getTsfRegion() {
return tsfRegion;
}
public void setTsfRegion(final String tsfRegion) {
this.tsfRegion = tsfRegion;
}
public String getTsfZone() {
return tsfZone;
}
public void setTsfZone(final String tsfZone) {
this.tsfZone = tsfZone;
}
public Map<String, String> getServiceMeta() { public Map<String, String> getServiceMeta() {
return serviceMeta; return serviceMeta;
} }
@ -629,7 +499,6 @@ public class TsfDiscoveryProperties {
public String toString() { public String toString() {
return "ConsulDiscoveryProperties{" + return "ConsulDiscoveryProperties{" +
"hostInfo=" + hostInfo + "hostInfo=" + hostInfo +
", tags=" + tags +
", enabled=" + enabled + ", enabled=" + enabled +
", managementTags=" + managementTags + ", managementTags=" + managementTags +
", healthCheckPath='" + healthCheckPath + '\'' + ", healthCheckPath='" + healthCheckPath + '\'' +
@ -647,11 +516,6 @@ public class TsfDiscoveryProperties {
", catalogServicesWatchDelay=" + catalogServicesWatchDelay + ", catalogServicesWatchDelay=" + catalogServicesWatchDelay +
", catalogServicesWatchTimeout=" + catalogServicesWatchTimeout + ", catalogServicesWatchTimeout=" + catalogServicesWatchTimeout +
", serviceName='" + serviceName + '\'' + ", serviceName='" + serviceName + '\'' +
", instanceId='" + instanceId + '\'' +
", instanceZone='" + instanceZone + '\'' +
", instanceGroup='" + instanceGroup + '\'' +
", defaultZoneMetadataName='" + defaultZoneMetadataName + '\'' +
", scheme='" + scheme + '\'' +
", managementSuffix='" + managementSuffix + '\'' + ", managementSuffix='" + managementSuffix + '\'' +
", serverListQueryTags=" + serverListQueryTags + ", serverListQueryTags=" + serverListQueryTags +
", datacenters=" + datacenters + ", datacenters=" + datacenters +

@ -44,21 +44,14 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnTsfEnabled @ConditionalOnTsfEnabled
@AutoConfigureBefore(PolarisServiceRegistryAutoConfiguration.class) @AutoConfigureBefore(PolarisServiceRegistryAutoConfiguration.class)
public class TsfDiscoveryRegistryAutoConfiguration { public class TsfDiscoveryRegistryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TsfMetadataPolarisRegistrationCustomizer tsfMetadataPolarisRegistrationCustomizer(
TsfCoreProperties tsfCoreProperties, TsfDiscoveryProperties tsfDiscoveryProperties) {
return new TsfMetadataPolarisRegistrationCustomizer(tsfCoreProperties, tsfDiscoveryProperties);
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public TsfPortPolarisRegistrationCustomizer tsfPortPolarisRegistrationCustomizer( public TsfPortPolarisRegistrationCustomizer tsfPortPolarisRegistrationCustomizer(
AutoServiceRegistrationProperties autoServiceRegistrationProperties, AutoServiceRegistrationProperties autoServiceRegistrationProperties,
ApplicationContext context, TsfDiscoveryProperties tsfDiscoveryProperties, ApplicationContext context, TsfDiscoveryProperties tsfDiscoveryProperties, TsfCoreProperties tsfCoreProperties,
TsfHeartbeatProperties tsfHeartbeatProperties, PolarisSDKContextManager polarisSDKContextManager) { TsfHeartbeatProperties tsfHeartbeatProperties, PolarisSDKContextManager polarisSDKContextManager) {
return new TsfPortPolarisRegistrationCustomizer(autoServiceRegistrationProperties, context, return new TsfPortPolarisRegistrationCustomizer(autoServiceRegistrationProperties, context,
tsfDiscoveryProperties, tsfHeartbeatProperties, polarisSDKContextManager.getSDKContext()); tsfDiscoveryProperties, tsfCoreProperties, tsfHeartbeatProperties, polarisSDKContextManager.getSDKContext());
} }
@Bean @Bean

@ -1,74 +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.tsf.registry;
import java.util.Map;
import com.tencent.cloud.common.constant.SdkVersion;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import com.tencent.cloud.polaris.registry.PolarisRegistration;
import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer;
import com.tencent.cloud.polaris.tsf.TsfDiscoveryProperties;
import com.tencent.cloud.polaris.tsf.consts.WarmupCons;
import com.tencent.cloud.polaris.tsf.util.RegistrationUtil;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_APPLICATION_ID;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_GROUP_ID;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_INSTNACE_ID;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_NAMESPACE_ID;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_PROG_VERSION;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_REGION;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_SDK_VERSION;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_TAGS;
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_ZONE;
/**
*
*
* @author Haotian Zhang
*/
public class TsfMetadataPolarisRegistrationCustomizer implements PolarisRegistrationCustomizer {
private final TsfCoreProperties tsfCoreProperties;
private final TsfDiscoveryProperties tsfDiscoveryProperties;
public TsfMetadataPolarisRegistrationCustomizer(TsfCoreProperties tsfCoreProperties, TsfDiscoveryProperties tsfDiscoveryProperties) {
this.tsfCoreProperties = tsfCoreProperties;
this.tsfDiscoveryProperties = tsfDiscoveryProperties;
}
@Override
public void customize(PolarisRegistration registration) {
Map<String, String> metadata = registration.getMetadata();
metadata.put(TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId());
metadata.put(TSF_PROG_VERSION, tsfDiscoveryProperties.getTsfProgVersion());
metadata.put(TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId());
metadata.put(TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId());
metadata.put(TSF_INSTNACE_ID, tsfDiscoveryProperties.getInstanceId());
metadata.put(TSF_REGION, tsfDiscoveryProperties.getTsfRegion());
metadata.put(TSF_ZONE, tsfDiscoveryProperties.getTsfZone());
// 处理预热相关的参数
metadata.put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis()));
metadata.put(TSF_SDK_VERSION, SdkVersion.get());
metadata.put(TSF_TAGS, JacksonUtils.serialize2Json(RegistrationUtil.createTags(tsfDiscoveryProperties)));
RegistrationUtil.appendMetaIpAddress(metadata);
}
}

@ -17,6 +17,7 @@
package com.tencent.cloud.polaris.tsf.registry; package com.tencent.cloud.polaris.tsf.registry;
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import com.tencent.cloud.polaris.registry.PolarisRegistration; import com.tencent.cloud.polaris.registry.PolarisRegistration;
import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer;
import com.tencent.cloud.polaris.tsf.TsfDiscoveryProperties; import com.tencent.cloud.polaris.tsf.TsfDiscoveryProperties;
@ -37,15 +38,17 @@ public class TsfPortPolarisRegistrationCustomizer implements PolarisRegistration
private final AutoServiceRegistrationProperties autoServiceRegistrationProperties; private final AutoServiceRegistrationProperties autoServiceRegistrationProperties;
private final ApplicationContext context; private final ApplicationContext context;
private final TsfDiscoveryProperties tsfDiscoveryProperties; private final TsfDiscoveryProperties tsfDiscoveryProperties;
private final TsfCoreProperties tsfCoreProperties;
private final TsfHeartbeatProperties tsfHeartbeatProperties; private final TsfHeartbeatProperties tsfHeartbeatProperties;
private final SDKContext sdkContext; private final SDKContext sdkContext;
public TsfPortPolarisRegistrationCustomizer(AutoServiceRegistrationProperties autoServiceRegistrationProperties, public TsfPortPolarisRegistrationCustomizer(AutoServiceRegistrationProperties autoServiceRegistrationProperties,
ApplicationContext context, TsfDiscoveryProperties tsfDiscoveryProperties, ApplicationContext context, TsfDiscoveryProperties tsfDiscoveryProperties, TsfCoreProperties tsfCoreProperties,
TsfHeartbeatProperties tsfHeartbeatProperties, SDKContext sdkContext) { TsfHeartbeatProperties tsfHeartbeatProperties, SDKContext sdkContext) {
this.autoServiceRegistrationProperties = autoServiceRegistrationProperties; this.autoServiceRegistrationProperties = autoServiceRegistrationProperties;
this.context = context; this.context = context;
this.tsfDiscoveryProperties = tsfDiscoveryProperties; this.tsfDiscoveryProperties = tsfDiscoveryProperties;
this.tsfCoreProperties = tsfCoreProperties;
this.tsfHeartbeatProperties = tsfHeartbeatProperties; this.tsfHeartbeatProperties = tsfHeartbeatProperties;
this.sdkContext = sdkContext; this.sdkContext = sdkContext;
} }
@ -56,7 +59,7 @@ public class TsfPortPolarisRegistrationCustomizer implements PolarisRegistration
registration.setPort(tsfDiscoveryProperties.getPort()); registration.setPort(tsfDiscoveryProperties.getPort());
} }
// we know the port and can set the check // we know the port and can set the check
RegistrationUtil.setCheck(autoServiceRegistrationProperties, tsfDiscoveryProperties, context, RegistrationUtil.setCheck(autoServiceRegistrationProperties, tsfDiscoveryProperties, tsfCoreProperties, context,
tsfHeartbeatProperties, registration, sdkContext.getConfig()); tsfHeartbeatProperties, registration, sdkContext.getConfig());
} }
} }

@ -17,14 +17,12 @@
package com.tencent.cloud.polaris.tsf.util; package com.tencent.cloud.polaris.tsf.util;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.ecwid.consul.v1.agent.model.NewService; import com.ecwid.consul.v1.agent.model.NewService;
import com.tencent.cloud.common.util.AddressUtils; import com.tencent.cloud.common.util.AddressUtils;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.inet.PolarisInetUtils; import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import com.tencent.cloud.polaris.tsf.TsfDiscoveryProperties; import com.tencent.cloud.polaris.tsf.TsfDiscoveryProperties;
import com.tencent.cloud.polaris.tsf.TsfHeartbeatProperties; import com.tencent.cloud.polaris.tsf.TsfHeartbeatProperties;
import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.config.Configuration;
@ -58,15 +56,6 @@ public final class RegistrationUtil {
*/ */
public static final String ID = "consul"; public static final String ID = "consul";
private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationUtil.class); private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationUtil.class);
/**
* IPV4.
*/
public static String TSF_ADDRESS_IPV4 = "TSF_ADDRESS_IPV4";
/**
* IPV6.
*/
public static String TSF_ADDRESS_IPV6 = "TSF_ADDRESS_IPV6";
private RegistrationUtil() { private RegistrationUtil() {
} }
@ -79,7 +68,7 @@ public final class RegistrationUtil {
return env.getProperty("spring.application.name", "application"); return env.getProperty("spring.application.name", "application");
} }
public static String getInstanceId(TsfDiscoveryProperties properties, ApplicationContext context) { public static String getInstanceId(TsfCoreProperties properties, ApplicationContext context) {
// tsf consul 不支持 dns所以这里不需要 normalize并且由于优雅下线readiness probe 联动都是依赖 service id 的normalize 后两边对不上,所以需要去掉 normalize // tsf consul 不支持 dns所以这里不需要 normalize并且由于优雅下线readiness probe 联动都是依赖 service id 的normalize 后两边对不上,所以需要去掉 normalize
if (!StringUtils.hasText(properties.getInstanceId())) { if (!StringUtils.hasText(properties.getInstanceId())) {
return IdUtils.getDefaultInstanceId(context.getEnvironment(), false); return IdUtils.getDefaultInstanceId(context.getEnvironment(), false);
@ -123,40 +112,8 @@ public final class RegistrationUtil {
return normalized.toString(); return normalized.toString();
} }
public static List<String> createTags(TsfDiscoveryProperties properties) {
List<String> tags = new LinkedList<>(properties.getTags());
if (StringUtils.hasText(properties.getInstanceZone())) {
tags.add(properties.getDefaultZoneMetadataName() + "=" + properties.getInstanceZone());
}
if (StringUtils.hasText(properties.getInstanceGroup())) {
tags.add("group=" + properties.getInstanceGroup());
}
//store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically
tags.add("secure=" + properties.getScheme().equalsIgnoreCase("https"));
return tags;
}
public static Map<String, String> appendMetaIpAddress(Map<String, String> meta) {
if (meta == null) {
return null;
}
String ipv4Address = PolarisInetUtils.getIpString(false);
if (ipv4Address != null) {
meta.put(TSF_ADDRESS_IPV4, ipv4Address);
}
String ipv6Address = PolarisInetUtils.getIpString(true);
if (ipv6Address != null) {
meta.put(TSF_ADDRESS_IPV6, ipv6Address);
}
return meta;
}
public static void setCheck(AutoServiceRegistrationProperties autoServiceRegistrationProperties, public static void setCheck(AutoServiceRegistrationProperties autoServiceRegistrationProperties,
TsfDiscoveryProperties properties, ApplicationContext context, TsfDiscoveryProperties properties, TsfCoreProperties tsfCoreProperties, ApplicationContext context,
TsfHeartbeatProperties tsfHeartbeatProperties, Registration registration, Configuration configuration) { TsfHeartbeatProperties tsfHeartbeatProperties, Registration registration, Configuration configuration) {
if (properties.isRegisterHealthCheck()) { if (properties.isRegisterHealthCheck()) {
Integer checkPort; Integer checkPort;
@ -171,7 +128,7 @@ public final class RegistrationUtil {
for (ServerConnectorConfigImpl config : configuration.getGlobal().getServerConnectors()) { for (ServerConnectorConfigImpl config : configuration.getGlobal().getServerConnectors()) {
if (org.apache.commons.lang.StringUtils.equals(config.getId(), ID)) { if (org.apache.commons.lang.StringUtils.equals(config.getId(), ID)) {
Map<String, String> metadata = config.getMetadata(); Map<String, String> metadata = config.getMetadata();
NewService.Check check = createCheck(checkPort, tsfHeartbeatProperties, properties); NewService.Check check = createCheck(checkPort, tsfHeartbeatProperties, properties, tsfCoreProperties);
String checkJson = JacksonUtils.serialize2Json(check); String checkJson = JacksonUtils.serialize2Json(check);
LOGGER.debug("Check is : {}", checkJson); LOGGER.debug("Check is : {}", checkJson);
metadata.put(ConsulConstant.MetadataMapKey.CHECK_KEY, checkJson); metadata.put(ConsulConstant.MetadataMapKey.CHECK_KEY, checkJson);
@ -182,7 +139,7 @@ public final class RegistrationUtil {
} }
public static NewService.Check createCheck(Integer port, TsfHeartbeatProperties ttlConfig, public static NewService.Check createCheck(Integer port, TsfHeartbeatProperties ttlConfig,
TsfDiscoveryProperties properties) { TsfDiscoveryProperties properties, TsfCoreProperties tsfCoreProperties) {
NewService.Check check = new NewService.Check(); NewService.Check check = new NewService.Check();
if (ttlConfig.isEnabled()) { if (ttlConfig.isEnabled()) {
check.setTtl(ttlConfig.getTtl()); check.setTtl(ttlConfig.getTtl());
@ -196,7 +153,7 @@ public final class RegistrationUtil {
check.setHttp(properties.getHealthCheckUrl()); check.setHttp(properties.getHealthCheckUrl());
} }
else { else {
check.setHttp(String.format("%s://%s:%s%s", properties.getScheme(), check.setHttp(String.format("%s://%s:%s%s", tsfCoreProperties.getScheme(),
AddressUtils.getIpCompatible(properties.getHostname()), port, AddressUtils.getIpCompatible(properties.getHostname()), port,
properties.getHealthCheckPath())); properties.getHealthCheckPath()));
} }

@ -181,7 +181,7 @@ public class PolarisRegistrationTest {
Map<String, String> metadata = polarisRegistration1.getMetadata(); Map<String, String> metadata = polarisRegistration1.getMetadata();
assertThat(metadata).isNotNull(); assertThat(metadata).isNotNull();
assertThat(metadata).isNotEmpty(); assertThat(metadata).isNotEmpty();
assertThat(metadata.size()).isEqualTo(4); assertThat(metadata.size()).isEqualTo(2);
assertThat(metadata.get("key1")).isEqualTo("value1"); assertThat(metadata.get("key1")).isEqualTo("value1");
} }
@ -211,7 +211,7 @@ public class PolarisRegistrationTest {
Map<String, String> metadata = polarisRegistration1.getMetadata(); Map<String, String> metadata = polarisRegistration1.getMetadata();
assertThat(metadata).isNotNull(); assertThat(metadata).isNotNull();
assertThat(metadata).isNotEmpty(); assertThat(metadata).isNotEmpty();
assertThat(metadata.size()).isEqualTo(4); assertThat(metadata.size()).isEqualTo(2);
assertThat(metadata.get("nacos.cluster")).isEqualTo(clusterName); assertThat(metadata.get("nacos.cluster")).isEqualTo(clusterName);
} }
} }

@ -18,10 +18,8 @@
package com.tencent.cloud.polaris.router; package com.tencent.cloud.polaris.router;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -79,25 +77,6 @@ public class PolarisRouterContext {
return routerLabels.get(labelKey); return routerLabels.get(labelKey);
} }
public Set<String> getLabelAsSet(String labelKey) {
Map<String, String> routerLabels = labels.get(RouterConstant.ROUTER_LABELS);
if (CollectionUtils.isEmpty(routerLabels)) {
return Collections.emptySet();
}
for (Map.Entry<String, String> entry : routerLabels.entrySet()) {
if (StringUtils.equalsIgnoreCase(labelKey, entry.getKey())) {
String keysStr = entry.getValue();
if (StringUtils.isNotBlank(keysStr)) {
String[] keysArr = StringUtils.split(keysStr, ",");
return new HashSet<>(Arrays.asList(keysArr));
}
}
}
return Collections.emptySet();
}
public void putLabels(String labelType, Map<String, String> subLabels) { public void putLabels(String labelType, Map<String, String> subLabels) {
if (this.labels == null) { if (this.labels == null) {
this.labels = new HashMap<>(); this.labels = new HashMap<>();

@ -32,7 +32,6 @@ import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.pojo.PolarisServiceInstance; import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerRequest;
import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor;
import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor; import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
@ -100,15 +99,10 @@ public class PolarisRouterServiceInstanceListSupplier extends DelegatingServiceI
PolarisRouterContext routerContext = null; PolarisRouterContext routerContext = null;
DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext(); DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
if (requestContext != null) {
if (requestContext instanceof RequestDataContext) { if (requestContext instanceof RequestDataContext) {
routerContext = buildRouterContext(((RequestDataContext) requestContext).getClientRequest().getHeaders()); routerContext = buildRouterContext(((RequestDataContext) requestContext).getClientRequest()
}
else if (requestContext.getClientRequest() instanceof PolarisLoadBalancerRequest) {
routerContext = buildRouterContext(((PolarisLoadBalancerRequest<?>) requestContext.getClientRequest()).getRequest()
.getHeaders()); .getHeaders());
} }
}
if (routerContext == null) { if (routerContext == null) {
// return all servers if router context is null. // return all servers if router context is null.
@ -120,15 +114,11 @@ public class PolarisRouterServiceInstanceListSupplier extends DelegatingServiceI
PolarisRouterContext buildRouterContext(HttpHeaders headers) { PolarisRouterContext buildRouterContext(HttpHeaders headers) {
Collection<String> labelHeaderValues = headers.get(RouterConstant.ROUTER_LABEL_HEADER); Collection<String> labelHeaderValues = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
if (CollectionUtils.isEmpty(labelHeaderValues)) { if (CollectionUtils.isEmpty(labelHeaderValues)) {
return null; labelHeaderValues = new ArrayList<>();
} }
PolarisRouterContext routerContext = new PolarisRouterContext(); PolarisRouterContext routerContext = new PolarisRouterContext();
routerContext.putLabels(RouterConstant.TRANSITIVE_LABELS, MetadataContextHolder.get().getTransitiveMetadata());
Map<String, String> labelHeaderValuesMap = new HashMap<>(); Map<String, String> labelHeaderValuesMap = new HashMap<>();
try { try {
Optional<String> labelHeaderValuesOptional = labelHeaderValues.stream().findFirst(); Optional<String> labelHeaderValuesOptional = labelHeaderValues.stream().findFirst();
@ -178,6 +168,7 @@ public class PolarisRouterServiceInstanceListSupplier extends DelegatingServiceI
serviceInfo.setNamespace(MetadataContext.LOCAL_NAMESPACE); serviceInfo.setNamespace(MetadataContext.LOCAL_NAMESPACE);
serviceInfo.setService(MetadataContext.LOCAL_SERVICE); serviceInfo.setService(MetadataContext.LOCAL_SERVICE);
processRoutersRequest.setSourceService(serviceInfo); processRoutersRequest.setSourceService(serviceInfo);
processRoutersRequest.setMetadataContainerGroup(MetadataContextHolder.get().getMetadataContainerGroup(false));
return processRoutersRequest; return processRoutersRequest;
} }

@ -1,76 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.specification.api.v1.model.ModelProto;
import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto;
import org.springframework.util.CollectionUtils;
/**
* Resolve label expressions from routing rules.
*
* @author lepdou 2022-05-19
*/
public class RouterRuleLabelResolver {
private final ServiceRuleManager serviceRuleManager;
public RouterRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
this.serviceRuleManager = serviceRuleManager;
}
public Set<String> getExpressionLabelKeys(String namespace, String sourceService, String dstService) {
List<RoutingProto.Route> rules = serviceRuleManager.getServiceRouterRule(namespace, sourceService, dstService);
if (CollectionUtils.isEmpty(rules)) {
return Collections.emptySet();
}
Set<String> expressionLabels = new HashSet<>();
for (RoutingProto.Route rule : rules) {
List<RoutingProto.Source> sources = rule.getSourcesList();
if (CollectionUtils.isEmpty(sources)) {
continue;
}
for (RoutingProto.Source source : sources) {
Map<String, ModelProto.MatchString> labels = source.getMetadataMap();
if (CollectionUtils.isEmpty(labels)) {
continue;
}
for (String labelKey : labels.keySet()) {
if (ExpressionLabelUtils.isExpressionLabel(labelKey)) {
expressionLabels.add(labelKey);
}
}
}
}
return expressionLabels;
}
}

@ -19,7 +19,9 @@ package com.tencent.cloud.polaris.router;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -64,12 +66,14 @@ public final class RouterUtils {
.collect(Collectors.toList()))).subscribe(instance -> instanceList.add((Instance) instance)); .collect(Collectors.toList()))).subscribe(instance -> instanceList.add((Instance) instance));
String serviceName = ""; String serviceName = "";
Map<String, String> serviceMetadata = new HashMap<>();
if (!CollectionUtils.isEmpty(instanceList)) { if (!CollectionUtils.isEmpty(instanceList)) {
serviceName = instanceList.get(0).getService(); serviceName = instanceList.get(0).getService();
serviceMetadata = instanceList.get(0).getServiceMetadata();
} }
ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceName); ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceName);
return new DefaultServiceInstances(serviceKey, instanceList); return new DefaultServiceInstances(serviceKey, instanceList, serviceMetadata);
} }
} }

@ -1,55 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.beanprocessor;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
/**
* Replace LoadBalancerInterceptor with PolarisLoadBalancerInterceptor.
* PolarisLoadBalancerInterceptor can pass routing context information.
*
*@author lepdou 2022-05-18
*/
public class LoadBalancerInterceptorBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private BeanFactory factory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LoadBalancerInterceptor) {
LoadBalancerRequestFactory requestFactory = this.factory.getBean(LoadBalancerRequestFactory.class);
LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class);
return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
return bean;
}
}

@ -1,72 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.beanprocessor;
import java.util.List;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.util.BeanFactoryUtils;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.scg.PolarisReactiveLoadBalancerClientFilter;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
/**
* Replaced ReactiveLoadBalancerClientFilter with PolarisReactiveLoadBalancerClientFilter during creating bean phase.
*
* @author lepdou 2022-06-20
*/
public class ReactiveLoadBalancerClientFilterBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private BeanFactory factory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// Support spring cloud gateway router.
// Replaces the default ReactiveLoadBalancerClientFilter implementation
// and returns a custom PolarisReactiveLoadBalancerClientFilter
if (bean instanceof ReactiveLoadBalancerClientFilter) {
LoadBalancerClientFactory loadBalancerClientFactory = this.factory.getBean(LoadBalancerClientFactory.class);
GatewayLoadBalancerProperties gatewayLoadBalancerProperties = this.factory.getBean(GatewayLoadBalancerProperties.class);
LoadBalancerProperties loadBalancerProperties = this.factory.getBean(LoadBalancerProperties.class);
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 PolarisReactiveLoadBalancerClientFilter(
loadBalancerClientFactory, gatewayLoadBalancerProperties, loadBalancerProperties,
staticMetadataManager, routerRuleLabelResolver, routerLabelResolvers, polarisContextProperties);
}
return bean;
}
}

@ -18,18 +18,11 @@
package com.tencent.cloud.polaris.router.config; package com.tencent.cloud.polaris.router.config;
import java.util.List;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor;
import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisRouterEnabled @ConditionalOnPolarisRouterEnabled
@ -37,10 +30,7 @@ import org.springframework.lang.Nullable;
public class FeignAutoConfiguration { public class FeignAutoConfiguration {
@Bean @Bean
public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List<FeignRouterLabelResolver> routerLabelResolvers, public RouterLabelFeignInterceptor routerLabelInterceptor() {
StaticMetadataManager staticMetadataManager, return new RouterLabelFeignInterceptor();
RouterRuleLabelResolver routerRuleLabelResolver,
PolarisContextProperties polarisContextProperties) {
return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager, routerRuleLabelResolver, polarisContextProperties);
} }
} }

@ -22,12 +22,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor;
import com.tencent.cloud.polaris.router.beanprocessor.ReactiveLoadBalancerClientFilterBeanPostProcessor;
import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties;
import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties;
import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties;
@ -35,7 +29,7 @@ import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterce
import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.resttemplate.RouterLabelRestTemplateInterceptor; import com.tencent.cloud.polaris.router.resttemplate.RouterLabelRestTemplateInterceptor;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; import com.tencent.cloud.polaris.router.scg.RouterLabelGlobalFilter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor;
import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.SmartInitializingSingleton;
@ -45,12 +39,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
/** /**
* configuration for router module singleton beans. * configuration for router module singleton beans.
* *
@ -61,25 +52,6 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
@LoadBalancerClients(defaultConfiguration = LoadBalancerConfiguration.class) @LoadBalancerClients(defaultConfiguration = LoadBalancerConfiguration.class)
public class RouterAutoConfiguration { public class RouterAutoConfiguration {
@Bean
@Order(HIGHEST_PRECEDENCE)
@ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor")
public LoadBalancerInterceptorBeanPostProcessor loadBalancerInterceptorBeanPostProcessor() {
return new LoadBalancerInterceptorBeanPostProcessor();
}
@Bean
@Order(HIGHEST_PRECEDENCE)
@ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter")
public ReactiveLoadBalancerClientFilterBeanPostProcessor loadBalancerClientFilterBeanPostProcessor() {
return new ReactiveLoadBalancerClientFilterBeanPostProcessor();
}
@Bean
public RouterRuleLabelResolver routerRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
return new RouterRuleLabelResolver(serviceRuleManager);
}
@Bean @Bean
@ConditionalOnProperty(value = "spring.cloud.polaris.router.metadata-router.enabled", matchIfMissing = true) @ConditionalOnProperty(value = "spring.cloud.polaris.router.metadata-router.enabled", matchIfMissing = true)
public MetadataRouterRequestInterceptor metadataRouterRequestInterceptor(PolarisMetadataRouterProperties polarisMetadataRouterProperties) { public MetadataRouterRequestInterceptor metadataRouterRequestInterceptor(PolarisMetadataRouterProperties polarisMetadataRouterProperties) {
@ -98,6 +70,21 @@ public class RouterAutoConfiguration {
return new RuleBasedRouterRequestInterceptor(polarisRuleBasedRouterProperties); return new RuleBasedRouterRequestInterceptor(polarisRuleBasedRouterProperties);
} }
/**
* Create when gateway application is SCG.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter")
protected static class RouterLabelScgFilterConfig {
@Bean
public RouterLabelGlobalFilter routerLabelGlobalFilter() {
return new RouterLabelGlobalFilter();
}
}
/** /**
* Create when RestTemplate exists. * Create when RestTemplate exists.
* @author liuye 2022-09-14 * @author liuye 2022-09-14
@ -111,13 +98,8 @@ public class RouterAutoConfiguration {
private List<RestTemplate> restTemplates = Collections.emptyList(); private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean @Bean
public RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor( public RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor() {
List<SpringWebRouterLabelResolver> routerLabelResolvers, return new RouterLabelRestTemplateInterceptor();
StaticMetadataManager staticMetadataManager,
RouterRuleLabelResolver routerRuleLabelResolver,
PolarisContextProperties polarisContextProperties) {
return new RouterLabelRestTemplateInterceptor(routerLabelResolvers, staticMetadataManager,
routerRuleLabelResolver, polarisContextProperties);
} }
@Bean @Bean

@ -17,6 +17,8 @@
package com.tencent.cloud.polaris.router.config.properties; package com.tencent.cloud.polaris.router.config.properties;
import com.tencent.polaris.api.rpc.RuleBasedRouterFailoverType;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
@ -29,6 +31,8 @@ public class PolarisRuleBasedRouterProperties {
private boolean enabled = true; private boolean enabled = true;
private RuleBasedRouterFailoverType failOver = RuleBasedRouterFailoverType.all;
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
@ -37,10 +41,19 @@ public class PolarisRuleBasedRouterProperties {
this.enabled = enabled; this.enabled = enabled;
} }
public RuleBasedRouterFailoverType getFailOver() {
return failOver;
}
public void setFailOver(RuleBasedRouterFailoverType failOver) {
this.failOver = failOver;
}
@Override @Override
public String toString() { public String toString() {
return "PolarisNearByRouterProperties{" + return "PolarisRuleBasedRouterProperties{" +
"enabled=" + enabled + "enabled=" + enabled +
", failOver=" + failOver +
'}'; '}';
} }
} }

@ -1,98 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.feign;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import feign.RequestTemplate;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
/**
* Resolve rule expression label from feign request.
*
* @author lepdou 2022-05-20
*/
public final class FeignExpressionLabelUtils {
private FeignExpressionLabelUtils() {
}
public static Map<String, String> resolve(RequestTemplate request, Set<String> labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
}
Map<String, String> labels = new HashMap<>();
for (String labelKey : labelKeys) {
if (ExpressionLabelUtils.isHeaderLabel(labelKey)) {
String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey);
if (StringUtils.isBlank(headerKey)) {
continue;
}
labels.put(labelKey, getHeaderValue(request, headerKey));
}
else if (ExpressionLabelUtils.isQueryLabel(labelKey)) {
String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey);
if (StringUtils.isBlank(queryKey)) {
continue;
}
labels.put(labelKey, getQueryValue(request, queryKey));
}
else if (ExpressionLabelUtils.isCookieLabel(labelKey)) {
String cookieKey = ExpressionLabelUtils.parseCookieKey(labelKey);
if (StringUtils.isBlank(cookieKey)) {
continue;
}
labels.put(labelKey, getCookieValue(request, cookieKey));
}
else if (ExpressionLabelUtils.isMethodLabel(labelKey)) {
labels.put(labelKey, request.method());
}
else if (ExpressionLabelUtils.isUriLabel(labelKey)) {
URI uri = URI.create(request.request().url());
labels.put(labelKey, uri.getPath());
}
}
return labels;
}
public static String getHeaderValue(RequestTemplate request, String key) {
Map<String, Collection<String>> headers = request.headers();
return ExpressionLabelUtils.getFirstValue(headers, key);
}
public static String getQueryValue(RequestTemplate request, String key) {
return ExpressionLabelUtils.getFirstValue(request.queries(), key);
}
public static String getCookieValue(RequestTemplate request, String key) {
Map<String, Collection<String>> headers = request.headers();
return ExpressionLabelUtils.getCookieFirstValue(headers, key);
}
}

@ -18,63 +18,21 @@
package com.tencent.cloud.polaris.router.feign; package com.tencent.cloud.polaris.router.feign;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.metadata.provider.FeignRequestTemplateMetadataProvider;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.polaris.metadata.core.MetadataType;
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; import feign.RequestInterceptor;
import feign.RequestTemplate; import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
/** /**
* Resolver labels from request. * Interceptor used for setting Feign RequestTemplate metadata provider.
* *
* @author lepdou, cheese8, Hoatian Zhang * @author lepdou, cheese8, Hoatian Zhang
*/ */
public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered { public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered {
private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelFeignInterceptor.class);
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,
PolarisContextProperties polarisContextProperties) {
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder));
this.routerLabelResolvers = routerLabelResolvers;
}
else {
this.routerLabelResolvers = null;
}
this.staticMetadataManager = staticMetadataManager;
this.routerRuleLabelResolver = routerRuleLabelResolver;
this.polarisContextProperties = polarisContextProperties;
}
@Override @Override
public int getOrder() { public int getOrder() {
@ -83,62 +41,7 @@ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered
@Override @Override
public void apply(RequestTemplate requestTemplate) { public void apply(RequestTemplate requestTemplate) {
// local service labels MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false)
Map<String, String> labels = new HashMap<>(staticMetadataManager.getMergedStaticMetadata()); .setMetadataProvider(new FeignRequestTemplateMetadataProvider(requestTemplate));
// labels from rule expression
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);
// labels from custom spi
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.forEach(resolver -> {
try {
Map<String, String> customResolvedLabels = resolver.resolve(requestTemplate, expressionLabelKeys);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
}
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
});
}
// labels from downstream
Map<String, String> transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata();
labels.putAll(transitiveLabels);
// pass label by header
String encodedLabelsContent;
try {
encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(labels), UTF_8);
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException("unsupported charset exception " + UTF_8);
}
requestTemplate.header(RouterConstant.ROUTER_LABEL_HEADER, encodedLabelsContent);
}
private Map<String, String> getRuleExpressionLabels(RequestTemplate requestTemplate, Set<String> labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
}
//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;
} }
} }

@ -18,20 +18,16 @@
package com.tencent.cloud.polaris.router.interceptor; package com.tencent.cloud.polaris.router.interceptor;
import java.util.HashSet; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties;
import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor;
import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.TransitiveType;
import com.tencent.polaris.plugins.router.metadata.MetadataRouter; import com.tencent.polaris.plugins.router.metadata.MetadataRouter;
import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest;
import org.springframework.util.CollectionUtils;
/** /**
* Router request interceptor for metadata router. * Router request interceptor for metadata router.
* @author lepdou, Hoatian Zhang * @author lepdou, Hoatian Zhang
@ -51,18 +47,10 @@ public class MetadataRouterRequestInterceptor implements RouterRequestIntercepto
return; return;
} }
// 1. get metadata router label keys // set metadata router label keys
Set<String> metadataRouterKeys = routerContext.getLabelAsSet(LABEL_KEY_METADATA_ROUTER_KEYS); MetadataContainer metadataContainer = MetadataContextHolder.get()
// 2. get metadata router labels .getMetadataContainer(MetadataType.CUSTOM, false);
Map<String, String> metadataRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS, String metadataRouteKeys = metadataContainer.getRawMetadataStringValue(LABEL_KEY_METADATA_ROUTER_KEYS);
metadataRouterKeys); metadataContainer.putMetadataMapValue(MetadataRouter.ROUTER_TYPE_METADATA, MetadataRouter.KEY_METADATA_KEYS, metadataRouteKeys, TransitiveType.NONE);
// 3. set metadata router labels to request
Set<RouteArgument> routeArguments = new HashSet<>();
if (!CollectionUtils.isEmpty(metadataRouterKeys)) {
for (Map.Entry<String, String> entry : metadataRouterLabels.entrySet()) {
routeArguments.add(RouteArgument.fromLabel(entry.getKey(), entry.getValue()));
}
}
request.putRouterArgument(MetadataRouter.ROUTER_TYPE_METADATA, routeArguments);
} }
} }

@ -18,13 +18,13 @@
package com.tencent.cloud.polaris.router.interceptor; package com.tencent.cloud.polaris.router.interceptor;
import java.util.HashSet; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import java.util.Set;
import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties;
import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor;
import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.TransitiveType;
import com.tencent.polaris.plugins.router.nearby.NearbyRouter; import com.tencent.polaris.plugins.router.nearby.NearbyRouter;
import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest;
@ -42,13 +42,10 @@ public class NearbyRouterRequestInterceptor implements RouterRequestInterceptor
@Override @Override
public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) {
if (!polarisNearByRouterProperties.isEnabled()) { // set nearby router enable
return; boolean nearbyRouterEnabled = polarisNearByRouterProperties.isEnabled();
} MetadataContainer metadataContainer = MetadataContextHolder.get()
.getMetadataContainer(MetadataType.CUSTOM, false);
Set<RouteArgument> routeArguments = new HashSet<>(1); metadataContainer.putMetadataMapValue(NearbyRouter.ROUTER_TYPE_NEAR_BY, NearbyRouter.ROUTER_ENABLED, String.valueOf(nearbyRouterEnabled), TransitiveType.NONE);
routeArguments.add(RouteArgument.buildCustom(NearbyRouter.ROUTER_ENABLED, "true"));
request.putRouterArgument(NearbyRouter.ROUTER_TYPE_NEAR_BY, routeArguments);
} }
} }

@ -17,20 +17,16 @@
package com.tencent.cloud.polaris.router.interceptor; package com.tencent.cloud.polaris.router.interceptor;
import java.util.HashSet; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties;
import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor;
import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.TransitiveType;
import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; import com.tencent.polaris.plugins.router.rule.RuleBasedRouter;
import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest;
import org.springframework.util.CollectionUtils;
/** /**
* Router request interceptor for rule based router. * Router request interceptor for rule based router.
* @author lepdou, Hoatian Zhang * @author lepdou, Hoatian Zhang
@ -45,24 +41,12 @@ public class RuleBasedRouterRequestInterceptor implements RouterRequestIntercept
@Override @Override
public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) {
// set rule based router enable
boolean ruleBasedRouterEnabled = polarisRuleBasedRouterProperties.isEnabled(); boolean ruleBasedRouterEnabled = polarisRuleBasedRouterProperties.isEnabled();
MetadataContainer metadataContainer = MetadataContextHolder.get()
// set dynamic switch for rule based router .getMetadataContainer(MetadataType.CUSTOM, false);
Set<RouteArgument> routeArguments = new HashSet<>(); metadataContainer.putMetadataMapValue(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, RuleBasedRouter.ROUTER_ENABLED, String.valueOf(ruleBasedRouterEnabled), TransitiveType.NONE);
routeArguments.add(RouteArgument.buildCustom(RuleBasedRouter.ROUTER_ENABLED, String.valueOf(ruleBasedRouterEnabled))); // set rule based router fail over type.
request.setRuleBasedRouterFailoverType(polarisRuleBasedRouterProperties.getFailOver());
// The label information that the rule based routing depends on
// is placed in the metadata of the source service for transmission.
// Later, can consider putting it in routerMetadata like other routers.
if (ruleBasedRouterEnabled) {
Map<String, String> ruleRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS);
if (!CollectionUtils.isEmpty(ruleRouterLabels)) {
for (Map.Entry<String, String> label : ruleRouterLabels.entrySet()) {
routeArguments.add(RouteArgument.fromLabel(label.getKey(), label.getValue()));
}
}
}
request.putRouterArgument(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, routeArguments);
} }
} }

@ -1,60 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.resttemplate;
import java.io.IOException;
import java.net.URI;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.Assert;
/**
* PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor capabilities.
* Parses the label from the request and puts it into the RouterContext for routing.
*
* @author lepdou, cheese8
*/
public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
private final LoadBalancerClient loadBalancer;
private final LoadBalancerRequestFactory requestFactory;
public PolarisLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
super(loadBalancer, requestFactory);
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String peerServiceName = originalUri.getHost();
Assert.state(peerServiceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(peerServiceName,
new PolarisLoadBalancerRequest<>(request, this.requestFactory.createRequest(request, body, execution)));
}
}

@ -1,52 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.http.HttpRequest;
/**
* Wrapper of {@link LoadBalancerRequest}.
*
* @author Haotian Zhang
*/
public class PolarisLoadBalancerRequest<T> implements LoadBalancerRequest<T> {
private HttpRequest request;
private LoadBalancerRequest<T> delegate;
public PolarisLoadBalancerRequest(HttpRequest request, LoadBalancerRequest<T> delegate) {
this.request = request;
this.delegate = delegate;
}
@Override
public T apply(ServiceInstance instance) throws Exception {
return delegate.apply(instance);
}
public HttpRequest getRequest() {
return request;
}
public LoadBalancerRequest<T> getDelegate() {
return delegate;
}
}

@ -18,73 +18,25 @@
package com.tencent.cloud.polaris.router.resttemplate; package com.tencent.cloud.polaris.router.resttemplate;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.metadata.provider.RestTemplateMetadataProvider;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
/** /**
* Interceptor used for adding the route label in http headers from context when web client * Interceptor used for setting RestTemplate HttpRequest metadata provider.
* is RestTemplate.
* *
* @author liuye, Hoatian Zhang * @author liuye, Hoatian Zhang
*/ */
public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered {
private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelRestTemplateInterceptor.class);
private final List<SpringWebRouterLabelResolver> routerLabelResolvers;
private final StaticMetadataManager staticMetadataManager;
private final RouterRuleLabelResolver routerRuleLabelResolver;
private final PolarisContextProperties polarisContextProperties;
public RouterLabelRestTemplateInterceptor(List<SpringWebRouterLabelResolver> routerLabelResolvers,
StaticMetadataManager staticMetadataManager,
RouterRuleLabelResolver routerRuleLabelResolver,
PolarisContextProperties polarisContextProperties) {
this.staticMetadataManager = staticMetadataManager;
this.routerRuleLabelResolver = routerRuleLabelResolver;
this.polarisContextProperties = polarisContextProperties;
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder));
this.routerLabelResolvers = routerLabelResolvers;
}
else {
this.routerLabelResolvers = null;
}
}
@Override @Override
public int getOrder() { public int getOrder() {
@ -94,82 +46,8 @@ public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInte
@Override @Override
public ClientHttpResponse intercept(@NonNull HttpRequest request, @NonNull byte[] body, public ClientHttpResponse intercept(@NonNull HttpRequest request, @NonNull byte[] body,
@NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
final URI originalUri = request.getURI(); MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false)
String peerServiceName = originalUri.getHost(); .setMetadataProvider(new RestTemplateMetadataProvider(request));
Assert.state(peerServiceName != null, return clientHttpRequestExecution.execute(request, body);
"Request URI does not contain a valid hostname: " + originalUri);
setLabelsToHeaders(request, body, peerServiceName);
ClientHttpResponse response = clientHttpRequestExecution.execute(request, body);
if (!CollectionUtils.isEmpty(request.getHeaders().get(RouterConstant.ROUTER_LABEL_HEADER))) {
HttpHeaders responseHeaders = HttpHeaders.writableHttpHeaders(response.getHeaders());
responseHeaders.addAll(RouterConstant.ROUTER_LABEL_HEADER, Objects.requireNonNull(request.getHeaders()
.get(RouterConstant.ROUTER_LABEL_HEADER)));
}
return response;
}
void setLabelsToHeaders(HttpRequest request, byte[] body, String peerServiceName) {
// local service labels
Map<String, String> labels = new HashMap<>(staticMetadataManager.getMergedStaticMetadata());
// labels from rule expression
Set<String> expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE, peerServiceName);
Map<String, String> ruleExpressionLabels = getExpressionLabels(request, expressionLabelKeys);
if (!CollectionUtils.isEmpty(ruleExpressionLabels)) {
labels.putAll(ruleExpressionLabels);
}
// labels from request
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.forEach(resolver -> {
try {
Map<String, String> customResolvedLabels = resolver.resolve(request, body, expressionLabelKeys);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
}
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
});
}
// labels from downstream
Map<String, String> transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata();
labels.putAll(transitiveLabels);
// pass label by header
String encodedLabelsContent;
try {
encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(labels), UTF_8);
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException("unsupported charset exception " + UTF_8);
}
request.getHeaders().set(RouterConstant.ROUTER_LABEL_HEADER, encodedLabelsContent);
}
private Map<String, String> getExpressionLabels(HttpRequest request, Set<String> labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
}
//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;
} }
} }

@ -1,282 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.scg;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.PolarisRouterServiceInstanceListSupplier;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.CompletionContext;
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycle;
import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycleValidator;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.RequestData;
import org.springframework.cloud.client.loadbalancer.RequestDataContext;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.client.loadbalancer.ResponseData;
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
import org.springframework.cloud.gateway.support.DelegatingServiceInstance;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/**
* ReactiveLoadBalancerClientFilter does not have the ability to pass route labels, so it is replaced
* with PolarisReactiveLoadBalancerClientFilter. The passed route labels are used in
* {@link PolarisRouterServiceInstanceListSupplier}.
*
* @author lepdou, Hoatian Zhang
*/
public class PolarisReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter {
private static final Logger log = LoggerFactory.getLogger(PolarisReactiveLoadBalancerClientFilter.class);
private final LoadBalancerClientFactory clientFactory;
private final GatewayLoadBalancerProperties gatewayLoadBalancerProperties;
private final LoadBalancerProperties loadBalancerProperties;
private final StaticMetadataManager staticMetadataManager;
private final RouterRuleLabelResolver routerRuleLabelResolver;
private final List<SpringWebRouterLabelResolver> routerLabelResolvers;
private final PolarisContextProperties polarisContextProperties;
public PolarisReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory,
GatewayLoadBalancerProperties gatewayLoadBalancerProperties,
LoadBalancerProperties loadBalancerProperties,
StaticMetadataManager staticMetadataManager,
RouterRuleLabelResolver routerRuleLabelResolver,
List<SpringWebRouterLabelResolver> routerLabelResolvers,
PolarisContextProperties polarisContextProperties) {
super(clientFactory, gatewayLoadBalancerProperties, loadBalancerProperties);
this.clientFactory = clientFactory;
this.gatewayLoadBalancerProperties = gatewayLoadBalancerProperties;
this.loadBalancerProperties = loadBalancerProperties;
this.staticMetadataManager = staticMetadataManager;
this.routerRuleLabelResolver = routerRuleLabelResolver;
this.routerLabelResolvers = routerLabelResolvers;
this.polarisContextProperties = polarisContextProperties;
}
/**
* Copied from ReactiveLoadBalancerClientFilter, and create new RequestData for passing router labels.
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
return chain.filter(exchange);
}
// preserve the original url
addOriginalRequestUrl(exchange, url);
if (log.isTraceEnabled()) {
log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
}
URI requestUri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String serviceId = requestUri.getHost();
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
// Pass route tags through http headers
HttpHeaders routerHttpHeaders = genRouterHttpHeaders(exchange, serviceId);
ServerHttpRequest request = exchange.getRequest();
RequestData requestData = new RequestData(request.getMethod(), request.getURI(), routerHttpHeaders,
new HttpHeaders(), new HashMap<>());
DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(new RequestDataContext(
requestData, getHint(serviceId, loadBalancerProperties.getHint())));
return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> {
if (!response.hasServer()) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, response)));
throw NotFoundException.create(gatewayLoadBalancerProperties.isUse404(),
"Unable to find instance for " + url.getHost());
}
ServiceInstance retrievedInstance = response.getServer();
URI uri = exchange.getRequest().getURI();
// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
// if the loadbalancer doesn't provide one.
String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";
if (schemePrefix != null) {
overrideScheme = url.getScheme();
}
DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance,
overrideScheme);
URI requestUrl = reconstructURI(serviceInstance, uri);
if (log.isTraceEnabled()) {
log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
}
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
exchange.getAttributes().put(GATEWAY_LOADBALANCER_RESPONSE_ATTR, response);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, response));
}).then(chain.filter(exchange))
.doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
CompletionContext.Status.FAILED, throwable, lbRequest,
exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR)))))
.doOnSuccess(aVoid -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
CompletionContext.Status.SUCCESS, lbRequest,
exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR),
new ResponseData(exchange.getResponse(), new RequestData(exchange.getRequest()))))));
}
@Override
protected URI reconstructURI(ServiceInstance serviceInstance, URI original) {
return LoadBalancerUriTools.reconstructURI(serviceInstance, original);
}
private Mono<Response<ServiceInstance>> choose(Request<RequestDataContext> lbRequest, String serviceId,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors) {
ReactorLoadBalancer<ServiceInstance> loadBalancer = this.clientFactory.getInstance(serviceId,
ReactorServiceInstanceLoadBalancer.class);
if (loadBalancer == null) {
throw new NotFoundException("No loadbalancer available for " + serviceId);
}
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
return loadBalancer.choose(lbRequest);
}
// no actual used
private String getHint(String serviceId, Map<String, String> hints) {
String defaultHint = hints.getOrDefault("default", "default");
String hintPropertyValue = hints.get(serviceId);
return hintPropertyValue != null ? hintPropertyValue : defaultHint;
}
// In order to be consistent with feign and restTemplate,
// the router label is passed through the http header uniformly instead of the original hint mechanism.
HttpHeaders genRouterHttpHeaders(ServerWebExchange exchange, String peerServiceName) {
HttpHeaders headers = new HttpHeaders();
headers.add(RouterConstant.ROUTER_LABEL_HEADER, genRouterHint(exchange, peerServiceName));
return headers;
}
private String genRouterHint(ServerWebExchange exchange, String peerServiceName) {
Map<String, String> routerLabels = genRouterLabels(exchange, peerServiceName);
String encodedLabelsContent;
try {
encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(routerLabels), UTF_8);
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException("unsupported charset exception " + UTF_8);
}
return encodedLabelsContent;
}
private Map<String, String> genRouterLabels(ServerWebExchange exchange, String peerServiceName) {
// local service labels
Map<String, String> labels = new HashMap<>(staticMetadataManager.getMergedStaticMetadata());
// labels from rule expression
Set<String> expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE, peerServiceName);
Map<String, String> ruleExpressionLabels = getExpressionLabels(exchange, expressionLabelKeys);
if (!CollectionUtils.isEmpty(ruleExpressionLabels)) {
labels.putAll(ruleExpressionLabels);
}
// labels from request
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.forEach(resolver -> {
try {
Map<String, String> customResolvedLabels = resolver.resolve(exchange, expressionLabelKeys);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
}
}
catch (Throwable t) {
log.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
});
}
// labels from downstream
Map<String, String> transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata();
labels.putAll(transitiveLabels);
return labels;
}
private Map<String, String> getExpressionLabels(ServerWebExchange exchange, Set<String> labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
}
//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;
}
}

@ -0,0 +1,57 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.scg;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
/**
* Interceptor used for setting SCG ServerWebExchange metadata provider.
*
* @author Hoatian Zhang
*/
public class RouterLabelGlobalFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
return LOAD_BALANCER_CLIENT_FILTER_ORDER - 1;
}
/**
* Copied from ReactiveLoadBalancerClientFilter, and create new RequestData for passing router labels.
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false)
.setMetadataProvider(new ReactiveMetadataProvider(exchange.getRequest(),
CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
.getRawMetadataStringValue(MetadataConstants.LOCAL_IP)));
return chain.filter(exchange);
}
}

@ -1,42 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.spi;
import java.util.Map;
import java.util.Set;
import feign.RequestTemplate;
import org.springframework.core.Ordered;
/**
* Router label resolver for feign request.
* @author lepdou 2022-07-20
*/
public interface FeignRouterLabelResolver extends Ordered {
/**
* Resolve labels from feign request. User can customize expression parser to extract labels.
*
* @param requestTemplate the feign request.
* @param expressionLabelKeys the expression labels which are configured in router rule.
* @return resolved labels
*/
Map<String, String> resolve(RequestTemplate requestTemplate, Set<String> expressionLabelKeys);
}

@ -1,57 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.spi;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.springframework.core.Ordered;
import org.springframework.http.HttpRequest;
import org.springframework.web.server.ServerWebExchange;
/**
* Router label resolver for spring web http request.
* @author lepdou 2022-07-20
*/
public interface SpringWebRouterLabelResolver extends Ordered {
/**
* resolve labels from rest template request. User can customize expression parser to extract labels.
*
* @param request the rest template request.
* @param body the rest template request body.
* @param expressionLabelKeys the expression labels which are configured in router rule.
* @return resolved labels
*/
default Map<String, String> resolve(HttpRequest request, byte[] body, Set<String> expressionLabelKeys) {
return Collections.emptyMap();
}
/**
* resolve labels from server web exchange. User can customize expression parser to extract labels.
*
* @param exchange the server web exchange.
* @param expressionLabelKeys the expression labels which are configured in router rule.
* @return resolved labels
*/
default Map<String, String> resolve(ServerWebExchange exchange, Set<String> expressionLabelKeys) {
return Collections.emptyMap();
}
}

@ -24,6 +24,12 @@
"defaultValue": true, "defaultValue": true,
"description": "the switch for rule based router." "description": "the switch for rule based router."
}, },
{
"name": "spring.cloud.polaris.router.rule-router.failOver",
"type": "java.lang.String",
"defaultValue": "all",
"description": "the fail over type for rule based router."
},
{ {
"name": "spring.cloud.polaris.router.enabled", "name": "spring.cloud.polaris.router.enabled",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",

@ -20,7 +20,6 @@ package com.tencent.cloud.polaris.router;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.tencent.cloud.common.constant.RouterConstant; import com.tencent.cloud.common.constant.RouterConstant;
@ -97,20 +96,4 @@ public class PolarisRouterContextTest {
String resolvedLabel = routerContext.getLabel("k1"); String resolvedLabel = routerContext.getLabel("k1");
assertThat(resolvedLabel).isEqualTo("v1"); assertThat(resolvedLabel).isEqualTo("v1");
} }
@Test
public void testGetLabelAsSet() {
Map<String, String> labels = new HashMap<>();
labels.put("k1", "v1,v2,v3");
PolarisRouterContext routerContext = new PolarisRouterContext();
routerContext.putLabels(RouterConstant.ROUTER_LABELS, labels);
Set<String> resolvedLabels = routerContext.getLabelAsSet("k1");
assertThat(resolvedLabels.size()).isEqualTo(3);
assertThat(resolvedLabels).contains("v1");
assertThat(resolvedLabels).contains("v2");
assertThat(resolvedLabels).contains("v3");
}
} }

@ -24,7 +24,6 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import com.tencent.cloud.common.constant.RouterConstant; import com.tencent.cloud.common.constant.RouterConstant;
@ -38,7 +37,6 @@ import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouter
import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerRequest;
import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor;
import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor; import com.tencent.cloud.polaris.router.spi.RouterResponseInterceptor;
import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer;
@ -46,9 +44,11 @@ import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.DefaultServiceInstances; import com.tencent.polaris.api.pojo.DefaultServiceInstances;
import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.RouteArgument;
import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.polaris.metadata.core.TransitiveType;
import com.tencent.polaris.plugins.router.metadata.MetadataRouter; import com.tencent.polaris.plugins.router.metadata.MetadataRouter;
import com.tencent.polaris.plugins.router.nearby.NearbyRouter; import com.tencent.polaris.plugins.router.nearby.NearbyRouter;
import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; import com.tencent.polaris.plugins.router.rule.RuleBasedRouter;
@ -66,7 +66,6 @@ import reactor.core.publisher.Flux;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultRequest; import org.springframework.cloud.client.loadbalancer.DefaultRequest;
import org.springframework.cloud.client.loadbalancer.DefaultRequestContext;
import org.springframework.cloud.client.loadbalancer.RequestData; import org.springframework.cloud.client.loadbalancer.RequestData;
import org.springframework.cloud.client.loadbalancer.RequestDataContext; import org.springframework.cloud.client.loadbalancer.RequestDataContext;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
@ -123,27 +122,18 @@ public class PolarisRouterServiceInstanceListSupplierTest {
PolarisRouterServiceInstanceListSupplier polarisSupplier = new PolarisRouterServiceInstanceListSupplier( PolarisRouterServiceInstanceListSupplier polarisSupplier = new PolarisRouterServiceInstanceListSupplier(
delegate, routerAPI, requestInterceptors, null, new PolarisInstanceTransformer()); delegate, routerAPI, requestInterceptors, null, new PolarisInstanceTransformer());
MetadataContainer metadataContainer = MetadataContextHolder.get()
.getMetadataContainer(MetadataType.CUSTOM, false);
metadataContainer.putMetadataStringValue("system-metadata-router-keys", "k2", TransitiveType.NONE);
ServiceInstances serviceInstances = assembleServiceInstances(); ServiceInstances serviceInstances = assembleServiceInstances();
PolarisRouterContext routerContext = assembleRouterContext(); PolarisRouterContext routerContext = assembleRouterContext();
Map<String, String> oldRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS);
Map<String, String> newRouterLabels = new HashMap<>(oldRouterLabels);
newRouterLabels.put("system-metadata-router-keys", "k2");
routerContext.putLabels(RouterConstant.ROUTER_LABELS, newRouterLabels);
ProcessRoutersRequest request = polarisSupplier.buildProcessRoutersRequest(serviceInstances, routerContext); ProcessRoutersRequest request = polarisSupplier.buildProcessRoutersRequest(serviceInstances, routerContext);
polarisSupplier.processRouterRequestInterceptors(request, routerContext); polarisSupplier.processRouterRequestInterceptors(request, routerContext);
Set<RouteArgument> routerMetadata = request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA); String result = metadataContainer.getRawMetadataMapValue(MetadataRouter.ROUTER_TYPE_METADATA, MetadataRouter.KEY_METADATA_KEYS);
assertThat(result).isEqualTo("k2");
assertThat(routerMetadata.size()).isEqualTo(1);
assertThat(request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()).isEqualTo(0);
assertThat(request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED).size()).isEqualTo(1);
for (RouteArgument routeArgument : request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED)) {
assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED);
assertThat(routeArgument.getValue()).isEqualTo("false");
}
} }
} }
@ -166,22 +156,10 @@ public class PolarisRouterServiceInstanceListSupplierTest {
ProcessRoutersRequest request = polarisSupplier.buildProcessRoutersRequest(serviceInstances, routerContext); ProcessRoutersRequest request = polarisSupplier.buildProcessRoutersRequest(serviceInstances, routerContext);
polarisSupplier.processRouterRequestInterceptors(request, routerContext); polarisSupplier.processRouterRequestInterceptors(request, routerContext);
Set<RouteArgument> routerMetadata = request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY); MetadataContainer metadataContainer = MetadataContextHolder.get()
.getMetadataContainer(MetadataType.CUSTOM, false);
assertThat(request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA).size()).isEqualTo(0); String result = metadataContainer.getRawMetadataMapValue(NearbyRouter.ROUTER_TYPE_NEAR_BY, NearbyRouter.ROUTER_ENABLED);
assertThat(routerMetadata.size()).isEqualTo(1); assertThat(result).isEqualTo("true");
for (RouteArgument routeArgument : routerMetadata) {
assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED);
assertThat(routeArgument.getValue()).isEqualTo("true");
}
assertThat(request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED).size()).isEqualTo(1);
for (RouteArgument routeArgument : request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED)) {
assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED);
assertThat(routeArgument.getValue()).isEqualTo("false");
}
} }
} }
@ -204,11 +182,10 @@ public class PolarisRouterServiceInstanceListSupplierTest {
ProcessRoutersRequest request = polarisSupplier.buildProcessRoutersRequest(serviceInstances, routerContext); ProcessRoutersRequest request = polarisSupplier.buildProcessRoutersRequest(serviceInstances, routerContext);
polarisSupplier.processRouterRequestInterceptors(request, routerContext); polarisSupplier.processRouterRequestInterceptors(request, routerContext);
Set<RouteArgument> routerMetadata = request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED); MetadataContainer metadataContainer = MetadataContextHolder.get()
.getMetadataContainer(MetadataType.CUSTOM, false);
assertThat(routerMetadata.size()).isEqualTo(3); String result = metadataContainer.getRawMetadataMapValue(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, RuleBasedRouter.ROUTER_ENABLED);
assertThat(request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA).size()).isEqualTo(0); assertThat(result).isEqualTo("true");
assertThat(request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()).isEqualTo(0);
} }
} }
@ -242,7 +219,7 @@ public class PolarisRouterServiceInstanceListSupplierTest {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
PolarisRouterContext context = polarisSupplier.buildRouterContext(headers); PolarisRouterContext context = polarisSupplier.buildRouterContext(headers);
assertThat(context).isNull(); assertThat(context).isNotNull();
// mock // mock
try (MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { try (MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) {
@ -266,25 +243,6 @@ public class PolarisRouterServiceInstanceListSupplierTest {
@Test @Test
public void testGet02() { public void testGet02() {
try (MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) {
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(testCallerService);
PolarisRouterServiceInstanceListSupplier polarisSupplier = new PolarisRouterServiceInstanceListSupplier(
delegate, routerAPI, requestInterceptors, null, new PolarisInstanceTransformer());
MockServerHttpRequest httpRequest = MockServerHttpRequest.get("/" + testCalleeService + "/users")
.header("k1", "v1")
.queryParam("userid", "zhangsan")
.build();
RequestDataContext requestDataContext = new RequestDataContext(new RequestData(httpRequest), "blue");
DefaultRequest request = new DefaultRequest(requestDataContext);
assertThat(polarisSupplier.get(request)).isNull();
}
}
@Test
public void testGet03() {
try (MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { try (MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) {
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(testCallerService); .thenReturn(testCallerService);
@ -299,14 +257,14 @@ public class PolarisRouterServiceInstanceListSupplierTest {
MockServerHttpRequest httpRequest = MockServerHttpRequest.get("/" + testCalleeService + "/users") MockServerHttpRequest httpRequest = MockServerHttpRequest.get("/" + testCalleeService + "/users")
.header("k1", "v1") .header("k1", "v1")
.header(RouterConstant.ROUTER_LABEL_HEADER, "{\"k1\":\"v1\"}")
.queryParam("userid", "zhangsan") .queryParam("userid", "zhangsan")
.build(); .build();
DefaultRequestContext requestDataContext = new DefaultRequestContext(new PolarisLoadBalancerRequest(httpRequest, null), "blue"); RequestDataContext requestDataContext = new RequestDataContext(new RequestData(httpRequest), "blue");
DefaultRequest request = new DefaultRequest(requestDataContext); DefaultRequest request = new DefaultRequest(requestDataContext);
assertThat(polarisSupplier.get(request).blockFirst().size()).isEqualTo(0); assertThat(polarisSupplier.get(request)).isNotNull();
} }
} }
private void setTransitiveMetadata() { private void setTransitiveMetadata() {
if (initTransitiveMetadata.compareAndSet(false, true)) { if (initTransitiveMetadata.compareAndSet(false, true)) {
// mock transitive metadata // mock transitive metadata

@ -1,95 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.specification.api.v1.model.ModelProto;
import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
/**
* test for {@link RouterRuleLabelResolver}.
*
* @author lepdou 2022-05-26
*/
@ExtendWith(MockitoExtension.class)
public class RouterRuleLabelResolverTest {
private final String testNamespace = "testNamespace";
private final String testSourceService = "sourceService";
private final String testDstService = "dstService";
@Mock
private ServiceRuleManager serviceRuleManager;
@Test
public void test() {
Map<String, ModelProto.MatchString> labels = new HashMap<>();
ModelProto.MatchString matchString = ModelProto.MatchString.getDefaultInstance();
String validKey1 = "${http.header.uid}";
String validKey2 = "${http.query.name}";
String validKey3 = "${http.method}";
String validKey4 = "${http.uri}";
String validKey5 = "${http.body.customkey}";
String invalidKey = "$http.expression.wrong}";
labels.put(validKey1, matchString);
labels.put(validKey2, matchString);
labels.put(validKey3, matchString);
labels.put(validKey4, matchString);
labels.put(validKey5, matchString);
labels.put(invalidKey, matchString);
RoutingProto.Source source1 = RoutingProto.Source.newBuilder().putAllMetadata(labels).build();
RoutingProto.Source source2 = RoutingProto.Source.newBuilder().putAllMetadata(labels).build();
RoutingProto.Source source3 = RoutingProto.Source.newBuilder().putAllMetadata(new HashMap<>()).build();
List<RoutingProto.Route> routes = new LinkedList<>();
RoutingProto.Route route = RoutingProto.Route.newBuilder()
.addAllSources(Lists.list(source1, source2, source3))
.build();
routes.add(route);
when(serviceRuleManager.getServiceRouterRule(testNamespace, testSourceService, testDstService)).thenReturn(routes);
RouterRuleLabelResolver resolver = new RouterRuleLabelResolver(serviceRuleManager);
Set<String> resolvedExpressionLabelKeys = resolver.getExpressionLabelKeys(testNamespace, testSourceService, testDstService);
assertThat(resolvedExpressionLabelKeys).isNotNull();
assertThat(resolvedExpressionLabelKeys.size()).isEqualTo(6);
assertThat(resolvedExpressionLabelKeys).contains(validKey1);
assertThat(resolvedExpressionLabelKeys).contains(validKey2);
assertThat(resolvedExpressionLabelKeys).contains(validKey3);
assertThat(resolvedExpressionLabelKeys).contains(validKey4);
assertThat(resolvedExpressionLabelKeys).contains(validKey5);
assertThat(resolvedExpressionLabelKeys).contains(invalidKey);
}
}

@ -28,6 +28,7 @@ import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer;
import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceInstances;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
@ -51,6 +52,11 @@ public class RouterUtilsTest {
private static final String testNamespaceAndService = "testNamespaceAndService"; private static final String testNamespaceAndService = "testNamespaceAndService";
@BeforeAll
static void beforeAll() {
MetadataContext.LOCAL_NAMESPACE = testNamespaceAndService;
}
@Test @Test
public void testTransferEmptyInstances() { public void testTransferEmptyInstances() {
ServiceInstances serviceInstances = RouterUtils.transferServersToServiceInstances(Flux.empty(), new PolarisInstanceTransformer()); ServiceInstances serviceInstances = RouterUtils.transferServersToServiceInstances(Flux.empty(), new PolarisInstanceTransformer());

@ -1,86 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.beanprocessor;
import com.tencent.cloud.common.util.BeanFactoryUtils;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
/**
* Test for ${@link LoadBalancerInterceptorBeanPostProcessor}.
*
* @author lepdou 2022-05-26
*/
@ExtendWith(MockitoExtension.class)
public class LoadBalancerInterceptorBeanPostProcessorTest {
@Mock
private LoadBalancerClient loadBalancerClient;
@Mock
private LoadBalancerRequestFactory loadBalancerRequestFactory;
@Mock
private BeanFactory beanFactory;
@Test
public void testWrapperLoadBalancerInterceptor() {
when(beanFactory.getBean(LoadBalancerRequestFactory.class)).thenReturn(loadBalancerRequestFactory);
when(beanFactory.getBean(LoadBalancerClient.class)).thenReturn(loadBalancerClient);
try (MockedStatic<BeanFactoryUtils> mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) {
mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, SpringWebRouterLabelResolver.class))
.thenReturn(null);
LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(loadBalancerClient, loadBalancerRequestFactory);
LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Object bean = processor.postProcessBeforeInitialization(loadBalancerInterceptor, "");
assertThat(bean).isInstanceOf(PolarisLoadBalancerInterceptor.class);
}
}
@Test
public void testNotWrapperLoadBalancerInterceptor() {
LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor();
processor.setBeanFactory(beanFactory);
OtherBean otherBean = new OtherBean();
Object bean = processor.postProcessBeforeInitialization(otherBean, "");
assertThat(bean).isNotInstanceOf(PolarisLoadBalancerInterceptor.class);
assertThat(bean).isInstanceOf(OtherBean.class);
}
static class OtherBean {
}
}

@ -1,100 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.beanprocessor;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.util.BeanFactoryUtils;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.scg.PolarisReactiveLoadBalancerClientFilter;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
/**
* Test for ${@link ReactiveLoadBalancerClientFilterBeanPostProcessor}.
*
* @author lepdou 2022-07-04
*/
@ExtendWith(MockitoExtension.class)
public class ReactiveLoadBalancerClientFilterBeanPostProcessorTest {
@Mock
private BeanFactory beanFactory;
@Mock
private LoadBalancerClientFactory loadBalancerClientFactory;
@Mock
private GatewayLoadBalancerProperties gatewayLoadBalancerProperties;
@Mock
private LoadBalancerProperties loadBalancerProperties;
@Mock
private StaticMetadataManager staticMetadataManager;
@Mock
private RouterRuleLabelResolver routerRuleLabelResolver;
@Test
public void testWrapReactiveLoadBalancerClientFilter() {
when(beanFactory.getBean(LoadBalancerClientFactory.class)).thenReturn(loadBalancerClientFactory);
when(beanFactory.getBean(GatewayLoadBalancerProperties.class)).thenReturn(gatewayLoadBalancerProperties);
when(beanFactory.getBean(LoadBalancerProperties.class)).thenReturn(loadBalancerProperties);
when(beanFactory.getBean(StaticMetadataManager.class)).thenReturn(staticMetadataManager);
when(beanFactory.getBean(RouterRuleLabelResolver.class)).thenReturn(routerRuleLabelResolver);
try (MockedStatic<BeanFactoryUtils> mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) {
mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, SpringWebRouterLabelResolver.class))
.thenReturn(null);
ReactiveLoadBalancerClientFilter reactiveLoadBalancerClientFilter = new ReactiveLoadBalancerClientFilter(
loadBalancerClientFactory, gatewayLoadBalancerProperties, loadBalancerProperties);
ReactiveLoadBalancerClientFilterBeanPostProcessor processor = new ReactiveLoadBalancerClientFilterBeanPostProcessor();
processor.setBeanFactory(beanFactory);
Object bean = processor.postProcessBeforeInitialization(reactiveLoadBalancerClientFilter, "");
assertThat(bean).isInstanceOf(PolarisReactiveLoadBalancerClientFilter.class);
}
}
@Test
public void testNotWrapLoadBalancerInterceptor() {
ReactiveLoadBalancerClientFilterBeanPostProcessor processor = new ReactiveLoadBalancerClientFilterBeanPostProcessor();
processor.setBeanFactory(beanFactory);
OtherBean otherBean = new OtherBean();
Object bean = processor.postProcessBeforeInitialization(otherBean, "");
assertThat(bean).isNotInstanceOf(PolarisReactiveLoadBalancerClientFilter.class);
assertThat(bean).isInstanceOf(OtherBean.class);
}
static class OtherBean {
}
}

@ -49,7 +49,7 @@ public class PolarisRuleBasedRouterPropertiesTest {
@Test @Test
public void testToString() { public void testToString() {
assertThat(properties.toString()) assertThat(properties.toString())
.isEqualTo("PolarisNearByRouterProperties{enabled=true}"); .isEqualTo("PolarisRuleBasedRouterProperties{enabled=true, failOver=all}");
} }
} }

@ -1,162 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.feign;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import feign.Request;
import feign.RequestTemplate;
import org.junit.jupiter.api.Test;
import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link FeignExpressionLabelUtils}.
*
* @author lepdou 2022-05-26
*/
public class FeignExpressionLabelUtilsTest {
@Test
public void testGetHeaderLabel() {
String headerKey = "uid";
String headerValue = "1000";
String headerKey2 = "teacher.age";
String headerValue2 = "1000";
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.header(headerKey, headerValue);
requestTemplate.header(headerKey2, headerValue2);
String labelKey1 = "${http.header.uid}";
String labelKey2 = "${http.header.name}";
String labelKey3 = "${http.headername}";
String labelKey4 = "${http.header.}";
String labelKey5 = "${http.header.teacher.age}";
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate,
Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet()));
assertThat(result).isNotEmpty();
assertThat(result.get(labelKey1)).isEqualTo(headerValue);
assertThat(result.get(labelKey5)).isEqualTo(headerValue2);
assertThat(result.get(labelKey2)).isBlank();
assertThat(result.get(labelKey3)).isBlank();
assertThat(result.get(labelKey4)).isBlank();
}
@Test
public void testGetQueryLabel() {
String headerKey = "uid";
String headerValue = "1000";
String headerKey2 = "teacher.age";
String headerValue2 = "1000";
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.query(headerKey, headerValue);
requestTemplate.query(headerKey2, headerValue2);
String labelKey1 = "${http.query.uid}";
String labelKey2 = "${http.query.name}";
String labelKey3 = "${http.queryname}";
String labelKey4 = "${http.query.}";
String labelKey5 = "${http.query.teacher.age}";
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate,
Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet()));
assertThat(result).isNotEmpty();
assertThat(result.get(labelKey1)).isEqualTo(headerValue);
assertThat(result.get(labelKey5)).isEqualTo(headerValue2);
assertThat(result.get(labelKey2)).isBlank();
assertThat(result.get(labelKey3)).isBlank();
assertThat(result.get(labelKey4)).isBlank();
}
@Test
public void testGetMethod() {
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.method(Request.HttpMethod.GET);
String labelKey1 = "${http.method}";
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
.collect(toSet()));
assertThat(result).isNotEmpty();
assertThat(result.get(labelKey1)).isEqualTo("GET");
}
@Test
public void testGetUri() {
String uri = "/user/get";
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.uri(uri);
requestTemplate.method(Request.HttpMethod.GET);
requestTemplate.target("http://localhost");
requestTemplate = requestTemplate.resolve(new HashMap<>());
String labelKey1 = "${http.uri}";
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
.collect(toSet()));
assertThat(result).isNotEmpty();
assertThat(result.get(labelKey1)).isEqualTo(uri);
}
@Test
public void testGetUri2() {
String uri = "/";
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.uri(uri);
requestTemplate.method(Request.HttpMethod.GET);
requestTemplate.target("http://localhost");
requestTemplate = requestTemplate.resolve(new HashMap<>());
String labelKey1 = "${http.uri}";
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
.collect(toSet()));
assertThat(result).isNotEmpty();
assertThat(result.get(labelKey1)).isEqualTo(uri);
}
@Test
public void testGetCookie() {
String uri = "/";
String cookieValue = "zhangsan";
RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.uri(uri);
requestTemplate.method(Request.HttpMethod.GET);
requestTemplate.target("http://localhost");
requestTemplate = requestTemplate.resolve(new HashMap<>());
requestTemplate.header("cookie", Collections.singleton("uid=zhangsan; auth-token=dfhuwshfy77"));
String labelKey1 = "${http.cookie.uid}";
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
.collect(toSet()));
assertThat(result).isNotEmpty();
assertThat(result.get(labelKey1)).isEqualTo(cookieValue);
}
}

@ -18,124 +18,81 @@
package com.tencent.cloud.polaris.router.feign; package com.tencent.cloud.polaris.router.feign;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import feign.Request;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver;
import feign.RequestTemplate; import feign.RequestTemplate;
import feign.Target; import io.netty.handler.codec.http.HttpHeaderNames;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.mockito.Mockito; import org.springframework.boot.test.context.SpringBootTest;
import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.mock;
/** /**
* test for {@link RouterLabelFeignInterceptor}. * test for {@link RouterLabelFeignInterceptor}.
* *
* @author lepdou, cheese8 * @author lepdou 2022-05-26
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(SpringExtension.class)
@SpringBootTest(classes = RouterLabelFeignInterceptorTest.TestApplication.class,
properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", "spring.cloud.gateway.enabled=false"})
public class RouterLabelFeignInterceptorTest { public class RouterLabelFeignInterceptorTest {
@Mock
private StaticMetadataManager staticMetadataManager;
@Mock
private RouterRuleLabelResolver routerRuleLabelResolver;
@Mock
private FeignRouterLabelResolver routerLabelResolver;
@Mock
private PolarisContextProperties polarisContextProperties;
@Test @Test
public void testResolveRouterLabel() throws UnsupportedEncodingException { public void testRouterLabel() {
RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor( RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor();
Collections.singletonList(routerLabelResolver),
staticMetadataManager, routerRuleLabelResolver, polarisContextProperties);
assertThat(routerLabelFeignInterceptor.getOrder()).isEqualTo(OrderConstant.Client.Feign.ROUTER_LABEL_INTERCEPTOR_ORDER); assertThat(routerLabelFeignInterceptor.getOrder()).isEqualTo(OrderConstant.Client.Feign.ROUTER_LABEL_INTERCEPTOR_ORDER);
// mock request template // mock request template
RequestTemplate requestTemplate = new RequestTemplate(); RequestTemplate requestTemplate = mock(RequestTemplate.class);
String headerUidKey = "uid"; String headerUidKey = "uid";
String headerUidValue = "1000"; String headerUidValue = "1000";
requestTemplate.header(headerUidKey, headerUidValue); Map<String, List<String>> headerMap = new HashMap<>();
String peerService = "peerService"; headerMap.put(headerUidKey, Collections.singletonList(headerUidValue));
Target.EmptyTarget<Object> target = Target.EmptyTarget.create(Object.class, peerService); headerMap.put(HttpHeaderNames.COOKIE.toString(), Collections.singletonList("k1=v1"));
requestTemplate.feignTarget(target); doReturn(headerMap).when(requestTemplate).headers();
doReturn(Request.HttpMethod.POST.toString()).when(requestTemplate).method();
// mock ApplicationContextAwareUtils#getProperties Request request = mock(Request.class);
try (MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { doReturn(request).when(requestTemplate).request();
String testService = "callerService"; doReturn("http://callee/test/path").when(request).url();
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) Map<String, List<String>> queryMap = new HashMap<>();
.thenReturn(testService); queryMap.put("q1", Collections.singletonList("a1"));
doReturn(queryMap).when(requestTemplate).queries();
MetadataContext metadataContext = Mockito.mock(MetadataContext.class);
// mock transitive metadata
Map<String, String> transitiveLabels = new HashMap<>();
transitiveLabels.put("k1", "v1");
transitiveLabels.put("k2", "v22");
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
// mock MetadataContextHolder#get
try (MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) {
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
// mock expression rule labels
Set<String> expressionKeys = new HashSet<>();
expressionKeys.add("${http.header.uid}");
expressionKeys.add("${http.header.name}");
when(routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE, peerService)).thenReturn(expressionKeys);
// mock custom resolved labels from request
Map<String, String> customResolvedLabels = new HashMap<>();
customResolvedLabels.put("k2", "v2");
customResolvedLabels.put("k3", "v3");
when(routerLabelResolver.resolve(requestTemplate, expressionKeys)).thenReturn(customResolvedLabels);
Map<String, String> localMetadata = new HashMap<>();
localMetadata.put("k3", "v31");
localMetadata.put("k4", "v4");
when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata);
routerLabelFeignInterceptor.apply(requestTemplate); routerLabelFeignInterceptor.apply(requestTemplate);
Collection<String> routerLabels = requestTemplate.headers().get(RouterConstant.ROUTER_LABEL_HEADER); // get message metadata container
MetadataContainer metadataContainer = MetadataContextHolder.get()
.getMetadataContainer(MetadataType.MESSAGE, false);
// method
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString());
// path
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path");
// header
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerUidKey)).isEqualTo(headerUidValue);
// cookie
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1");
// query
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1");
}
assertThat(routerLabels).isNotNull(); @SpringBootApplication
for (String value : routerLabels) { protected static class TestApplication {
Map<String, String> labels = JacksonUtils.deserialize2Map(URLDecoder.decode(value, "UTF-8"));
assertThat(labels.get("k1")).isEqualTo("v1");
assertThat(labels.get("k2")).isEqualTo("v22");
assertThat(labels.get("k3")).isEqualTo("v3");
assertThat(labels.get("k4")).isEqualTo("v4");
assertThat(labels.get("${http.header.uid}")).isEqualTo(headerUidValue);
assertThat(labels.get("${http.header.name}")).isEqualTo("");
}
}
}
} }
} }

@ -1,59 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.resttemplate;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.http.HttpRequest;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
/**
* test for {@link PolarisLoadBalancerRequest}.
* @author dongyinuo
*/
public class PolarisLoadBalancerRequestTests {
@Test
public void test() throws Exception {
String calleeService = "calleeService";
HttpRequest request = new RouterLabelRestTemplateInterceptorTest.MockedHttpRequest("http://" + calleeService + "/user/get");
MockLoadBalancerRequest mockLoadBalancerRequest = new MockLoadBalancerRequest();
PolarisLoadBalancerRequest<ServiceInstance> polarisLoadBalancerRequest = new PolarisLoadBalancerRequest<>(request, mockLoadBalancerRequest);
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(calleeService);
ServiceInstance apply = polarisLoadBalancerRequest.apply(serviceInstance);
assertThat(apply.getServiceId()).isEqualTo(calleeService);
assertThat(polarisLoadBalancerRequest.getRequest()).isEqualTo(request);
assertThat(polarisLoadBalancerRequest.getDelegate()).isEqualTo(mockLoadBalancerRequest);
}
static class MockLoadBalancerRequest implements LoadBalancerRequest {
@Override
public Object apply(ServiceInstance instance) throws Exception {
return instance;
}
}
}

@ -13,39 +13,26 @@
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * 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 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*
*/ */
package com.tencent.cloud.polaris.router.resttemplate; package com.tencent.cloud.polaris.router.resttemplate;
import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder; import com.tencent.cloud.common.constant.OrderConstant;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
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.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.polaris.metadata.core.MetadataType;
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; import feign.Request;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import io.netty.handler.codec.http.HttpHeaderNames;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.Ordered; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
@ -53,14 +40,11 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
/** /**
@ -68,117 +52,63 @@ import static org.mockito.Mockito.when;
* *
* @author liuye, Haotian Zhang * @author liuye, Haotian Zhang
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(SpringExtension.class)
@SpringBootTest(classes = RouterLabelRestTemplateInterceptorTest.TestApplication.class,
properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", "spring.cloud.gateway.enabled=false"})
public class RouterLabelRestTemplateInterceptorTest { public class RouterLabelRestTemplateInterceptorTest {
private static final String testNamespaceAndService = "testNamespaceAndService";
@Mock
private SpringWebRouterLabelResolver routerLabelResolver;
@Mock
private StaticMetadataManager staticMetadataManager;
@Mock
private RouterRuleLabelResolver routerRuleLabelResolver;
@Mock
private PolarisContextProperties polarisContextProperties;
@Mock @Mock
private ClientHttpRequestExecution clientHttpRequestExecution; private ClientHttpRequestExecution clientHttpRequestExecution;
@Test @Test
public void testRouterContext() throws Exception { public void testRouterLabel() throws Exception {
try ( RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor = new RouterLabelRestTemplateInterceptor();
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class) assertThat(routerLabelRestTemplateInterceptor.getOrder()).isEqualTo(OrderConstant.Client.RestTemplate.ROUTER_LABEL_INTERCEPTOR_ORDER);
) {
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(testNamespaceAndService);
String calleeService = "calleeService"; String calleeService = "calleeService";
HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/user/get"); HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/test/path?q1=a1");
// mock local metadata
Map<String, String> localMetadata = new HashMap<>();
localMetadata.put("k1", "v1");
localMetadata.put("k2", "v2");
when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata);
Map<String, String> routerLabels = new HashMap<>(localMetadata);
// mock expression rule labels
Set<String> expressionKeys = new HashSet<>();
expressionKeys.add("${http.method}");
expressionKeys.add("${http.uri}");
when(routerRuleLabelResolver.getExpressionLabelKeys(testNamespaceAndService, testNamespaceAndService, calleeService)).thenReturn(expressionKeys);
routerLabels.putAll(SpringWebExpressionLabelUtils.resolve(request, expressionKeys));
// mock custom resolved from request
Map<String, String> customResolvedLabels = new HashMap<>();
customResolvedLabels.put("k2", "v22");
customResolvedLabels.put("k4", "v4");
when(routerLabelResolver.resolve(request, null, expressionKeys)).thenReturn(customResolvedLabels);
routerLabels.putAll(customResolvedLabels);
MetadataContext metadataContext = Mockito.mock(MetadataContext.class);
// mock transitive metadata
Map<String, String> transitiveLabels = new HashMap<>();
transitiveLabels.put("k1", "v1");
transitiveLabels.put("k2", "v22");
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
routerLabels.putAll(transitiveLabels);
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor = new RouterLabelRestTemplateInterceptor(
Collections.singletonList(routerLabelResolver), staticMetadataManager, routerRuleLabelResolver, polarisContextProperties);
ClientHttpResponse mockedResponse = new MockClientHttpResponse(new byte[] {}, HttpStatus.OK); ClientHttpResponse mockedResponse = new MockClientHttpResponse(new byte[] {}, HttpStatus.OK);
when(clientHttpRequestExecution.execute(eq(request), any())).thenReturn(mockedResponse); when(clientHttpRequestExecution.execute(eq(request), any())).thenReturn(mockedResponse);
assertThat(routerLabelRestTemplateInterceptor.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);
routerLabelRestTemplateInterceptor.intercept(request, null, clientHttpRequestExecution); routerLabelRestTemplateInterceptor.intercept(request, null, clientHttpRequestExecution);
verify(staticMetadataManager).getMergedStaticMetadata(); // get message metadata container
verify(routerRuleLabelResolver).getExpressionLabelKeys(testNamespaceAndService, testNamespaceAndService, calleeService); MetadataContainer metadataContainer = MetadataContextHolder.get()
verify(routerLabelResolver).resolve(request, null, expressionKeys); .getMetadataContainer(MetadataType.MESSAGE, false);
// method
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString());
Map<String, String> headers = JacksonUtils.deserialize2Map(URLDecoder.decode(Objects.requireNonNull(request.getHeaders() // path
.get(RouterConstant.ROUTER_LABEL_HEADER)).get(0), "UTF-8")); assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path");
assertThat("v1").isEqualTo(headers.get("k1")); // header
assertThat("v22").isEqualTo(headers.get("k2")); assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000");
assertThat("v4").isEqualTo(headers.get("k4")); // cookie
assertThat("GET").isEqualTo(headers.get("${http.method}")); assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1");
assertThat("/user/get").isEqualTo(headers.get("${http.uri}")); // query
String encodedLabelsContent; assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1");
try {
encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(routerLabels), UTF_8);
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException("unsupported charset exception " + UTF_8);
}
assertThat(mockedResponse.getHeaders().get(RouterConstant.ROUTER_LABEL_HEADER).get(0))
.isEqualTo(encodedLabelsContent);
}
} }
static class MockedHttpRequest implements HttpRequest { static class MockedHttpRequest implements HttpRequest {
private URI uri; private final URI uri;
private HttpHeaders httpHeaders = new HttpHeaders(); private final HttpHeaders httpHeaders = new HttpHeaders();
MockedHttpRequest(String url) { MockedHttpRequest(String url) {
this.uri = URI.create(url); this.uri = URI.create(url);
this.httpHeaders.add("uid", "1000");
this.httpHeaders.add(HttpHeaderNames.COOKIE.toString(), "k1=v1");
} }
@Override
public HttpMethod getMethod() {
return HttpMethod.POST;
}
@Override @Override
public String getMethodValue() { public String getMethodValue() {
return HttpMethod.GET.name(); return HttpMethod.POST.toString();
} }
@Override @Override
public URI getURI() { public URI getURI() {
return uri; return uri;
@ -189,4 +119,9 @@ public class RouterLabelRestTemplateInterceptorTest {
return httpHeaders; return httpHeaders;
} }
} }
@SpringBootApplication
protected static class TestApplication {
}
} }

@ -1,201 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.scg;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.assertj.core.util.Lists;
import org.assertj.core.util.Sets;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR;
/**
* Test for ${@link PolarisReactiveLoadBalancerClientFilter}.
*
* @author lepdou 2022-07-04
*/
@ExtendWith(MockitoExtension.class)
public class PolarisReactiveLoadBalancerClientFilterTest {
private static final String testNamespaceAndService = "testNamespaceAndService";
private static final String calleeService = "calleeService";
@Mock
private StaticMetadataManager staticMetadataManager;
@Mock
private SpringWebRouterLabelResolver routerLabelResolver;
@Mock
private RouterRuleLabelResolver routerRuleLabelResolver;
@Mock
private LoadBalancerClientFactory loadBalancerClientFactory;
@Mock
private GatewayLoadBalancerProperties gatewayLoadBalancerProperties;
@Mock
private LoadBalancerProperties loadBalancerProperties;
@Mock
private PolarisContextProperties polarisContextProperties;
@Test
public void testGenRouterHttpHeaders() throws UnsupportedEncodingException {
try (
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class)
) {
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(testNamespaceAndService);
MetadataContext metadataContext = mock(MetadataContext.class);
// mock transitive metadata
Map<String, String> transitiveLabels = new HashMap<>();
transitiveLabels.put("t1", "v1");
transitiveLabels.put("t2", "v2");
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
gatewayLoadBalancerProperties, loadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
Collections.singletonList(routerLabelResolver), polarisContextProperties);
Map<String, String> localMetadata = new HashMap<>();
localMetadata.put("env", "blue");
when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata);
Set<String> expressionLabelKeys = Sets.newLinkedHashSet("${http.header.k1}", "${http.query.userid}");
when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString())).thenReturn(expressionLabelKeys);
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users")
.header("k1", "v1")
.queryParam("userid", "zhangsan")
.build();
MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build();
Map<String, String> customMetadata = new HashMap<>();
customMetadata.put("k2", "v2");
when(routerLabelResolver.resolve(webExchange, expressionLabelKeys)).thenReturn(customMetadata);
HttpHeaders headers = filter.genRouterHttpHeaders(webExchange, calleeService);
assertThat(headers).isNotNull();
List<String> routerHeaders = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
assertThat(routerHeaders).isNotNull();
Map<String, String> routerLabels = JacksonUtils.deserialize2Map(URLDecoder.decode(routerHeaders.get(0), UTF_8));
assertThat(routerLabels.get("${http.header.k1}")).isEqualTo("v1");
assertThat(routerLabels.get("${http.query.userid}")).isEqualTo("zhangsan");
assertThat(routerLabels.get("env")).isEqualTo("blue");
assertThat(routerLabels.get("t1")).isEqualTo("v1");
assertThat(routerLabels.get("t2")).isEqualTo("v2");
}
}
@Test
public void testFilter01() throws Exception {
try (
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class)
) {
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(testNamespaceAndService);
MetadataContext metadataContext = mock(MetadataContext.class);
// mock transitive metadata
Map<String, String> transitiveLabels = new HashMap<>();
transitiveLabels.put("t1", "v1");
transitiveLabels.put("t2", "v2");
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
gatewayLoadBalancerProperties, loadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
Lists.list(routerLabelResolver), polarisContextProperties);
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users").build();
MockServerWebExchange exchange = new MockServerWebExchange.Builder(request).build();
// mock no lb
EmptyGatewayFilterChain chain = new EmptyGatewayFilterChain();
Mono<Void> ret = filter.filter(exchange, chain);
assertThat(ret).isEqualTo(Mono.empty());
// mock with lb
exchange = new MockServerWebExchange.Builder(request).build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("https://" + calleeService + ":8091"));
exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, "lb");
NoopServiceInstanceListSupplier serviceInstanceListSupplier = new NoopServiceInstanceListSupplier();
RoundRobinLoadBalancer roundRobinLoadBalancer = new RoundRobinLoadBalancer(new SimpleObjectProvider<>(serviceInstanceListSupplier), calleeService);
when(loadBalancerClientFactory.getInstance(calleeService, ReactorServiceInstanceLoadBalancer.class)).thenReturn(roundRobinLoadBalancer);
filter.filter(exchange, chain);
}
}
static class EmptyGatewayFilterChain implements GatewayFilterChain {
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.empty();
}
}
}

@ -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.polaris.router.scg;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataContainer;
import com.tencent.polaris.metadata.core.MetadataType;
import feign.Request;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpCookie;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.server.ServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
/**
* Test for ${@link RouterLabelGlobalFilter}.
*
* @author Haotian Zhang
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = RouterLabelGlobalFilterTest.TestApplication.class,
properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", "spring.main.web-application-type=reactive"})
public class RouterLabelGlobalFilterTest {
@Test
public void testRouterLabel() {
RouterLabelGlobalFilter routerLabelGlobalFilter = new RouterLabelGlobalFilter();
assertThat(routerLabelGlobalFilter.getOrder())
.isEqualTo(LOAD_BALANCER_CLIENT_FILTER_ORDER - 1);
MockServerHttpRequest request = MockServerHttpRequest.post("/test/path")
.header("uid", "1000")
.cookie(new HttpCookie("k1", "v1"))
.queryParam("q1", "a1")
.build();
MockServerWebExchange mockWebExchange = new MockServerWebExchange.Builder(request).build();
routerLabelGlobalFilter.filter(mockWebExchange, new EmptyGatewayFilterChain());
// get message metadata container
MetadataContainer metadataContainer = MetadataContextHolder.get()
.getMetadataContainer(MetadataType.MESSAGE, false);
// method
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString());
// path
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path");
// header
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000");
// cookie
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1");
// query
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1");
}
static class EmptyGatewayFilterChain implements GatewayFilterChain {
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.empty();
}
}
@SpringBootApplication
protected static class TestApplication {
}
}

@ -23,7 +23,6 @@ import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer;
import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.Instance;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
import org.mockito.Mockito; import org.mockito.Mockito;
@ -37,20 +36,14 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
public class PolarisInstanceTransformerTest { public class PolarisInstanceTransformerTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; @Test
public void test() {
@BeforeAll try (
public static void beforeAll() { MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace")) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace"))
.thenReturn("default"); .thenReturn("default");
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service")) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service"))
.thenReturn("test"); .thenReturn("test");
}
@Test
public void test() {
PolarisInstanceTransformer polarisInstanceTransformer = new PolarisInstanceTransformer(); PolarisInstanceTransformer polarisInstanceTransformer = new PolarisInstanceTransformer();
DefaultInstance instance = new DefaultInstance(); DefaultInstance instance = new DefaultInstance();
instance.setZone("zone"); instance.setZone("zone");
@ -59,3 +52,4 @@ public class PolarisInstanceTransformerTest {
assertThat(instance1.getZone()).isEqualTo("zone"); assertThat(instance1.getZone()).isEqualTo("zone");
} }
} }
}

@ -62,9 +62,9 @@ public final class MetadataConstant {
public static final String CUSTOM_DISPOSABLE_METADATA = "SCT-CUSTOM-DISPOSABLE-METADATA"; public static final String CUSTOM_DISPOSABLE_METADATA = "SCT-CUSTOM-DISPOSABLE-METADATA";
/** /**
* System Metadata. * Application Metadata.
*/ */
public static final String SYSTEM_METADATA = "SCT-SYSTEM-METADATA"; public static final String APPLICATION_METADATA = "SCT-APPLICATION-METADATA";
/** /**
* Metadata context. * Metadata context.

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*/ */
package com.tencent.cloud.polaris.tsf.consts; package com.tencent.cloud.common.constant;
/** /**
* . * .

@ -56,6 +56,16 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
*/ */
public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable"; public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable";
/**
* disposable Context.
*/
public static final String FRAGMENT_APPLICATION = "application";
/**
* upstream disposable Context.
*/
public static final String FRAGMENT_UPSTREAM_APPLICATION = "upstream-application";
/** /**
* the key of the header(key) list needed to be transmitted from upstream to downstream. * the key of the header(key) list needed to be transmitted from upstream to downstream.
*/ */
@ -93,8 +103,6 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
if (!StringUtils.hasText(namespace)) { if (!StringUtils.hasText(namespace)) {
LOG.error("namespace should not be blank. please configure spring.cloud.polaris.namespace or " LOG.error("namespace should not be blank. please configure spring.cloud.polaris.namespace or "
+ "spring.cloud.polaris.discovery.namespace"); + "spring.cloud.polaris.discovery.namespace");
throw new RuntimeException("namespace should not be blank. please configure spring.cloud.polaris.namespace or "
+ "spring.cloud.polaris.discovery.namespace");
} }
namespace = DiscoveryUtil.rewriteNamespace(namespace); namespace = DiscoveryUtil.rewriteNamespace(namespace);
LOCAL_NAMESPACE = namespace; LOCAL_NAMESPACE = namespace;
@ -109,8 +117,6 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
if (!StringUtils.hasText(serviceName)) { if (!StringUtils.hasText(serviceName)) {
LOG.error("service name should not be blank. please configure spring.cloud.polaris.service or " LOG.error("service name should not be blank. please configure spring.cloud.polaris.service or "
+ "spring.cloud.polaris.discovery.service or spring.application.name"); + "spring.cloud.polaris.discovery.service or spring.application.name");
throw new RuntimeException("service name should not be blank. please configure spring.cloud.polaris.service or "
+ "spring.cloud.polaris.discovery.service or spring.application.name");
} }
serviceName = DiscoveryUtil.rewriteServiceId(serviceName); serviceName = DiscoveryUtil.rewriteServiceId(serviceName);
LOCAL_SERVICE = serviceName; LOCAL_SERVICE = serviceName;
@ -120,8 +126,8 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
super(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX); super(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX);
} }
private Map<String, String> getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream) { private Map<String, String> getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
Map<String, String> values = new HashMap<>(); Map<String, String> values = new HashMap<>();
metadataContainer.iterateMetadataValues(new BiConsumer<String, MetadataValue>() { metadataContainer.iterateMetadataValues(new BiConsumer<String, MetadataValue>() {
@Override @Override
@ -144,8 +150,8 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
} }
} }
private Map<String, String> getMapMetadataAsMap(MetadataType metadataType, String mapKey, TransitiveType transitiveType, boolean downstream) { private Map<String, String> getMapMetadataAsMap(MetadataType metadataType, String mapKey, TransitiveType transitiveType, boolean caller) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
Map<String, String> values = new HashMap<>(); Map<String, String> values = new HashMap<>();
MetadataValue metadataValue = metadataContainer.getMetadataValue(mapKey); MetadataValue metadataValue = metadataContainer.getMetadataValue(mapKey);
if (!(metadataValue instanceof MetadataMapValue)) { if (!(metadataValue instanceof MetadataMapValue)) {
@ -167,8 +173,8 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
} }
private void putMapMetadataAsMap(MetadataType metadataType, String mapKey, private void putMapMetadataAsMap(MetadataType metadataType, String mapKey,
TransitiveType transitiveType, boolean downstream, Map<String, String> values) { TransitiveType transitiveType, boolean caller, Map<String, String> values) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
for (Map.Entry<String, String> entry : values.entrySet()) { for (Map.Entry<String, String> entry : values.entrySet()) {
metadataContainer.putMetadataMapValue(mapKey, entry.getKey(), entry.getValue(), transitiveType); metadataContainer.putMetadataMapValue(mapKey, entry.getKey(), entry.getValue(), transitiveType);
} }
@ -178,10 +184,22 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
return getFragmentContext(FRAGMENT_DISPOSABLE); return getFragmentContext(FRAGMENT_DISPOSABLE);
} }
public void setDisposableMetadata(Map<String, String> disposableMetadata) {
putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata));
}
public Map<String, String> getTransitiveMetadata() { public Map<String, String> getTransitiveMetadata() {
return getFragmentContext(FRAGMENT_TRANSITIVE); return getFragmentContext(FRAGMENT_TRANSITIVE);
} }
public void setTransitiveMetadata(Map<String, String> transitiveMetadata) {
putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata));
}
public Map<String, String> getApplicationMetadata() {
return getFragmentContext(FRAGMENT_APPLICATION);
}
public Map<String, String> getCustomMetadata() { public Map<String, String> getCustomMetadata() {
Map<String, String> transitiveMetadata = this.getTransitiveMetadata(); Map<String, String> transitiveMetadata = this.getTransitiveMetadata();
Map<String, String> disposableMetadata = this.getDisposableMetadata(); Map<String, String> disposableMetadata = this.getDisposableMetadata();
@ -227,14 +245,6 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
metadataContainer.putMetadataMapObjectValue(FRAGMENT_LB_METADATA, key, value); metadataContainer.putMetadataMapObjectValue(FRAGMENT_LB_METADATA, key, value);
} }
public void setTransitiveMetadata(Map<String, String> transitiveMetadata) {
putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata));
}
public void setDisposableMetadata(Map<String, String> disposableMetadata) {
putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata));
}
public void setUpstreamDisposableMetadata(Map<String, String> upstreamDisposableMetadata) { public void setUpstreamDisposableMetadata(Map<String, String> upstreamDisposableMetadata) {
putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata));
} }
@ -255,6 +265,10 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false); return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false);
case FRAGMENT_UPSTREAM_DISPOSABLE: case FRAGMENT_UPSTREAM_DISPOSABLE:
return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true); return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true);
case FRAGMENT_APPLICATION:
return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false);
case FRAGMENT_UPSTREAM_APPLICATION:
return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true);
case FRAGMENT_RAW_TRANSHEADERS: case FRAGMENT_RAW_TRANSHEADERS:
return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false); return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false);
case FRAGMENT_RAW_TRANSHEADERS_KV: case FRAGMENT_RAW_TRANSHEADERS_KV:
@ -289,6 +303,12 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
case FRAGMENT_UPSTREAM_DISPOSABLE: case FRAGMENT_UPSTREAM_DISPOSABLE:
putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true, context); putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true, context);
break; break;
case FRAGMENT_APPLICATION:
putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false, context);
break;
case FRAGMENT_UPSTREAM_APPLICATION:
putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true, context);
break;
case FRAGMENT_RAW_TRANSHEADERS: case FRAGMENT_RAW_TRANSHEADERS:
putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false, context); putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false, context);
break; break;

@ -22,7 +22,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MessageMetadataContainer;
import com.tencent.polaris.metadata.core.MetadataContainer; import com.tencent.polaris.metadata.core.MetadataContainer;
@ -43,8 +42,6 @@ import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_UPSTREA
*/ */
public final class MetadataContextHolder { public final class MetadataContextHolder {
private static MetadataLocalProperties metadataLocalProperties;
private static StaticMetadataManager staticMetadataManager; private static StaticMetadataManager staticMetadataManager;
static { static {
@ -60,28 +57,38 @@ public final class MetadataContextHolder {
private static MetadataContext createMetadataManager() { private static MetadataContext createMetadataManager() {
MetadataContext metadataManager = new MetadataContext(); MetadataContext metadataManager = new MetadataContext();
if (metadataLocalProperties == null) {
metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext()
.getBean(MetadataLocalProperties.class);
}
if (staticMetadataManager == null) { if (staticMetadataManager == null) {
staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext()
.getBean(StaticMetadataManager.class); .getBean(StaticMetadataManager.class);
} }
// local custom metadata
MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false);
Map<String, String> mergedStaticMetadata = staticMetadataManager.getMergedStaticMetadata();
for (Map.Entry<String, String> entry : mergedStaticMetadata.entrySet()) {
metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.NONE);
}
// local custom transitive metadata
Map<String, String> mergedStaticTransitiveMetadata = staticMetadataManager.getMergedStaticTransitiveMetadata(); Map<String, String> mergedStaticTransitiveMetadata = staticMetadataManager.getMergedStaticTransitiveMetadata();
for (Map.Entry<String, String> entry : mergedStaticTransitiveMetadata.entrySet()) { for (Map.Entry<String, String> entry : mergedStaticTransitiveMetadata.entrySet()) {
metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH);
} }
// local custom disposable metadata
Map<String, String> mergedStaticDisposableMetadata = staticMetadataManager.getMergedStaticDisposableMetadata(); Map<String, String> mergedStaticDisposableMetadata = staticMetadataManager.getMergedStaticDisposableMetadata();
for (Map.Entry<String, String> entry : mergedStaticDisposableMetadata.entrySet()) { for (Map.Entry<String, String> entry : mergedStaticDisposableMetadata.entrySet()) {
metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE);
} }
// local trans header
if (StringUtils.hasText(staticMetadataManager.getTransHeader())) { if (StringUtils.hasText(staticMetadataManager.getTransHeader())) {
String transHeader = staticMetadataManager.getTransHeader(); String transHeader = staticMetadataManager.getTransHeader();
metadataContainer.putMetadataMapValue(MetadataContext.FRAGMENT_RAW_TRANSHEADERS, transHeader, "", TransitiveType.NONE); metadataContainer.putMetadataMapValue(MetadataContext.FRAGMENT_RAW_TRANSHEADERS, transHeader, "", TransitiveType.NONE);
} }
// local application disposable metadata
MetadataContainer applicationMetadataContainer = metadataManager.getMetadataContainer(MetadataType.APPLICATION, false);
Map<String, String> mergedApplicationMetadata = staticMetadataManager.getMergedStaticMetadata();
for (Map.Entry<String, String> entry : mergedApplicationMetadata.entrySet()) {
applicationMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE);
}
return metadataManager; return metadataManager;
} }
@ -133,24 +140,36 @@ public final class MetadataContextHolder {
* Save metadata map to thread local. * Save metadata map to thread local.
* *
* @param dynamicTransitiveMetadata custom metadata collection * @param dynamicTransitiveMetadata custom metadata collection
* @param dynamicDisposableMetadata custom disposable metadata connection * @param dynamicDisposableMetadata custom disposable metadata collection
* @param dynamicApplicationMetadata application metadata collection
* @param callerMetadataProvider caller metadata provider * @param callerMetadataProvider caller metadata provider
*/ */
public static void init(Map<String, String> dynamicTransitiveMetadata, Map<String, String> dynamicDisposableMetadata, public static void init(Map<String, String> dynamicTransitiveMetadata, Map<String, String> dynamicDisposableMetadata,
MetadataProvider callerMetadataProvider) { Map<String, String> dynamicApplicationMetadata, MetadataProvider callerMetadataProvider) {
com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> { com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> {
// caller transitive metadata to local custom transitive metadata
MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false);
if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) {
for (Map.Entry<String, String> entry : dynamicTransitiveMetadata.entrySet()) { for (Map.Entry<String, String> entry : dynamicTransitiveMetadata.entrySet()) {
metadataContainerUpstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); metadataContainerUpstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH);
} }
} }
// caller disposable metadata to caller custom disposable metadata
MetadataContainer metadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, true); MetadataContainer metadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, true);
if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) {
for (Map.Entry<String, String> entry : dynamicDisposableMetadata.entrySet()) { for (Map.Entry<String, String> entry : dynamicDisposableMetadata.entrySet()) {
metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE);
} }
} }
// caller application metadata to caller application disposable metadata
MetadataContainer applicationMetadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.APPLICATION, true);
if (!CollectionUtils.isEmpty(dynamicApplicationMetadata)) {
for (Map.Entry<String, String> entry : dynamicApplicationMetadata.entrySet()) {
applicationMetadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE);
}
}
// caller message metadata
if (callerMetadataProvider != null) { if (callerMetadataProvider != null) {
MessageMetadataContainer callerMessageContainer = metadataManager.getMetadataContainer(MetadataType.MESSAGE, true); MessageMetadataContainer callerMessageContainer = metadataManager.getMetadataContainer(MetadataType.MESSAGE, true);
callerMessageContainer.setMetadataProvider(callerMetadataProvider); callerMessageContainer.setMetadataProvider(callerMetadataProvider);

@ -261,7 +261,8 @@ public class StaticMetadataManager {
List<InstanceMetadataProvider> instanceMetadataProviders) { List<InstanceMetadataProvider> instanceMetadataProviders) {
// resolve region info // resolve region info
if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { if (!CollectionUtils.isEmpty(instanceMetadataProviders)) {
Set<String> providerRegions = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getRegion).filter(region -> !StringUtils.isBlank(region)).collect(Collectors.toSet()); Set<String> providerRegions = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getRegion)
.filter(region -> !StringUtils.isBlank(region)).collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(providerRegions)) { if (!CollectionUtils.isEmpty(providerRegions)) {
if (providerRegions.size() > 1) { if (providerRegions.size() > 1) {
throw new IllegalArgumentException("Multiple Regions Provided in InstanceMetadataProviders"); throw new IllegalArgumentException("Multiple Regions Provided in InstanceMetadataProviders");
@ -278,7 +279,8 @@ public class StaticMetadataManager {
// resolve zone info // resolve zone info
if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { if (!CollectionUtils.isEmpty(instanceMetadataProviders)) {
Set<String> providerZones = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getZone).filter(zone -> !StringUtils.isBlank(zone)).collect(Collectors.toSet()); Set<String> providerZones = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getZone)
.filter(zone -> !StringUtils.isBlank(zone)).collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(providerZones)) { if (!CollectionUtils.isEmpty(providerZones)) {
if (providerZones.size() > 1) { if (providerZones.size() > 1) {
throw new IllegalArgumentException("Multiple Zones Provided in InstanceMetadataProviders"); throw new IllegalArgumentException("Multiple Zones Provided in InstanceMetadataProviders");
@ -295,7 +297,8 @@ public class StaticMetadataManager {
// resolve campus info // resolve campus info
if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { if (!CollectionUtils.isEmpty(instanceMetadataProviders)) {
Set<String> providerCampus = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getCampus).filter(campus -> !StringUtils.isBlank(campus)).collect(Collectors.toSet()); Set<String> providerCampus = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getCampus)
.filter(campus -> !StringUtils.isBlank(campus)).collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(providerCampus)) { if (!CollectionUtils.isEmpty(providerCampus)) {
if (providerCampus.size() > 1) { if (providerCampus.size() > 1) {
throw new IllegalArgumentException("Multiple Campus Provided in InstanceMetadataProviders"); throw new IllegalArgumentException("Multiple Campus Provided in InstanceMetadataProviders");

@ -18,10 +18,12 @@
package com.tencent.cloud.common.pojo; package com.tencent.cloud.common.pojo;
import java.net.URI; import java.net.URI;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.utils.CollectionUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
@ -40,7 +42,13 @@ public class PolarisServiceInstance implements ServiceInstance {
private final String scheme; private final String scheme;
private final Map<String, String> serviceMetadata;
public PolarisServiceInstance(Instance instance) { public PolarisServiceInstance(Instance instance) {
this(instance, null);
}
public PolarisServiceInstance(Instance instance, Map<String, String> metadata) {
this.instance = instance; this.instance = instance;
this.isSecure = StringUtils.equalsIgnoreCase(instance.getProtocol(), "https"); this.isSecure = StringUtils.equalsIgnoreCase(instance.getProtocol(), "https");
if (isSecure) { if (isSecure) {
@ -49,6 +57,10 @@ public class PolarisServiceInstance implements ServiceInstance {
else { else {
scheme = "http"; scheme = "http";
} }
this.serviceMetadata = new HashMap<>();
if (CollectionUtils.isNotEmpty(metadata)) {
this.serviceMetadata.putAll(metadata);
}
} }
public Instance getPolarisInstance() { public Instance getPolarisInstance() {
@ -95,6 +107,10 @@ public class PolarisServiceInstance implements ServiceInstance {
return this.scheme; return this.scheme;
} }
public Map<String, String> getServiceMetadata() {
return serviceMetadata;
}
/** /**
* To fix loadbalancer not working bug when importing spring-retry. * To fix loadbalancer not working bug when importing spring-retry.
* @param o object * @param o object
@ -116,4 +132,14 @@ public class PolarisServiceInstance implements ServiceInstance {
public int hashCode() { public int hashCode() {
return Objects.hash(instance, scheme); return Objects.hash(instance, scheme);
} }
@Override
public String toString() {
return "PolarisServiceInstance{" +
"instance=" + instance +
", isSecure=" + isSecure +
", scheme='" + scheme + '\'' +
", serviceMetadata=" + serviceMetadata +
'}';
}
} }

@ -1,73 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.common.tsf;
/**
* Constant for TSF.
*
* @author Haotian Zhang
*/
public final class TsfConstant {
/**
* tsf application id.
*/
public static String TSF_APPLICATION_ID = "TSF_APPLICATION_ID";
/**
* tsf program version.
*/
public static String TSF_PROG_VERSION = "TSF_PROG_VERSION";
/**
* tsf group id.
*/
public static String TSF_GROUP_ID = "TSF_GROUP_ID";
/**
* tsf namespace id.
*/
public static String TSF_NAMESPACE_ID = "TSF_NAMESPACE_ID";
/**
* tsf instance id.
*/
public static String TSF_INSTNACE_ID = "TSF_INSTNACE_ID";
/**
* tsf region.
*/
public static String TSF_REGION = "TSF_REGION";
/**
* tsf zone.
*/
public static String TSF_ZONE = "TSF_ZONE";
/**
* tsf SDK version.
*/
public static String TSF_SDK_VERSION = "TSF_SDK_VERSION";
/**
* tsf tags.
*/
public static String TSF_TAGS = "TSF_TAGS";
private TsfConstant() {
}
}

@ -137,7 +137,7 @@ public final class ExpressionLabelUtils {
} }
public static String getQueryValue(String queryString, String queryKey) { public static String getQueryValue(String queryString, String queryKey) {
return getQueryValue(queryString, queryKey, StringUtils.EMPTY); return getQueryValue(queryString, queryKey, null);
} }
public static String getQueryValue(String queryString, String queryKey, String defaultValue) { public static String getQueryValue(String queryString, String queryKey, String defaultValue) {
@ -159,31 +159,31 @@ public final class ExpressionLabelUtils {
public static String getFirstValue(Map<String, Collection<String>> valueMaps, String key) { public static String getFirstValue(Map<String, Collection<String>> valueMaps, String key) {
if (CollectionUtils.isEmpty(valueMaps)) { if (CollectionUtils.isEmpty(valueMaps)) {
return StringUtils.EMPTY; return null;
} }
Collection<String> values = valueMaps.get(key); Collection<String> values = valueMaps.get(key);
if (CollectionUtils.isEmpty(values)) { if (CollectionUtils.isEmpty(values)) {
return StringUtils.EMPTY; return null;
} }
for (String value : values) { for (String value : values) {
return value; return value;
} }
return StringUtils.EMPTY; return null;
} }
public static String getCookieFirstValue(Map<String, Collection<String>> valueMaps, String key) { public static String getCookieFirstValue(Map<String, Collection<String>> valueMaps, String key) {
if (CollectionUtils.isEmpty(valueMaps)) { if (CollectionUtils.isEmpty(valueMaps)) {
return StringUtils.EMPTY; return null;
} }
Collection<String> values = valueMaps.get(HttpHeaderNames.COOKIE.toString()); Collection<String> values = valueMaps.get(HttpHeaderNames.COOKIE.toString());
if (CollectionUtils.isEmpty(values)) { if (CollectionUtils.isEmpty(values)) {
return StringUtils.EMPTY; return null;
} }
for (String value : values) { for (String value : values) {
@ -195,6 +195,6 @@ public final class ExpressionLabelUtils {
} }
} }
} }
return StringUtils.EMPTY; return null;
} }
} }

@ -75,7 +75,7 @@ public final class SpringWebExpressionLabelUtils {
labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey)); labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey));
} }
else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { else if (ExpressionLabelUtils.isMethodLabel(labelKey)) {
labels.put(labelKey, exchange.getRequest().getMethodValue()); labels.put(labelKey, exchange.getRequest().getMethod().toString());
} }
else if (ExpressionLabelUtils.isUriLabel(labelKey)) { else if (ExpressionLabelUtils.isUriLabel(labelKey)) {
labels.put(labelKey, exchange.getRequest().getURI().getPath()); labels.put(labelKey, exchange.getRequest().getURI().getPath());
@ -118,7 +118,7 @@ public final class SpringWebExpressionLabelUtils {
labels.put(labelKey, getCookieValue(request, cookieKey)); labels.put(labelKey, getCookieValue(request, cookieKey));
} }
else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { else if (ExpressionLabelUtils.isMethodLabel(labelKey)) {
labels.put(labelKey, request.getMethodValue()); labels.put(labelKey, request.getMethod().toString());
} }
else if (ExpressionLabelUtils.isUriLabel(labelKey)) { else if (ExpressionLabelUtils.isUriLabel(labelKey)) {
labels.put(labelKey, request.getURI().getPath()); labels.put(labelKey, request.getURI().getPath());
@ -129,7 +129,7 @@ public final class SpringWebExpressionLabelUtils {
} }
public static String getHeaderValue(ServerHttpRequest request, String key) { public static String getHeaderValue(ServerHttpRequest request, String key) {
return getHeaderValue(request, key, StringUtils.EMPTY); return getHeaderValue(request, key, null);
} }
public static String getHeaderValue(ServerHttpRequest request, String key, String defaultValue) { public static String getHeaderValue(ServerHttpRequest request, String key, String defaultValue) {
@ -141,7 +141,7 @@ public final class SpringWebExpressionLabelUtils {
} }
public static String getQueryValue(ServerHttpRequest request, String key) { public static String getQueryValue(ServerHttpRequest request, String key) {
return getQueryValue(request, key, StringUtils.EMPTY); return getQueryValue(request, key, null);
} }
public static String getQueryValue(ServerHttpRequest request, String key, String defaultValue) { public static String getQueryValue(ServerHttpRequest request, String key, String defaultValue) {
@ -157,7 +157,7 @@ public final class SpringWebExpressionLabelUtils {
} }
public static String getCookieValue(ServerHttpRequest request, String key) { public static String getCookieValue(ServerHttpRequest request, String key) {
return getCookieValue(request, key, StringUtils.EMPTY); return getCookieValue(request, key, null);
} }
public static String getCookieValue(ServerHttpRequest request, String key, String defaultValue) { public static String getCookieValue(ServerHttpRequest request, String key, String defaultValue) {
@ -181,7 +181,7 @@ public final class SpringWebExpressionLabelUtils {
public static String getCookieValue(HttpRequest request, String key) { public static String getCookieValue(HttpRequest request, String key) {
String first = request.getHeaders().getFirst(HttpHeaders.COOKIE); String first = request.getHeaders().getFirst(HttpHeaders.COOKIE);
if (StringUtils.isEmpty(first)) { if (StringUtils.isEmpty(first)) {
return StringUtils.EMPTY; return null;
} }
String[] cookieArray = StringUtils.split(first, ";"); String[] cookieArray = StringUtils.split(first, ";");
for (String cookieItem : cookieArray) { for (String cookieItem : cookieArray) {
@ -190,6 +190,6 @@ public final class SpringWebExpressionLabelUtils {
return cookieKv[1]; return cookieKv[1];
} }
} }
return StringUtils.EMPTY; return null;
} }
} }

@ -63,7 +63,7 @@ public class MetadataContextHolderTest {
customMetadata.put("a", "1"); customMetadata.put("a", "1");
customMetadata.put("b", "22"); customMetadata.put("b", "22");
customMetadata.put("c", "3"); customMetadata.put("c", "3");
MetadataContextHolder.init(customMetadata, new HashMap<>(), null); MetadataContextHolder.init(customMetadata, new HashMap<>(), new HashMap<>(), null);
metadataContext = MetadataContextHolder.get(); metadataContext = MetadataContextHolder.get();
customMetadata = metadataContext.getTransitiveMetadata(); customMetadata = metadataContext.getTransitiveMetadata();
Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1");

@ -123,4 +123,10 @@ public class QuickstartCalleeController {
LOG.info("Quickstart Callee Service [{}:{}] is detected right.", ip, port); LOG.info("Quickstart Callee Service [{}:{}] is detected right.", ip, port);
return String.format("Quickstart Callee Service [%s:%s] is detected right.", ip, port); return String.format("Quickstart Callee Service [%s:%s] is detected right.", ip, port);
} }
@GetMapping("/test/{num}/echo")
public String test(@PathVariable int num) {
LOG.info("Quickstart Callee Service [%s] is detected right.", num);
return String.format("Quickstart Callee Service [%s] is detected right.", num);
}
} }

@ -18,18 +18,24 @@
package com.tencent.cloud.quickstart.caller; package com.tencent.cloud.quickstart.caller;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -76,8 +82,25 @@ public class QuickstartCallerController {
* @return information of callee * @return information of callee
*/ */
@GetMapping("/rest") @GetMapping("/rest")
public String rest() { public ResponseEntity<String> rest(@RequestHeader Map<String, String> headerMap) {
return restTemplate.getForObject("http://QuickstartCalleeService/quickstart/callee/info", String.class); String url = "http://QuickstartCalleeService/quickstart/callee/info";
HttpHeaders headers = new HttpHeaders();
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
if (StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())
&& !entry.getKey().contains("sct-")
&& !entry.getKey().contains("SCT-")
&& !entry.getKey().contains("polaris-")
&& !entry.getKey().contains("POLARIS-")) {
headers.add(entry.getKey(), entry.getValue());
}
}
// 创建 HttpEntity 实例并传入 HttpHeaders
HttpEntity<String> entity = new HttpEntity<>(headers);
// 使用 exchange 方法发送 GET 请求,并获取响应
return restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
} }
/** /**

@ -1,54 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.quickstart.caller.router;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.google.gson.Gson;
import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
/**
*
* Customize the business tag information obtained from the request
*
*@author lepdou 2022-05-12
*/
@Component
public class CustomRouterLabelResolver implements FeignRouterLabelResolver {
private final Gson gson = new Gson();
@Override
public Map<String, String> resolve(RequestTemplate requestTemplate, Set<String> expressionLabelKeys) {
Map<String, String> labels = new HashMap<>();
labels.put("label1", "value1");
return labels;
}
@Override
public int getOrder() {
return 0;
}
}

@ -27,6 +27,11 @@
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>

@ -22,6 +22,7 @@ import java.util.Map;
import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderDemoService; import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderDemoService;
import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderService; import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderService;
import com.tencent.polaris.api.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.tsf.core.context.TsfContext; import org.springframework.tsf.core.context.TsfContext;
@ -29,6 +30,7 @@ import org.springframework.tsf.core.entity.Tag;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@ -42,7 +44,12 @@ public class ConsumerController {
private ProviderDemoService providerDemoService; private ProviderDemoService providerDemoService;
@RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET)
public String restProvider(@PathVariable String str) { public String restProvider(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) {
if (StringUtils.isNotBlank(tagName)) {
TsfContext.putTag(tagName, tagValue);
}
TsfContext.putTag("operation", "rest"); TsfContext.putTag("operation", "rest");
Map<String, String> mTags = new HashMap<>(); Map<String, String> mTags = new HashMap<>();
mTags.put("rest-trace-key1", "value1"); mTags.put("rest-trace-key1", "value1");
@ -52,7 +59,12 @@ public class ConsumerController {
} }
@RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET) @RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET)
public String feignProvider(@PathVariable String str) { public String feignProvider(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) {
if (StringUtils.isNotBlank(tagName)) {
TsfContext.putTag(tagName, tagValue);
}
TsfContext.putTag("operation", "feign"); TsfContext.putTag("operation", "feign");
Map<String, String> mTags = new HashMap<>(); Map<String, String> mTags = new HashMap<>();
mTags.put("feign-trace-key1", "value1"); mTags.put("feign-trace-key1", "value1");
@ -62,7 +74,12 @@ public class ConsumerController {
} }
@RequestMapping(value = "/echo-feign-url/{str}", method = RequestMethod.GET) @RequestMapping(value = "/echo-feign-url/{str}", method = RequestMethod.GET)
public String feignUrlProvider(@PathVariable String str) { public String feignUrlProvider(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) {
if (StringUtils.isNotBlank(tagName)) {
TsfContext.putTag(tagName, tagValue);
}
TsfContext.putTag("operation", "feignUrl"); TsfContext.putTag("operation", "feignUrl");
Map<String, String> mTags = new HashMap<>(); Map<String, String> mTags = new HashMap<>();
mTags.put("feignUrl-trace-key1", "value1"); mTags.put("feignUrl-trace-key1", "value1");

@ -21,11 +21,11 @@ package com.tencent.cloud.plugin.trace.tsf;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.tencent.cloud.common.tsf.TsfConstant;
import com.tencent.cloud.plugin.trace.SpanAttributesProvider; import com.tencent.cloud.plugin.trace.SpanAttributesProvider;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
@ -39,11 +39,11 @@ public class TsfSpanAttributesProvider implements SpanAttributesProvider {
} }
ServiceInstance targetServiceInstance = context.getTargetServiceInstance(); ServiceInstance targetServiceInstance = context.getTargetServiceInstance();
if (null != targetServiceInstance && CollectionUtils.isNotEmpty(targetServiceInstance.getMetadata())) { if (null != targetServiceInstance && CollectionUtils.isNotEmpty(targetServiceInstance.getMetadata())) {
String nsId = targetServiceInstance.getMetadata().get(TsfConstant.TSF_NAMESPACE_ID); String nsId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_NAMESPACE_ID);
attributes.put("remote.namespace-id", StringUtils.defaultString(nsId)); attributes.put("remote.namespace-id", StringUtils.defaultString(nsId));
String groupId = targetServiceInstance.getMetadata().get(TsfConstant.TSF_GROUP_ID); String groupId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_GROUP_ID);
attributes.put("remote.group-id", StringUtils.defaultString(groupId)); attributes.put("remote.group-id", StringUtils.defaultString(groupId));
String applicationId = targetServiceInstance.getMetadata().get(TsfConstant.TSF_APPLICATION_ID); String applicationId = targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_APPLICATION_ID);
attributes.put("remote.application-id", StringUtils.defaultString(applicationId)); attributes.put("remote.application-id", StringUtils.defaultString(applicationId));
} }
return attributes; return attributes;

@ -173,6 +173,16 @@
<artifactId>polaris-router-factory</artifactId> <artifactId>polaris-router-factory</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-circuitbreaker-factory</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-ratelimit-factory</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>loadbalancer-random</artifactId> <artifactId>loadbalancer-random</artifactId>

@ -0,0 +1,80 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.context.tsf;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.tencent.cloud.common.util.inet.PolarisInetUtils;
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import org.springframework.util.StringUtils;
/**
*
*
* @author Haotian Zhang
*/
public final class TsfUtils {
/**
* IPV4.
*/
public static String TSF_ADDRESS_IPV4 = "TSF_ADDRESS_IPV4";
/**
* IPV6.
*/
public static String TSF_ADDRESS_IPV6 = "TSF_ADDRESS_IPV6";
private TsfUtils() {
}
public static List<String> createTags(TsfCoreProperties properties) {
List<String> tags = new LinkedList<>(properties.getTags());
if (StringUtils.hasText(properties.getInstanceZone())) {
tags.add(properties.getDefaultZoneMetadataName() + "=" + properties.getInstanceZone());
}
if (StringUtils.hasText(properties.getInstanceGroup())) {
tags.add("group=" + properties.getInstanceGroup());
}
//store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically
tags.add("secure=" + properties.getScheme().equalsIgnoreCase("https"));
return tags;
}
public static Map<String, String> appendMetaIpAddress(Map<String, String> meta) {
if (meta == null) {
return null;
}
String ipv4Address = PolarisInetUtils.getIpString(false);
if (ipv4Address != null) {
meta.put(TSF_ADDRESS_IPV4, ipv4Address);
}
String ipv6Address = PolarisInetUtils.getIpString(true);
if (ipv6Address != null) {
meta.put(TSF_ADDRESS_IPV6, ipv6Address);
}
return meta;
}
}

@ -17,6 +17,9 @@
package com.tencent.cloud.polaris.context.tsf.config; package com.tencent.cloud.polaris.context.tsf.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
@ -37,6 +40,12 @@ public class TsfCoreProperties {
@Value("${tse_polaris_enable:false}") @Value("${tse_polaris_enable:false}")
private boolean tsePolarisEnable = false; private boolean tsePolarisEnable = false;
/**
* Unique service instance id.
*/
@Value("${tsf_instance_id:${spring.cloud.consul.discovery.instanceId:${SPRING_CLOUD_CONSUL_DISCOVERY_INSTANCEID:}}}")
private String instanceId;
/** /**
* tsf service consul registration tags. * tsf service consul registration tags.
* <p> * <p>
@ -53,12 +62,67 @@ public class TsfCoreProperties {
@Value("${tsf_group_id:}") @Value("${tsf_group_id:}")
private String tsfGroupId; private String tsfGroupId;
/**
* tsf service consul registration tags.
*
* progVersion
*/
@Value("${tsf_prog_version:}")
private String tsfProgVersion;
/** /**
* 使. * 使.
*/ */
@Value("${tsf_namespace_id:}") @Value("${tsf_namespace_id:}")
private String tsfNamespaceId; private String tsfNamespaceId;
/**
* tsf service consul registration tags.
*
*
*/
@Value("${tsf_region:}")
private String tsfRegion;
/**
* tsf service consul registration tags.
*
*
*/
@Value("${tsf_zone:}")
private String tsfZone;
/**
* Tags to use when registering service.
*/
@Value("${tsf.discovery.tags:}")
private List<String> tags = new ArrayList<>();
/**
* Service instance zone.
*/
@Value("${tsf.discovery.instanceZone:}")
private String instanceZone;
/**
* Service instance group.
*/
@Value("${tsf.discovery.instanceGroup:}")
private String instanceGroup;
/**
* Service instance zone comes from metadata.
* This allows changing the metadata tag name.
*/
@Value("${tsf.discovery.defaultZoneMetadataName:zone}")
private String defaultZoneMetadataName = "zone";
/**
* Whether to register an http or https service.
*/
@Value("${tsf.discovery.scheme:http}")
private String scheme = "http";
public String getTsePolarisIp() { public String getTsePolarisIp() {
return tsePolarisIp; return tsePolarisIp;
} }
@ -83,6 +147,14 @@ public class TsfCoreProperties {
this.tsePolarisEnable = tsePolarisEnable; this.tsePolarisEnable = tsePolarisEnable;
} }
public String getInstanceId() {
return instanceId;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
public String getTsfApplicationId() { public String getTsfApplicationId() {
return tsfApplicationId; return tsfApplicationId;
} }
@ -99,6 +171,14 @@ public class TsfCoreProperties {
this.tsfGroupId = tsfGroupId; this.tsfGroupId = tsfGroupId;
} }
public String getTsfProgVersion() {
return tsfProgVersion;
}
public void setTsfProgVersion(final String tsfProgVersion) {
this.tsfProgVersion = tsfProgVersion;
}
public String getTsfNamespaceId() { public String getTsfNamespaceId() {
return tsfNamespaceId; return tsfNamespaceId;
} }
@ -107,15 +187,80 @@ public class TsfCoreProperties {
this.tsfNamespaceId = tsfNamespaceId; this.tsfNamespaceId = tsfNamespaceId;
} }
public String getTsfRegion() {
return tsfRegion;
}
public void setTsfRegion(final String tsfRegion) {
this.tsfRegion = tsfRegion;
}
public String getTsfZone() {
return tsfZone;
}
public void setTsfZone(final String tsfZone) {
this.tsfZone = tsfZone;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public String getInstanceZone() {
return instanceZone;
}
public void setInstanceZone(String instanceZone) {
this.instanceZone = instanceZone;
}
public String getInstanceGroup() {
return instanceGroup;
}
public void setInstanceGroup(String instanceGroup) {
this.instanceGroup = instanceGroup;
}
public String getDefaultZoneMetadataName() {
return defaultZoneMetadataName;
}
public void setDefaultZoneMetadataName(String defaultZoneMetadataName) {
this.defaultZoneMetadataName = defaultZoneMetadataName;
}
public String getScheme() {
return scheme;
}
public void setScheme(String scheme) {
this.scheme = scheme;
}
@Override @Override
public String toString() { public String toString() {
return "TsfCoreProperties{" + return "TsfCoreProperties{" +
"tsePolarisIp='" + tsePolarisIp + '\'' + "tsePolarisIp='" + tsePolarisIp + '\'' +
", tsfConsulEnable=" + tsfConsulEnable + ", tsfConsulEnable=" + tsfConsulEnable +
", tsePolarisEnable=" + tsePolarisEnable + ", tsePolarisEnable=" + tsePolarisEnable +
", instanceId='" + instanceId + '\'' +
", tsfApplicationId='" + tsfApplicationId + '\'' + ", tsfApplicationId='" + tsfApplicationId + '\'' +
", tsfGroupId='" + tsfGroupId + '\'' + ", tsfGroupId='" + tsfGroupId + '\'' +
", tsfProgVersion='" + tsfProgVersion + '\'' +
", tsfNamespaceId='" + tsfNamespaceId + '\'' + ", tsfNamespaceId='" + tsfNamespaceId + '\'' +
", tsfRegion='" + tsfRegion + '\'' +
", tsfZone='" + tsfZone + '\'' +
", tags=" + tags +
", instanceZone='" + instanceZone + '\'' +
", instanceGroup='" + instanceGroup + '\'' +
", defaultZoneMetadataName='" + defaultZoneMetadataName + '\'' +
", scheme='" + scheme + '\'' +
'}'; '}';
} }
} }

@ -122,7 +122,7 @@ public final class TsfCoreEnvironmentPostProcessor implements EnvironmentPostPro
// tse_polaris_ip // tse_polaris_ip
defaultProperties.put("spring.cloud.polaris.address", "grpc://" + environment.getProperty("tse_polaris_ip", "") + ":8091"); defaultProperties.put("spring.cloud.polaris.address", "grpc://" + environment.getProperty("tse_polaris_ip", "") + ":8091");
// tsf_sctt_extensions_port // tse_polaris_ip
defaultProperties.put("spring.cloud.polaris.stat.port", environment.getProperty("tsf_sctt_extensions_port", "11134")); defaultProperties.put("spring.cloud.polaris.stat.port", environment.getProperty("tsf_sctt_extensions_port", "11134"));
// rule based router fail over type // rule based router fail over type

@ -0,0 +1,43 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.context.tsf.metadata;
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
import com.tencent.cloud.common.tsf.ConditionalOnTsfEnabled;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto configuration for instanceMetadataProvider for TSF.
*
* @author Hoatian Zhang
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
@ConditionalOnTsfEnabled
public class TsfInstanceMetadataAutoConfiguration {
@Bean
public InstanceMetadataProvider tsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) {
return new TsfInstanceMetadataProvider(tsfCoreProperties);
}
}

@ -0,0 +1,77 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.context.tsf.metadata;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.constant.SdkVersion;
import com.tencent.cloud.common.constant.WarmupCons;
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.inet.PolarisInetUtils;
import com.tencent.cloud.polaris.context.tsf.TsfUtils;
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
import static com.tencent.cloud.polaris.context.tsf.TsfUtils.TSF_ADDRESS_IPV4;
import static com.tencent.cloud.polaris.context.tsf.TsfUtils.TSF_ADDRESS_IPV6;
/**
* InstanceMetadataProvider for TSF.
*
* @author Hoatian Zhang
*/
public class TsfInstanceMetadataProvider implements InstanceMetadataProvider {
private final TsfCoreProperties tsfCoreProperties;
public TsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) {
this.tsfCoreProperties = tsfCoreProperties;
}
@Override
public Map<String, String> getMetadata() {
return new HashMap<String, String>() {{
put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion());
put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId());
put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId());
put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId());
put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion());
put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId());
put(TsfMetadataConstants.TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId());
put(TsfMetadataConstants.TSF_INSTNACE_ID, tsfCoreProperties.getInstanceId());
put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion());
put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone());
// 处理预热相关的参数
put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis()));
put(TsfMetadataConstants.TSF_SDK_VERSION, SdkVersion.get());
put(TsfMetadataConstants.TSF_TAGS, JacksonUtils.serialize2Json(TsfUtils.createTags(tsfCoreProperties)));
String ipv4Address = PolarisInetUtils.getIpString(false);
if (StringUtils.isNotBlank(ipv4Address)) {
put(TSF_ADDRESS_IPV4, ipv4Address);
}
String ipv6Address = PolarisInetUtils.getIpString(true);
if (StringUtils.isNotBlank(ipv6Address)) {
put(TSF_ADDRESS_IPV6, ipv6Address);
}
}};
}
}

@ -2,7 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration,\ com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration,\
com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration,\ com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration,\
com.tencent.cloud.polaris.context.tsf.consul.TsfConsulAutoConfiguration,\ com.tencent.cloud.polaris.context.tsf.consul.TsfConsulAutoConfiguration,\
com.tencent.cloud.polaris.context.tsf.config.TsfCorePropertiesAutoConfiguration com.tencent.cloud.polaris.context.tsf.config.TsfCorePropertiesAutoConfiguration,\
com.tencent.cloud.polaris.context.tsf.metadata.TsfInstanceMetadataAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration,\ com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration,\
com.tencent.cloud.polaris.context.tsf.config.TsfCorePropertiesBootstrapConfiguration,\ com.tencent.cloud.polaris.context.tsf.config.TsfCorePropertiesBootstrapConfiguration,\

@ -20,6 +20,7 @@ package com.tencent.cloud.rpc.enhancement.transformer;
import com.tencent.cloud.common.pojo.PolarisServiceInstance; import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.utils.CollectionUtils;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
@ -38,6 +39,9 @@ public class PolarisInstanceTransformer implements InstanceTransformer {
instance.setZone(polarisServiceInstance.getPolarisInstance().getZone()); instance.setZone(polarisServiceInstance.getPolarisInstance().getZone());
instance.setCampus(polarisServiceInstance.getPolarisInstance().getCampus()); instance.setCampus(polarisServiceInstance.getPolarisInstance().getCampus());
instance.setWeight(polarisServiceInstance.getPolarisInstance().getWeight()); instance.setWeight(polarisServiceInstance.getPolarisInstance().getWeight());
if (CollectionUtils.isNotEmpty(polarisServiceInstance.getServiceMetadata())) {
instance.getServiceMetadata().putAll(polarisServiceInstance.getServiceMetadata());
}
} }
} }

Loading…
Cancel
Save