diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java index 6e782ca92..face83f1c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfiguration.java @@ -17,20 +17,32 @@ package com.tencent.cloud.metadata.config; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.metadata.core.DecodeTransferMetadataReactiveFilter; import com.tencent.cloud.metadata.core.DecodeTransferMetadataServletFilter; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; +import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; +import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer; +import org.springframework.cloud.client.loadbalancer.RetryLoadBalancerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; import static jakarta.servlet.DispatcherType.ASYNC; import static jakarta.servlet.DispatcherType.ERROR; @@ -118,9 +130,59 @@ public class MetadataTransferAutoConfiguration { @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferRestTemplateConfig { + @Autowired(required = false) + private List restTemplates = Collections.emptyList(); + + @Bean + public EncodeTransferMedataRestTemplateInterceptor encodeTransferMedataRestTemplateInterceptor() { + return new EncodeTransferMedataRestTemplateInterceptor(); + } + + @Bean + public SmartInitializingSingleton addEncodeTransferMetadataInterceptorForRestTemplate(EncodeTransferMedataRestTemplateInterceptor interceptor) { + return () -> restTemplates.forEach(restTemplate -> { + List list = new ArrayList<>(restTemplate.getInterceptors()); + list.add(interceptor); + restTemplate.setInterceptors(list); + }); + } + @Bean - public EncodeTransferMedataRestTemplateEnhancedPlugin encodeTransferMedataRestTemplateEnhancedPlugin() { - return new EncodeTransferMedataRestTemplateEnhancedPlugin(); + public RestTemplateCustomizer polarisRestTemplateCustomizer( + @Autowired(required = false) RetryLoadBalancerInterceptor retryLoadBalancerInterceptor, + @Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) { + return restTemplate -> { + List list = new ArrayList<>(restTemplate.getInterceptors()); + // LoadBalancerInterceptor must invoke before EncodeTransferMedataRestTemplateInterceptor + int addIndex = list.size(); + if (CollectionUtils.containsInstance(list, retryLoadBalancerInterceptor) || CollectionUtils.containsInstance(list, loadBalancerInterceptor)) { + ClientHttpRequestInterceptor enhancedRestTemplateInterceptor = null; + for (int i = 0; i < list.size(); i++) { + if (list.get(i) instanceof EncodeTransferMedataRestTemplateInterceptor) { + enhancedRestTemplateInterceptor = list.get(i); + addIndex = i; + } + } + if (enhancedRestTemplateInterceptor != null) { + list.remove(addIndex); + list.add(enhancedRestTemplateInterceptor); + } + } + else { + if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i) instanceof EncodeTransferMedataRestTemplateInterceptor) { + addIndex = i; + } + } + list.add(addIndex, + retryLoadBalancerInterceptor != null + ? retryLoadBalancerInterceptor + : loadBalancerInterceptor); + } + } + restTemplate.setInterceptors(list); + }; } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java similarity index 77% rename from spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java rename to spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java index b2cee99ce..541398b11 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateEnhancedPlugin.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java @@ -1,7 +1,7 @@ /* - * Tencent is pleased to support the open source community by making spring-cloud-tencent available. + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. * - * Copyright (C) 2021 Tencent. All rights reserved. + * 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. @@ -13,27 +13,32 @@ * 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.io.IOException; import java.util.Map; +import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.tsf.TsfContextUtils; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.TsfTagUtils; import com.tencent.cloud.common.util.UrlUtils; -import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; -import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; -import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; -import com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant; import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MetadataType; import shade.polaris.com.google.common.collect.ImmutableMap; +import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; +import org.springframework.core.Ordered; 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.MetadataConstant.HeaderName.APPLICATION_METADATA; @@ -41,31 +46,33 @@ import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUST import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** - * Pre EnhancedPlugin for rest template to encode transfer metadata. + * Interceptor used for adding the metadata in http headers from context when web client + * is RestTemplate. + * + * It needs to execute after {@link LoadBalancerInterceptor}, because LaneRouter may add calleeTransitiveHeaders. * - * @author Shedfree Wu + * @author Haotian Zhang */ -public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedPlugin { +public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { + @Override - public EnhancedPluginType getType() { - return EnhancedPluginType.Client.PRE; + public int getOrder() { + return OrderConstant.Client.RestTemplate.ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER; } @Override - public void run(EnhancedPluginContext context) throws Throwable { - if (!(context.getOriginRequest() instanceof HttpRequest)) { - return; - } - HttpRequest httpRequest = (HttpRequest) context.getOriginRequest(); - + 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.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); Map applicationMetadata = metadataContext.getApplicationMetadata(); Map transHeaders = metadataContext.getTransHeadersKV(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); + if (TsfContextUtils.isOnlyTsfConsulEnabled()) { Map tsfMetadataMap = TsfTagUtils.getTsfMetadataMap(calleeTransitiveHeaders, disposableMetadata, customMetadata, applicationMetadata); this.buildHeaderMap(httpRequest, tsfMetadataMap); @@ -86,7 +93,7 @@ public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedP // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(httpRequest, transHeaders); - + return clientHttpRequestExecution.execute(httpRequest, bytes); } private void buildTransmittedHeader(HttpRequest request, Map transHeaders) { @@ -115,9 +122,4 @@ public class EncodeTransferMedataRestTemplateEnhancedPlugin implements EnhancedP buildHeaderMap(request, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); } } - - @Override - public int getOrder() { - return PluginOrderConstant.ClientPluginOrder.CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER; - } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java index a106265fc..7813e5add 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/config/MetadataTransferAutoConfigurationTest.java @@ -18,7 +18,6 @@ package com.tencent.cloud.metadata.config; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignEnhancedPlugin; -import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.Test; @@ -52,7 +51,6 @@ public class MetadataTransferAutoConfigurationTest { .run(context -> { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); }); @@ -68,7 +66,6 @@ public class MetadataTransferAutoConfigurationTest { assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); assertThat(context).hasSingleBean(EncodeTransferMedataFeignEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class); - assertThat(context).hasSingleBean(EncodeTransferMedataRestTemplateEnhancedPlugin.class); assertThat(context).hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class); assertThat(context).hasSingleBean(EncodeTransferMedataWebClientEnhancedPlugin.class); }); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java index 7ae1c170c..746a06d5e 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -43,7 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; /** - * Test for {@link EncodeTransferMedataRestTemplateEnhancedPlugin}. + * Test for {@link EncodeTransferMedataRestTemplateInterceptor}. * * @author Haotian Zhang */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java index 8eb0edf8f..9c7f9fda4 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/OrderConstant.java @@ -51,7 +51,7 @@ public class OrderConstant { /** * Order of encode transfer metadata interceptor. */ - public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; + public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE; /** * Order of encode router label interceptor.