Merge branch 'main' of github.com:Tencent/spring-cloud-tencent

pull/197/head
SkyeBeFreeman 3 years ago
commit ecb5819648

@ -6,3 +6,5 @@
- [Feature: Router support request label.](https://github.com/Tencent/spring-cloud-tencent/pull/165)
- [Feature: Support router expression label](https://github.com/Tencent/spring-cloud-tencent/pull/190)
- [Add metadata transfer example.](https://github.com/Tencent/spring-cloud-tencent/pull/184)
- [Feature: Support metadata router.](https://github.com/Tencent/spring-cloud-tencent/pull/191)
- [Feature: Misc optimize metadata router.](https://github.com/Tencent/spring-cloud-tencent/pull/192)

@ -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.metadata.core;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
/**
* resolve custom transitive metadata from request.
*@author lepdou 2022-05-20
*/
public class CustomTransitiveMetadataResolver {
private static final String TRANSITIVE_HEADER_PREFIX = "X-SCT-Metadata-Transitive-";
private static final int TRANSITIVE_HEADER_PREFIX_LENGTH = TRANSITIVE_HEADER_PREFIX.length();
public static Map<String, String> resolve(ServerWebExchange exchange) {
Map<String, String> result = new HashMap<>();
HttpHeaders headers = exchange.getRequest().getHeaders();
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String key = entry.getKey();
if (StringUtils.isNotBlank(key) &&
StringUtils.startsWithIgnoreCase(key, TRANSITIVE_HEADER_PREFIX)
&& !CollectionUtils.isEmpty(entry.getValue())) {
String sourceKey = StringUtils.substring(key, TRANSITIVE_HEADER_PREFIX_LENGTH);
result.put(sourceKey, entry.getValue().get(0));
}
}
return result;
}
public static Map<String, String> resolve(HttpServletRequest request) {
Map<String, String> result = new HashMap<>();
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String key = headers.nextElement();
if (StringUtils.isNotBlank(key) &&
StringUtils.startsWithIgnoreCase(key, TRANSITIVE_HEADER_PREFIX)
&& StringUtils.isNotBlank(request.getHeader(key))) {
String sourceKey = StringUtils.substring(key, TRANSITIVE_HEADER_PREFIX_LENGTH);
result.put(sourceKey, request.getHeader(key));
}
}
return result;
}
}

@ -20,6 +20,7 @@ package com.tencent.cloud.metadata.core;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.constant.MetadataConstant;
@ -58,6 +59,28 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
WebFilterChain webFilterChain) {
// Get metadata string from http header.
ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest();
Map<String, String> internalTransitiveMetadata = getIntervalTransitiveMetadata(serverHttpRequest);
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange);
Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(internalTransitiveMetadata);
mergedTransitiveMetadata.putAll(customTransitiveMetadata);
MetadataContextHolder.init(mergedTransitiveMetadata);
// Save to ServerWebExchange.
serverWebExchange.getAttributes().put(
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get());
return webFilterChain.filter(serverWebExchange)
.doOnError(throwable -> LOG.error("handle metadata[{}] error.",
MetadataContextHolder.get(), throwable))
.doFinally((type) -> MetadataContextHolder.remove());
}
private Map<String, String> getIntervalTransitiveMetadata(ServerHttpRequest serverHttpRequest) {
HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
String customMetadataStr = httpHeaders
.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
@ -71,20 +94,8 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered
}
LOG.debug("Get upstream metadata string: {}", customMetadataStr);
// create custom metadata.
Map<String, String> upstreamCustomMetadataMap = JacksonUtils
.deserialize2Map(customMetadataStr);
MetadataContextHolder.init(upstreamCustomMetadataMap);
// Save to ServerWebExchange.
serverWebExchange.getAttributes().put(
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get());
return webFilterChain.filter(serverWebExchange)
.doOnError(throwable -> LOG.error("handle metadata[{}] error.",
MetadataContextHolder.get(), throwable))
.doFinally((type) -> MetadataContextHolder.remove());
return JacksonUtils.deserialize2Map(customMetadataStr);
}
}

@ -21,6 +21,7 @@ package com.tencent.cloud.metadata.core;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.FilterChain;
@ -54,6 +55,24 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, FilterChain filterChain)
throws ServletException, IOException {
Map<String, String> internalTransitiveMetadata = getInternalTransitiveMetadata(httpServletRequest);
Map<String, String> customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest);
Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(internalTransitiveMetadata);
mergedTransitiveMetadata.putAll(customTransitiveMetadata);
try {
MetadataContextHolder.init(mergedTransitiveMetadata);
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
catch (IOException | ServletException | RuntimeException e) {
throw e;
}
}
private Map<String, String> getInternalTransitiveMetadata(HttpServletRequest httpServletRequest) {
// Get custom metadata string from http header.
String customMetadataStr = httpServletRequest
.getHeader(MetadataConstant.HeaderName.CUSTOM_METADATA);
@ -68,20 +87,7 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter {
LOG.debug("Get upstream metadata string: {}", customMetadataStr);
// create custom metadata.
Map<String, String> upstreamCustomMetadataMap = JacksonUtils
.deserialize2Map(customMetadataStr);
try {
MetadataContextHolder.init(upstreamCustomMetadataMap);
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
catch (IOException | ServletException | RuntimeException e) {
throw e;
}
finally {
MetadataContextHolder.remove();
}
return JacksonUtils.deserialize2Map(customMetadataStr);
}
}

@ -56,32 +56,18 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor,
public void apply(RequestTemplate requestTemplate) {
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();
// add new metadata and cover old
if (!CollectionUtils.isEmpty(requestTemplate.headers()) && !CollectionUtils
.isEmpty(requestTemplate.headers().get(CUSTOM_METADATA))) {
for (String headerMetadataStr : requestTemplate.headers()
.get(CUSTOM_METADATA)) {
Map<String, String> headerMetadataMap = JacksonUtils
.deserialize2Map(headerMetadataStr);
for (String key : headerMetadataMap.keySet()) {
metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key));
}
}
}
Map<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
if (!CollectionUtils.isEmpty(customMetadata)) {
String metadataStr = JacksonUtils.serialize2Json(customMetadata);
String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata);
requestTemplate.removeHeader(CUSTOM_METADATA);
try {
requestTemplate.header(CUSTOM_METADATA,
URLEncoder.encode(metadataStr, "UTF-8"));
URLEncoder.encode(encodedTransitiveMetadata, "UTF-8"));
}
catch (UnsupportedEncodingException e) {
LOG.error("Set header failed.", e);
requestTemplate.header(CUSTOM_METADATA, metadataStr);
requestTemplate.header(CUSTOM_METADATA, encodedTransitiveMetadata);
}
}
}

@ -34,7 +34,6 @@ import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* Interceptor used for adding the metadata in http headers from context when web client
@ -55,29 +54,20 @@ public class EncodeTransferMedataRestTemplateInterceptor
ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();
// add new metadata and cover old
String metadataStr = httpRequest.getHeaders()
.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
if (!StringUtils.isEmpty(metadataStr)) {
Map<String, String> headerMetadataMap = JacksonUtils
.deserialize2Map(metadataStr);
for (String key : headerMetadataMap.keySet()) {
metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key));
}
}
Map<String, String> customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
if (!CollectionUtils.isEmpty(customMetadata)) {
metadataStr = JacksonUtils.serialize2Json(customMetadata);
String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata);
try {
httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA,
URLEncoder.encode(metadataStr, "UTF-8"));
URLEncoder.encode(encodedTransitiveMetadata, "UTF-8"));
}
catch (UnsupportedEncodingException e) {
httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA,
metadataStr);
encodedTransitiveMetadata);
}
}
return clientHttpRequestExecution.execute(httpRequest, bytes);
}

@ -22,8 +22,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor;
import feign.RequestInterceptor;
@ -67,20 +65,11 @@ public class EncodeTransferMedataFeignInterceptorTest {
public void test1() {
String metadata = testFeign.test();
Assertions.assertThat(metadata)
.isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
.isEqualTo("{\"b\":\"2\"}");
Assertions.assertThat(metadataLocalProperties.getContent().get("a"))
.isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a"))
.isEqualTo("11");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"))
.isEqualTo("22");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c"))
.isEqualTo("33");
}
@SpringBootApplication
@ -99,8 +88,9 @@ public class EncodeTransferMedataFeignInterceptorTest {
public interface TestFeign {
@RequestMapping(value = "/test",
headers = {MetadataConstant.HeaderName.CUSTOM_METADATA
+ "={\"a\":\"11" + "\",\"b\":\"22\",\"c\":\"33\"}"})
headers = {"X-SCT-Metadata-Transitive-a=11",
"X-SCT-Metadata-Transitive-b=22",
"X-SCT-Metadata-Transitive-c=33"})
String test();
}

@ -22,11 +22,8 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -35,9 +32,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
@ -68,29 +62,29 @@ public class EncodeTransferMedataRestTemplateInterceptorTest {
@Test
public void test1() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA,
"{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
String metadata = restTemplate
.exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET,
httpEntity, String.class)
.getBody();
Assertions.assertThat(metadata)
.isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
Assertions.assertThat(metadataLocalProperties.getContent().get("a"))
.isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a"))
.isEqualTo("11");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"))
.isEqualTo("22");
Assertions
.assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c"))
.isEqualTo("33");
// HttpHeaders httpHeaders = new HttpHeaders();
// httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA,
// "{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
// HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
// String metadata = restTemplate
// .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET,
// httpEntity, String.class)
// .getBody();
// Assertions.assertThat(metadata)
// .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
// Assertions.assertThat(metadataLocalProperties.getContent().get("a"))
// .isEqualTo("1");
// Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
// .isEqualTo("2");
// Assertions
// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a"))
// .isEqualTo("11");
// Assertions
// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"))
// .isEqualTo("22");
// Assertions
// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c"))
// .isEqualTo("33");
}
@SpringBootApplication

@ -22,7 +22,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import com.tencent.cloud.polaris.util.OkHttpUtil;
@ -60,16 +60,16 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
private final PolarisDiscoveryHandler polarisDiscoveryHandler;
private final MetadataLocalProperties metadataLocalProperties;
private final StaticMetadataManager staticMetadataManager;
private final ScheduledExecutorService heartbeatExecutor;
public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties,
PolarisDiscoveryHandler polarisDiscoveryHandler,
MetadataLocalProperties metadataLocalProperties) {
StaticMetadataManager staticMetadataManager) {
this.polarisDiscoveryProperties = polarisDiscoveryProperties;
this.polarisDiscoveryHandler = polarisDiscoveryHandler;
this.metadataLocalProperties = metadataLocalProperties;
this.staticMetadataManager = staticMetadataManager;
if (polarisDiscoveryProperties.isHeartbeatEnabled()) {
this.heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(
@ -98,7 +98,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
if (null != heartbeatExecutor) {
instanceRegisterRequest.setTtl(ttl);
}
instanceRegisterRequest.setMetadata(metadataLocalProperties.getContent());
instanceRegisterRequest.setMetadata(staticMetadataManager.getMergedStaticMetadata());
instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol());
instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion());
try {
@ -107,7 +107,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
log.info("polaris registry, {} {} {}:{} {} register finished",
polarisDiscoveryProperties.getNamespace(),
registration.getServiceId(), registration.getHost(),
registration.getPort(), metadataLocalProperties.getContent());
registration.getPort(), staticMetadataManager.getMergedStaticMetadata());
if (null != heartbeatExecutor) {
InstanceHeartbeatRequest heartbeatRequest = new InstanceHeartbeatRequest();

@ -18,7 +18,7 @@
package com.tencent.cloud.polaris.registry;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration;
@ -45,16 +45,16 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnPolarisRegisterEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class,
PolarisDiscoveryAutoConfiguration.class })
PolarisDiscoveryAutoConfiguration.class})
public class PolarisServiceRegistryAutoConfiguration {
@Bean
public PolarisServiceRegistry polarisServiceRegistry(
PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler,
MetadataLocalProperties metadataLocalProperties) {
return new PolarisServiceRegistry(polarisDiscoveryProperties, polarisDiscoveryHandler, metadataLocalProperties);
StaticMetadataManager staticMetadataManager) {
return new PolarisServiceRegistry(polarisDiscoveryProperties, polarisDiscoveryHandler, staticMetadataManager);
}
@Bean

@ -19,6 +19,10 @@
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
<!-- Spring Cloud Tencent dependencies end -->
<!-- Polaris dependencies start -->
@ -26,6 +30,10 @@
<groupId>com.tencent.polaris</groupId>
<artifactId>router-rule</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>router-metadata</artifactId>
</dependency>
<!-- Polaris dependencies end -->
<dependency>
@ -39,7 +47,7 @@
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

@ -42,6 +42,7 @@ import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperti
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInfo;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.plugins.router.metadata.MetadataRouter;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest;
import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse;
@ -133,13 +134,8 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule {
ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest();
processRoutersRequest.setDstInstances(serviceInstances);
Map<String, String> routerMetadata;
if (key instanceof PolarisRouterContext) {
routerMetadata = ((PolarisRouterContext) key).getLabels();
}
else {
routerMetadata = Collections.emptyMap();
}
Map<String, String> transitiveLabels = getRouterLabels(key, PolarisRouterContext.TRANSITIVE_LABELS);
processRoutersRequest.putRouterMetadata(MetadataRouter.ROUTER_TYPE_METADATA, transitiveLabels);
String srcNamespace = MetadataContext.LOCAL_NAMESPACE;
String srcService = MetadataContext.LOCAL_SERVICE;
@ -148,13 +144,21 @@ public class PolarisLoadBalancerCompositeRule extends AbstractLoadBalancerRule {
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setNamespace(srcNamespace);
serviceInfo.setService(srcService);
serviceInfo.setMetadata(routerMetadata);
Map<String, String> ruleRouterLabels = getRouterLabels(key, PolarisRouterContext.RULE_ROUTER_LABELS);
serviceInfo.setMetadata(ruleRouterLabels);
processRoutersRequest.setSourceService(serviceInfo);
}
return processRoutersRequest;
}
private Map<String, String> getRouterLabels(Object key, String type) {
if (key instanceof PolarisRouterContext) {
return ((PolarisRouterContext) key).getLabels(type);
}
return Collections.emptyMap();
}
public AbstractLoadBalancerRule getRule() {
String loadBalanceStrategy = loadBalancerProperties.getStrategy();
if (org.springframework.util.StringUtils.isEmpty(loadBalanceStrategy)) {

@ -31,23 +31,28 @@ import org.springframework.util.CollectionUtils;
*/
public class PolarisRouterContext {
private Map<String, String> labels;
public Map<String, String> getLabels() {
/**
* the label for rule router.
*/
public static final String RULE_ROUTER_LABELS = "ruleRouter";
/**
* transitive labels.
*/
public static final String TRANSITIVE_LABELS = "transitive";
private Map<String, Map<String, String>> labels;
public Map<String, String> getLabels(String labelType) {
if (CollectionUtils.isEmpty(labels)) {
return Collections.emptyMap();
}
return Collections.unmodifiableMap(labels);
}
public void setLabels(Map<String, String> labels) {
this.labels = labels;
return Collections.unmodifiableMap(labels.get(labelType));
}
public void putLabel(String key, String value) {
if (labels == null) {
labels = new HashMap<>();
public void setLabels(String labelType, Map<String, String> subLabels) {
if (this.labels == null) {
this.labels = new HashMap<>();
}
labels.put(key, value);
labels.put(labelType, subLabels);
}
}

@ -18,11 +18,13 @@
package com.tencent.cloud.polaris.router.config;
import java.util.List;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory;
import com.tencent.cloud.polaris.router.feign.RouterLabelInterceptor;
import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerBeanPostProcessor;
import com.tencent.cloud.polaris.router.spi.RouterLabelResolver;
@ -45,10 +47,10 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
public class RouterAutoConfiguration {
@Bean
public RouterLabelInterceptor routerLabelInterceptor(@Nullable RouterLabelResolver resolver,
public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List<RouterLabelResolver> routerLabelResolvers,
MetadataLocalProperties metadataLocalProperties,
RouterRuleLabelResolver routerRuleLabelResolver) {
return new RouterLabelInterceptor(resolver, metadataLocalProperties, routerRuleLabelResolver);
return new RouterLabelFeignInterceptor(routerLabelResolvers, metadataLocalProperties, routerRuleLabelResolver);
}
@Bean

@ -25,6 +25,8 @@ import java.util.Map;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.reactive.LoadBalancerCommand;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.ExpressionLabelUtils;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
@ -58,6 +60,9 @@ public class PolarisFeignLoadBalancer extends FeignLoadBalancer {
PolarisRouterContext routerContext = new PolarisRouterContext();
routerContext.setLabels(PolarisRouterContext.TRANSITIVE_LABELS, MetadataContextHolder.get()
.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE));
labelHeaderValues.forEach(labelHeaderValue -> {
Map<String, String> labels = JacksonUtils.deserialize2Map(labelHeaderValue);
if (!CollectionUtils.isEmpty(labels)) {
@ -67,7 +72,7 @@ public class PolarisFeignLoadBalancer extends FeignLoadBalancer {
String escapedValue = ExpressionLabelUtils.unescape(entry.getValue());
unescapeLabels.put(escapedKey, escapedValue);
}
routerContext.setLabels(unescapeLabels);
routerContext.setLabels(PolarisRouterContext.RULE_ROUTER_LABELS, unescapeLabels);
}
});

@ -19,7 +19,9 @@
package com.tencent.cloud.polaris.router.feign;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -44,17 +46,23 @@ import org.springframework.util.CollectionUtils;
*
*@author lepdou 2022-05-12
*/
public class RouterLabelInterceptor implements RequestInterceptor, Ordered {
private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelInterceptor.class);
public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered {
private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelFeignInterceptor.class);
private final RouterLabelResolver resolver;
private final List<RouterLabelResolver> routerLabelResolvers;
private final MetadataLocalProperties metadataLocalProperties;
private final RouterRuleLabelResolver routerRuleLabelResolver;
public RouterLabelInterceptor(RouterLabelResolver resolver,
public RouterLabelFeignInterceptor(List<RouterLabelResolver> routerLabelResolvers,
MetadataLocalProperties metadataLocalProperties,
RouterRuleLabelResolver routerRuleLabelResolver) {
this.resolver = resolver;
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder));
this.routerLabelResolvers = routerLabelResolvers;
}
else {
this.routerLabelResolvers = null;
}
this.metadataLocalProperties = metadataLocalProperties;
this.routerRuleLabelResolver = routerRuleLabelResolver;
}
@ -74,16 +82,18 @@ public class RouterLabelInterceptor implements RequestInterceptor, Ordered {
labels.putAll(transitiveLabels);
// labels from request
if (resolver != null) {
try {
Map<String, String> customResolvedLabels = resolver.resolve(requestTemplate);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.forEach(resolver -> {
try {
Map<String, String> customResolvedLabels = resolver.resolve(requestTemplate);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
}
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
});
}
// labels from rule expression

@ -18,7 +18,10 @@
package com.tencent.cloud.polaris.router.resttemplate;
import java.util.List;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.BeanFactoryUtils;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.RouterLabelResolver;
@ -50,12 +53,12 @@ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor,
if (bean instanceof LoadBalancerInterceptor) {
LoadBalancerRequestFactory requestFactory = this.factory.getBean(LoadBalancerRequestFactory.class);
LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class);
RouterLabelResolver routerLabelResolver = this.factory.getBean(RouterLabelResolver.class);
List<RouterLabelResolver> routerLabelResolvers = BeanFactoryUtils.getBeans(factory, RouterLabelResolver.class);
MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class);
RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class);
return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory,
routerLabelResolver, metadataLocalProperties, routerRuleLabelResolver);
routerLabelResolvers, metadataLocalProperties, routerRuleLabelResolver);
}
return bean;
}

@ -21,7 +21,9 @@ package com.tencent.cloud.polaris.router.resttemplate;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -39,6 +41,7 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.core.Ordered;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
@ -56,7 +59,7 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
private final LoadBalancerClient loadBalancer;
private final LoadBalancerRequestFactory requestFactory;
private final RouterLabelResolver resolver;
private final List<RouterLabelResolver> routerLabelResolvers;
private final MetadataLocalProperties metadataLocalProperties;
private final RouterRuleLabelResolver routerRuleLabelResolver;
@ -64,16 +67,23 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
public PolarisLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory,
RouterLabelResolver resolver,
List<RouterLabelResolver> routerLabelResolvers,
MetadataLocalProperties metadataLocalProperties,
RouterRuleLabelResolver routerRuleLabelResolver) {
super(loadBalancer, requestFactory);
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
this.resolver = resolver;
this.metadataLocalProperties = metadataLocalProperties;
this.routerRuleLabelResolver = routerRuleLabelResolver;
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder));
this.routerLabelResolvers = routerLabelResolvers;
}
else {
this.routerLabelResolvers = null;
}
this.isRibbonLoadBalanceClient = loadBalancer instanceof RibbonLoadBalancerClient;
}
@ -104,28 +114,33 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
labels.putAll(transitiveLabels);
// labels from request
if (resolver != null) {
try {
Map<String, String> customResolvedLabels = resolver.resolve(request, body);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.forEach(resolver -> {
try {
Map<String, String> customResolvedLabels = resolver.resolve(request, body);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
}
}
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
});
}
// labels from rule expression
Map<String, String> ruleExpressionLabels = getExpressionLabels(request, peerServiceName);
if (!CollectionUtils.isEmpty(ruleExpressionLabels)) {
labels.putAll(ruleExpressionLabels);
}
//local service labels
// local service labels
labels.putAll(metadataLocalProperties.getContent());
PolarisRouterContext routerContext = new PolarisRouterContext();
routerContext.setLabels(labels);
routerContext.setLabels(PolarisRouterContext.RULE_ROUTER_LABELS, labels);
routerContext.setLabels(PolarisRouterContext.TRANSITIVE_LABELS, transitiveLabels);
return routerContext;
}

@ -22,6 +22,7 @@ import java.util.Map;
import feign.RequestTemplate;
import org.springframework.core.Ordered;
import org.springframework.http.HttpRequest;
/**
@ -29,7 +30,7 @@ import org.springframework.http.HttpRequest;
*
* @author lepdou 2022-05-11
*/
public interface RouterLabelResolver {
public interface RouterLabelResolver extends Ordered {
/**
* resolve labels from feign request.

@ -18,8 +18,8 @@
package com.tencent.cloud.common.metadata;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
@ -37,9 +37,9 @@ public final class MetadataContextHolder {
private static final ThreadLocal<MetadataContext> METADATA_CONTEXT = new InheritableThreadLocal<>();
private static MetadataLocalProperties metadataLocalProperties;
private static StaticMetadataManager staticMetadataManager;
private MetadataContextHolder() {
}
/**
@ -47,39 +47,27 @@ public final class MetadataContextHolder {
* @return METADATA_CONTEXT
*/
public static MetadataContext get() {
if (null == METADATA_CONTEXT.get()) {
MetadataContext metadataContext = new MetadataContext();
if (metadataLocalProperties == null) {
metadataLocalProperties = (MetadataLocalProperties) ApplicationContextAwareUtils
.getApplicationContext().getBean("metadataLocalProperties");
}
// init custom metadata and load local metadata
Map<String, String> transitiveMetadataMap = getTransitiveMetadataMap(
metadataLocalProperties.getContent(),
metadataLocalProperties.getTransitive());
metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, transitiveMetadataMap);
METADATA_CONTEXT.set(metadataContext);
if (METADATA_CONTEXT.get() != null) {
return METADATA_CONTEXT.get();
}
return METADATA_CONTEXT.get();
}
/**
* Filter and store the transitive metadata to transitive metadata context.
* @param source all metadata content
* @param transitiveMetadataKeyList transitive metadata name list
* @return result
*/
private static Map<String, String> getTransitiveMetadataMap(
Map<String, String> source, List<String> transitiveMetadataKeyList) {
Map<String, String> result = new HashMap<>();
for (String key : transitiveMetadataKeyList) {
if (source.containsKey(key)) {
result.put(key, source.get(key));
}
if (metadataLocalProperties == null) {
metadataLocalProperties = (MetadataLocalProperties) ApplicationContextAwareUtils
.getApplicationContext().getBean("metadataLocalProperties");
}
if (staticMetadataManager == null) {
staticMetadataManager = (StaticMetadataManager) ApplicationContextAwareUtils
.getApplicationContext().getBean("metadataManager");
}
return result;
// init static transitive metadata
MetadataContext metadataContext = new MetadataContext();
metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE,
staticMetadataManager.getMergedStaticTransitiveMetadata());
METADATA_CONTEXT.set(metadataContext);
return METADATA_CONTEXT.get();
}
/**
@ -92,16 +80,22 @@ public final class MetadataContextHolder {
/**
* Save metadata map to thread local.
* @param customMetadataMap custom metadata collection
* @param dynamicTransitiveMetadata custom metadata collection
*/
public static void init(Map<String, String> customMetadataMap) {
public static void init(Map<String, String> dynamicTransitiveMetadata) {
// Init ThreadLocal.
MetadataContextHolder.remove();
MetadataContext metadataContext = MetadataContextHolder.get();
// Save to ThreadLocal.
if (!CollectionUtils.isEmpty(customMetadataMap)) {
metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, customMetadataMap);
// Save transitive metadata to ThreadLocal.
if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) {
Map<String, String> staticTransitiveMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
Map<String, String> mergedTransitiveMetadata = new HashMap<>();
mergedTransitiveMetadata.putAll(staticTransitiveMetadata);
mergedTransitiveMetadata.putAll(dynamicTransitiveMetadata);
metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE,
Collections.unmodifiableMap(mergedTransitiveMetadata));
}
MetadataContextHolder.set(metadataContext);
}

@ -0,0 +1,145 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.common.metadata;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* manage metadata from env/config file.
*
*@author lepdou 2022-05-20
*/
public class StaticMetadataManager {
private static final Logger LOGGER = LoggerFactory.getLogger(StaticMetadataManager.class);
private static final String ENV_METADATA_PREFIX = "SCT_METADATA_CONTENT_";
private static final int ENV_METADATA_PREFIX_LENGTH = ENV_METADATA_PREFIX.length();
private static final String ENV_METADATA_CONTENT_TRANSITIVE = "SCT_METADATA_CONTENT_TRANSITIVE";
private Map<String, String> envMetadata;
private Map<String, String> envTransitiveMetadata;
private Map<String, String> configMetadata;
private Map<String, String> configTransitiveMetadata;
private Map<String, String> mergedStaticMetadata;
private Map<String, String> mergedStaticTransitiveMetadata;
public StaticMetadataManager(MetadataLocalProperties metadataLocalProperties) {
parseConfigMetadata(metadataLocalProperties);
parseEnvMetadata();
merge();
}
private void parseEnvMetadata() {
Map<String, String> allEnvs = System.getenv();
envMetadata = new HashMap<>();
// parse all metadata
for (Map.Entry<String, String> entry : allEnvs.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (StringUtils.isNotBlank(key) && key.startsWith(ENV_METADATA_PREFIX)
&& !key.equals(ENV_METADATA_CONTENT_TRANSITIVE)) {
String sourceKey = StringUtils.substring(key, ENV_METADATA_PREFIX_LENGTH);
envMetadata.put(sourceKey, value);
LOGGER.info("[SCT] resolve metadata from env. key = {}, value = {}", sourceKey, value);
}
}
envMetadata = Collections.unmodifiableMap(envMetadata);
envTransitiveMetadata = new HashMap<>();
// parse transitive metadata
String transitiveKeys = allEnvs.get(ENV_METADATA_CONTENT_TRANSITIVE);
if (StringUtils.isNotBlank(transitiveKeys)) {
String[] keyArr = StringUtils.split(transitiveKeys, ",");
if (keyArr != null && keyArr.length > 0) {
for (String key : keyArr) {
String value = envMetadata.get(key);
if (StringUtils.isNotBlank(value)) {
envTransitiveMetadata.put(key, value);
}
}
}
}
envTransitiveMetadata = Collections.unmodifiableMap(envTransitiveMetadata);
}
private void parseConfigMetadata(MetadataLocalProperties metadataLocalProperties) {
Map<String, String> allMetadata = metadataLocalProperties.getContent();
List<String> transitiveKeys = metadataLocalProperties.getTransitive();
Map<String, String> result = new HashMap<>();
for (String key : transitiveKeys) {
if (allMetadata.containsKey(key)) {
result.put(key, allMetadata.get(key));
}
}
configTransitiveMetadata = Collections.unmodifiableMap(result);
configMetadata = Collections.unmodifiableMap(allMetadata);
}
private void merge() {
// env priority is bigger than config
Map<String, String> mergedMetadataResult = new HashMap<>();
mergedMetadataResult.putAll(configMetadata);
mergedMetadataResult.putAll(envMetadata);
this.mergedStaticMetadata = Collections.unmodifiableMap(mergedMetadataResult);
Map<String, String> mergedTransitiveMetadataResult = new HashMap<>();
mergedTransitiveMetadataResult.putAll(configTransitiveMetadata);
mergedTransitiveMetadataResult.putAll(envTransitiveMetadata);
this.mergedStaticTransitiveMetadata = Collections.unmodifiableMap(mergedTransitiveMetadataResult);
}
public Map<String, String> getAllEnvMetadata() {
return envMetadata;
}
public Map<String, String> getEnvTransitiveMetadata() {
return envTransitiveMetadata;
}
public Map<String, String> getAllConfigMetadata() {
return configMetadata;
}
public Map<String, String> getConfigTransitiveMetadata() {
return configTransitiveMetadata;
}
public Map<String, String> getMergedStaticMetadata() {
return mergedStaticMetadata;
}
Map<String, String> getMergedStaticTransitiveMetadata() {
return mergedStaticTransitiveMetadata;
}
}

@ -18,6 +18,7 @@
package com.tencent.cloud.common.metadata.config;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -42,6 +43,11 @@ public class MetadataAutoConfiguration {
return new MetadataLocalProperties();
}
@Bean
public StaticMetadataManager metadataManager(MetadataLocalProperties metadataLocalProperties) {
return new StaticMetadataManager(metadataLocalProperties);
}
/**
* Create when gateway application is SCG.
*/

@ -0,0 +1,51 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.common.util;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
/**
* the utils for bean factory.
* @author lepdou 2022-05-23
*/
public class BeanFactoryUtils {
public static <T> List<T> getBeans(BeanFactory beanFactory, Class<T> requiredType) {
if (!(beanFactory instanceof DefaultListableBeanFactory)) {
throw new RuntimeException("bean factory not support get list bean. factory type = " + beanFactory.getClass()
.getName());
}
String[] beanNames = ((DefaultListableBeanFactory) beanFactory).getBeanNamesForType(requiredType);
if (beanNames.length == 0) {
return Collections.emptyList();
}
return Arrays.stream(beanNames).map(
beanName -> beanFactory.getBean(beanName, requiredType)
).collect(Collectors.toList());
}
}

@ -71,7 +71,7 @@
<properties>
<revision>1.5.0-Hoxton.SR9-SNAPSHOT</revision>
<polaris.version>1.5.2</polaris.version>
<polaris.version>1.6.0-SNAPSHOT</polaris.version>
<powermock.version>2.0.0</powermock.version>
<!-- Maven Plugin Versions -->

@ -57,4 +57,9 @@ public class CustomRouterLabelResolver implements RouterLabelResolver {
labels.put("user", user.getName());
return labels;
}
@Override
public int getOrder() {
return 0;
}
}

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tencent-examples</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>polaris-router-grayrelease-example</artifactId>
<packaging>pom</packaging>
<name>Spring Cloud Tencent Polaris Router GrayRelease Example</name>
<description>Example of Spring Cloud Tencent Polaris Router GrayRelease</description>
<modules>
<module>router-grayrelease-gateway</module>
<module>router-grayrelease-frontend</module>
<module>router-grayrelease-middle</module>
<module>router-grayrelease-backend</module>
</modules>
</project>

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>polaris-router-grayrelease-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>router-grayrelease-backend</artifactId>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,15 @@
############################################################
# Dockerfile to build polaris-java quickstart example provider
# 1. You need to build the binary from the source code,
# use `mvn clean install` to build the binary.
# 2. You need to copy the quickstart-example-provider-*.jar to this directory
# 3. Replace the ${VERSION} to the real version of the project
############################################################
FROM java:8
ADD router-grayrelease-backend-1.5.0-Hoxton.SR9-SNAPSHOT.jar /root/app.jar
ENTRYPOINT ["java","-jar","/root/app.jar"]

@ -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.router.grayrelease.back;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/router/gray")
public class BackController {
@Autowired
private Environment environment;
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/rest")
public String rest() {
String env = System.getenv("SCT_METADATA_CONTENT_env");
String appName = environment.getProperty("spring.application.name");
return appName + "[" + env + "]";
}
}

@ -0,0 +1,29 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.grayrelease.back;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GrayReleaseBackendApplication {
public static void main(String[] args) {
SpringApplication.run(GrayReleaseBackendApplication.class, args);
}
}

@ -0,0 +1,17 @@
server:
session-timeout: 1800
port: 59002
spring:
application:
name: gray-release-back
cloud:
polaris:
address: ${polaris_address}
namespace: default
enabled: true
discovery:
service-list-refresh-interval: 1000
logging:
level:
org.springframework.cloud.gateway: info
com.tencent.cloud.polaris: debug

@ -0,0 +1,6 @@
global:
statReporter:
enable: true
plugin:
prometheus:
pushgatewayAddress: ${prometheus_address}

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>polaris-router-grayrelease-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>router-grayrelease-frontend</artifactId>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,15 @@
############################################################
# Dockerfile to build polaris-java quickstart example provider
# 1. You need to build the binary from the source code,
# use `mvn clean install` to build the binary.
# 2. You need to copy the quickstart-example-provider-*.jar to this directory
# 3. Replace the ${VERSION} to the real version of the project
############################################################
FROM java:8
ADD router-grayrelease-frontend-1.5.0-Hoxton.SR9-SNAPSHOT.jar /root/app.jar
ENTRYPOINT ["java","-jar","/root/app.jar"]

@ -0,0 +1,49 @@
/*
* 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.grayrelease.front;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/router/gray")
public class FrontController {
@Autowired
private Environment environment;
@Autowired
private RouterService routerService;
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/rest")
public String rest() {
String env = System.getenv("SCT_METADATA_CONTENT_env");
String appName = environment.getProperty("spring.application.name");
String curName = appName + "[" + env + "]";
String resp = routerService.rest();
return curName + " -> " + resp;
}
}

@ -0,0 +1,33 @@
/*
* 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.grayrelease.front;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class GrayReleaseFrontApplication {
public static void main(String[] args) {
SpringApplication.run(GrayReleaseFrontApplication.class, args);
}
}

@ -0,0 +1,35 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.grayrelease.front;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* Router callee feign client.
*
* @author lepdou 2022-04-06
*/
@FeignClient("gray-release-middle")
public interface RouterService {
@GetMapping("/router/gray/rest")
String rest();
}

@ -0,0 +1,17 @@
server:
session-timeout: 1800
port: 59000
spring:
application:
name: gray-release-front
cloud:
polaris:
address: ${polaris_address}
namespace: default
enabled: true
discovery:
service-list-refresh-interval: 1000
logging:
level:
org.springframework.cloud.gateway: info
com.tencent.cloud.polaris: debug

@ -0,0 +1,6 @@
global:
statReporter:
enable: true
plugin:
prometheus:
pushgatewayAddress: ${prometheus_address}

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>polaris-router-grayrelease-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>router-grayrelease-gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,15 @@
############################################################
# Dockerfile to build polaris-java quickstart example provider
# 1. You need to build the binary from the source code,
# use `mvn clean install` to build the binary.
# 2. You need to copy the quickstart-example-provider-*.jar to this directory
# 3. Replace the ${VERSION} to the real version of the project
############################################################
FROM java:8
ADD router-grayrelease-gateway-1.5.0-Hoxton.SR9-SNAPSHOT.jar /root/app.jar
ENTRYPOINT ["java","-jar","/root/app.jar"]

@ -0,0 +1,47 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.grayrelease.gateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/router/gray")
public class GatewayController {
@Autowired
private Environment environment;
@Autowired
private RouterService routerService;
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/entry")
public String rest() {
String appName = environment.getProperty("spring.application.name");
String resp = routerService.rest();
return appName + " -> " + resp;
}
}

@ -0,0 +1,33 @@
/*
* 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.grayrelease.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class GrayReleaseGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GrayReleaseGatewayApplication.class, args);
}
}

@ -0,0 +1,35 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.grayrelease.gateway;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* Router callee feign client.
*
* @author lepdou 2022-04-06
*/
@FeignClient("gray-release-front")
public interface RouterService {
@GetMapping("/router/gray/rest")
String rest();
}

@ -0,0 +1,17 @@
server:
session-timeout: 1800
port: 59100
spring:
application:
name: gray-release-gateway
cloud:
polaris:
address: ${polaris_address}
namespace: default
enabled: true
discovery:
service-list-refresh-interval: 1000
logging:
level:
org.springframework.cloud.gateway: info
com.tencent.cloud.polaris: debug

@ -0,0 +1,6 @@
global:
statReporter:
enable: true
plugin:
prometheus:
pushgatewayAddress: ${prometheus_address}

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>polaris-router-grayrelease-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>router-grayrelease-middle</artifactId>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,15 @@
############################################################
# Dockerfile to build polaris-java quickstart example provider
# 1. You need to build the binary from the source code,
# use `mvn clean install` to build the binary.
# 2. You need to copy the quickstart-example-provider-*.jar to this directory
# 3. Replace the ${VERSION} to the real version of the project
############################################################
FROM java:8
ADD router-grayrelease-middle-1.5.0-Hoxton.SR9-SNAPSHOT.jar /root/app.jar
ENTRYPOINT ["java","-jar","/root/app.jar"]

@ -0,0 +1,33 @@
/*
* 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.grayrelease.middle;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class GrayReleaseMiddleApplication {
public static void main(String[] args) {
SpringApplication.run(GrayReleaseMiddleApplication.class, args);
}
}

@ -0,0 +1,49 @@
/*
* 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.grayrelease.middle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/router/gray")
public class MiddleController {
@Autowired
private Environment environment;
@Autowired
private RouterService routerService;
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/rest")
public String rest() {
String env = System.getenv("SCT_METADATA_CONTENT_env");
String appName = environment.getProperty("spring.application.name");
String curName = appName + "[" + env + "]";
String resp = routerService.rest();
return curName + " -> " + resp;
}
}

@ -0,0 +1,35 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.router.grayrelease.middle;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* Router callee feign client.
*
* @author lepdou 2022-04-06
*/
@FeignClient("gray-release-back")
public interface RouterService {
@GetMapping("/router/gray/rest")
String rest();
}

@ -0,0 +1,17 @@
server:
session-timeout: 1800
port: 59001
spring:
application:
name: gray-release-middle
cloud:
polaris:
address: ${polaris_address}
namespace: default
enabled: true
discovery:
service-list-refresh-interval: 1000
logging:
level:
org.springframework.cloud.gateway: info
com.tencent.cloud.polaris: debug

@ -0,0 +1,6 @@
global:
statReporter:
enable: true
plugin:
prometheus:
pushgatewayAddress: ${prometheus_address}

@ -23,6 +23,7 @@
<module>polaris-config-example</module>
<module>polaris-router-example</module>
<module>metadata-transfer-example</module>
<module>polaris-router-grayrelease-example</module>
</modules>
<properties>

Loading…
Cancel
Save