diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d662788..68031ab3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,4 @@ - [Add configurable heartbeat interval support](https://github.com/Tencent/spring-cloud-tencent/pull/444) - [feat:enhance Feign and RestTemplate and support Polaris monitor.](https://github.com/Tencent/spring-cloud-tencent/pull/447) - [Optimize feign & rest-template circuit-breaker logic](https://github.com/Tencent/spring-cloud-tencent/pull/454) +- [Feature: Add disposable metadata transfer support](https://github.com/Tencent/spring-cloud-tencent/pull/459) diff --git a/pom.xml b/pom.xml index 179477dd..82546eb5 100644 --- a/pom.xml +++ b/pom.xml @@ -93,10 +93,10 @@ 2021.0.3 - 2.6.9 + 2.6.10 - 5.3.21 + 5.3.22 0.8.8 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 b8815c51..957493ca 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 @@ -39,6 +39,8 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -60,27 +62,32 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); - Map internalTransitiveMetadata = getIntervalTransitiveMetadata(serverHttpRequest); + Map internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA); Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - MetadataContextHolder.init(mergedTransitiveMetadata); + Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); + Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); + + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); // Save to ServerWebExchange. - serverWebExchange.getAttributes() - .put(MetadataConstant.HeaderName.METADATA_CONTEXT, MetadataContextHolder.get()); + serverWebExchange.getAttributes().put( + MetadataConstant.HeaderName.METADATA_CONTEXT, + MetadataContextHolder.get()); return webFilterChain.filter(serverWebExchange) - .doOnError(throwable -> LOG.error("handle metadata[{}] error.", MetadataContextHolder.get(), throwable)) + .doOnError(throwable -> LOG.error("handle metadata[{}] error.", + MetadataContextHolder.get(), throwable)) .doFinally((type) -> MetadataContextHolder.remove()); } - private Map getIntervalTransitiveMetadata(ServerHttpRequest serverHttpRequest) { + private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); - String customMetadataStr = httpHeaders.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA); + String customMetadataStr = httpHeaders.getFirst(headerName); try { if (StringUtils.hasText(customMetadataStr)) { customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); 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 20df1dc7..a6756391 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 @@ -36,10 +36,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; +import org.springframework.lang.NonNull; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -53,28 +56,27 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); @Override - protected void doFilterInternal(HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { - Map internalTransitiveMetadata = getInternalTransitiveMetadata(httpServletRequest); + protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, + @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) + throws ServletException, IOException { + Map internalTransitiveMetadata = getInternalMetadata(httpServletRequest, CUSTOM_METADATA); Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - try { - MetadataContextHolder.init(mergedTransitiveMetadata); + Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); + Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - filterChain.doFilter(httpServletRequest, httpServletResponse); - } - catch (IOException | ServletException | RuntimeException e) { - throw e; - } + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); + + filterChain.doFilter(httpServletRequest, httpServletResponse); } - private Map getInternalTransitiveMetadata(HttpServletRequest httpServletRequest) { + private Map getInternalMetadata(HttpServletRequest httpServletRequest, String headerName) { // Get custom metadata string from http header. - String customMetadataStr = httpServletRequest.getHeader(MetadataConstant.HeaderName.CUSTOM_METADATA); + String customMetadataStr = httpServletRequest.getHeader(headerName); try { if (StringUtils.hasText(customMetadataStr)) { customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); 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 3bfefe03..fa63f3df 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java @@ -19,7 +19,7 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -33,9 +33,12 @@ import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static java.net.URLEncoder.encode; /** * Interceptor used for adding the metadata in http headers from context when web client @@ -57,16 +60,37 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - if (!CollectionUtils.isEmpty(customMetadata)) { - String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata); - requestTemplate.removeHeader(CUSTOM_METADATA); + // Clean up one-time metadata coming from upstream . + Map newestCustomMetadata = new HashMap<>(); + customMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + newestCustomMetadata.put(key, value); + } + }); + this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // process custom metadata finally + this.buildMetadataHeader(requestTemplate, newestCustomMetadata, CUSTOM_METADATA); + } + + /** + * Set metadata into the request header for {@link RestTemplate} . + * @param requestTemplate instance of {@link RestTemplate} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(RequestTemplate requestTemplate, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + String encodedMetadata = JacksonUtils.serialize2Json(metadata); + requestTemplate.removeHeader(headerName); try { - requestTemplate.header(CUSTOM_METADATA, URLEncoder.encode(encodedTransitiveMetadata, UTF_8)); + requestTemplate.header(headerName, encode(encodedMetadata, UTF_8)); } catch (UnsupportedEncodingException e) { LOG.error("Set header failed.", e); - requestTemplate.header(CUSTOM_METADATA, encodedTransitiveMetadata); + requestTemplate.header(headerName, encodedMetadata); } } } 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 75f19819..513310da 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java @@ -21,6 +21,7 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -33,9 +34,12 @@ import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** * Interceptor used for adding the metadata in http headers from context when web client @@ -51,22 +55,44 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe } @Override - public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, - ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes, + @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - if (!CollectionUtils.isEmpty(customMetadata)) { - String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata); + Map newestCustomMetadata = new HashMap<>(); + customMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + newestCustomMetadata.put(key, value); + } + }); + // build custom disposable metadata request header + this.buildMetadataHeader(httpRequest, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // build custom metadata request header + this.buildMetadataHeader(httpRequest, newestCustomMetadata, CUSTOM_METADATA); + + return clientHttpRequestExecution.execute(httpRequest, bytes); + } + + /** + * Set metadata into the request header for {@link HttpRequest} . + * + * @param request instance of {@link HttpRequest} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(HttpRequest request, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + String encodedMetadata = JacksonUtils.serialize2Json(metadata); try { - httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA, - URLEncoder.encode(encodedTransitiveMetadata, UTF_8)); + request.getHeaders().set(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); } catch (UnsupportedEncodingException e) { - httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA, encodedTransitiveMetadata); + request.getHeaders().set(headerName, encodedMetadata); } } - return clientHttpRequestExecution.execute(httpRequest, bytes); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java index 4f6c0010..95d7b5b2 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java @@ -20,6 +20,7 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -36,6 +37,8 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; /** @@ -59,22 +62,42 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { // get metadata of current thread MetadataContext metadataContext = exchange.getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT); - - // add new metadata and cover old if (metadataContext == null) { metadataContext = MetadataContextHolder.get(); } + Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - if (!CollectionUtils.isEmpty(customMetadata)) { - String metadataStr = JacksonUtils.serialize2Json(customMetadata); + Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + + // Clean upstream disposable metadata. + Map newestCustomMetadata = new HashMap<>(); + customMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + newestCustomMetadata.put(key, value); + } + }); + + this.buildMetadataHeader(builder, newestCustomMetadata, CUSTOM_METADATA); + this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + return chain.filter(exchange.mutate().request(builder.build()).build()); + } + + /** + * Set metadata into the request header for {@link ServerHttpRequest.Builder} . + * @param builder instance of {@link ServerHttpRequest.Builder} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(ServerHttpRequest.Builder builder, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + String encodedMetadata = JacksonUtils.serialize2Json(metadata); try { - builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, URLEncoder.encode(metadataStr, UTF_8)); + builder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); } catch (UnsupportedEncodingException e) { - builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr); + builder.header(headerName, encodedMetadata); } } - - return chain.filter(exchange.mutate().request(builder.build()).build()); } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java index 09e17e1e..5e451f3d 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java @@ -26,6 +26,12 @@ import org.springframework.core.Ordered; */ public final class MetadataConstant { + /** + * Default Private Constructor. + */ + private MetadataConstant() { + } + /** * Order of filter, interceptor, ... */ @@ -57,6 +63,11 @@ public final class MetadataConstant { */ public static final String CUSTOM_METADATA = "SCT-CUSTOM-METADATA"; + /** + * Custom Disposable Metadata. + */ + public static final String CUSTOM_DISPOSABLE_METADATA = "SCT-CUSTOM-DISPOSABLE-METADATA"; + /** * System Metadata. */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java index bd18111a..caa9ceef 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java @@ -40,6 +40,17 @@ public class MetadataContext { * transitive context. */ public static final String FRAGMENT_TRANSITIVE = "transitive"; + + /** + * disposable Context. + */ + public static final String FRAGMENT_DISPOSABLE = "disposable"; + + /** + * upstream disposable Context. + */ + public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable"; + private static final Logger LOG = LoggerFactory.getLogger(MetadataContext.class); /** * Namespace of local instance. 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 3d3064ba..28520517 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 @@ -20,12 +20,17 @@ package com.tencent.cloud.common.metadata; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import org.springframework.util.CollectionUtils; +import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_DISPOSABLE; +import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_TRANSITIVE; +import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_UPSTREAM_DISPOSABLE; + /** * Metadata Context Holder. * @@ -36,6 +41,7 @@ public final class MetadataContextHolder { private static final ThreadLocal METADATA_CONTEXT = new InheritableThreadLocal<>(); private static MetadataLocalProperties metadataLocalProperties; + private static StaticMetadataManager staticMetadataManager; private MetadataContextHolder() { @@ -51,24 +57,55 @@ public final class MetadataContextHolder { } if (metadataLocalProperties == null) { - metadataLocalProperties = (MetadataLocalProperties) ApplicationContextAwareUtils - .getApplicationContext().getBean("metadataLocalProperties"); + metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext().getBean(MetadataLocalProperties.class); } if (staticMetadataManager == null) { - staticMetadataManager = (StaticMetadataManager) ApplicationContextAwareUtils - .getApplicationContext().getBean("metadataManager"); + staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext().getBean(StaticMetadataManager.class); } // init static transitive metadata MetadataContext metadataContext = new MetadataContext(); - metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, - staticMetadataManager.getMergedStaticTransitiveMetadata()); + metadataContext.putFragmentContext(FRAGMENT_TRANSITIVE, staticMetadataManager.getMergedStaticTransitiveMetadata()); + metadataContext.putFragmentContext(FRAGMENT_DISPOSABLE, staticMetadataManager.getMergedStaticDisposableMetadata()); METADATA_CONTEXT.set(metadataContext); return METADATA_CONTEXT.get(); } + /** + * Get disposable metadata value from thread local . + * @param key metadata key . + * @param upstream upstream disposable , otherwise will return local static disposable metadata . + * @return target disposable metadata value . + */ + public static Optional getDisposableMetadata(String key, boolean upstream) { + MetadataContext context = get(); + if (upstream) { + return Optional.ofNullable(context.getContext(FRAGMENT_UPSTREAM_DISPOSABLE, key)); + } + else { + return Optional.ofNullable(context.getContext(FRAGMENT_DISPOSABLE, key)); + } + } + + /** + * Get all disposable metadata value from thread local . + * @param upstream upstream disposable , otherwise will return local static disposable metadata . + * @return target disposable metadata value . + */ + public static Map getAllDisposableMetadata(boolean upstream) { + Map disposables = new HashMap<>(); + MetadataContext context = get(); + if (upstream) { + disposables.putAll(context.getFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE)); + } + else { + disposables.putAll(context.getFragmentContext(FRAGMENT_DISPOSABLE)); + } + return Collections.unmodifiableMap(disposables); + } + /** * Set metadata context. * @param metadataContext metadata context @@ -80,21 +117,26 @@ public final class MetadataContextHolder { /** * Save metadata map to thread local. * @param dynamicTransitiveMetadata custom metadata collection + * @param dynamicDisposableMetadata custom disposable metadata connection */ - public static void init(Map dynamicTransitiveMetadata) { + public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata) { // Init ThreadLocal. MetadataContextHolder.remove(); MetadataContext metadataContext = MetadataContextHolder.get(); // Save transitive metadata to ThreadLocal. if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { - Map staticTransitiveMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map staticTransitiveMetadata = metadataContext.getFragmentContext(FRAGMENT_TRANSITIVE); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(staticTransitiveMetadata); mergedTransitiveMetadata.putAll(dynamicTransitiveMetadata); + metadataContext.putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(mergedTransitiveMetadata)); + + Map mergedDisposableMetadata = new HashMap<>(dynamicDisposableMetadata); + metadataContext.putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(mergedDisposableMetadata)); - metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, - Collections.unmodifiableMap(mergedTransitiveMetadata)); + Map staticDisposableMetadata = metadataContext.getFragmentContext(FRAGMENT_DISPOSABLE); + metadataContext.putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(staticDisposableMetadata)); } 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 index a717db43..554694fa 100644 --- 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 @@ -54,18 +54,22 @@ public class StaticMetadataManager { 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 static final String ENV_METADATA_CONTENT_DISPOSABLE = "SCT_METADATA_CONTENT_DISPOSABLE"; private static final String ENV_METADATA_ZONE = "SCT_METADATA_ZONE"; private static final String ENV_METADATA_REGION = "SCT_METADATA_REGION"; private static final String ENV_METADATA_CAMPUS = "SCT_METADATA_CAMPUS"; private Map envMetadata; private Map envTransitiveMetadata; + private Map envDisposableMetadata; private Map configMetadata; private Map configTransitiveMetadata; + private Map configDisposableMetadata; private Map customSPIMetadata; private Map customSPITransitiveMetadata; - + private Map customSPIDisposableMetadata; private Map mergedStaticMetadata; private Map mergedStaticTransitiveMetadata; + private Map mergedStaticDisposableMetadata; private String zone; private String region; private String campus; @@ -85,6 +89,7 @@ public class StaticMetadataManager { LOGGER.info("[SCT] Loaded static metadata info. {}", this); } + @SuppressWarnings("DuplicatedCode") private void parseEnvMetadata() { Map allEnvs = System.getenv(); @@ -118,27 +123,54 @@ public class StaticMetadataManager { } } envTransitiveMetadata = Collections.unmodifiableMap(envTransitiveMetadata); + + envDisposableMetadata = new HashMap<>(); + // parse disposable metadata + String disposableKeys = allEnvs.get(ENV_METADATA_CONTENT_DISPOSABLE); + if (StringUtils.isNotBlank(disposableKeys)) { + String[] keyArr = StringUtils.split(disposableKeys, ","); + if (keyArr != null && keyArr.length > 0) { + for (String key : keyArr) { + String value = envMetadata.get(key); + if (StringUtils.isNotBlank(value)) { + envDisposableMetadata.put(key, value); + } + } + } + } + envDisposableMetadata = Collections.unmodifiableMap(envDisposableMetadata); } private void parseConfigMetadata(MetadataLocalProperties metadataLocalProperties) { Map allMetadata = metadataLocalProperties.getContent(); List transitiveKeys = metadataLocalProperties.getTransitive(); + List disposableKeys = metadataLocalProperties.getDisposable(); - Map result = new HashMap<>(); + Map transitiveResult = new HashMap<>(); for (String key : transitiveKeys) { if (allMetadata.containsKey(key)) { - result.put(key, allMetadata.get(key)); + transitiveResult.put(key, allMetadata.get(key)); } } - configTransitiveMetadata = Collections.unmodifiableMap(result); + Map disposableResult = new HashMap<>(); + for (String key : disposableKeys) { + if (allMetadata.containsKey(key)) { + disposableResult.put(key, allMetadata.get(key)); + } + } + + configTransitiveMetadata = Collections.unmodifiableMap(transitiveResult); + configDisposableMetadata = Collections.unmodifiableMap(disposableResult); configMetadata = Collections.unmodifiableMap(allMetadata); } + @SuppressWarnings("DuplicatedCode") private void parseCustomMetadata(InstanceMetadataProvider instanceMetadataProvider) { if (instanceMetadataProvider == null) { customSPIMetadata = Collections.emptyMap(); customSPITransitiveMetadata = Collections.emptyMap(); + customSPIDisposableMetadata = Collections.emptyMap(); return; } @@ -162,6 +194,17 @@ public class StaticMetadataManager { } } customSPITransitiveMetadata = Collections.unmodifiableMap(transitiveMetadata); + + Set disposableKeys = instanceMetadataProvider.getDisposableMetadataKeys(); + Map disposableMetadata = new HashMap<>(); + if (!CollectionUtils.isEmpty(disposableKeys)) { + for (String key : disposableKeys) { + if (customSPIMetadata.containsKey(key)) { + disposableMetadata.put(key, customSPIMetadata.get(key)); + } + } + } + customSPIDisposableMetadata = Collections.unmodifiableMap(disposableMetadata); } private void merge() { @@ -173,15 +216,19 @@ public class StaticMetadataManager { mergedMetadataResult.putAll(customSPIMetadata); // set location info as metadata mergedMetadataResult.putAll(getLocationMetadata()); - this.mergedStaticMetadata = Collections.unmodifiableMap(mergedMetadataResult); Map mergedTransitiveMetadataResult = new HashMap<>(); mergedTransitiveMetadataResult.putAll(configTransitiveMetadata); mergedTransitiveMetadataResult.putAll(envTransitiveMetadata); mergedTransitiveMetadataResult.putAll(customSPITransitiveMetadata); - this.mergedStaticTransitiveMetadata = Collections.unmodifiableMap(mergedTransitiveMetadataResult); + + Map mergedDisposableMetadataResult = new HashMap<>(); + mergedDisposableMetadataResult.putAll(configDisposableMetadata); + mergedDisposableMetadataResult.putAll(envDisposableMetadata); + mergedDisposableMetadataResult.putAll(customSPIDisposableMetadata); + this.mergedStaticDisposableMetadata = Collections.unmodifiableMap(mergedDisposableMetadataResult); } private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperties, @@ -228,6 +275,10 @@ public class StaticMetadataManager { return envTransitiveMetadata; } + public Map getEnvDisposableMetadata() { + return envDisposableMetadata; + } + public Map getAllConfigMetadata() { return configMetadata; } @@ -236,6 +287,10 @@ public class StaticMetadataManager { return configTransitiveMetadata; } + public Map getConfigDisposableMetadata() { + return configDisposableMetadata; + } + public Map getAllCustomMetadata() { return customSPIMetadata; } @@ -244,6 +299,10 @@ public class StaticMetadataManager { return customSPITransitiveMetadata; } + public Map getCustomSPIDisposableMetadata() { + return customSPIDisposableMetadata; + } + public Map getMergedStaticMetadata() { return mergedStaticMetadata; } @@ -252,6 +311,10 @@ public class StaticMetadataManager { return mergedStaticTransitiveMetadata; } + public Map getMergedStaticDisposableMetadata() { + return mergedStaticDisposableMetadata; + } + public String getZone() { return zone; } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java index 0d0039bc..2964e017 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java @@ -43,6 +43,11 @@ public class MetadataLocalProperties { */ private List transitive; + /** + * A disposable metadata key list . + */ + private List disposable; + public Map getContent() { if (CollectionUtils.isEmpty(content)) { content = new HashMap<>(); @@ -64,4 +69,15 @@ public class MetadataLocalProperties { public void setTransitive(List transitive) { this.transitive = transitive; } + + public List getDisposable() { + if (CollectionUtils.isEmpty(disposable)) { + disposable = new ArrayList<>(); + } + return disposable; + } + + public void setDisposable(List disposable) { + this.disposable = disposable; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java index 360018ea..ea7954c3 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java @@ -45,9 +45,14 @@ public class PolarisMetadataEndpoint { result.put("Env", staticMetadataManager.getAllEnvMetadata()); result.put("EnvTransitive", staticMetadataManager.getEnvTransitiveMetadata()); result.put("ConfigTransitive", staticMetadataManager.getConfigTransitiveMetadata()); + result.put("ConfigDisposable", staticMetadataManager.getConfigDisposableMetadata()); result.put("Config", staticMetadataManager.getAllConfigMetadata()); result.put("MergeStatic", staticMetadataManager.getMergedStaticMetadata()); - result.put("CustomSPI", staticMetadataManager.getCustomSPITransitiveMetadata()); + result.put("MergeStaticTransitive", staticMetadataManager.getMergedStaticTransitiveMetadata()); + result.put("MergeStaticDisposable", staticMetadataManager.getMergedStaticDisposableMetadata()); + result.put("CustomSPI", staticMetadataManager.getAllCustomMetadata()); + result.put("CustomSPITransitive", staticMetadataManager.getCustomSPITransitiveMetadata()); + result.put("CustomSPIDisposable", staticMetadataManager.getCustomSPIDisposableMetadata()); result.put("zone", staticMetadataManager.getZone()); result.put("region", staticMetadataManager.getRegion()); result.put("campus", staticMetadataManager.getCampus()); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java index 5434aa14..44cfaf60 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java @@ -43,6 +43,13 @@ public interface InstanceMetadataProvider { return Collections.emptySet(); } + /** + * @return the keys of disposable metadata. + */ + default Set getDisposableMetadataKeys() { + return Collections.emptySet(); + } + /** * The region of current instance. * diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java index 609026dc..521866c3 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java @@ -22,6 +22,7 @@ import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +52,25 @@ public final class JacksonUtils { * @return Json String */ public static String serialize2Json(T object) { + return serialize2Json(object, false); + } + + /** + * Object to Json. + * @param object object to be serialized + * @param pretty pretty print + * @param type of object + * @return Json String + */ + public static String serialize2Json(T object, boolean pretty) { try { - return OM.writeValueAsString(object); + if (pretty) { + ObjectWriter objectWriter = OM.writerWithDefaultPrettyPrinter(); + return objectWriter.writeValueAsString(object); + } + else { + return OM.writeValueAsString(object); + } } catch (JsonProcessingException e) { LOG.error("Object to Json failed. {}", object, e); diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java index 811b3c2d..c6b7cbcd 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java @@ -58,7 +58,7 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - MetadataContextHolder.init(customMetadata); + MetadataContextHolder.init(customMetadata, new HashMap<>()); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md b/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md index 9af9aff6..764a80c3 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md +++ b/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md @@ -4,7 +4,7 @@ 本样例将介绍如何在Spring Cloud项目中使用```spring-cloud-starter-tencent-metadata-transfer```以使用其各项功能。 -本样例包括```metadata-callee-service```、```metadata-caller-service```。 +本样例包括```metadata-frontend```、```metadata-middle```、```metadata-backend```。 ## 使用说明 @@ -41,8 +41,9 @@ spring: ##### IDEA启动 分别启动 -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service```的```MetadataCalleeService``` -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service```的```MetadataCallerService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```的```MetadataFrontendService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle```的```MetadataMiddleService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend```的```MetadataBackendService``` ##### Maven打包启动 @@ -53,7 +54,7 @@ spring: mvn clean package ``` -然后在```metadata-callee-service```、```metadata-caller-service```下找到生成的jar包,运行 +然后在```metadata-frontend```、```metadata-middle```、```metadata-backend```下找到生成的jar包,运行 ``` java -jar ${app.jar} @@ -63,7 +64,7 @@ java -jar ${app.jar} ### 元数据配置 -在```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service```项目的```bootstrap.yml```配置文件中 +- 在```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```项目的```bootstrap.yml```配置文件中 ```yaml spring: @@ -76,10 +77,37 @@ spring: CUSTOM-METADATA-KEY-LOCAL: CUSTOM-VALUE-LOCAL # 示例:可传递元数据 CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE + # 示例:一次性元数据 + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-FRONTEND # 指定哪个元数据的键值将沿着链接传递 transitive: - CUSTOM-METADATA-KEY-TRANSITIVE + # 指定哪个元数据的键值只进行一次性传递(一跳) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE +``` + +- 在```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```项目的```bootstrap.yml```配置文件中 +```yaml +spring: + cloud: + tencent: + metadata: + # 定义元数据的键值对 + content: + # 示例:本地元数据,默认不在链路中传递 + CUSTOM-METADATA-KEY-LOCAL-2: CUSTOM-VALUE-LOCAL-2 + # 示例:可传递元数据 + CUSTOM-METADATA-KEY-TRANSITIVE-2: CUSTOM-VALUE-TRANSITIVE-2 + # 示例:一次性元数据 + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-MIDDLE + # 指定哪个元数据的键值将沿着链接传递 + transitive: + - CUSTOM-METADATA-KEY-TRANSITIVE-2 + # 指定哪个元数据的键值只进行一次性传递(一跳) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE ``` ### 验证 @@ -87,31 +115,85 @@ spring: #### 请求调用 ```shell -curl -L -X GET 'http://127.0.0.1:48080/metadata/service/caller/feign/info' +curl -L -X GET 'http://127.0.0.1:48080/metadata/service/frontend/feign/info' ``` 预期返回值 -``` +```json { - "caller-metadata-contents": { + "frontend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + }, + "frontend-upstream-disposable-metadata": { + }, + "frontend-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" + }, + + "middle-transitive-metadata": { "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", - "CUSTOM-METADATA-KEY-LOCAL": "CUSTOM-VALUE-LOCAL" + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" }, - "callee-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" }, - "caller-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + + "backend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" + }, + "backend-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + "backend-local-disposable-metadata": { } } ``` 返回值解析 -- Key `caller-metadata-contents` 表示 `metadata-caller-service` 项目中默认配置的所有的元数据。 -- Key `caller-transitive-metadata` 表示 `metadata-caller-service` 项目中指定的可以在链路中传递的元数据列表。 -- Key `callee-transitive-metadata` 表示 `metadata-callee-service` 项目被 `metadata-caller-service` 调用时传递过来的上游的元数据列表。 +> `*`(星号),代表示例中的`frontend`、`middle`、`backend`。 + +- Key `*-transitive-metadata` 表示服务中默认配置的所有的可传递(全链路)的元数据。 +- Key `*-upstream-disposable-metadata` 表示服务中从上游请求中获取到的一次性传递的元数据。 +- Key `*-local-disposable-metadata` 表示当前服务配置的往下游传递的一次性的元数据。 + +### 如何通过Api获取传递的元数据 + +- 获取全局传递的元数据 + +```java +MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + +customMetadataMap.forEach((key, value) -> { + // ... +}); + +``` + +- 获取上游传递过来的一次性元数据 + +```java +Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); +upstreamDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + +- 获取本地配置的一次性元数据 + +```java +Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); +localDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + ### Wiki参考 diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/README.md b/spring-cloud-tencent-examples/metadata-transfer-example/README.md index b0d912ce..9fc66366 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/README.md +++ b/spring-cloud-tencent-examples/metadata-transfer-example/README.md @@ -2,9 +2,10 @@ ## Example Introduction -This example shows how to use ```spring-cloud-starter-tencent-metadata-transfer``` in Spring Cloud project for its features. +This example shows how to use ```spring-cloud-starter-tencent-metadata-transfer``` in Spring Cloud project for its +features. -This example contains ```metadata-callee-service```、```metadata-caller-service```. +This example contains ```metadata-frontend```、```metadata-middle```、```metadata-backend```. ## Instruction @@ -40,8 +41,10 @@ Reference to [Polaris Getting Started](https://github.com/PolarisMesh/polaris#ge - IDEA Launching -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service```‘s```MetadataCalleeService``` -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service```'s```MetadataCallerService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```'s ```MetadataFrontendService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle```'s ```MetadataMiddleService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend```'s ```MetadataBackendService``` + - Maven Package Launching @@ -51,7 +54,7 @@ Execute under ```spring-cloud-tencent-examples/metadata-transfer-example``` mvn clean package ``` -Then find the jars under ```metadata-callee-service```、```metadata-caller-service```, and run it: +Then find the jars under ```metadata-frontend```、```metadata-middle```、```metadata-backend```, and run it: ``` java -jar ${app.jar} @@ -62,7 +65,7 @@ Launch application, change ${app.jar} to jar's package name. ### Metadata Configuration -In the ```bootstrap.yml``` configuration file of the ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service``` project +- In the ```bootstrap.yml``` configuration file of the ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend``` project ```yaml spring: @@ -75,9 +78,38 @@ spring: CUSTOM-METADATA-KEY-LOCAL: CUSTOM-VALUE-LOCAL # Example: transitive CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-FRONTEND # Assigned which metadata key-value will be passed along the link transitive: - CUSTOM-METADATA-KEY-TRANSITIVE + # Specify which metadata key value will be passed only once (one-step) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE + +``` + +- In the ```bootstrap.yml``` configuration file of the ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle``` project + +```yaml +spring: + cloud: + tencent: + metadata: + # Defined your metadata keys & values + content: + # Example: intransitive + CUSTOM-METADATA-KEY-LOCAL-2: CUSTOM-VALUE-LOCAL-2 + # Example: transitive + CUSTOM-METADATA-KEY-TRANSITIVE-2: CUSTOM-VALUE-TRANSITIVE-2 + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-MIDDLE + # Assigned which metadata key-value will be passed along the link + transitive: + - CUSTOM-METADATA-KEY-TRANSITIVE-2 + # Specify which metadata key value will be passed only once (one-step) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE ``` @@ -93,24 +125,77 @@ Expected return rate ``` { - "caller-metadata-contents": { + "frontend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + }, + "frontend-upstream-disposable-metadata": { + }, + "frontend-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" + }, + + "middle-transitive-metadata": { "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", - "CUSTOM-METADATA-KEY-LOCAL": "CUSTOM-VALUE-LOCAL" + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" }, - "callee-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" }, - "caller-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + + "backend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" + }, + "backend-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + "backend-local-disposable-metadata": { } } ``` Response value description -- Key `caller-metadata-contents` represents all metadata configured by default in the `metadata-caller-service` project. -- Key `caller-transitive-metadata` represents the list of metadata that can be passed in the link specified in the `metadata-caller-service` item. -- Key `callee-transitive-metadata` represents the list of upstream metadata passed when the `metadata-callee-service` project is called by `metadata-caller-service`. +> `*` (asterisk), representing `frontend`, `middle`, `backend` in the example. + +- Key `*-transitive-metadata` represents all the passable (fully linked) metadata configured by default in the service. +- Key `*-upstream-disposable-metadata` indicates the one-time transmissible metadata obtained from upstream requests in the service. +- Key `*-local-disposable-metadata` indicates the one-time metadata passed downstream as configured by the current service. + +### How to get the passed metadata via Api + +- Get the metadata passed globally + +```java +MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + +customMetadataMap.forEach((key, value) -> { + // ... +}); +``` + +- Get disposable(one-time) metadata passed from upstream + +```java +Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); +upstreamDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + +- Get disposable(one-time) metadata for local configuration + +```java +Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); +localDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + ### Wiki Reference diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/pom.xml similarity index 93% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/pom.xml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/pom.xml index 1c130680..106c2ed7 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/pom.xml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/pom.xml @@ -10,8 +10,8 @@ 4.0.0 - metadata-caller-service - Spring Cloud Tencent Metadata Transfer Caller Service + metadata-backend + Spring Cloud Tencent Metadata Transfer Backend Service diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java similarity index 57% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeController.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java index 4966e9bd..7da621e8 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeController.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java @@ -15,8 +15,9 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.callee; +package com.tencent.cloud.metadata.service.backend; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.metadata.MetadataContext; @@ -35,10 +36,10 @@ import org.springframework.web.bind.annotation.RestController; * @author Palmer Xu */ @RestController -@RequestMapping("/metadata/service/callee") -public class MetadataCalleeController { +@RequestMapping("/metadata/service/backend") +public class MetadataBackendController { - private static final Logger LOG = LoggerFactory.getLogger(MetadataCalleeController.class); + private static final Logger LOG = LoggerFactory.getLogger(MetadataBackendController.class); @Value("${server.port:0}") private int port; @@ -48,18 +49,36 @@ public class MetadataCalleeController { * @return information of callee */ @GetMapping("/info") - public Map info() { - LOG.info("Metadata Service Callee [{}] is called.", port); + public Map> info() { + LOG.info("Metadata Backend Service [{}] is called.", port); + Map> ret = new HashMap<>(); // Get Custom Metadata From Context MetadataContext context = MetadataContextHolder.get(); Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); customMetadataMap.forEach((key, value) -> { - LOG.info("Custom Metadata (Key-Value): {} : {}", key, value); + LOG.info("Metadata Backend Custom Metadata (Key-Value): {} : {}", key, value); }); - return customMetadataMap; - } + ret.put("backend-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("backend-upstream-disposable-metadata", upstreamDisposableMetadatas); + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("backend-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendService.java similarity index 86% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeService.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendService.java index 06771a5e..964cb827 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeService.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendService.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.callee; +package com.tencent.cloud.metadata.service.backend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -26,10 +26,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; * @author Palmer Xu */ @SpringBootApplication -public class MetadataCalleeService { +public class MetadataBackendService { public static void main(String[] args) { - SpringApplication.run(MetadataCalleeService.class, args); + SpringApplication.run(MetadataBackendService.class, args); } - } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/resources/bootstrap.yml similarity index 58% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/resources/bootstrap.yml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/resources/bootstrap.yml index 85c842c7..4188f3cc 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/resources/bootstrap.yml @@ -1,8 +1,8 @@ server: - port: 48084 + port: 48088 spring: application: - name: MetadataCalleeService + name: MetadataBackendService cloud: polaris: address: grpc://183.47.111.80:8091 @@ -11,3 +11,10 @@ spring: discovery: enabled: true register: true + +management: + endpoints: + web: + exposure: + include: + - polaris-metadata \ No newline at end of file diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerController.java deleted file mode 100644 index cf9ec84e..00000000 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerController.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.metadata.service.caller; - -import java.util.Map; - -import com.google.common.collect.Maps; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -/** - * Metadata caller controller. - * - * @author Palmer Xu - */ -@RestController -@RequestMapping("/metadata/service/caller") -public class MetadataCallerController { - - private final RestTemplate restTemplate; - - private final MetadataCalleeService metadataCalleeService; - - private final MetadataLocalProperties metadataLocalProperties; - - public MetadataCallerController(RestTemplate restTemplate, - MetadataCalleeService metadataCalleeService, - MetadataLocalProperties metadataLocalProperties) { - this.restTemplate = restTemplate; - this.metadataCalleeService = metadataCalleeService; - this.metadataLocalProperties = metadataLocalProperties; - } - - /** - * Get metadata info from remote service. - * @return metadata map - */ - @GetMapping("/feign/info") - public Map> feign() { - Map> ret = Maps.newHashMap(); - - // Call remote service with feign client - Map calleeMetadata = metadataCalleeService.info(); - ret.put("callee-transitive-metadata", calleeMetadata); - - // Get Custom Metadata From Context - MetadataContext context = MetadataContextHolder.get(); - Map callerTransitiveMetadata = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - ret.put("caller-transitive-metadata", callerTransitiveMetadata); - ret.put("caller-metadata-contents", metadataLocalProperties.getContent()); - - return ret; - } - - /** - * Get metadata information of callee. - * @return information of callee - */ - @SuppressWarnings("unchecked") - @GetMapping("/rest/info") - public Map> rest() { - Map> ret = Maps.newHashMap(); - - // Call remote service with RestTemplate - Map calleeMetadata = restTemplate.getForObject( - "http://MetadataCalleeService/metadata/service/callee/info", - Map.class); - ret.put("callee-transitive-metadata", calleeMetadata); - - // Get Custom Metadata From Context - MetadataContext context = MetadataContextHolder.get(); - Map callerTransitiveMetadata = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - ret.put("caller-transitive-metadata", callerTransitiveMetadata); - ret.put("caller-metadata-contents", metadataLocalProperties.getContent()); - - return ret; - } - - /** - * health check. - * @return health check info - */ - @GetMapping("/healthCheck") - public String healthCheck() { - return "pk ok"; - } - -} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/pom.xml new file mode 100644 index 00000000..4b6adb14 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/pom.xml @@ -0,0 +1,51 @@ + + + + metadata-transfer-example + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + metadata-frontend + Spring Cloud Tencent Metadata Transfer Frontent Service + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java new file mode 100644 index 00000000..3d107f55 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java @@ -0,0 +1,155 @@ +/* + * 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.service.frontend; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * Metadata caller controller. + * + * @author Palmer Xu + */ +@RestController +@RequestMapping("/metadata/service/frontend") +public class MetadataFrontendController { + + private static final Logger LOG = LoggerFactory.getLogger(MetadataFrontendController.class); + + private final RestTemplate restTemplate; + + private final MetadataMiddleService metadataMiddleService; + + public MetadataFrontendController(RestTemplate restTemplate, + MetadataMiddleService metadataMiddleService) { + this.restTemplate = restTemplate; + this.metadataMiddleService = metadataMiddleService; + } + + /** + * Get metadata info from remote service. + * + * @return metadata map + */ + @GetMapping("/feign/info") + public Map> feign() { + Map> ret = new HashMap<>(); + + // Call remote service with feign client + Map> middleResult = metadataMiddleService.info(); + + if (middleResult != null) { + ret.putAll(middleResult); + } + + // Get Custom Metadata From Context + MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + customMetadataMap.forEach((key, value) -> { + LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-upstream-disposable-metadata", upstreamDisposableMetadatas); + + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } + + /** + * Get metadata information of callee. + * + * @return information of callee + */ + @SuppressWarnings("unchecked") + @GetMapping("/rest/info") + public Map> rest() { + Map> ret = new HashMap<>(); + + // Call remote service with RestTemplate + Map> middleResult = restTemplate.getForObject( + "http://MetadataMiddleService/metadata/service/middle/info", Map.class); + + if (middleResult != null) { + ret.putAll(middleResult); + } + + // Get Custom Metadata From Context + MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + customMetadataMap.forEach((key, value) -> { + LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-upstream-disposable-metadata", upstreamDisposableMetadatas); + + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } + + /** + * health check. + * + * @return health check info + */ + @GetMapping("/healthCheck") + public String healthCheck() { + return "pk ok"; + } +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendService.java similarity index 84% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerService.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendService.java index a586c7e7..cdea235d 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerService.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendService.java @@ -15,11 +15,10 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.caller; +package com.tencent.cloud.metadata.service.frontend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; @@ -31,12 +30,11 @@ import org.springframework.web.client.RestTemplate; * @author Palmer Xu */ @SpringBootApplication -@EnableDiscoveryClient @EnableFeignClients -public class MetadataCallerService { +public class MetadataFrontendService { public static void main(String[] args) { - SpringApplication.run(MetadataCallerService.class, args); + SpringApplication.run(MetadataFrontendService.class, args); } @Bean @@ -44,5 +42,4 @@ public class MetadataCallerService { public RestTemplate restTemplate() { return new RestTemplate(); } - } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleService.java similarity index 78% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeService.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleService.java index 65bea670..ea0bde43 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeService.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleService.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.caller; +package com.tencent.cloud.metadata.service.frontend; import java.util.Map; @@ -27,15 +27,14 @@ import org.springframework.web.bind.annotation.GetMapping; * * @author Palmer Xu */ -@FeignClient(value = "MetadataCalleeService", - fallback = MetadataCalleeServiceFallback.class) -public interface MetadataCalleeService { +@FeignClient(value = "MetadataMiddleService", + fallback = MetadataMiddleServiceFallback.class) +public interface MetadataMiddleService { /** * Get information of callee. * @return information of callee */ - @GetMapping("/metadata/service/callee/info") - Map info(); - + @GetMapping("/metadata/service/middle/info") + Map> info(); } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeServiceFallback.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleServiceFallback.java similarity index 84% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeServiceFallback.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleServiceFallback.java index ba508831..727f65c6 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeServiceFallback.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleServiceFallback.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.caller; +package com.tencent.cloud.metadata.service.frontend; import java.util.Map; @@ -29,11 +29,10 @@ import org.springframework.stereotype.Component; * @author Palmer Xu */ @Component -public class MetadataCalleeServiceFallback implements MetadataCalleeService { +public class MetadataMiddleServiceFallback implements MetadataMiddleService { @Override - public Map info() { + public Map> info() { return Maps.newHashMap(); } - } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/resources/bootstrap.yml similarity index 71% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/resources/bootstrap.yml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/resources/bootstrap.yml index a390f51a..71942413 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/resources/bootstrap.yml @@ -2,7 +2,7 @@ server: port: 48080 spring: application: - name: MetadataCallerService + name: MetadataFrontendService cloud: polaris: address: grpc://183.47.111.80:8091 @@ -12,18 +12,22 @@ spring: enabled: true register: true heartbeat-enabled: true - health-check-url: /metadata/service/caller/healthCheck + health-check-url: /metadata/service/frontend/healthCheck tencent: metadata: # Defined your metadata keys & values content: # Example: intransitive CUSTOM-METADATA-KEY-LOCAL: CUSTOM-VALUE-LOCAL + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE # Example: transitive - CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE + CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE-FRONTEND # Assigned which metadata key-value will be passed along the link transitive: - CUSTOM-METADATA-KEY-TRANSITIVE + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE management: endpoints: web: diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/pom.xml similarity index 93% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/pom.xml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/pom.xml index 237c9877..41c4cd13 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/pom.xml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/pom.xml @@ -10,8 +10,8 @@ 4.0.0 - metadata-callee-service - Spring Cloud Tencent Metadata Transfer Callee Service + metadata-middle + Spring Cloud Tencent Metadata Transfer Middle Service diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendService.java new file mode 100644 index 00000000..b8e9855c --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendService.java @@ -0,0 +1,40 @@ +/* + * 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.service.middle; + +import java.util.Map; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * Metadata callee feign client. + * + * @author Palmer Xu + */ +@FeignClient(value = "MetadataBackendService", + fallback = MetadataBackendServiceFallback.class) +public interface MetadataBackendService { + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/metadata/service/backend/info") + Map> info(); +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendServiceFallback.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendServiceFallback.java new file mode 100644 index 00000000..cbe5edd7 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendServiceFallback.java @@ -0,0 +1,38 @@ +/* + * 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.service.middle; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import org.springframework.stereotype.Component; + +/** + * Metadata callee feign client fallback. + * + * @author Palmer Xu + */ +@Component +public class MetadataBackendServiceFallback implements MetadataBackendService { + + @Override + public Map> info() { + return Maps.newHashMap(); + } +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java new file mode 100644 index 00000000..7ea673a5 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java @@ -0,0 +1,122 @@ +/* + * 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.service.middle; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import static com.tencent.cloud.common.util.JacksonUtils.serialize2Json; + +/** + * Metadata callee controller. + * + * @author Palmer Xu + */ +@RestController +@RequestMapping("/metadata/service/middle") +public class MetadataMiddleController { + + private static final Logger LOG = LoggerFactory.getLogger(MetadataMiddleController.class); + + @Value("${server.port:0}") + private int port; + + private final MetadataBackendService metadataBackendService; + + private final RestTemplate restTemplate; + + public MetadataMiddleController(MetadataBackendService metadataBackendService, RestTemplate restTemplate) { + this.metadataBackendService = metadataBackendService; + this.restTemplate = restTemplate; + } + + /** + * Get information of callee. + * + * @return information of callee + */ + @GetMapping("/info") + public Map> info() { + + // Build result + Map> ret = new HashMap<>(); + + LOG.info("Metadata Middle Service [{}] is called.", port); + + // Call remote service with RestTemplate + Map> backendResult = restTemplate.getForObject( + "http://MetadataBackendService/metadata/service/backend/info", Map.class); + + if (backendResult != null) { + LOG.info("RestTemplate Backend Metadata"); + LOG.info("\r{}", serialize2Json(backendResult, true)); + backendResult.clear(); + } + + // Call remote service with Feign + backendResult = metadataBackendService.info(); + if (backendResult != null) { + LOG.info("Feign Backend Metadata"); + LOG.info("\r{}", serialize2Json(backendResult, true)); + } + + if (backendResult != null) { + ret.putAll(backendResult); + } + + // Get Custom Metadata From Context + MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + customMetadataMap.forEach((key, value) -> { + LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("middle-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("middle-upstream-disposable-metadata", upstreamDisposableMetadatas); + + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("middle-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } + +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleService.java new file mode 100644 index 00000000..f7c8d3d0 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleService.java @@ -0,0 +1,46 @@ +/* + * 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.service.middle; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +/** + * Metadata callee application. + * + * @author Palmer Xu + */ +@SpringBootApplication +@EnableFeignClients +public class MetadataMiddleService { + + public static void main(String[] args) { + SpringApplication.run(MetadataMiddleService.class, args); + } + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..db78677b --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/resources/bootstrap.yml @@ -0,0 +1,35 @@ +server: + port: 48084 +spring: + application: + name: MetadataMiddleService + cloud: + polaris: + address: grpc://183.47.111.80:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + tencent: + metadata: + # Defined your metadata keys & values + content: + # Example: intransitive + CUSTOM-METADATA-KEY-LOCAL-2: CUSTOM-VALUE-LOCAL-2 + # Example: transitive + CUSTOM-METADATA-KEY-TRANSITIVE-2: CUSTOM-VALUE-TRANSITIVE-2 + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-MIDDLE + # Assigned which metadata key-value will be passed along the link + transitive: + - CUSTOM-METADATA-KEY-TRANSITIVE-2 + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE + +management: + endpoints: + web: + exposure: + include: + - polaris-metadata \ No newline at end of file diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml index bd2b961e..2cbc55a3 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml @@ -15,8 +15,9 @@ Spring Cloud Starter Tencent Metadata Transfer Example - metadata-callee-service - metadata-caller-service + metadata-frontend + metadata-middle + metadata-backend