diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/CustomTransitiveMetadataResolver.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/CustomTransitiveMetadataResolver.java new file mode 100644 index 00000000..b8645efb --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/CustomTransitiveMetadataResolver.java @@ -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 resolve(ServerWebExchange exchange) { + Map result = new HashMap<>(); + + HttpHeaders headers = exchange.getRequest().getHeaders(); + for (Map.Entry> 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 resolve(HttpServletRequest request) { + Map result = new HashMap<>(); + + Enumeration 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; + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java index 2dea4fd6..48a540f1 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -20,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 internalTransitiveMetadata = getIntervalTransitiveMetadata(serverHttpRequest); + Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); + + Map 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 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 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); } + } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index 23934ede..35a3f13c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -21,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 internalTransitiveMetadata = getInternalTransitiveMetadata(httpServletRequest); + Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest); + + Map 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 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 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); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java index 2e6e78d2..7b290d7d 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java @@ -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 headerMetadataMap = JacksonUtils - .deserialize2Map(headerMetadataStr); - for (String key : headerMetadataMap.keySet()) { - metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key)); - } - } - } - Map 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); } } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java index c97ddb9d..96c6439a 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java @@ -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 headerMetadataMap = JacksonUtils - .deserialize2Map(metadataStr); - for (String key : headerMetadataMap.keySet()) { - metadataContext.putContext(MetadataContext.FRAGMENT_TRANSITIVE, key, headerMetadataMap.get(key)); - } - } Map 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); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java index 7d781142..ca967163 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java @@ -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(); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java index 26f1bc39..ba5524c9 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -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 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 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 diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java index 0d39c726..9756a08a 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java @@ -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 { 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 { 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 { 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(); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index 68f338c5..c3f370a6 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -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 diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 6f0fa315..644612dc 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -26,6 +26,10 @@ com.tencent.polaris router-rule + + com.tencent.polaris + router-metadata + diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java index d270f766..863cb553 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java @@ -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 routerMetadata; - if (key instanceof PolarisRouterContext) { - routerMetadata = ((PolarisRouterContext) key).getLabels(); - } - else { - routerMetadata = Collections.emptyMap(); - } + Map 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 ruleRouterLabels = getRouterLabels(key, PolarisRouterContext.RULE_ROUTER_LABELS); + serviceInfo.setMetadata(ruleRouterLabels); processRoutersRequest.setSourceService(serviceInfo); } return processRoutersRequest; } + private Map 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)) { diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java index 2ed7e727..ebcc8fd4 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java @@ -31,23 +31,28 @@ import org.springframework.util.CollectionUtils; */ public class PolarisRouterContext { - private Map labels; - - public Map 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> labels; + + public Map getLabels(String labelType) { if (CollectionUtils.isEmpty(labels)) { return Collections.emptyMap(); } - return Collections.unmodifiableMap(labels); - } - - public void setLabels(Map 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 subLabels) { + if (this.labels == null) { + this.labels = new HashMap<>(); } - labels.put(key, value); + labels.put(labelType, subLabels); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java index 067332dd..5a13e219 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java @@ -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 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); } }); diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java index 2e3e691f..a432830b 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerInterceptor.java @@ -116,16 +116,19 @@ public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor { } } + // labels from rule expression Map 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; } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index d12dd79e..b270c368 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -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 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 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 getTransitiveMetadataMap( - Map source, List transitiveMetadataKeyList) { - Map 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 customMetadataMap) { + public static void init(Map 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 staticTransitiveMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map mergedTransitiveMetadata = new HashMap<>(); + mergedTransitiveMetadata.putAll(staticTransitiveMetadata); + mergedTransitiveMetadata.putAll(dynamicTransitiveMetadata); + + metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, + Collections.unmodifiableMap(mergedTransitiveMetadata)); } MetadataContextHolder.set(metadataContext); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java new file mode 100644 index 00000000..a1619fb1 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java @@ -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 envMetadata; + private Map envTransitiveMetadata; + private Map configMetadata; + private Map configTransitiveMetadata; + private Map mergedStaticMetadata; + private Map mergedStaticTransitiveMetadata; + + public StaticMetadataManager(MetadataLocalProperties metadataLocalProperties) { + parseConfigMetadata(metadataLocalProperties); + parseEnvMetadata(); + merge(); + } + + private void parseEnvMetadata() { + Map allEnvs = System.getenv(); + + envMetadata = new HashMap<>(); + // parse all metadata + for (Map.Entry 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 allMetadata = metadataLocalProperties.getContent(); + List transitiveKeys = metadataLocalProperties.getTransitive(); + + Map 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 mergedMetadataResult = new HashMap<>(); + + mergedMetadataResult.putAll(configMetadata); + mergedMetadataResult.putAll(envMetadata); + + this.mergedStaticMetadata = Collections.unmodifiableMap(mergedMetadataResult); + + Map mergedTransitiveMetadataResult = new HashMap<>(); + mergedTransitiveMetadataResult.putAll(configTransitiveMetadata); + mergedTransitiveMetadataResult.putAll(envTransitiveMetadata); + + this.mergedStaticTransitiveMetadata = Collections.unmodifiableMap(mergedTransitiveMetadataResult); + } + + public Map getAllEnvMetadata() { + return envMetadata; + } + + public Map getEnvTransitiveMetadata() { + return envTransitiveMetadata; + } + + public Map getAllConfigMetadata() { + return configMetadata; + } + + public Map getConfigTransitiveMetadata() { + return configTransitiveMetadata; + } + + public Map getMergedStaticMetadata() { + return mergedStaticMetadata; + } + + Map getMergedStaticTransitiveMetadata() { + return mergedStaticTransitiveMetadata; + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java index 6188c61a..5bcc0fd3 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataAutoConfiguration.java @@ -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. */ diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 02465fb0..573b296f 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -71,7 +71,7 @@ 1.5.0-Hoxton.SR9-SNAPSHOT - 1.5.2 + 1.6.0-SNAPSHOT 2.0.0