diff --git a/CHANGELOG.md b/CHANGELOG.md index b3e204968b..6f8a4057d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,4 +15,5 @@ - [fix:fix the ratelimit bug for hoxton](https://github.com/Tencent/spring-cloud-tencent/pull/1301) - [feat:upgrade jacoco version.](https://github.com/Tencent/spring-cloud-tencent/pull/1306) - [fix:fix no registry when lossless is disabled.](https://github.com/Tencent/spring-cloud-tencent/pull/1313) -- [fix: memory not released while using wildcard api call with circuitbreaker enabled](https://github.com/Tencent/spring-cloud-tencent/pull/1335) \ No newline at end of file +- [fix: memory not released while using wildcard api call with circuitbreaker enabled](https://github.com/Tencent/spring-cloud-tencent/pull/1335) +- [feat: support 2.0.0](https://github.com/Tencent/spring-cloud-tencent/pull/1458) \ No newline at end of file diff --git a/pom.xml b/pom.xml index f7ee98e328..070e126a85 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ - 1.14.0-Hoxton.SR12-RC3 + 2.0.0.0-Hoxton.SR12-SNAPSHOT 5.2.25.RELEASE diff --git a/spring-cloud-starter-tencent-all/pom.xml b/spring-cloud-starter-tencent-all/pom.xml index 79bba53e0c..767a25866e 100644 --- a/spring-cloud-starter-tencent-all/pom.xml +++ b/spring-cloud-starter-tencent-all/pom.xml @@ -49,6 +49,11 @@ com.tencent.cloud spring-cloud-starter-tencent-polaris-contract + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + 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 ea8a33189c..5ea82792a5 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 @@ -26,7 +26,6 @@ import com.tencent.cloud.metadata.core.EncodeTransferMedataScgEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMedataWebClientEnhancedPlugin; import com.tencent.cloud.metadata.core.EncodeTransferMetadataZuulEnhancedPlugin; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -67,8 +66,8 @@ public FilterRegistrationBean metadataServl } @Bean - public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextProperties polarisContextProperties) { - return new DecodeTransferMetadataServletFilter(polarisContextProperties); + public DecodeTransferMetadataServletFilter metadataServletFilter() { + return new DecodeTransferMetadataServletFilter(); } } @@ -80,8 +79,8 @@ public DecodeTransferMetadataServletFilter metadataServletFilter(PolarisContextP protected static class MetadataReactiveFilterConfig { @Bean - public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisContextProperties polarisContextProperties) { - return new DecodeTransferMetadataReactiveFilter(polarisContextProperties); + public DecodeTransferMetadataReactiveFilter metadataReactiveFilter() { + return new DecodeTransferMetadataReactiveFilter(); } } @@ -91,11 +90,10 @@ public DecodeTransferMetadataReactiveFilter metadataReactiveFilter(PolarisContex */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet") - @ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) protected static class MetadataTransferZuulFilterConfig { @Bean - public EncodeTransferMetadataZuulEnhancedPlugin encodeTransferMedataZuulEnhancedPlugin() { + public EncodeTransferMetadataZuulEnhancedPlugin encodeTransferMetadataZuulEnhancedPlugin() { return new EncodeTransferMetadataZuulEnhancedPlugin(); } 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 44a8e881be..f462f67fef 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 @@ -27,7 +27,7 @@ import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; @@ -39,8 +39,10 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL_IP; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -50,14 +52,8 @@ */ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered { - private PolarisContextProperties polarisContextProperties; - private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataReactiveFilter.class); - public DecodeTransferMetadataReactiveFilter(PolarisContextProperties polarisContextProperties) { - this.polarisContextProperties = polarisContextProperties; - } - @Override public int getOrder() { return OrderConstant.Server.Reactive.DECODE_TRANSFER_METADATA_FILTER_ORDER; @@ -67,16 +63,34 @@ public int getOrder() { public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); - Map internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA); - Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); + // transitive metadata + // from specific header + Map internalTransitiveMetadata = getInternalMetadata(serverHttpRequest, CUSTOM_METADATA); + // from header with specific prefix + Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); + + // disposable metadata + // from specific header + Map internalDisposableMetadata = getInternalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - ReactiveMetadataProvider metadataProvider = new ReactiveMetadataProvider(serverHttpRequest, polarisContextProperties.getLocalIpAddress()); - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); + + // application metadata + Map internalApplicationMetadata = getInternalMetadata(serverHttpRequest, APPLICATION_METADATA); + Map mergedApplicationMetadata = new HashMap<>(internalApplicationMetadata); + + String callerIp = ""; + if (StringUtils.isNotBlank(mergedApplicationMetadata.get(LOCAL_IP))) { + callerIp = mergedApplicationMetadata.get(LOCAL_IP); + } + // message metadata + ReactiveMetadataProvider callerMessageMetadataProvider = new ReactiveMetadataProvider(serverHttpRequest, callerIp); + + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider); + // Save to ServerWebExchange. serverWebExchange.getAttributes().put( MetadataConstant.HeaderName.METADATA_CONTEXT, @@ -89,7 +103,7 @@ public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain web .doFinally((type) -> MetadataContextHolder.remove()); } - private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { + private Map getInternalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); String customMetadataStr = UrlUtils.decode(httpHeaders.getFirst(headerName)); LOG.debug("Get upstream metadata string: {}", customMetadataStr); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index 44865dcd3e..bea520eb12 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 @@ -32,7 +32,7 @@ import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.UrlUtils; import com.tencent.cloud.metadata.provider.ServletMetadataProvider; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,8 +40,10 @@ import org.springframework.lang.NonNull; import org.springframework.web.filter.OncePerRequestFilter; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static com.tencent.polaris.metadata.core.constant.MetadataConstants.LOCAL_IP; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -54,26 +56,36 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); - private PolarisContextProperties polarisContextProperties; - - public DecodeTransferMetadataServletFilter(PolarisContextProperties polarisContextProperties) { - this.polarisContextProperties = polarisContextProperties; - } - @Override protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + // transitive metadata + // from specific header Map internalTransitiveMetadata = getInternalMetadata(httpServletRequest, CUSTOM_METADATA); + // from header with specific prefix Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest); - Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); + + // disposable metadata + // from specific header Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - ServletMetadataProvider metadataProvider = new ServletMetadataProvider(httpServletRequest, polarisContextProperties.getLocalIpAddress()); - MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, metadataProvider); + + // application metadata + Map internalApplicationMetadata = getInternalMetadata(httpServletRequest, APPLICATION_METADATA); + Map mergedApplicationMetadata = new HashMap<>(internalApplicationMetadata); + + String callerIp = ""; + if (StringUtils.isNotBlank(mergedApplicationMetadata.get(LOCAL_IP))) { + callerIp = mergedApplicationMetadata.get(LOCAL_IP); + } + // message metadata + ServletMetadataProvider callerMessageMetadataProvider = new ServletMetadataProvider(httpServletRequest, callerIp); + + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata, mergedApplicationMetadata, callerMessageMetadataProvider); TransHeadersTransfer.transfer(httpServletRequest); try { diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java index ff722edc66..3e07c3bf0d 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignEnhancedPlugin.java @@ -39,6 +39,7 @@ import org.springframework.util.CollectionUtils; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -64,6 +65,7 @@ public void run(EnhancedPluginContext context) throws Throwable { 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); @@ -77,6 +79,9 @@ public void run(EnhancedPluginContext context) throws Throwable { // process custom metadata this.buildMetadataHeader(request, customMetadata, CUSTOM_METADATA); + // add application metadata + this.buildMetadataHeader(request, applicationMetadata, APPLICATION_METADATA); + // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(request, transHeaders); } 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/EncodeTransferMedataRestTemplateEnhancedPlugin.java index 50e42885b4..f3637494e2 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/EncodeTransferMedataRestTemplateEnhancedPlugin.java @@ -35,6 +35,7 @@ import org.springframework.http.HttpRequest; import org.springframework.util.CollectionUtils; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -60,6 +61,7 @@ public void run(EnhancedPluginContext context) throws Throwable { 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(); @@ -72,6 +74,9 @@ public void run(EnhancedPluginContext context) throws Throwable { // build custom metadata request header this.buildMetadataHeader(httpRequest, customMetadata, CUSTOM_METADATA); + // build application metadata request header + this.buildMetadataHeader(httpRequest, applicationMetadata, APPLICATION_METADATA); + // set headers that need to be transmitted from the upstream this.buildTransmittedHeader(httpRequest, transHeaders); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java index 8c996bbf10..7974bd71df 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgEnhancedPlugin.java @@ -37,6 +37,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -69,6 +70,7 @@ public void run(EnhancedPluginContext context) throws Throwable { Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); @@ -77,6 +79,7 @@ public void run(EnhancedPluginContext context) throws Throwable { this.buildMetadataHeader(builder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + this.buildMetadataHeader(builder, applicationMetadata, APPLICATION_METADATA); TransHeadersTransfer.transfer(exchange.getRequest()); context.setOriginRequest(exchange.mutate().request(builder.build()).build()); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java index 2967a2b4c6..441b334468 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataWebClientEnhancedPlugin.java @@ -35,6 +35,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.reactive.function.client.ClientRequest; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; @@ -59,6 +60,7 @@ public void run(EnhancedPluginContext context) throws Throwable { 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(); @@ -70,6 +72,7 @@ public void run(EnhancedPluginContext context) throws Throwable { this.buildMetadataHeader(requestBuilder, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestBuilder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + this.buildMetadataHeader(requestBuilder, applicationMetadata, APPLICATION_METADATA); this.buildTransmittedHeader(requestBuilder, transHeaders); context.setOriginRequest(requestBuilder.build()); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java index c1957bda78..585a40eb3b 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulEnhancedPlugin.java @@ -18,9 +18,10 @@ package com.tencent.cloud.metadata.core; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.Map; -import com.google.common.collect.ImmutableMap; import com.netflix.zuul.context.RequestContext; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; @@ -35,15 +36,14 @@ import org.springframework.util.CollectionUtils; +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.APPLICATION_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; -/** - * Pre EnhancedPlugin for zuul to encode transfer metadata. - * - * @author Shedfree Wu - */ + public class EncodeTransferMetadataZuulEnhancedPlugin implements EnhancedPlugin { + @Override public EnhancedPluginType getType() { return EnhancedPluginType.Client.PRE; @@ -54,6 +54,8 @@ public void run(EnhancedPluginContext context) throws Throwable { if (!(context.getOriginRequest() instanceof RequestContext)) { return; } + + // get request context RequestContext requestContext = (RequestContext) context.getOriginRequest(); // get metadata of current thread @@ -61,21 +63,26 @@ public void run(EnhancedPluginContext context) throws Throwable { Map customMetadata = metadataContext.getCustomMetadata(); Map disposableMetadata = metadataContext.getDisposableMetadata(); + Map applicationMetadata = metadataContext.getApplicationMetadata(); + MessageMetadataContainer calleeMessageMetadataContainer = metadataContext.getMetadataContainer(MetadataType.MESSAGE, false); Map calleeTransitiveHeaders = calleeMessageMetadataContainer.getTransitiveHeaders(); // currently only support transitive header from calleeMessageMetadataContainer this.buildHeaderMap(requestContext, calleeTransitiveHeaders); + // Rebuild Metadata Header this.buildMetadataHeader(requestContext, customMetadata, CUSTOM_METADATA); this.buildMetadataHeader(requestContext, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + this.buildMetadataHeader(requestContext, applicationMetadata, APPLICATION_METADATA); TransHeadersTransfer.transfer(requestContext.getRequest()); + } - private void buildHeaderMap(RequestContext context, Map headerMap) { + private void buildHeaderMap(RequestContext requestContext, Map headerMap) { if (!CollectionUtils.isEmpty(headerMap)) { - headerMap.forEach((key, value) -> context.addZuulRequestHeader(key, UrlUtils.encode(value))); + headerMap.forEach((key, value) -> requestContext.addZuulRequestHeader(key, UrlUtils.encode(value))); } } @@ -88,7 +95,13 @@ private void buildHeaderMap(RequestContext context, Map headerMa */ private void buildMetadataHeader(RequestContext context, Map metadata, String headerName) { if (!CollectionUtils.isEmpty(metadata)) { - buildHeaderMap(context, ImmutableMap.of(headerName, JacksonUtils.serialize2Json(metadata))); + String encodedMetadata = JacksonUtils.serialize2Json(metadata); + try { + context.addZuulRequestHeader(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); + } + catch (UnsupportedEncodingException e) { + context.addZuulRequestHeader(headerName, encodedMetadata); + } } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.java new file mode 100644 index 0000000000..1d62416a5f --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/FeignRequestTemplateMetadataProvider.java @@ -0,0 +1,75 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.metadata.provider; + +import java.net.URI; +import java.util.Collection; +import java.util.Map; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; +import feign.RequestTemplate; + +/** + * MetadataProvider used for Feign RequestTemplate. + * + * @author Haotian Zhang + */ +public class FeignRequestTemplateMetadataProvider implements MetadataProvider { + + private final RequestTemplate requestTemplate; + + public FeignRequestTemplateMetadataProvider(RequestTemplate requestTemplate) { + this.requestTemplate = requestTemplate; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return requestTemplate.method(); + case MessageMetadataContainer.LABEL_KEY_PATH: + URI uri = URI.create(requestTemplate.request().url()); + return UrlUtils.decode(uri.getPath()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + Map> headers = requestTemplate.headers(); + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(headers, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(ExpressionLabelUtils.getCookieFirstValue(headers, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(requestTemplate.queries(), mapKey)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java index 70aee3cf8c..d39d74ed83 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ReactiveMetadataProvider.java @@ -45,7 +45,7 @@ public ReactiveMetadataProvider(ServerHttpRequest serverHttpRequest, String call public String getRawMetadataStringValue(String key) { switch (key) { case MessageMetadataContainer.LABEL_KEY_METHOD: - return serverHttpRequest.getMethodValue(); + return serverHttpRequest.getMethod().name(); case MessageMetadataContainer.LABEL_KEY_PATH: return UrlUtils.decode(serverHttpRequest.getPath().toString()); case MessageMetadataContainer.LABEL_KEY_CALLER_IP: diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java new file mode 100644 index 0000000000..31eea10f83 --- /dev/null +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/RestTemplateMetadataProvider.java @@ -0,0 +1,70 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.metadata.provider; + +import com.tencent.cloud.common.util.UrlUtils; +import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataProvider; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; + +import org.springframework.http.HttpRequest; + +/** + * MetadataProvider used for RestTemplate HttpRequest. + * + * @author Haotian Zhang + */ +public class RestTemplateMetadataProvider implements MetadataProvider { + + private final HttpRequest request; + + public RestTemplateMetadataProvider(HttpRequest request) { + this.request = request; + } + + @Override + public String getRawMetadataStringValue(String key) { + switch (key) { + case MessageMetadataContainer.LABEL_KEY_METHOD: + return request.getMethod().toString(); + case MessageMetadataContainer.LABEL_KEY_PATH: + return UrlUtils.decode(request.getURI().getPath()); + case MessageMetadataContainer.LABEL_KEY_CALLER_IP: + return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP); + default: + return null; + } + } + + @Override + public String getRawMetadataMapValue(String key, String mapKey) { + switch (key) { + case MessageMetadataContainer.LABEL_MAP_KEY_HEADER: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(request, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(request, mapKey)); + case MessageMetadataContainer.LABEL_MAP_KEY_QUERY: + return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(request, mapKey)); + default: + return null; + } + } +} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java index e34eccc3bf..082e13f11f 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/provider/ServletMetadataProvider.java @@ -17,7 +17,6 @@ */ package com.tencent.cloud.metadata.provider; - import javax.servlet.http.HttpServletRequest; import com.tencent.cloud.common.util.UrlUtils; @@ -26,6 +25,7 @@ import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MetadataProvider; + /** * MetadataProvider used for Servlet. * diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java index ff27c0c4da..bbee696c90 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilterTest.java @@ -20,7 +20,6 @@ import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -55,7 +54,7 @@ public class DecodeTransferMetadataReactiveFilterTest { @BeforeEach public void setUp() { - this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(new PolarisContextProperties()); + this.metadataReactiveFilter = new DecodeTransferMetadataReactiveFilter(); } @Test diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java deleted file mode 100644 index 1c72c5d5a8..0000000000 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMetadataZuulFilterTest.java +++ /dev/null @@ -1,106 +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.core; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Map; - -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.util.JacksonUtils; -import com.tencent.cloud.rpc.enhancement.zuul.EnhancedPreZuulFilter; -import org.assertj.core.api.Assertions; -import org.assertj.core.util.Maps; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.mock.web.MockMultipartHttpServletRequest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -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.assertj.core.api.Assertions.assertThat; -import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; -import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY; - -/** - * Test for {@link EncodeTransferMetadataZuulEnhancedPlugin}. - * - * @author quan, Shedfree Wu - */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = RANDOM_PORT, - classes = EncodeTransferMetadataZuulFilterTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) -public class EncodeTransferMetadataZuulFilterTest { - - private final MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); - @Autowired - private ApplicationContext applicationContext; - - @BeforeEach - void setUp() { - RequestContext ctx = RequestContext.getCurrentContext(); - ctx.clear(); - ctx.setRequest(this.request); - } - - @Test - public void testRun() throws ZuulException, UnsupportedEncodingException { - EnhancedPreZuulFilter filter = applicationContext.getBean(EnhancedPreZuulFilter.class); - RequestContext context = RequestContext.getCurrentContext(); - context.set(SERVICE_ID_KEY, "test-service"); - - MetadataContext metadataContext = MetadataContextHolder.get(); - metadataContext.setTransitiveMetadata(Maps.newHashMap("t-key", "t-value")); - metadataContext.setDisposableMetadata(Maps.newHashMap("d-key", "d-value")); - filter.run(); - - final RequestContext ctx = RequestContext.getCurrentContext(); - Map zuulRequestHeaders = ctx.getZuulRequestHeaders(); - // convert header to lower case in com.netflix.zuul.context.RequestContext.addZuulRequestHeader - assertThat(zuulRequestHeaders.get(CUSTOM_METADATA.toLowerCase())).isNotNull(); - assertThat(zuulRequestHeaders.get(CUSTOM_DISPOSABLE_METADATA.toLowerCase())).isNotNull(); - - String metadata = zuulRequestHeaders.get(CUSTOM_METADATA.toLowerCase()); - - Assertions.assertThat(metadata).isNotNull(); - - String decode = URLDecoder.decode(metadata, UTF_8); - Map transitiveMap = JacksonUtils.deserialize2Map(decode); - // expect {"b":"2","t-key":"t-value"} - Assertions.assertThat(transitiveMap.size()).isEqualTo(2); - Assertions.assertThat(transitiveMap.get("b")).isEqualTo("2"); - } - - @SpringBootApplication - protected static class TestApplication { - - } -} diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java index add6928d5a..dab78d99ab 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/provider/MetadataProviderTest.java @@ -20,7 +20,7 @@ import com.tencent.cloud.common.util.UrlUtils; import com.tencent.polaris.metadata.core.MessageMetadataContainer; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.http.HttpCookie; import org.springframework.http.HttpMethod; diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml index 6a760d13fc..7525a4c921 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml @@ -26,7 +26,6 @@ true - org.springframework.cloud spring-cloud-starter-openfeign @@ -64,6 +63,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java index 3f247093da..c086fda919 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreaker.java @@ -44,15 +44,20 @@ public class PolarisCircuitBreaker implements CircuitBreaker, InvokeHandler { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisCircuitBreaker.class); + + private final FunctionalDecorator decorator; + private final PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf; + private final ConsumerAPI consumerAPI; - private final FunctionalDecorator decorator; + private final InvokeHandler invokeHandler; public PolarisCircuitBreaker(PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf, ConsumerAPI consumerAPI, CircuitBreakAPI circuitBreakAPI) { - FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest(new ServiceKey(conf.getNamespace(), conf.getService()), conf.getMethod()); + FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest( + new ServiceKey(conf.getNamespace(), conf.getService()), conf.getProtocol(), conf.getMethod(), conf.getPath()); makeDecoratorRequest.setSourceService(new ServiceKey(conf.getSourceNamespace(), conf.getSourceService())); makeDecoratorRequest.setResultToErrorCode(new PolarisResultToErrorCode()); this.consumerAPI = consumerAPI; diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java index 1c789befe7..70c3c3395e 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerFactory.java @@ -17,13 +17,21 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.circuitbreaker.util.PolarisCircuitBreakerUtils; import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.utils.ThreadPoolUtils; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; +import com.tencent.polaris.client.util.NamedThreadFactory; +import org.springframework.beans.factory.DisposableBean; import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; @@ -33,7 +41,14 @@ * @author seanyu 2023-02-27 */ public class PolarisCircuitBreakerFactory - extends CircuitBreakerFactory { + extends CircuitBreakerFactory implements DisposableBean { + + private final CircuitBreakAPI circuitBreakAPI; + + private final ConsumerAPI consumerAPI; + + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-circuitbreaker-cleanup", true)); private Function defaultConfiguration = id -> { @@ -41,18 +56,22 @@ public class PolarisCircuitBreakerFactory return new PolarisCircuitBreakerConfigBuilder() .namespace(metadata[0]) .service(metadata[1]) - .method(metadata[2]) + .path(metadata[2]) + .protocol(metadata[3]) + .method(metadata[4]) .build(); }; - - private final CircuitBreakAPI circuitBreakAPI; - - private final ConsumerAPI consumerAPI; - - public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { + public PolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; this.consumerAPI = consumerAPI; + cleanupService.scheduleWithFixedDelay( + () -> { + getConfigurations().clear(); + }, + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS); } @Override @@ -65,7 +84,7 @@ public CircuitBreaker create(String id) { @Override protected PolarisCircuitBreakerConfigBuilder configBuilder(String id) { String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id); - return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2]); + return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2], metadata[3], metadata[4]); } @Override @@ -73,4 +92,9 @@ public void configureDefault(Function { + ReactiveCircuitBreakerFactory implements DisposableBean { + + private final CircuitBreakAPI circuitBreakAPI; + + private final ConsumerAPI consumerAPI; + + private final ScheduledExecutorService cleanupService = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("sct-reactive-circuitbreaker-cleanup", true)); private Function defaultConfiguration = id -> { @@ -41,17 +56,22 @@ public class ReactivePolarisCircuitBreakerFactory extends return new PolarisCircuitBreakerConfigBuilder() .namespace(metadata[0]) .service(metadata[1]) - .method(metadata[2]) + .path(metadata[2]) + .protocol(metadata[3]) + .method(metadata[4]) .build(); }; - private final CircuitBreakAPI circuitBreakAPI; - - private final ConsumerAPI consumerAPI; - - public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { + public ReactivePolarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { this.circuitBreakAPI = circuitBreakAPI; this.consumerAPI = consumerAPI; + cleanupService.scheduleWithFixedDelay( + () -> { + getConfigurations().clear(); + }, + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), + polarisCircuitBreakerProperties.getConfigurationCleanupInterval(), TimeUnit.MILLISECONDS); } @Override @@ -64,7 +84,7 @@ public ReactiveCircuitBreaker create(String id) { @Override protected PolarisCircuitBreakerConfigBuilder configBuilder(String id) { String[] metadata = PolarisCircuitBreakerUtils.resolveCircuitBreakerId(id); - return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2]); + return new PolarisCircuitBreakerConfigBuilder(metadata[0], metadata[1], metadata[2], metadata[3], metadata[4]); } @Override @@ -73,4 +93,8 @@ public void configureDefault( this.defaultConfiguration = defaultConfiguration; } + @Override + public void destroy() { + ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[] {cleanupService}); + } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java index 7331804915..d33a92638f 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/common/PolarisCircuitBreakerConfigBuilder.java @@ -32,15 +32,21 @@ public class PolarisCircuitBreakerConfigBuilder implements ConfigBuilder customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java new file mode 100644 index 0000000000..7f26803059 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerProperties.java @@ -0,0 +1,57 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.circuitbreaker.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties of Polaris CircuitBreaker . + * + */ +@ConfigurationProperties("spring.cloud.polaris.circuitbreaker") +public class PolarisCircuitBreakerProperties { + + /** + * Whether enable polaris circuit-breaker function. + */ + @Value("${spring.cloud.polaris.circuitbreaker.enabled:#{true}}") + private boolean enabled = true; + + /** + * Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond. + */ + @Value("${spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval:#{300000}}") + private long configurationCleanupInterval = 300000; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public long getConfigurationCleanupInterval() { + return configurationCleanupInterval; + } + + public void setConfigurationCleanupInterval(long configurationCleanupInterval) { + this.configurationCleanupInterval = configurationCleanupInterval; + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java index 23c3f281d9..1b0f24b2f6 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/ReactivePolarisCircuitBreakerAutoConfiguration.java @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory; import org.springframework.context.annotation.Bean; @@ -45,6 +46,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = {"reactor.core.publisher.Mono", "reactor.core.publisher.Flux"}) @ConditionalOnPolarisCircuitBreakerEnabled +@EnableConfigurationProperties(PolarisCircuitBreakerProperties.class) @AutoConfigureAfter(RpcEnhancementAutoConfiguration.class) public class ReactivePolarisCircuitBreakerAutoConfiguration { @@ -67,9 +69,10 @@ public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhanc @Bean @ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class) - public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager) { + public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(PolarisSDKContextManager polarisSDKContextManager, + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties) { ReactivePolarisCircuitBreakerFactory factory = new ReactivePolarisCircuitBreakerFactory( - polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI()); + polarisSDKContextManager.getCircuitBreakAPI(), polarisSDKContextManager.getConsumerAPI(), polarisCircuitBreakerProperties); customizers.forEach(customizer -> customizer.customize(factory)); return factory; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpoint.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpoint.java index f9ada51210..3b49979152 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/endpoint/PolarisCircuitBreakerEndpoint.java @@ -41,7 +41,7 @@ * * @author wenxuan70 */ -@Endpoint(id = "polaris-circuit-breaker") +@Endpoint(id = "polariscircuitbreaker") public class PolarisCircuitBreakerEndpoint { private static final Logger LOG = LoggerFactory.getLogger(PolarisCircuitBreakerEndpoint.class); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java index 28539cd6b5..b86e9415fb 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolver.java @@ -22,12 +22,15 @@ import java.net.URISyntaxException; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.StringUtils; +import feign.Request; import feign.Target; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation; @@ -45,7 +48,7 @@ public String resolveCircuitBreakerName(String feignClientName, Target target String path = ""; // Get path in @FeignClient. - if (StringUtils.hasText(target.url())) { + if (StringUtils.isNotBlank(target.url())) { URI uri = null; try { uri = new URI(target.url()); @@ -58,16 +61,24 @@ public String resolveCircuitBreakerName(String feignClientName, Target target } } - // Get path in @RequestMapping. + // Get path and method in @RequestMapping. RequestMapping requestMapping = findMergedAnnotation(method, RequestMapping.class); + String httpMethod = Request.HttpMethod.GET.name(); if (requestMapping != null) { path += requestMapping.path().length == 0 ? requestMapping.value().length == 0 ? "" : requestMapping.value()[0] : requestMapping.path()[0]; + + RequestMethod[] requestMethods = requestMapping.method(); + if (CollectionUtils.isNotEmpty(requestMethods)) { + httpMethod = requestMethods[0].name(); + } } - return "".equals(path) ? + + + return StringUtils.isBlank(path) ? MetadataContext.LOCAL_NAMESPACE + "#" + serviceName : - MetadataContext.LOCAL_NAMESPACE + "#" + serviceName + "#" + path; + MetadataContext.LOCAL_NAMESPACE + "#" + serviceName + "#" + path + "#http#" + httpMethod; } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java index 0379c9977b..1319410976 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignCircuitBreakerInvocationHandler.java @@ -76,24 +76,6 @@ public PolarisFeignCircuitBreakerInvocationHandler(CircuitBreakerFactory factory this.decoder = decoder; } - /** - * If the method param of {@link InvocationHandler#invoke(Object, Method, Object[])} - * is not accessible, i.e in a package-private interface, the fallback call will cause - * of access restrictions. But methods in dispatch are copied methods. So setting - * access to dispatch method doesn't take effect to the method in - * InvocationHandler.invoke. Use map to store a copy of method to invoke the fallback - * to bypass this and reducing the count of reflection calls. - * @return cached methods map for fallback invoking - */ - static Map toFallbackMethod(Map dispatch) { - Map result = new LinkedHashMap<>(); - for (Method method : dispatch.keySet()) { - method.setAccessible(true); - result.put(method, method); - } - return result; - } - @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { // early exit if the invoked method is from java.lang.Object @@ -113,41 +95,40 @@ else if ("hashCode".equals(method.getName())) { else if ("toString".equals(method.getName())) { return toString(); } + // disable feign.hystrix + if (circuitBreakerNameResolver == null) { + return this.dispatch.get(method).invoke(args); + } + + String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method); + CircuitBreaker circuitBreaker = factory.create(circuitName); Supplier supplier = asSupplier(method, args); - if (circuitBreakerNameResolver != null) { - String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method); - CircuitBreaker circuitBreaker = factory.create(circuitName); - - Function fallbackFunction; - if (this.nullableFallbackFactory != null) { - fallbackFunction = throwable -> { - Object fallback = this.nullableFallbackFactory.create(throwable); - try { - return this.fallbackMethodMap.get(method).invoke(fallback, args); - } - catch (Exception exception) { - unwrapAndRethrow(exception); - } - return null; - }; - } - else { - fallbackFunction = throwable -> { - PolarisCircuitBreakerFallbackFactory.DefaultFallback fallback = - (PolarisCircuitBreakerFallbackFactory.DefaultFallback) new PolarisCircuitBreakerFallbackFactory(this.decoder).create(throwable); - return fallback.fallback(method); - }; - } - try { - return circuitBreaker.run(supplier, fallbackFunction); - } - catch (FallbackWrapperException e) { - // unwrap And Rethrow - throw e.getCause(); - } + Function fallbackFunction; + if (this.nullableFallbackFactory != null) { + fallbackFunction = throwable -> { + Object fallback = this.nullableFallbackFactory.create(throwable); + try { + return this.fallbackMethodMap.get(method).invoke(fallback, args); + } + catch (Exception exception) { + unwrapAndRethrow(exception); + } + return null; + }; } else { - return supplier.get(); + fallbackFunction = throwable -> { + PolarisCircuitBreakerFallbackFactory.DefaultFallback fallback = + (PolarisCircuitBreakerFallbackFactory.DefaultFallback) new PolarisCircuitBreakerFallbackFactory(this.decoder).create(throwable); + return fallback.fallback(method); + }; + } + try { + return circuitBreaker.run(supplier, fallbackFunction); + } + catch (FallbackWrapperException e) { + // unwrap And Rethrow + throw e.getCause(); } } @@ -189,6 +170,24 @@ private Supplier asSupplier(final Method method, final Object[] args) { }; } + /** + * If the method param of {@link InvocationHandler#invoke(Object, Method, Object[])} + * is not accessible, i.e in a package-private interface, the fallback call will cause + * of access restrictions. But methods in dispatch are copied methods. So setting + * access to dispatch method doesn't take effect to the method in + * InvocationHandler.invoke. Use map to store a copy of method to invoke the fallback + * to bypass this and reducing the count of reflection calls. + * @return cached methods map for fallback invoking + */ + static Map toFallbackMethod(Map dispatch) { + Map result = new LinkedHashMap<>(); + for (Method method : dispatch.keySet()) { + method.setAccessible(true); + result.put(method, method); + } + return result; + } + @Override public boolean equals(Object obj) { if (obj instanceof PolarisFeignCircuitBreakerInvocationHandler) { diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java index 0b474f8e5a..250a84c63a 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerFilterFactory.java @@ -28,6 +28,7 @@ import java.util.Set; import java.util.stream.Collectors; +import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.polaris.api.pojo.CircuitBreakerStatus; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; import reactor.core.publisher.Flux; @@ -186,20 +187,21 @@ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { serviceName = route.getUri().getHost(); } String path = exchange.getRequest().getPath().value(); - ReactiveCircuitBreaker cb = reactiveCircuitBreakerFactory.create(serviceName + "#" + path); + String method = exchange.getRequest().getMethod() == null ? + "GET" : exchange.getRequest().getMethod().name(); + ReactiveCircuitBreaker cb = reactiveCircuitBreakerFactory.create(MetadataContext.LOCAL_NAMESPACE + "#" + serviceName + "#" + path + "#http#" + method); return cb.run( - chain.filter(exchange) - .doOnSuccess(v -> { - // throw CircuitBreakerStatusCodeException by default for all need checking status - // so polaris can report right error status - Set statusNeedToCheck = new HashSet<>(); - statusNeedToCheck.addAll(statuses); - statusNeedToCheck.addAll(getDefaultStatus()); - HttpStatus status = exchange.getResponse().getStatusCode(); - if (statusNeedToCheck.contains(status)) { - throw new CircuitBreakerStatusCodeException(status); - } - }), + chain.filter(exchange).doOnSuccess(v -> { + // throw CircuitBreakerStatusCodeException by default for all need checking status + // so polaris can report right error status + Set statusNeedToCheck = new HashSet<>(); + statusNeedToCheck.addAll(statuses); + statusNeedToCheck.addAll(getDefaultStatus()); + HttpStatus status = exchange.getResponse().getStatusCode(); + if (statusNeedToCheck.contains(status)) { + throw new CircuitBreakerStatusCodeException(status); + } + }), t -> { // pre-check CircuitBreakerStatusCodeException's status matches input status if (t instanceof CircuitBreakerStatusCodeException) { diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java index 8cb26902f1..f2bc52ab7b 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateInterceptor.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.lang.reflect.Method; +import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.circuitbreaker.exception.FallbackWrapperException; import com.tencent.polaris.api.pojo.CircuitBreakerStatus; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; @@ -59,13 +60,18 @@ public PolarisCircuitBreakerRestTemplateInterceptor( this.polarisCircuitBreaker = polarisCircuitBreaker; this.applicationContext = applicationContext; this.circuitBreakerFactory = circuitBreakerFactory; - this.restTemplate = restTemplate; + this.restTemplate = restTemplate; } @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { try { - return circuitBreakerFactory.create(request.getURI().getHost() + "#" + request.getURI().getPath()).run( + String httpMethod = "GET"; + if (request.getMethod() != null) { + httpMethod = request.getMethod().name(); + } + return circuitBreakerFactory.create(MetadataContext.LOCAL_NAMESPACE + "#" + request.getURI() + .getHost() + "#" + request.getURI().getPath() + "#http#" + httpMethod).run( () -> { try { ClientHttpResponse response = execution.execute(request, body); @@ -84,7 +90,8 @@ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttp CircuitBreakerStatus.FallbackInfo fallbackInfo = new CircuitBreakerStatus.FallbackInfo(200, null, polarisCircuitBreaker.fallback()); return new PolarisCircuitBreakerHttpResponse(fallbackInfo); } - if (!PolarisCircuitBreakerFallback.class.toGenericString().equals(polarisCircuitBreaker.fallbackClass().toGenericString())) { + if (!PolarisCircuitBreakerFallback.class.toGenericString() + .equals(polarisCircuitBreaker.fallbackClass().toGenericString())) { Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerFallback.class, "fallback"); PolarisCircuitBreakerFallback polarisCircuitBreakerFallback = applicationContext.getBean(polarisCircuitBreaker.fallbackClass()); return (PolarisCircuitBreakerHttpResponse) ReflectionUtils.invokeMethod(method, polarisCircuitBreakerFallback); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java index 961c308025..349af2326c 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtils.java @@ -45,29 +45,36 @@ private PolarisCircuitBreakerUtils() { } /** + * Format: + * 0. namespace#service#path#protocol#method + * 1. namespace#service#method + * 2. service#method + * 3. service + * namespace set as default spring.cloud.polaris.namespace if absent. * * @param id CircuitBreakerId - * Format: namespace#service#method or service#method or service , - * namespace set as default spring.cloud.polaris.namespace if absent * @return String[]{namespace, service, method} */ public static String[] resolveCircuitBreakerId(String id) { Assert.hasText(id, "A CircuitBreaker must have an id. Id could be : namespace#service#method or service#method or service"); String[] polarisCircuitBreakerMetaData = id.split("#"); if (polarisCircuitBreakerMetaData.length == 2) { - return new String[]{MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1]}; + return new String[] {MetadataContext.LOCAL_NAMESPACE, polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], "http", ""}; } if (polarisCircuitBreakerMetaData.length == 3) { - return new String[]{polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2]}; + return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2], "http", ""}; } - return new String[]{MetadataContext.LOCAL_NAMESPACE, id, ""}; + if (polarisCircuitBreakerMetaData.length == 5) { + return new String[] {polarisCircuitBreakerMetaData[0], polarisCircuitBreakerMetaData[1], polarisCircuitBreakerMetaData[2], polarisCircuitBreakerMetaData[3], polarisCircuitBreakerMetaData[4]}; + } + return new String[] {MetadataContext.LOCAL_NAMESPACE, id, "", "http", ""}; } public static void reportStatus(ConsumerAPI consumerAPI, PolarisCircuitBreakerConfigBuilder.PolarisCircuitBreakerConfiguration conf, CallAbortedException e) { try { ServiceCallResult result = new ServiceCallResult(); - result.setMethod(conf.getMethod()); + result.setMethod(conf.getPath()); result.setNamespace(conf.getNamespace()); result.setService(conf.getService()); result.setRuleName(e.getRuleName()); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java index 37eccb6daa..a74fa769cb 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/zuul/PolarisCircuitBreakerZuulFilter.java @@ -97,11 +97,12 @@ public boolean shouldFilter() { @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); + String serviceId = ZuulFilterUtils.getServiceId(context); String path = ZuulFilterUtils.getPath(context); - String circuitName = "".equals(path) ? + String circuitName = com.tencent.polaris.api.utils.StringUtils.isBlank(path) ? MetadataContext.LOCAL_NAMESPACE + "#" + serviceId : - MetadataContext.LOCAL_NAMESPACE + "#" + serviceId + "#" + path; + MetadataContext.LOCAL_NAMESPACE + "#" + serviceId + "#" + path + "#http#" + context.getRequest().getMethod(); CircuitBreaker circuitBreaker = circuitBreakerFactory.create(circuitName); if (circuitBreaker instanceof PolarisCircuitBreaker) { PolarisCircuitBreaker polarisCircuitBreaker = (PolarisCircuitBreaker) circuitBreaker; diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java index 9ac2ad59bb..7ff9064e95 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/org/springframework/cloud/openfeign/PolarisFeignCircuitBreakerTargeter.java @@ -36,7 +36,8 @@ public class PolarisFeignCircuitBreakerTargeter implements Targeter { private final PolarisCircuitBreakerNameResolver circuitBreakerNameResolver; - public PolarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { + public PolarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, + PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { this.circuitBreakerFactory = circuitBreakerFactory; this.circuitBreakerNameResolver = circuitBreakerNameResolver; } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 99dc05518a..2f222b9999 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -3,7 +3,14 @@ { "name": "spring.cloud.polaris.circuitbreaker.enabled", "type": "java.lang.Boolean", - "defaultValue": "true" + "defaultValue": "true", + "description": "If polaris circuitbreaker enabled." + }, + { + "name": "spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval", + "type": "java.lang.Long", + "defaultValue": "300000", + "description": "Interval to clean up PolarisCircuitBreakerConfiguration, unit millisecond." } ], "hints": [] diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java index fcde4e4f95..7b4a80d74e 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerMockServerTest.java @@ -30,12 +30,14 @@ import com.google.protobuf.util.JsonFormat; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerProperties; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; +import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.util.Utils; import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; @@ -70,6 +72,8 @@ public class PolarisCircuitBreakerMockServerTest { private static MockedStatic mockedApplicationContextAwareUtils; private static NamingServer namingServer; + private static SDKContext context; + @BeforeAll public static void beforeAll() throws IOException { mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); @@ -78,11 +82,10 @@ public static void beforeAll() throws IOException { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service")) .thenReturn(SERVICE_CIRCUIT_BREAKER); PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(-1); System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_CIRCUIT_BREAKER); - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); InputStream inputStream = PolarisCircuitBreakerMockServerTest.class.getClassLoader() .getResourceAsStream("circuitBreakerRule.json"); @@ -93,6 +96,9 @@ public static void beforeAll() throws IOException { CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() .addRules(circuitBreakerRule).build(); namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + + Configuration configuration = TestUtils.configWithEnvAddress(); + context = SDKContext.initContextByConfig(configuration); } @AfterAll @@ -103,15 +109,17 @@ public static void afterAll() { if (null != mockedApplicationContextAwareUtils) { mockedApplicationContextAwareUtils.close(); } + if (null != context) { + context.close(); + } } @Test public void testCircuitBreaker() { - Configuration configuration = TestUtils.configWithEnvAddress(); - CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - - ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByContext(context); + ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(context); + PolarisCircuitBreakerProperties polarisCircuitBreakerProperties = new PolarisCircuitBreakerProperties(); + PolarisCircuitBreakerFactory polarisCircuitBreakerFactory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); CircuitBreaker cb = polarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); // trigger fallback for 5 times @@ -132,7 +140,7 @@ public void testCircuitBreaker() { assertThat(resList).isEqualTo(Arrays.asList("invoke success", "fallback", "fallback", "fallback", "fallback")); // always fallback - ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); + ReactivePolarisCircuitBreakerFactory reactivePolarisCircuitBreakerFactory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI, polarisCircuitBreakerProperties); ReactiveCircuitBreaker rcb = reactivePolarisCircuitBreakerFactory.create(SERVICE_CIRCUIT_BREAKER); assertThat(Mono.just("foobar").transform(it -> rcb.run(it, t -> Mono.just("fallback"))) diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java index bf35fa8f98..47f9df6977 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerTest.java @@ -18,13 +18,19 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.lang.reflect.Method; +import java.util.Map; + import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ReflectionUtils; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import com.tencent.polaris.client.util.Utils; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -56,7 +62,8 @@ public class PolarisCircuitBreakerTest { LoadBalancerAutoConfiguration.class, PolarisCircuitBreakerFeignClientAutoConfiguration.class, PolarisCircuitBreakerAutoConfiguration.class)) - .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000"); private static MockedStatic mockedApplicationContextAwareUtils; @@ -92,6 +99,18 @@ public void run() { throw new RuntimeException("boom"); }, t -> "fallback")).isEqualTo("fallback"); + Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class, + "getConfigurations"); + Assertions.assertNotNull(getConfigurationsMethod); + ReflectionUtils.makeAccessible(getConfigurationsMethod); + Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); + Assertions.assertNotNull(values); + + Assertions.assertEquals(1, values.size()); + + Utils.sleepUninterrupted(10 * 1000); + + Assertions.assertEquals(0, values.size()); }); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java index f06502c87e..6af1975ad6 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/ReactivePolarisCircuitBreakerTest.java @@ -17,15 +17,20 @@ package com.tencent.cloud.polaris.circuitbreaker; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; +import java.util.Map; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.common.util.ReflectionUtils; import com.tencent.cloud.polaris.circuitbreaker.common.PolarisCircuitBreakerConfigBuilder; import com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import com.tencent.polaris.client.util.Utils; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -58,7 +63,8 @@ public class ReactivePolarisCircuitBreakerTest { RpcEnhancementAutoConfiguration.class, LoadBalancerAutoConfiguration.class, ReactivePolarisCircuitBreakerAutoConfiguration.class)) - .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true") + .withPropertyValues("spring.cloud.polaris.circuitbreaker.configuration-cleanup-interval=5000"); private static MockedStatic mockedApplicationContextAwareUtils; @@ -97,6 +103,18 @@ public void run() { assertThat(Flux.error(new RuntimeException("boom")).transform(it -> cb.run(it, t -> Flux.just("fallback"))) .collectList().block()).isEqualTo(Collections.singletonList("fallback")); + + Method getConfigurationsMethod = ReflectionUtils.findMethod(PolarisCircuitBreakerFactory.class, + "getConfigurations"); + Assertions.assertNotNull(getConfigurationsMethod); + ReflectionUtils.makeAccessible(getConfigurationsMethod); + Map values = (Map) ReflectionUtils.invokeMethod(getConfigurationsMethod, polarisCircuitBreakerFactory); + Assertions.assertNotNull(values); + Assertions.assertTrue(values.size() >= 0); + + Utils.sleepUninterrupted(10 * 1000); + // clear by cleanupService in ReactivePolarisCircuitBreakerFactory + Assertions.assertEquals(0, values.size()); }); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java index 653ba8ffe6..747282ca55 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java @@ -17,8 +17,10 @@ package com.tencent.cloud.polaris.circuitbreaker.config; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -42,6 +44,11 @@ public class PolarisCircuitBreakerBootstrapConfigurationTest { .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); + @BeforeAll + static void beforeAll() { + PolarisSDKContextManager.innerDestroy(); + } + @Test public void testDefaultInitialization() { this.contextRunner.run(context -> { diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java index 689eed2e43..23a6c93429 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationDisableFeignHystrixTest.java @@ -36,7 +36,7 @@ @SpringBootTest(webEnvironment = RANDOM_PORT, classes = PolarisCircuitBreakerFeignIntegrationTest.TestConfig.class, properties = { - "feign.hystrix.enabled=false", + "feign.hystrix.enabled=false", "spring.cloud.gateway.enabled=false", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java index c3bf5e418e..999ec16fde 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerFeignIntegrationTest.java @@ -19,47 +19,32 @@ import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; import java.util.stream.Collectors; import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; -import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; -import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; -import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; -import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; -import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; import com.tencent.polaris.client.util.Utils; -import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; -import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; -import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FallbackFactory; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.cloud.openfeign.PolarisFeignCircuitBreakerTargeter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -68,7 +53,6 @@ import org.springframework.web.bind.annotation.RequestParam; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -82,6 +66,7 @@ properties = { "feign.hystrix.enabled=true", "spring.cloud.gateway.enabled=false", + "spring.cloud.polaris.address=grpc://127.0.0.1:10081", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, "spring.cloud.polaris.service=test" @@ -90,6 +75,8 @@ public class PolarisCircuitBreakerFeignIntegrationTest { private static final String TEST_SERVICE_NAME = "test-service-callee"; + private static NamingServer namingServer; + @Autowired private EchoService echoService; @@ -102,6 +89,31 @@ public class PolarisCircuitBreakerFeignIntegrationTest { @Autowired private BazService bazService; + @BeforeAll + static void beforeAll() throws Exception { + PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(10081); + ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); + + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerFeignIntegrationTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); + JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); + CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); + namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } + @Test public void contextLoads() { assertThat(echoService).isNotNull(); @@ -170,9 +182,6 @@ public interface BazClient extends BazService { @EnableFeignClients public static class TestConfig { - @Autowired(required = false) - private List> customizers = new ArrayList<>(); - @Bean public EchoServiceFallback echoServiceFallback() { return new EchoServiceFallback(); @@ -182,74 +191,6 @@ public EchoServiceFallback echoServiceFallback() { public CustomFallbackFactory customFallbackFactory() { return new CustomFallbackFactory(); } - - @Bean - public PreDestroy preDestroy(NamingServer namingServer) { - return new PreDestroy(namingServer); - } - - @Bean - public NamingServer namingServer() throws IOException { - NamingServer namingServer = NamingServer.startNamingServer(-1); - System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); - - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerFeignIntegrationTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); - CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); - namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); - return namingServer; - } - - @Bean - public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - } - - @Bean - public ConsumerAPI consumerAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - } - - @Bean - public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); - customizers.forEach(customizer -> customizer.customize(factory)); - return factory; - } - - @Bean - public PolarisCircuitBreakerNameResolver polarisCircuitBreakerNameResolver() { - return new PolarisCircuitBreakerNameResolver(); - } - - @Bean - @Primary - @ConditionalOnBean(CircuitBreakerFactory.class) - @ConditionalOnProperty(value = "feign.hystrix.enabled", havingValue = "true") - public PolarisFeignCircuitBreakerTargeter polarisFeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, PolarisCircuitBreakerNameResolver circuitBreakerNameResolver) { - return new PolarisFeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerNameResolver); - } } public static class EchoServiceFallback implements EchoService { @@ -284,19 +225,4 @@ public FooService create(Throwable throwable) { } } - - public static class PreDestroy implements DisposableBean { - - private final NamingServer namingServer; - - public PreDestroy(NamingServer namingServer) { - this.namingServer = namingServer; - } - - @Override - public void destroy() throws Exception { - namingServer.terminate(); - } - } - } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java index 52e9e4650d..27ea51f4ff 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisCircuitBreakerNameResolverTest.java @@ -93,7 +93,7 @@ public void test2() { Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerNameResolverTest.class, "mockRequestMapping2"); PolarisCircuitBreakerNameResolver resolver = new PolarisCircuitBreakerNameResolver(); String polarisCircuitBreakerName = resolver.resolveCircuitBreakerName("test", target, method); - assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/"); + assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/#http#GET"); } @Test @@ -103,7 +103,7 @@ public void test3() { Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerNameResolverTest.class, "mockRequestMapping3"); PolarisCircuitBreakerNameResolver resolver = new PolarisCircuitBreakerNameResolver(); String polarisCircuitBreakerName = resolver.resolveCircuitBreakerName("test", target, method); - assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/"); + assertThat(polarisCircuitBreakerName).isEqualTo("Test#test-svc#/#http#GET"); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java index 2511722bc7..294d1014c7 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/gateway/PolarisCircuitBreakerGatewayIntegrationTest.java @@ -19,43 +19,30 @@ import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.stream.Collectors; import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; -import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; -import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; -import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; -import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; -import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; import com.tencent.polaris.client.util.Utils; -import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; -import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import reactor.core.publisher.Mono; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; -import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.gateway.filter.factory.SpringCloudCircuitBreakerFilterFactory; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; @@ -69,8 +56,6 @@ import org.springframework.web.bind.annotation.RestController; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.Consts.SERVICE_CIRCUIT_BREAKER; -import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; @@ -83,7 +68,7 @@ properties = { "spring.cloud.gateway.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, - "spring.cloud.polaris.service=" + SERVICE_CIRCUIT_BREAKER, + "spring.cloud.polaris.service=test", "spring.main.web-application-type=reactive" }, classes = PolarisCircuitBreakerGatewayIntegrationTest.TestApplication.class @@ -94,12 +79,39 @@ public class PolarisCircuitBreakerGatewayIntegrationTest { private static final String TEST_SERVICE_NAME = "test-service-callee"; + private static NamingServer namingServer; + @Autowired private WebTestClient webClient; @Autowired private ApplicationContext applicationContext; + @BeforeAll + static void beforeAll() throws Exception { + PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(10081); + ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); + + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerGatewayIntegrationTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); + JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); + CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); + namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } + @Test public void fallback() throws Exception { SpringCloudCircuitBreakerFilterFactory.Config config = new SpringCloudCircuitBreakerFilterFactory.Config(); @@ -161,67 +173,6 @@ public void fallback() throws Exception { @EnableAutoConfiguration public static class TestApplication { - @Autowired(required = false) - private List> customizers = new ArrayList<>(); - - @Bean - public PreDestroy preDestroy(NamingServer namingServer) { - return new PreDestroy(namingServer); - } - - @Bean - public NamingServer namingServer() throws IOException { - NamingServer namingServer = NamingServer.startNamingServer(-1); - System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); - - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerGatewayIntegrationTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); - CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); - namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); - return namingServer; - } - - @Bean - public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) throws IOException { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - } - - @Bean - public ConsumerAPI consumerAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return DiscoveryAPIFactory.createConsumerAPIByConfig(configuration); - } - - @Bean - @ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class) - public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - @ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class) - public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - @ConditionalOnMissingBean(CircuitBreakerFactory.class) - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, ConsumerAPI consumerAPI) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory(circuitBreakAPI, consumerAPI); - customizers.forEach(customizer -> customizer.customize(factory)); - return factory; - } - @Bean public RouteLocator myRoutes(RouteLocatorBuilder builder) { Set codeSets = new HashSet<>(); @@ -264,19 +215,4 @@ public Mono fallback() { } } - - public static class PreDestroy implements DisposableBean { - - private final NamingServer namingServer; - - public PreDestroy(NamingServer namingServer) { - this.namingServer = namingServer; - } - - @Override - public void destroy() throws Exception { - namingServer.terminate(); - } - } - } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java index 1be0a170ce..d486ac3f52 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisCircuitBreakerRestTemplateIntegrationTest.java @@ -18,42 +18,31 @@ package com.tencent.cloud.polaris.circuitbreaker.resttemplate; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.stream.Collectors; import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerFactory; import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration; -import com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter; -import com.tencent.cloud.polaris.circuitbreaker.reporter.SuccessCircuitBreakerReporter; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.polaris.api.pojo.ServiceKey; -import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; -import com.tencent.polaris.circuitbreak.factory.CircuitBreakAPIFactory; import com.tencent.polaris.client.util.Utils; import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto; -import com.tencent.polaris.test.common.TestUtils; import com.tencent.polaris.test.mock.discovery.NamingServer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; -import org.springframework.cloud.client.circuitbreaker.Customizer; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ApplicationContext; @@ -72,7 +61,6 @@ import org.springframework.web.util.DefaultUriBuilderFactory; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; -import static com.tencent.polaris.test.common.TestUtils.SERVER_ADDRESS_ENV; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @@ -88,6 +76,7 @@ classes = PolarisCircuitBreakerRestTemplateIntegrationTest.TestConfig.class, properties = { "spring.cloud.gateway.enabled=false", + "spring.cloud.polaris.address=grpc://127.0.0.1:10081", "feign.circuitbreaker.enabled=true", "spring.cloud.polaris.namespace=" + NAMESPACE_TEST, "spring.cloud.polaris.service=test" @@ -96,6 +85,8 @@ public class PolarisCircuitBreakerRestTemplateIntegrationTest { private static final String TEST_SERVICE_NAME = "test-service-callee"; + private static NamingServer namingServer; + @Autowired @Qualifier("defaultRestTemplate") private RestTemplate defaultRestTemplate; @@ -123,6 +114,29 @@ public class PolarisCircuitBreakerRestTemplateIntegrationTest { @Autowired private ApplicationContext applicationContext; + @BeforeAll + static void beforeAll() throws Exception { + PolarisSDKContextManager.innerDestroy(); + namingServer = NamingServer.startNamingServer(10081); + ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); + CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); + InputStream inputStream = PolarisCircuitBreakerRestTemplateIntegrationTest.class.getClassLoader() + .getResourceAsStream("circuitBreakerRule.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); + JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); + CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); + CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() + .addRules(circuitBreakerRule).build(); + namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); + } + + @AfterAll + static void afterAll() { + if (null != namingServer) { + namingServer.terminate(); + } + } @Test public void testRestTemplate() throws URISyntaxException { @@ -149,7 +163,8 @@ public void testRestTemplate() throws URISyntaxException { Utils.sleepUninterrupted(2000); assertThat(restTemplateFallbackFromCode2.getForObject("/example/service/b/info", String.class)).isEqualTo("\"this is a fallback class\""); Utils.sleepUninterrupted(2000); - assertThat(restTemplateFallbackFromCode3.getForEntity("/example/service/b/info", String.class).getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(restTemplateFallbackFromCode3.getForEntity("/example/service/b/info", String.class) + .getStatusCode()).isEqualTo(HttpStatus.OK); Utils.sleepUninterrupted(2000); assertThat(restTemplateFallbackFromCode4.getForObject("/example/service/b/info", String.class)).isEqualTo("fallback"); Utils.sleepUninterrupted(2000); @@ -166,13 +181,6 @@ public void testRestTemplate() throws URISyntaxException { @EnableFeignClients public static class TestConfig { - @Autowired(required = false) - private List> customizers = new ArrayList<>(); - - { - PolarisSDKContextManager.innerDestroy(); - } - @Bean @com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreaker(fallback = "fallback") public RestTemplate defaultRestTemplate() { @@ -244,56 +252,6 @@ public CustomPolarisCircuitBreakerFallback3 customPolarisCircuitBreakerFallback3 return new CustomPolarisCircuitBreakerFallback3(); } - @Bean - public NamingServer namingServer() throws IOException { - NamingServer namingServer = NamingServer.startNamingServer(-1); - System.setProperty(SERVER_ADDRESS_ENV, String.format("127.0.0.1:%d", namingServer.getPort())); - ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, TEST_SERVICE_NAME); - CircuitBreakerProto.CircuitBreakerRule.Builder circuitBreakerRuleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder(); - InputStream inputStream = PolarisCircuitBreakerRestTemplateIntegrationTest.class.getClassLoader() - .getResourceAsStream("circuitBreakerRule.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() - .collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, circuitBreakerRuleBuilder); - CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule = circuitBreakerRuleBuilder.build(); - CircuitBreakerProto.CircuitBreaker circuitBreaker = CircuitBreakerProto.CircuitBreaker.newBuilder() - .addRules(circuitBreakerRule).build(); - namingServer.getNamingService().setCircuitBreaker(serviceKey, circuitBreaker); - return namingServer; - } - - @Bean - public PreDestroy preDestroy(NamingServer namingServer) { - return new PreDestroy(namingServer); - } - - @Bean - public CircuitBreakAPI circuitBreakAPI(NamingServer namingServer) { - com.tencent.polaris.api.config.Configuration configuration = TestUtils.configWithEnvAddress(); - return CircuitBreakAPIFactory.createCircuitBreakAPIByConfig(configuration); - } - - @Bean - public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, - CircuitBreakAPI circuitBreakAPI) { - return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI); - } - - @Bean - public CircuitBreakerFactory polarisCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI, - PolarisSDKContextManager polarisSDKContextManager) { - PolarisCircuitBreakerFactory factory = new PolarisCircuitBreakerFactory( - circuitBreakAPI, polarisSDKContextManager.getConsumerAPI()); - customizers.forEach(customizer -> customizer.customize(factory)); - return factory; - } - @RestController @RequestMapping("/example/service/b") public class ServiceBController { @@ -342,19 +300,4 @@ public PolarisCircuitBreakerHttpResponse fallback() { ); } } - - public static class PreDestroy implements DisposableBean { - - private final NamingServer namingServer; - - public PreDestroy(NamingServer namingServer) { - this.namingServer = namingServer; - } - - @Override - public void destroy() throws Exception { - namingServer.terminate(); - } - } - } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java index d05a0dcc28..eb752701b9 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/util/PolarisCircuitBreakerUtilsTests.java @@ -71,9 +71,11 @@ public void testReportStatus() { @Test public void testResolveCircuitBreakerId() { - assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc")).isEqualTo(new String[]{NAMESPACE_TEST, "test_svc", ""}); - assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc#test_path")).isEqualTo(new String[]{NAMESPACE_TEST, "test_svc", "test_path"}); - assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path")).isEqualTo(new String[]{"test_ns", "test_svc", "test_path"}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc")).isEqualTo(new String[] {NAMESPACE_TEST, "test_svc", "", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_svc#test_path")).isEqualTo(new String[] {NAMESPACE_TEST, "test_svc", "test_path", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path")).isEqualTo(new String[] {"test_ns", "test_svc", "test_path", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path")).isEqualTo(new String[] {"test_ns", "test_svc", "test_path", "http", ""}); + assertThat(PolarisCircuitBreakerUtils.resolveCircuitBreakerId("test_ns#test_svc#test_path#tcp#POST")).isEqualTo(new String[] {"test_ns", "test_svc", "test_path", "tcp", "POST"}); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml index 06481f2546..d484da8aae 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application-test-gateway.yml @@ -1,22 +1,15 @@ spring: + main: + web-application-type: reactive application: name: GatewayScgService cloud: - tencent: - plugin: - scg: - staining: - enabled: true - rule-staining: - enabled: true - router: - feature-env: - enabled: true polaris: address: grpc://127.0.0.1:10081 - namespace: default + namespace: Test enabled: true gateway: + enabled: true routes: - id: cb-test uri: http://localhost:${server.port}/hello/1 diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml index e7262c29f2..fceb2487fb 100644 --- a/spring-cloud-starter-tencent-polaris-config/pom.xml +++ b/spring-cloud-starter-tencent-polaris-config/pom.xml @@ -34,6 +34,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java index 3c5e87c5ae..69025b48ed 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConfigurationModifier.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.config; @@ -26,27 +25,27 @@ import com.tencent.cloud.common.util.AddressUtils; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.config.PolarisCryptoConfigProperties; -import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.PolarisConfigurationConfigModifier; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.factory.config.configuration.ConfigFilterConfigImpl; +import com.tencent.polaris.factory.config.configuration.ConnectorConfigImpl; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; +import static com.tencent.polaris.api.config.plugin.DefaultPlugins.LOCAL_FILE_CONNECTOR_TYPE; + /** * Read configuration from spring cloud's configuration file and override polaris.yaml. * * @author lepdou 2022-03-10 */ -public class ConfigurationModifier implements PolarisConfigModifier { +public class ConfigurationModifier implements PolarisConfigurationConfigModifier { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationModifier.class); - private static final String DATA_SOURCE_POLARIS = "polaris"; - private static final String DATA_SOURCE_LOCAL = "local"; - private final PolarisConfigProperties polarisConfigProperties; private final PolarisCryptoConfigProperties polarisCryptoConfigProperties; @@ -63,16 +62,15 @@ public ConfigurationModifier(PolarisConfigProperties polarisConfigProperties, @Override public void modify(ConfigurationImpl configuration) { - if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), DATA_SOURCE_POLARIS)) { - initByPolarisDataSource(configuration); - } - else if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), DATA_SOURCE_LOCAL)) { - initByLocalDataSource(configuration); - } - else { - throw new RuntimeException("Unsupported config data source"); + configuration.getGlobal().getAPI().setReportEnable(false); + configuration.getGlobal().getStatReporter().setEnable(false); + + if (!polarisContextProperties.getEnabled() || !polarisConfigProperties.isEnabled()) { + return; } + initDataSource(configuration); + ConfigFilterConfigImpl configFilterConfig = configuration.getConfigFile().getConfigFilterConfig(); configFilterConfig.setEnable(polarisCryptoConfigProperties.isEnabled()); if (polarisCryptoConfigProperties.isEnabled()) { @@ -81,18 +79,15 @@ else if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), D } } - private void initByLocalDataSource(ConfigurationImpl configuration) { - configuration.getConfigFile().getServerConnector().setConnectorType("localFile"); - - String localFileRootPath = polarisConfigProperties.getLocalFileRootPath(); - configuration.getConfigFile().getServerConnector().setPersistDir(localFileRootPath); - - LOGGER.info("[SCT] Run spring cloud tencent config with local data source. localFileRootPath = {}", localFileRootPath); - } - - private void initByPolarisDataSource(ConfigurationImpl configuration) { + private void initDataSource(ConfigurationImpl configuration) { // set connector type - configuration.getConfigFile().getServerConnector().setConnectorType("polaris"); + configuration.getConfigFile().getServerConnector().setConnectorType(polarisConfigProperties.getDataSource()); + if (StringUtils.equalsIgnoreCase(polarisConfigProperties.getDataSource(), LOCAL_FILE_CONNECTOR_TYPE)) { + String localFileRootPath = polarisConfigProperties.getLocalFileRootPath(); + configuration.getConfigFile().getServerConnector().setPersistDir(localFileRootPath); + LOGGER.info("[SCT] Run spring cloud tencent config with local data source. localFileRootPath = {}", localFileRootPath); + return; + } // set config server address List configAddresses; @@ -114,6 +109,11 @@ private void initByPolarisDataSource(ConfigurationImpl configuration) { configuration.getConfigFile().getServerConnector().setAddresses(configAddresses); + if (StringUtils.isNotEmpty(polarisConfigProperties.getToken())) { + ConnectorConfigImpl connectorConfig = configuration.getConfigFile().getServerConnector(); + connectorConfig.setToken(polarisConfigProperties.getToken()); + } + LOGGER.info("[SCT] Run spring cloud tencent config in polaris data source."); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java index 0d5855b86c..7b39f4bd1d 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java @@ -21,7 +21,6 @@ import com.tencent.cloud.polaris.config.adapter.AffectedConfigurationPropertiesRebinder; import com.tencent.cloud.polaris.config.adapter.PolarisConfigPropertyRefresher; import com.tencent.cloud.polaris.config.adapter.PolarisConfigRefreshScopeAnnotationDetector; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshAffectedContextRefresher; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefresher; import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProcessor; @@ -68,7 +67,6 @@ public PolarisConfigLoggerApplicationListener polarisConfigLoggerApplicationList return new PolarisConfigLoggerApplicationListener(); } - @Bean @Primary @ConditionalOnReflectRefreshType @@ -79,9 +77,9 @@ public ConfigurationPropertiesRebinder affectedConfigurationPropertiesRebinder( @Bean @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) - public PolarisConfigPropertyRefresher polarisRefreshContextPropertySourceAutoRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, ContextRefresher contextRefresher) { - return new PolarisRefreshEntireContextRefresher(polarisConfigProperties, polarisPropertySourceManager, contextRefresher); + public PolarisConfigPropertyRefresher polarisRefreshContextPropertySourceAutoRefresher( + PolarisConfigProperties polarisConfigProperties, ContextRefresher contextRefresher) { + return new PolarisRefreshEntireContextRefresher(polarisConfigProperties, contextRefresher); } @Configuration(proxyBeanMethods = false) @@ -105,10 +103,10 @@ public SpringValueProcessor springValueProcessor(PlaceholderHelper placeholderHe } @Bean - public PolarisConfigPropertyRefresher polarisReflectPropertySourceAutoRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, SpringValueRegistry springValueRegistry, + public PolarisConfigPropertyRefresher polarisReflectPropertySourceAutoRefresher( + PolarisConfigProperties polarisConfigProperties, SpringValueRegistry springValueRegistry, PlaceholderHelper placeholderHelper) { - return new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, polarisPropertySourceManager, + return new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, springValueRegistry, placeholderHelper); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java index 2383cbf6be..b7be26460c 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java @@ -20,7 +20,6 @@ import com.tencent.cloud.polaris.config.adapter.AffectedConfigurationPropertiesRebinder; import com.tencent.cloud.polaris.config.adapter.PolarisConfigFileLocator; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.condition.ConditionalOnReflectRefreshType; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.config.PolarisCryptoConfigProperties; @@ -37,6 +36,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; import org.springframework.core.env.Environment; /** @@ -59,16 +59,10 @@ public PolarisCryptoConfigProperties polarisCryptoConfigProperties() { return new PolarisCryptoConfigProperties(); } - @Bean - @ConditionalOnMissingBean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return new PolarisPropertySourceManager(); - } - @Bean @ConditionalOnConnectRemoteServerEnabled public ConfigFileService configFileService(PolarisSDKContextManager polarisSDKContextManager) { - return ConfigFileServiceFactory.createConfigFileService(polarisSDKContextManager.getSDKContext()); + return ConfigFileServiceFactory.createConfigFileService(polarisSDKContextManager.getConfigSDKContext()); } @Bean @@ -77,11 +71,9 @@ public PolarisConfigFileLocator polarisConfigFileLocator( PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, - PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { return new PolarisConfigFileLocator(polarisConfigProperties, - polarisContextProperties, configFileService, - polarisPropertySourceManager, environment); + polarisContextProperties, configFileService, environment); } @Bean @@ -93,6 +85,7 @@ public ConfigurationModifier configurationModifier(PolarisConfigProperties polar } @Bean + @Primary @ConditionalOnMissingBean(search = SearchStrategy.CURRENT) @ConditionalOnReflectRefreshType public ConfigurationPropertiesRebinder affectedConfigurationPropertiesRebinder( diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java index bbd6f3e55c..711df1483e 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java @@ -43,13 +43,16 @@ /** * Optimize {@link ConfigurationPropertiesRebinder}, only rebuild affected beans. - * @author weihubeats 2022-7-10 + * + * @author weihubeats */ public class AffectedConfigurationPropertiesRebinder extends ConfigurationPropertiesRebinder { + private static final Logger LOGGER = LoggerFactory.getLogger(AffectedConfigurationPropertiesRebinder.class); private ApplicationContext applicationContext; private Map propertiesBeans = new HashMap<>(); + private final Map> propertiesBeanDefaultValues = new ConcurrentHashMap<>(); public AffectedConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) { @@ -125,8 +128,7 @@ private void initPropertiesBeanDefaultValues(Map defaultValues = new HashMap<>(); try { - Object instance = propertiesBean.getInstance().getClass().getDeclaredConstructor((Class[]) null) - .newInstance(); + Object instance = propertiesBean.getInstance().getClass().getDeclaredConstructor((Class[]) null).newInstance(); ReflectionUtils.doWithFields(instance.getClass(), field -> { try { field.setAccessible(true); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java index 2549f0773e..592368c689 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java @@ -29,10 +29,13 @@ * @author juanyinyang */ public interface PolarisConfigCustomExtensionLayer { + boolean isEnabled(); + void initRegisterConfig(PolarisConfigPropertyAutoRefresher polarisConfigPropertyAutoRefresher); - void initConfigFiles(Environment environment, CompositePropertySource compositePropertySource, PolarisPropertySourceManager polarisPropertySourceManager, ConfigFileService configFileService); + void initConfigFiles(Environment environment, CompositePropertySource compositePropertySource, ConfigFileService configFileService); void executeAfterLocateConfigReturning(CompositePropertySource compositePropertySource); + boolean executeRegisterPublishChangeListener(PolarisPropertySource polarisPropertySource); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java index 0e67d7a18f..56a3d08ade 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.config.adapter; @@ -65,39 +64,40 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { private final ConfigFileService configFileService; - private final PolarisPropertySourceManager polarisPropertySourceManager; - private final Environment environment; // this class provides customized logic for some customers to configure special business group files private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil.getPolarisConfigCustomExtensionLayer(); - public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { + public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, Environment environment) { this.polarisConfigProperties = polarisConfigProperties; this.polarisContextProperties = polarisContextProperties; this.configFileService = configFileService; - this.polarisPropertySourceManager = polarisPropertySourceManager; this.environment = environment; } @Override public PropertySource locate(Environment environment) { - CompositePropertySource compositePropertySource = new CompositePropertySource(POLARIS_CONFIG_PROPERTY_SOURCE_NAME); - try { - // load custom config extension files - initCustomPolarisConfigExtensionFiles(compositePropertySource); - // load spring boot default config files - initInternalConfigFiles(compositePropertySource); - // load custom config files - List configFileGroups = polarisConfigProperties.getGroups(); - if (CollectionUtils.isEmpty(configFileGroups)) { + if (polarisConfigProperties.isEnabled()) { + CompositePropertySource compositePropertySource = new CompositePropertySource(POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + try { + // load custom config extension files + initCustomPolarisConfigExtensionFiles(compositePropertySource); + // load spring boot default config files + initInternalConfigFiles(compositePropertySource); + // load custom config files + List configFileGroups = polarisConfigProperties.getGroups(); + if (CollectionUtils.isEmpty(configFileGroups)) { + return compositePropertySource; + } + initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); return compositePropertySource; } - initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); - return compositePropertySource; - } - finally { - afterLocatePolarisConfigExtension(compositePropertySource); + finally { + afterLocatePolarisConfigExtension(compositePropertySource); + } } + return null; } private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compositePropertySource) { @@ -105,7 +105,7 @@ private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compo LOGGER.debug("[SCT Config] PolarisConfigCustomExtensionLayer is not init, ignore the following execution steps"); return; } - polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, polarisPropertySourceManager, configFileService); + polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, configFileService); } private void afterLocatePolarisConfigExtension(CompositePropertySource compositePropertySource) { @@ -117,6 +117,9 @@ private void afterLocatePolarisConfigExtension(CompositePropertySource composite } private void initInternalConfigFiles(CompositePropertySource compositePropertySource) { + if (!polarisConfigProperties.isInternalEnabled()) { + return; + } List internalConfigFiles = getInternalConfigFiles(); for (ConfigFileMetadata configFile : internalConfigFiles) { @@ -124,7 +127,7 @@ private void initInternalConfigFiles(CompositePropertySource compositePropertySo compositePropertySource.addPropertySource(polarisPropertySource); - polarisPropertySourceManager.addPropertySource(polarisPropertySource); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); LOGGER.info("[SCT Config] Load and inject polaris config file. file = {}", configFile); } @@ -191,8 +194,12 @@ private void initCustomPolarisConfigFiles(CompositePropertySource compositePrope String namespace = polarisContextProperties.getNamespace(); for (ConfigFileGroup configFileGroup : configFileGroups) { - String group = configFileGroup.getName(); + String groupNamespace = configFileGroup.getNamespace(); + if (!StringUtils.hasText(groupNamespace)) { + groupNamespace = namespace; + } + String group = configFileGroup.getName(); if (!StringUtils.hasText(group)) { throw new IllegalArgumentException("polaris config group name cannot be empty."); } @@ -203,26 +210,26 @@ private void initCustomPolarisConfigFiles(CompositePropertySource compositePrope } for (String fileName : files) { - PolarisPropertySource polarisPropertySource = loadPolarisPropertySource(namespace, group, fileName); + PolarisPropertySource polarisPropertySource = loadPolarisPropertySource(groupNamespace, group, fileName); compositePropertySource.addPropertySource(polarisPropertySource); - polarisPropertySourceManager.addPropertySource(polarisPropertySource); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); - LOGGER.info("[SCT Config] Load and inject polaris config file success. namespace = {}, group = {}, fileName = {}", namespace, group, fileName); + LOGGER.info("[SCT Config] Load and inject polaris config file success. namespace = {}, group = {}, fileName = {}", groupNamespace, group, fileName); } } } private PolarisPropertySource loadPolarisPropertySource(String namespace, String group, String fileName) { ConfigKVFile configKVFile; - // unknown extension is resolved as properties file - if (ConfigFileFormat.isPropertyFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) { - configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName); - } - else if (ConfigFileFormat.isYamlFile(fileName)) { + // unknown extension is resolved as yaml file + if (ConfigFileFormat.isYamlFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) { configKVFile = configFileService.getConfigYamlFile(namespace, group, fileName); } + else if (ConfigFileFormat.isPropertyFile(fileName)) { + configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName); + } else { LOGGER.warn("[SCT Config] Unsupported config file. namespace = {}, group = {}, fileName = {}", namespace, group, fileName); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java index 47ff8d951b..1d983c1b3c 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java @@ -18,14 +18,17 @@ package com.tencent.cloud.polaris.config.adapter; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.logger.PolarisConfigLoggerContext; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import com.tencent.polaris.configuration.client.internal.CompositeConfigFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +41,7 @@ * 1. Listen to the Polaris server configuration publishing event 2. Write the changed * configuration content to propertySource 3. Refresh the context through contextRefresher * - * @author lepdou 2022-03-28 + * @author lepdou */ public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationListener, PolarisConfigPropertyRefresher { @@ -46,16 +49,13 @@ public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationL private final PolarisConfigProperties polarisConfigProperties; - private final PolarisPropertySourceManager polarisPropertySourceManager; - private final AtomicBoolean registered = new AtomicBoolean(false); // this class provides customized logic for some customers to configure special business group files private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil.getPolarisConfigCustomExtensionLayer(); - public PolarisConfigPropertyAutoRefresher(PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager) { + public PolarisConfigPropertyAutoRefresher(PolarisConfigProperties polarisConfigProperties) { this.polarisConfigProperties = polarisConfigProperties; - this.polarisPropertySourceManager = polarisPropertySourceManager; } @Override @@ -68,7 +68,7 @@ private void registerPolarisConfigPublishEvent() { return; } - List polarisPropertySources = polarisPropertySourceManager.getAllPropertySources(); + List polarisPropertySources = PolarisPropertySourceManager.getAllPropertySources(); if (CollectionUtils.isEmpty(polarisPropertySources)) { return; } @@ -82,8 +82,18 @@ private void registerPolarisConfigPublishEvent() { // register polaris config publish event for (PolarisPropertySource polarisPropertySource : polarisPropertySources) { - registerPolarisConfigPublishChangeListener(polarisPropertySource); - customRegisterPolarisConfigPublishChangeListener(polarisPropertySource); + if (polarisPropertySource.getConfigKVFile() instanceof CompositeConfigFile) { + CompositeConfigFile configKVFile = (CompositeConfigFile) polarisPropertySource.getConfigKVFile(); + for (ConfigKVFile cf : configKVFile.getConfigKVFiles()) { + PolarisPropertySource p = new PolarisPropertySource(cf.getNamespace(), cf.getFileGroup(), cf.getFileName(), cf, new HashMap<>()); + registerPolarisConfigPublishChangeListener(p); + customRegisterPolarisConfigPublishChangeListener(p); + } + } + else { + registerPolarisConfigPublishChangeListener(polarisPropertySource); + customRegisterPolarisConfigPublishChangeListener(polarisPropertySource); + } } } @@ -96,6 +106,7 @@ private void customInitRegisterPolarisConfig(PolarisConfigPropertyAutoRefresher } public void registerPolarisConfigPublishChangeListener(PolarisPropertySource polarisPropertySource) { + LOGGER.info("{} will register polaris config publish listener", polarisPropertySource.getPropertySourceName()); polarisPropertySource.getConfigKVFile() .addChangeListener((ConfigKVFileChangeListener) configKVFileChangeEvent -> { @@ -144,4 +155,12 @@ private void customRegisterPolarisConfigPublishChangeListener(PolarisPropertySou } polarisConfigCustomExtensionLayer.executeRegisterPublishChangeListener(polarisPropertySource); } + + /** + * Just for junit test. + * @param registered if the polaris config property auto refresh is registered + */ + public void setRegistered(boolean registered) { + this.registered.set(registered); + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java index c1dcefa51e..34da593761 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java @@ -20,6 +20,7 @@ import java.util.Map; +import com.tencent.cloud.polaris.config.utils.PolarisPropertySourceUtils; import com.tencent.polaris.configuration.api.core.ConfigKVFile; import org.springframework.core.env.MapPropertySource; @@ -40,7 +41,7 @@ public class PolarisPropertySource extends MapPropertySource { private final ConfigKVFile configKVFile; public PolarisPropertySource(String namespace, String group, String fileName, ConfigKVFile configKVFile, Map source) { - super(namespace + "-" + group + "-" + fileName, source); + super(PolarisPropertySourceUtils.generateName(namespace, group, fileName), source); this.namespace = namespace; this.group = group; @@ -64,7 +65,7 @@ public String getPropertySourceName() { return namespace + "-" + group + "-" + fileName; } - ConfigKVFile getConfigKVFile() { + public ConfigKVFile getConfigKVFile() { return configKVFile; } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java index f8736e20ef..096ab7d96f 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceManager.java @@ -28,15 +28,25 @@ * * @author lepdou 2022-03-28 */ -public class PolarisPropertySourceManager { +public final class PolarisPropertySourceManager { - private final Map polarisPropertySources = new ConcurrentHashMap<>(); + private static final Map polarisPropertySources = new ConcurrentHashMap<>(); - public void addPropertySource(PolarisPropertySource polarisPropertySource) { - polarisPropertySources.putIfAbsent(polarisPropertySource.getPropertySourceName(), polarisPropertySource); + private PolarisPropertySourceManager() { } - public List getAllPropertySources() { + public static void addPropertySource(PolarisPropertySource polarisPropertySource) { + polarisPropertySources.put(polarisPropertySource.getPropertySourceName(), polarisPropertySource); + } + + public static List getAllPropertySources() { return new ArrayList<>(polarisPropertySources.values()); } + + /** + * Just for test. + */ + public static void clearPropertySources() { + polarisPropertySources.clear(); + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java index dffb23adff..146648ca3b 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshAffectedContextRefresher.java @@ -59,9 +59,8 @@ public class PolarisRefreshAffectedContextRefresher extends PolarisConfigPropert private TypeConverter typeConverter; public PolarisRefreshAffectedContextRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, SpringValueRegistry springValueRegistry, - PlaceholderHelper placeholderHelper) { - super(polarisConfigProperties, polarisPropertySourceManager); + SpringValueRegistry springValueRegistry, PlaceholderHelper placeholderHelper) { + super(polarisConfigProperties); this.springValueRegistry = springValueRegistry; this.placeholderHelper = placeholderHelper; } @@ -100,7 +99,7 @@ private void updateSpringValue(SpringValue springValue) { * Logic transplanted from DefaultListableBeanFactory. * * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, - * java.lang.String, java.util.Set, org.springframework.beans.TypeConverter) + * String, Set, TypeConverter) */ private Object resolvePropertyValue(SpringValue springValue) { // value will never be null diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java index a13a68be5a..3c2ca5ac72 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisRefreshEntireContextRefresher.java @@ -35,12 +35,16 @@ public class PolarisRefreshEntireContextRefresher extends PolarisConfigPropertyA private final ContextRefresher contextRefresher; public PolarisRefreshEntireContextRefresher(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager, ContextRefresher contextRefresher) { - super(polarisConfigProperties, polarisPropertySourceManager); + super(polarisConfigProperties); this.contextRefresher = contextRefresher; } + @Override + public void refreshSpringValue(String changedKey) { + // do nothing,all config will be refreshed by contextRefresher.refresh + } + @Override public void refreshConfigurationProperties(Set changeKeys) { contextRefresher.refresh(); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java index 343a5b3191..bf61aac4de 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java @@ -30,20 +30,25 @@ public final class PolarisServiceLoaderUtil { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisServiceLoaderUtil.class); - private PolarisServiceLoaderUtil() { - } // this class provides customized logic for some customers to configure special business group files private static PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer; + static { ServiceLoader polarisConfigCustomExtensionLayerLoader = ServiceLoader.load(PolarisConfigCustomExtensionLayer.class); Iterator polarisConfigCustomExtensionLayerIterator = polarisConfigCustomExtensionLayerLoader.iterator(); // Generally, there is only one implementation class. If there are multiple, the last one is loaded while (polarisConfigCustomExtensionLayerIterator.hasNext()) { - polarisConfigCustomExtensionLayer = polarisConfigCustomExtensionLayerIterator.next(); - LOGGER.info("[SCT Config] PolarisConfigFileLocator init polarisConfigCustomExtensionLayer:{}", polarisConfigCustomExtensionLayer); + PolarisConfigCustomExtensionLayer temp = polarisConfigCustomExtensionLayerIterator.next(); + if (temp.isEnabled()) { + polarisConfigCustomExtensionLayer = temp; + LOGGER.info("[SCT Config] PolarisConfigFileLocator init polarisConfigCustomExtensionLayer:{}", polarisConfigCustomExtensionLayer); + } } } + private PolarisServiceLoaderUtil() { + } + public static PolarisConfigCustomExtensionLayer getPolarisConfigCustomExtensionLayer() { return polarisConfigCustomExtensionLayer; } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java index 85e1f22594..ee0a3d2770 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java @@ -108,7 +108,8 @@ public boolean isAsync() { Set interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null; Set interestedKeyPrefixes = - annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) : null; + annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes) + : null; addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java index 0b5c2c335b..80cff02b8e 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/ConfigFileGroup.java @@ -15,7 +15,6 @@ * specific language governing permissions and limitations under the License. * */ - package com.tencent.cloud.polaris.config.config; import java.util.List; @@ -27,6 +26,8 @@ */ public class ConfigFileGroup { + private String namespace; + /** * group name. */ @@ -37,6 +38,14 @@ public class ConfigFileGroup { */ private List files; + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + public String getName() { return name; } @@ -55,6 +64,10 @@ public void setFiles(List files) { @Override public String toString() { - return "ConfigFileGroup{" + "name='" + name + '\'' + ", file=" + files + '}'; + return "ConfigFileGroup{" + + "namespace='" + namespace + '\'' + + ", name='" + name + '\'' + + ", files=" + files + + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java index 6a014aa043..4586134eef 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java @@ -50,6 +50,8 @@ public class PolarisConfigProperties { @Value("${spring.cloud.polaris.config.port:#{'8093'}}") private int port = 8093; + private String token; + /** * Whether to automatically update to the spring context when the configuration file. * is updated @@ -89,6 +91,11 @@ public class PolarisConfigProperties { */ private String localFileRootPath = "./polaris/backup/config"; + /** + * If internal config file enabled. + */ + private boolean internalEnabled = true; + public boolean isEnabled() { return enabled; } @@ -113,6 +120,14 @@ public void setPort(int port) { this.port = port; } + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + public boolean isAutoRefresh() { return autoRefresh; } @@ -168,4 +183,30 @@ public String getLocalFileRootPath() { public void setLocalFileRootPath(String localFileRootPath) { this.localFileRootPath = localFileRootPath; } + + public boolean isInternalEnabled() { + return internalEnabled; + } + + public void setInternalEnabled(boolean internalEnabled) { + this.internalEnabled = internalEnabled; + } + + @Override + public String toString() { + return "PolarisConfigProperties{" + + "enabled=" + enabled + + ", address='" + address + '\'' + + ", port=" + port + + ", token='" + token + '\'' + + ", autoRefresh=" + autoRefresh + + ", shutdownIfConnectToConfigServerFailed=" + shutdownIfConnectToConfigServerFailed + + ", preference=" + preference + + ", refreshType=" + refreshType + + ", groups=" + groups + + ", dataSource='" + dataSource + '\'' + + ", localFileRootPath='" + localFileRootPath + '\'' + + ", internalEnabled=" + internalEnabled + + '}'; + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java index 108c740953..52bdff7564 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpoint.java @@ -33,15 +33,13 @@ * * @author shuiqingliu **/ -@Endpoint(id = "polaris-config") +@Endpoint(id = "polarisconfig") public class PolarisConfigEndpoint { private final PolarisConfigProperties polarisConfigProperties; - private final PolarisPropertySourceManager polarisPropertySourceManager; - public PolarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager) { + public PolarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties) { this.polarisConfigProperties = polarisConfigProperties; - this.polarisPropertySourceManager = polarisPropertySourceManager; } @ReadOperation @@ -49,7 +47,7 @@ public Map polarisConfig() { Map configInfo = new HashMap<>(); configInfo.put("PolarisConfigProperties", polarisConfigProperties); - List propertySourceList = polarisPropertySourceManager.getAllPropertySources(); + List propertySourceList = PolarisPropertySourceManager.getAllPropertySources(); configInfo.put("PolarisPropertySource", propertySourceList); return configInfo; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java index 815d5798e8..3f530c3ab1 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointAutoConfiguration.java @@ -18,7 +18,6 @@ package com.tencent.cloud.polaris.config.endpoint; import com.tencent.cloud.polaris.config.ConditionalOnPolarisConfigEnabled; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint; @@ -41,8 +40,7 @@ public class PolarisConfigEndpointAutoConfiguration { @Bean @ConditionalOnAvailableEndpoint @ConditionalOnMissingBean - public PolarisConfigEndpoint polarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager) { - return new PolarisConfigEndpoint(polarisConfigProperties, polarisPropertySourceManager); + public PolarisConfigEndpoint polarisConfigEndpoint(PolarisConfigProperties polarisConfigProperties) { + return new PolarisConfigEndpoint(polarisConfigProperties); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java index 330e62fb0f..e05a939d81 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java @@ -66,7 +66,6 @@ public final class PolarisConfigChangeEventListener implements ApplicationListen */ @Override public void onApplicationEvent(@NonNull ApplicationEvent event) { - // Initialize application all environment properties . if (event instanceof ApplicationStartedEvent && started.compareAndSet(false, true)) { ApplicationStartedEvent applicationStartedEvent = (ApplicationStartedEvent) event; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java index 85bd2ab424..120ef7c73e 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java @@ -52,11 +52,9 @@ *

This source file was reference from: * * AbstractConfig - * * @author Palmer Xu 2022-06-06 */ public final class PolarisConfigListenerContext { - /** * Logger instance. */ diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java index 54f0c6246d..5989781122 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java @@ -21,7 +21,6 @@ import java.util.Collections; import com.tencent.cloud.polaris.config.adapter.PolarisConfigRefreshScopeAnnotationDetector; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefresher; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.enums.RefreshType; @@ -44,7 +43,7 @@ import static com.tencent.cloud.polaris.config.condition.ReflectRefreshTypeCondition.POLARIS_CONFIG_REFRESH_TYPE; /** - * When {@link com.tencent.cloud.polaris.config.adapter.PolarisConfigRefreshScopeAnnotationDetector} detects that + * When {@link PolarisConfigRefreshScopeAnnotationDetector} detects that * the annotation {@code @RefreshScope} exists and is used, but the config refresh type * {@code spring.cloud.polaris.config.refresh-type} is still {@code RefreshType.REFLECT}, then the framework will * automatically switch the config refresh type to {@code RefreshType.REFRESH_CONTEXT}. @@ -112,7 +111,7 @@ private void removeRelatedBeansOfReflect(ConfigurableApplicationContext applicat beanFactory.removeBeanDefinition(REFLECT_REBINDER_BEAN_NAME); } catch (BeansException e) { - // If there is a removeBean exception in this code, do not affect the main process startup. Some user usage may cause the polarisReflectPropertySourceAutoRefresher to not load, and the removeBeanDefinition will report an error + // If there is a removeBean exception in this code, do not affect the main process startup. Some user usage may cause the polarisReflectPropertySourceAutoRefresher to not load, and the removeBeanDefinition will report an error LOGGER.debug("removeRelatedBeansOfReflect occur error:", e); } } @@ -122,12 +121,10 @@ private void registerRefresherBeanOfRefreshContext(ConfigurableApplicationContex AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(PolarisRefreshEntireContextRefresher.class); PolarisConfigProperties polarisConfigProperties = beanFactory.getBean(PolarisConfigProperties.class); - PolarisPropertySourceManager polarisPropertySourceManager = beanFactory.getBean(PolarisPropertySourceManager.class); ContextRefresher contextRefresher = beanFactory.getBean(ContextRefresher.class); ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues(); constructorArgumentValues.addIndexedArgumentValue(0, polarisConfigProperties); - constructorArgumentValues.addIndexedArgumentValue(1, polarisPropertySourceManager); - constructorArgumentValues.addIndexedArgumentValue(2, contextRefresher); + constructorArgumentValues.addIndexedArgumentValue(1, contextRefresher); beanFactory.registerBeanDefinition(REFRESH_CONTEXT_REFRESHER_BEAN_NAME, beanDefinition); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java index 6a1058cd4d..ce34ab9540 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java @@ -32,7 +32,7 @@ public class PolarisConfigLoggerApplicationListener implements ApplicationListener { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisConfigLoggerApplicationListener.class); /** - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + * @see ApplicationListener#onApplicationEvent(ApplicationEvent) */ @Override public void onApplicationEvent(ApplicationEvent event) { diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java index 42f69f8d7c..cfbc5385bf 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/PolarisProcessor.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.config.spring.annotation; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java new file mode 100644 index 0000000000..4a1507a624 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/PolarisAdaptorTsfConfigAutoConfiguration.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.config.ConditionalOnPolarisConfigEnabled; +import com.tencent.cloud.polaris.config.tsf.controller.PolarisAdaptorTsfConfigController; +import com.tencent.tsf.consul.config.watch.TsfConsulConfigRefreshEventListener; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author juanyinyang + * @Date Jul 23, 2023 3:52:48 PM + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +@ConditionalOnPolarisConfigEnabled +public class PolarisAdaptorTsfConfigAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "spring.cloud.consul.config.watch.enabled", matchIfMissing = true) + public TsfConsulConfigRefreshEventListener polarisAdaptorTsfConsulRefreshEventListener() { + return new TsfConsulConfigRefreshEventListener(); + } + + /** + * 初始化本类的条件: + * 1、关闭Spring Cloud Consul Config配置开关(如果开启Consul Config配置开关,那么初始化的是tsf自身的类ConfigController) + * 2、开启北极星配置(本类通过注解@ConditionalOnPolarisConfigEnabled开启) + * 3、tsf.config.instance.released-config.lookup.enabled的开关是打开的(默认不配置就是打开的). + * @return polarisAdaptorTsfConfigController + */ + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "tsf.config.instance.released-config.lookup.enabled", matchIfMissing = true) + public PolarisAdaptorTsfConfigController polarisAdaptorTsfConfigController() { + return new PolarisAdaptorTsfConfigController(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java new file mode 100755 index 0000000000..0c4760c0c0 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/controller/PolarisAdaptorTsfConfigController.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.tsf.controller; + + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author juanyinyang + * @Date 2023年8月2日 下午5:08:29 + */ +@RestController +public class PolarisAdaptorTsfConfigController { + + private static final Logger LOG = LoggerFactory.getLogger(PolarisAdaptorTsfConfigController.class); + + @Autowired + Environment environment; + + public PolarisAdaptorTsfConfigController() { + LOG.info("init PolarisAdaptorTsfConfigController"); + } + + /** + * 兼容目前TSF控制台的用法,提供北极星查询当前SDK配置接口. + * @return config map + */ + @RequestMapping("/tsf/innerApi/config/findAllConfig") + public Map findAllConfig() { + List propertySourceList = PolarisPropertySourceManager.getAllPropertySources(); + + Set keys = new HashSet<>(); + for (PolarisPropertySource propertySource : propertySourceList) { + keys.addAll(Arrays.asList(propertySource.getPropertyNames())); + } + + return keys.stream() + .collect(HashMap::new, (map, key) -> map.put(key, environment.getProperty(key)), HashMap::putAll); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.java new file mode 100644 index 0000000000..d6084889e1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptAESProvider.java @@ -0,0 +1,48 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.tsf.encrypt; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConfigEncryptAESProvider extends ConfigEncryptProvider { + + private static final Logger log = LoggerFactory.getLogger(ConfigEncryptAESProvider.class); + + @Override + public String encrypt(String content, String password) { + try { + return EncryptAlgorithm.AES256.encrypt(content, password); + } + catch (Exception e) { + log.error("Error on encrypting.", e); + throw e; + } + } + + @Override + public String decrypt(String encryptedContent, String password) { + try { + return EncryptAlgorithm.AES256.decrypt(encryptedContent, password); + } + catch (Exception e) { + log.error("Error on decrypting.", e); + throw e; + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.java similarity index 53% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java rename to spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.java index 05e1366b45..e5cafca173 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/FeignRouterLabelResolver.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProvider.java @@ -15,27 +15,30 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.router.spi; - -import java.util.Map; -import java.util.Set; - -import feign.RequestTemplate; - -import org.springframework.core.Ordered; +package com.tencent.cloud.polaris.config.tsf.encrypt; /** - * Router label resolver for feign request. - * @author lepdou 2022-07-20 + * TSF 配置加密提供器接口. + * + * @author hongweizhu */ -public interface FeignRouterLabelResolver extends Ordered { +public abstract class ConfigEncryptProvider { + + /** + * 加密. + * + * @param content 明文 + * @param password 密码 + * @return 密文 + */ + public abstract String encrypt(String content, String password); /** - * Resolve labels from feign request. User can customize expression parser to extract labels. + * 解密. * - * @param requestTemplate the feign request. - * @param expressionLabelKeys the expression labels which are configured in router rule. - * @return resolved labels + * @param encryptedContent 密文 + * @param password 密码 + * @return 明文 */ - Map resolve(RequestTemplate requestTemplate, Set expressionLabelKeys); + public abstract String decrypt(String encryptedContent, String password); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java new file mode 100644 index 0000000000..980417bb41 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/ConfigEncryptProviderFactory.java @@ -0,0 +1,39 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.tsf.encrypt; + +public final class ConfigEncryptProviderFactory { + + private static ConfigEncryptProvider configEncryptProvider = null; + + private ConfigEncryptProviderFactory() { + } + + public static ConfigEncryptProvider getInstance() { + if (null == configEncryptProvider) { + try { + Class providerClass = Class.forName(EncryptConfig.getProviderClass()); + configEncryptProvider = (ConfigEncryptProvider) providerClass.newInstance(); + } + catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + return configEncryptProvider; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java new file mode 100644 index 0000000000..1ce56b75a7 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptAlgorithm.java @@ -0,0 +1,146 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.tsf.encrypt; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Base64; + +public class EncryptAlgorithm { + public static class AES256 { + + /** + * 加密. + * + * @param content 明文 + * @param password 密钥 + * @return 密文 + */ + public static final String encrypt(String content, String password) { + if (null == password || "".equals(password)) { + throw new PasswordNotFoundException(); + } + try { + // AES SK生成器 + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + // SHA-256摘要密钥后生成安全随机数 + SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); + sr.setSeed(SHA256.encode(password)); + kgen.init(256, sr); + // 生成秘密(对称)密钥 + SecretKey secretKey = kgen.generateKey(); + // 返回基本编码格式的密钥 + byte[] enCodeFormat = secretKey.getEncoded(); + // 根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称 + SecretKeySpec skSpec = new SecretKeySpec(enCodeFormat, "AES"); + // 将提供程序添加到下一个可用位置 + Security.addProvider(new BouncyCastleProvider()); + // 创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。 + // "AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称 + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + // 初始化cipher:加密模式 + cipher.init(Cipher.ENCRYPT_MODE, skSpec); + byte[] byteContent = content.getBytes(StandardCharsets.UTF_8); + byte[] cryptograph = cipher.doFinal(byteContent); + byte[] enryptedContent = Base64.encode(cryptograph); + return new String(enryptedContent); + } + catch (Exception e) { + throw new RuntimeException("Failed encrypt.", e); + } + } + + /** + * 解密. + * + * @param encryptedContent 密文 + * @param password 密钥 + * @return 明文 + */ + public static final String decrypt(String encryptedContent, String password) { + if (null == password || "".equals(password)) { + throw new PasswordNotFoundException(); + } + try { + // AES SK生成器 + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + // SHA-256摘要密钥后生成安全随机数 + SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); + sr.setSeed(SHA256.encode(password)); + kgen.init(256, sr); + // 生成秘密(对称)密钥 + SecretKey secretKey = kgen.generateKey(); + // 返回基本编码格式的密钥 + byte[] enCodeFormat = secretKey.getEncoded(); + // 根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称 + SecretKeySpec skSpec = new SecretKeySpec(enCodeFormat, "AES"); + // 将提供程序添加到下一个可用位置 + Security.addProvider(new BouncyCastleProvider()); + // 创建一个实现指定转换的 Cipher对象,该转换由指定的提供程序提供。 + // "AES/ECB/PKCS7Padding":转换的名称;"BC":提供程序的名称 + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); + // 初始化cipher:解密模式 + cipher.init(Cipher.DECRYPT_MODE, skSpec); + byte[] result = cipher.doFinal(Base64.decode(encryptedContent.getBytes(StandardCharsets.UTF_8))); + return new String(result); + } + catch (Exception e) { + throw new RuntimeException("Failed decrypt.", e); + } + } + } + + public static class SHA256 { + + /** + * 计算SHA-256摘要. + * + * @param content 原文 + * @return 摘要 + * @throws NoSuchAlgorithmException 算法不存在时抛出 + */ + public static byte[] encode(String content) throws NoSuchAlgorithmException { + MessageDigest digester = MessageDigest.getInstance("SHA-256"); + digester.update(content.getBytes(StandardCharsets.UTF_8)); + return digester.digest(); + } + } + + public static class PasswordNotFoundException extends RuntimeException { + + /** + * serialVersionUID. + */ + private static final long serialVersionUID = -2843758461182470411L; + + public PasswordNotFoundException() { + super("Password not found."); + } + + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java new file mode 100644 index 0000000000..9cd08140f9 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/tsf/encrypt/EncryptConfig.java @@ -0,0 +1,115 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.tsf.encrypt; + +import org.springframework.util.StringUtils; + +public final class EncryptConfig { + + private static final String PASSWORD_KEY = "tsf_config_encrypt_password"; + /** + * 加密前缀. + */ + public static String ENCRYPT_PREFIX = "ENC("; + /** + * 加密后缀. + */ + public static String ENCRYPT_SUFFIX = ")"; + /** + * 密码. + */ + private static String password; + /** + * 加解密提供器类名. + */ + private static String providerClass = "com.tencent.cloud.polaris.config.tsf.encrypt.ConfigEncryptAESProvider"; + + static { + // 环境变量 + if (null != System.getenv(PASSWORD_KEY)) { + password = System.getenv(PASSWORD_KEY); + } + // JVM参数 + if (null != System.getProperty(PASSWORD_KEY)) { + password = System.getProperty(PASSWORD_KEY); + } + } + + private EncryptConfig() { + + } + + /** + * 是否开启配置,判断 password 是否为空. + * @return true:开启;false:关闭 + */ + public static Boolean getEnabled() { + return !StringUtils.isEmpty(password); + } + + public static String getPassword() { + return EncryptConfig.password; + } + + public static void setPassword(String password) { + EncryptConfig.password = password; + } + + public static ConfigEncryptProvider getProvider() { + return ConfigEncryptProviderFactory.getInstance(); + } + + public static String getProviderClass() { + return providerClass; + } + + public static void setProviderClass(String providerClass) { + EncryptConfig.providerClass = providerClass; + } + + /** + * 是否需要进行解密. + * + * @param content 判断对象 + * @return true:需要解密;false:不需要解密 + */ + public static Boolean needDecrypt(Object content) { + if (null == content) { + return false; + } + else { + String stringValue = String.valueOf(content); + return stringValue.startsWith(ENCRYPT_PREFIX) && stringValue.endsWith(ENCRYPT_SUFFIX); + } + } + + /** + * 获取真实密文. + * + * @param content 原始配置值 + * @return 真实密文 + */ + public static String realContent(Object content) { + if (null != content) { + String stringValue = String.valueOf(content); + return stringValue.substring(ENCRYPT_PREFIX.length(), stringValue.length() - ENCRYPT_SUFFIX.length()); + } + return null; + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java new file mode 100644 index 0000000000..6eea01f4ba --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/utils/PolarisPropertySourceUtils.java @@ -0,0 +1,34 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config.utils; + +/** + * Utils for PolarisPropertySource. + * + * @author Haotian Zhang + */ +public final class PolarisPropertySourceUtils { + + private PolarisPropertySourceUtils() { + + } + + public static String generateName(String namespace, String group, String fileName) { + return namespace + "-" + group + "-" + fileName; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java new file mode 100644 index 0000000000..8845ac391a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeCallback.java @@ -0,0 +1,28 @@ +/* + * 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.tsf.consul.config.watch; + +public interface ConfigChangeCallback { + + /** + * 配置变更回调函数. + * @param lastConfigProperty 旧的配置属性 + * @param newConfigProperty 新的配置属性 + */ + void callback(ConfigProperty lastConfigProperty, ConfigProperty newConfigProperty); +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.java new file mode 100644 index 0000000000..7f51153848 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigChangeListener.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.tsf.consul.config.watch; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.stereotype.Component; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface ConfigChangeListener { + String prefix() default ""; + + String[] value() default {}; + + boolean async() default false; + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.java new file mode 100644 index 0000000000..45418efb1a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/ConfigProperty.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.tsf.consul.config.watch; + +public class ConfigProperty { + + private String key; + + private Object value; + + public ConfigProperty(String key, Object value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.java new file mode 100644 index 0000000000..688ffbe931 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/tsf/consul/config/watch/TsfConsulConfigRefreshEventListener.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.tsf.consul.config.watch; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent; +import com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext; +import com.tencent.cloud.polaris.config.listener.SyncConfigChangeListener; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.lang.NonNull; +import org.springframework.util.StringUtils; + +public class TsfConsulConfigRefreshEventListener implements BeanPostProcessor, PriorityOrdered { + private static final String DOT = "."; + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + @Override + public Object postProcessBeforeInitialization(@NonNull Object obj, @NonNull String beanName) throws BeansException { + return obj; + } + + @Override + public Object postProcessAfterInitialization(@NonNull Object obj, @NonNull String beanName) throws BeansException { + Class clz = obj.getClass(); + if (!clz.isAnnotationPresent(ConfigChangeListener.class) || !ConfigChangeCallback.class.isAssignableFrom(clz)) { + return obj; + } + + ConfigChangeListener targetAnno = clz.getAnnotation(ConfigChangeListener.class); + String watchedPrefix = targetAnno.prefix(); + String[] watchedConfirmedValue = targetAnno.value(); + boolean isAsync = targetAnno.async(); + if (watchedConfirmedValue.length == 0 && StringUtils.isEmpty(watchedPrefix)) { + return obj; + } + + ConfigChangeCallback bean = (ConfigChangeCallback) obj; + com.tencent.cloud.polaris.config.listener.ConfigChangeListener listener = new SyncConfigChangeListener() { + @Override + public void onChange(ConfigChangeEvent changeEvent) { + List paramList = parseConfigChangeEventToTsfCallbackParam(changeEvent); + for (TsfCallbackParam param : paramList) { + if (isAsync()) { + PolarisConfigListenerContext.executor() + .execute(() -> bean.callback(param.oldValue, param.newValue)); + } + else { + bean.callback(param.oldValue, param.newValue); + } + } + } + + @Override + public boolean isAsync() { + return isAsync; + } + }; + + Set interestedKeys = new HashSet<>(); + Set interestedKeyPrefixes = new HashSet<>(); + if (watchedConfirmedValue.length > 0) { + for (String value : watchedConfirmedValue) { + interestedKeys.add(StringUtils.isEmpty(watchedPrefix) ? value : watchedPrefix + DOT + value); + } + } + else { + interestedKeyPrefixes.add(watchedPrefix); + } + + PolarisConfigListenerContext.addChangeListener(listener, interestedKeys, interestedKeyPrefixes); + return bean; + } + + private List parseConfigChangeEventToTsfCallbackParam(ConfigChangeEvent event) { + List result = new ArrayList<>(); + Set changedKeys = event.changedKeys(); + for (String changedKey : changedKeys) { + ConfigProperty oldValue = new ConfigProperty(changedKey, event.getChange(changedKey).getOldValue()); + ConfigProperty newValue = new ConfigProperty(changedKey, event.getChange(changedKey).getNewValue()); + TsfCallbackParam param = new TsfCallbackParam(oldValue, newValue); + result.add(param); + } + return result; + } + + static class TsfCallbackParam { + ConfigProperty oldValue; + ConfigProperty newValue; + + TsfCallbackParam(ConfigProperty oldValue, ConfigProperty newValue) { + this.oldValue = oldValue; + this.newValue = newValue; + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories index 98221a39af..f9eb6a0bdd 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories @@ -1,5 +1,8 @@ -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration,\ - com.tencent.cloud.polaris.config.endpoint.PolarisConfigEndpointAutoConfiguration + com.tencent.cloud.polaris.config.endpoint.PolarisConfigEndpointAutoConfiguration,\ + com.tencent.cloud.polaris.config.tsf.PolarisAdaptorTsfConfigAutoConfiguration,\ + com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration + diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java index acdeb050c3..42dbd028f2 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java @@ -29,6 +29,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.configuration.api.core.ConfigFileService; import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -42,8 +43,7 @@ /** * test for {@link PolarisConfigFileLocator}. - * - * @author lepdou 2022-06-11 + *@author lepdou 2022-06-11 */ @ExtendWith(MockitoExtension.class) public class PolarisConfigFileLocatorTest { @@ -57,14 +57,17 @@ public class PolarisConfigFileLocatorTest { @Mock private ConfigFileService configFileService; @Mock - private PolarisPropertySourceManager polarisPropertySourceManager; - @Mock private Environment environment; + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testLoadApplicationPropertiesFile() { PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, - configFileService, polarisPropertySourceManager, environment); + configFileService, environment); when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); when(polarisContextProperties.getService()).thenReturn(testServiceName); @@ -86,7 +89,9 @@ public void testLoadApplicationPropertiesFile() { when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yaml")).thenReturn(emptyConfigFile); + when(polarisConfigProperties.isEnabled()).thenReturn(true); when(polarisConfigProperties.getGroups()).thenReturn(null); + when(polarisConfigProperties.isInternalEnabled()).thenReturn(true); when(environment.getActiveProfiles()).thenReturn(new String[] {}); PropertySource propertySource = locator.locate(environment); @@ -99,7 +104,7 @@ public void testLoadApplicationPropertiesFile() { @Test public void testActiveProfileFilesPriorityBiggerThanDefault() { PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, - configFileService, polarisPropertySourceManager, environment); + configFileService, environment); when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); when(polarisContextProperties.getService()).thenReturn(testServiceName); @@ -133,7 +138,9 @@ public void testActiveProfileFilesPriorityBiggerThanDefault() { when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yml")).thenReturn(emptyConfigFile); when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yaml")).thenReturn(emptyConfigFile); + when(polarisConfigProperties.isEnabled()).thenReturn(true); when(polarisConfigProperties.getGroups()).thenReturn(null); + when(polarisConfigProperties.isInternalEnabled()).thenReturn(true); when(environment.getActiveProfiles()).thenReturn(new String[] {"dev"}); PropertySource propertySource = locator.locate(environment); @@ -146,7 +153,7 @@ public void testActiveProfileFilesPriorityBiggerThanDefault() { @Test public void testGetCustomFiles() { PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, - configFileService, polarisPropertySourceManager, environment); + configFileService, environment); when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); when(polarisContextProperties.getService()).thenReturn(testServiceName); @@ -170,7 +177,9 @@ public void testGetCustomFiles() { configFileGroup.setFiles(Lists.newArrayList(customFile1, customFile2)); customFiles.add(configFileGroup); + when(polarisConfigProperties.isEnabled()).thenReturn(true); when(polarisConfigProperties.getGroups()).thenReturn(customFiles); + when(polarisConfigProperties.isInternalEnabled()).thenReturn(true); when(environment.getActiveProfiles()).thenReturn(new String[] {}); // file1.properties diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java index ba38d135e9..0d10255fa1 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java @@ -24,7 +24,6 @@ import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; import com.tencent.cloud.polaris.config.spring.property.SpringValue; @@ -32,6 +31,7 @@ import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -59,8 +59,6 @@ public class PolarisPropertiesSourceAutoRefresherTest { private final String testFileName = "application.properties"; @Mock private PolarisConfigProperties polarisConfigProperties; - @Mock - private PolarisPropertySourceManager polarisPropertySourceManager; @Mock private SpringValueRegistry springValueRegistry; @@ -68,10 +66,14 @@ public class PolarisPropertiesSourceAutoRefresherTest { @Mock private PlaceholderHelper placeholderHelper; + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testConfigFileChanged() throws Exception { - PolarisRefreshAffectedContextRefresher refresher = new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, - polarisPropertySourceManager, springValueRegistry, placeholderHelper); + PolarisRefreshAffectedContextRefresher refresher = new PolarisRefreshAffectedContextRefresher(polarisConfigProperties, springValueRegistry, placeholderHelper); ConfigurableApplicationContext applicationContext = mock(ConfigurableApplicationContext.class); ConfigurableListableBeanFactory beanFactory = mock(ConfigurableListableBeanFactory.class); TypeConverter typeConverter = mock(TypeConverter.class); @@ -99,7 +101,7 @@ public void testConfigFileChanged() throws Exception { PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, file, content); - when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); ConfigPropertyChangeInfo changeInfo2 = new ConfigPropertyChangeInfo("k4", null, "v4", ChangeType.ADDED); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java index ebde3e470b..058d4d1bae 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/condition/ConditionalOnReflectRefreshTypeTest.java @@ -24,7 +24,6 @@ import com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; -import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshAffectedContextRefresher; import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefresher; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; @@ -107,7 +106,6 @@ public void testWithoutReflectEnabled() { .withPropertyValues("spring.cloud.polaris.config.enabled=true"); contextRunner.run(context -> { assertThat(context).hasSingleBean(PolarisConfigProperties.class); - assertThat(context).hasSingleBean(PolarisPropertySourceManager.class); assertThat(context).hasSingleBean(ContextRefresher.class); assertThat(context).hasSingleBean(PolarisRefreshEntireContextRefresher.class); }); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java index 92933fcc77..0389f16079 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/endpoint/PolarisConfigEndpointTest.java @@ -26,13 +26,13 @@ import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; /** * Test for polaris config endpoint. @@ -48,8 +48,11 @@ public class PolarisConfigEndpointTest { @Mock private PolarisConfigProperties polarisConfigProperties; - @Mock - private PolarisPropertySourceManager polarisPropertySourceManager; + + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } @Test public void testPolarisConfigEndpoint() { @@ -60,9 +63,9 @@ public void testPolarisConfigEndpoint() { MockedConfigKVFile file = new MockedConfigKVFile(content); PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, file, content); - when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); - PolarisConfigEndpoint endpoint = new PolarisConfigEndpoint(polarisConfigProperties, polarisPropertySourceManager); + PolarisConfigEndpoint endpoint = new PolarisConfigEndpoint(polarisConfigProperties); Map info = endpoint.polarisConfig(); assertThat(polarisConfigProperties).isEqualTo(info.get("PolarisConfigProperties")); assertThat(Lists.newArrayList(polarisPropertySource)).isEqualTo(info.get("PolarisPropertySource")); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java index eef16a89f0..191af71103 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.adapter.MockedConfigKVFile; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; @@ -31,6 +30,7 @@ import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -77,6 +77,11 @@ public class PolarisConfigRefreshOptimizationListenerNotTriggeredTest { @Autowired private ConfigurableApplicationContext context; + @BeforeAll + static void beforeAll() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testNotSwitchConfigRefreshType() { RefreshType actualRefreshType = context.getEnvironment() @@ -100,12 +105,12 @@ public void testConfigFileChanged() { PolarisPropertySource polarisPropertySource = new PolarisPropertySource(TEST_NAMESPACE, TEST_SERVICE_NAME, TEST_FILE_NAME, file, content); - PolarisPropertySourceManager manager = context.getBean(PolarisPropertySourceManager.class); - when(manager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); PolarisRefreshAffectedContextRefresher refresher = context.getBean(PolarisRefreshAffectedContextRefresher.class); PolarisRefreshAffectedContextRefresher spyRefresher = Mockito.spy(refresher); + refresher.setRegistered(false); spyRefresher.onApplicationEvent(null); ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); @@ -134,12 +139,6 @@ public void testConfigFileChanged() { @SpringBootApplication protected static class TestApplication { - @Primary - @Bean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return mock(PolarisPropertySourceManager.class); - } - @Primary @Bean public ContextRefresher contextRefresher() { diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java index 24aa7ae083..ef273483e4 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.adapter.MockedConfigKVFile; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySource; import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; @@ -31,6 +30,7 @@ import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; @@ -78,6 +78,11 @@ public class PolarisConfigRefreshOptimizationListenerTriggeredTest { @Autowired private ConfigurableApplicationContext context; + @BeforeEach + public void setUp() { + PolarisPropertySourceManager.clearPropertySources(); + } + @Test public void testSwitchConfigRefreshType() { RefreshType actualRefreshType = context.getEnvironment() @@ -101,12 +106,12 @@ public void testConfigFileChanged() { PolarisPropertySource polarisPropertySource = new PolarisPropertySource(TEST_NAMESPACE, TEST_SERVICE_NAME, TEST_FILE_NAME, file, content); - PolarisPropertySourceManager manager = context.getBean(PolarisPropertySourceManager.class); - when(manager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + PolarisPropertySourceManager.addPropertySource(polarisPropertySource); PolarisRefreshEntireContextRefresher refresher = context.getBean(PolarisRefreshEntireContextRefresher.class); PolarisRefreshEntireContextRefresher spyRefresher = Mockito.spy(refresher); + refresher.setRegistered(false); spyRefresher.onApplicationEvent(null); ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); @@ -135,12 +140,6 @@ public void testConfigFileChanged() { @SpringBootApplication protected static class TestApplication { - @Primary - @Bean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return mock(PolarisPropertySourceManager.class); - } - @Primary @Bean public ContextRefresher contextRefresher() { diff --git a/spring-cloud-starter-tencent-polaris-contract/pom.xml b/spring-cloud-starter-tencent-polaris-contract/pom.xml index c17c92b328..39aca10018 100644 --- a/spring-cloud-starter-tencent-polaris-contract/pom.xml +++ b/spring-cloud-starter-tencent-polaris-contract/pom.xml @@ -36,28 +36,13 @@ - io.springfox - springfox-boot-starter - - - swagger-models - io.swagger - - - swagger-annotations - io.swagger - - + org.springdoc + springdoc-openapi-ui - io.swagger - swagger-models - - - - io.swagger - swagger-annotations + org.springdoc + springdoc-openapi-webflux-ui diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java index 1470136e84..c380be0c30 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/PolarisContractReporter.java @@ -17,27 +17,33 @@ package com.tencent.cloud.polaris.contract; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import com.tencent.cloud.common.util.JacksonUtils; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tencent.cloud.common.util.GzipUtil; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import com.tencent.polaris.api.core.ProviderAPI; import com.tencent.polaris.api.plugin.server.InterfaceDescriptor; import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest; import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse; -import io.swagger.models.HttpMethod; -import io.swagger.models.Operation; -import io.swagger.models.Path; -import io.swagger.models.Swagger; +import com.tencent.polaris.api.utils.StringUtils; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import springfox.documentation.service.Documentation; -import springfox.documentation.spring.web.DocumentationCache; -import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; +import org.springdoc.api.AbstractOpenApiResource; +import org.springdoc.api.AbstractOpenApiResourceUtil; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.OpenApiWebFluxUtil; +import org.springdoc.webmvc.api.OpenApiWebMvcUtil; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; @@ -52,50 +58,79 @@ public class PolarisContractReporter implements ApplicationListener { private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class); - private final ServiceModelToSwagger2Mapper swagger2Mapper; - private final DocumentationCache documentationCache; + + private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource; + private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; private final PolarisContractProperties polarisContractProperties; private final ProviderAPI providerAPI; private final PolarisDiscoveryProperties polarisDiscoveryProperties; - public PolarisContractReporter(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper swagger2Mapper, - PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, PolarisDiscoveryProperties polarisDiscoveryProperties) { - this.swagger2Mapper = swagger2Mapper; - this.documentationCache = documentationCache; + private final ObjectMapperProvider springdocObjectMapperProvider; + + public PolarisContractReporter(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, + PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, + PolarisDiscoveryProperties polarisDiscoveryProperties, ObjectMapperProvider springdocObjectMapperProvider) { + this.multipleOpenApiWebMvcResource = multipleOpenApiWebMvcResource; + this.multipleOpenApiWebFluxResource = multipleOpenApiWebFluxResource; this.polarisContractProperties = polarisContractProperties; this.providerAPI = providerAPI; this.polarisDiscoveryProperties = polarisDiscoveryProperties; + this.springdocObjectMapperProvider = springdocObjectMapperProvider; } @Override public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) { if (polarisContractProperties.isReportEnabled()) { try { - Documentation documentation = documentationCache.documentationByGroup(polarisContractProperties.getGroup()); - Swagger swagger = swagger2Mapper.mapDocumentation(documentation); - if (swagger != null) { + AbstractOpenApiResource openApiResource = null; + if (multipleOpenApiWebMvcResource != null) { + openApiResource = OpenApiWebMvcUtil.getOpenApiResourceOrThrow(multipleOpenApiWebMvcResource, polarisContractProperties.getGroup()); + } + else if (multipleOpenApiWebFluxResource != null) { + openApiResource = OpenApiWebFluxUtil.getOpenApiResourceOrThrow(multipleOpenApiWebFluxResource, polarisContractProperties.getGroup()); + } + OpenAPI openAPI = null; + if (openApiResource != null) { + openAPI = AbstractOpenApiResourceUtil.getOpenApi(openApiResource); + } + if (openAPI != null) { ReportServiceContractRequest request = new ReportServiceContractRequest(); - request.setName(polarisDiscoveryProperties.getService()); + String name = polarisContractProperties.getName(); + if (StringUtils.isBlank(name)) { + name = polarisDiscoveryProperties.getService(); + } + request.setName(name); request.setNamespace(polarisDiscoveryProperties.getNamespace()); request.setService(polarisDiscoveryProperties.getService()); request.setProtocol("http"); request.setVersion(polarisDiscoveryProperties.getVersion()); - List interfaceDescriptorList = getInterfaceDescriptorFromSwagger(swagger); + List interfaceDescriptorList = getInterfaceDescriptorFromSwagger(openAPI); request.setInterfaceDescriptors(interfaceDescriptorList); + String jsonValue; + if (springdocObjectMapperProvider != null && springdocObjectMapperProvider.jsonMapper() != null) { + jsonValue = springdocObjectMapperProvider.jsonMapper().writeValueAsString(openAPI); + } + else { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonValue = mapper.writeValueAsString(openAPI); + } + String serviceApiMeta = GzipUtil.compressBase64Encode(jsonValue, "utf-8"); + request.setContent(serviceApiMeta); ReportServiceContractResponse response = providerAPI.reportServiceContract(request); LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.", request.getNamespace(), request.getName(), request.getService(), request.getProtocol(), request.getVersion(), request.getInterfaceDescriptors().size()); if (LOG.isDebugEnabled()) { - String jsonValue = JacksonUtils.serialize2Json(swagger); LOG.debug("OpenApi json data: {}", jsonValue); + LOG.debug("OpenApi json base64 data: {}", serviceApiMeta); } } else { - LOG.warn("Swagger or json is null, documentationCache keys:{}, group:{}", documentationCache.all() - .keySet(), polarisContractProperties.getGroup()); + LOG.warn("OpenAPI or json is null, group:{}", polarisContractProperties.getGroup()); } } catch (Throwable t) { @@ -104,11 +139,11 @@ public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEv } } - private List getInterfaceDescriptorFromSwagger(Swagger swagger) { + private List getInterfaceDescriptorFromSwagger(OpenAPI openAPI) { List interfaceDescriptorList = new ArrayList<>(); - Map paths = swagger.getPaths(); - for (Map.Entry p : paths.entrySet()) { - Path path = p.getValue(); + Paths paths = openAPI.getPaths(); + for (Map.Entry p : paths.entrySet()) { + PathItem path = p.getValue(); Map operationMap = getOperationMapFromPath(path); if (CollectionUtils.isEmpty(operationMap)) { continue; @@ -117,36 +152,50 @@ private List getInterfaceDescriptorFromSwagger(Swagger swag InterfaceDescriptor interfaceDescriptor = new InterfaceDescriptor(); interfaceDescriptor.setPath(p.getKey()); interfaceDescriptor.setMethod(o.getKey()); - interfaceDescriptor.setContent(JacksonUtils.serialize2Json(p.getValue())); + try { + String jsonValue; + if (springdocObjectMapperProvider != null && springdocObjectMapperProvider.jsonMapper() != null) { + jsonValue = springdocObjectMapperProvider.jsonMapper().writeValueAsString(o.getValue()); + } + else { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonValue = mapper.writeValueAsString(o.getValue()); + } + interfaceDescriptor.setContent(GzipUtil.compressBase64Encode(jsonValue, "utf-8")); + } + catch (IOException ioe) { + LOG.warn("Encode operation [{}] failed.", o.getValue(), ioe); + } interfaceDescriptorList.add(interfaceDescriptor); } } return interfaceDescriptorList; } - private Map getOperationMapFromPath(Path path) { + private Map getOperationMapFromPath(PathItem path) { Map operationMap = new HashMap<>(); if (path.getGet() != null) { - operationMap.put(HttpMethod.GET.name(), path.getGet()); + operationMap.put(PathItem.HttpMethod.GET.name(), path.getGet()); } if (path.getPut() != null) { - operationMap.put(HttpMethod.PUT.name(), path.getPut()); + operationMap.put(PathItem.HttpMethod.PUT.name(), path.getPut()); } if (path.getPost() != null) { - operationMap.put(HttpMethod.POST.name(), path.getPost()); + operationMap.put(PathItem.HttpMethod.POST.name(), path.getPost()); } if (path.getHead() != null) { - operationMap.put(HttpMethod.HEAD.name(), path.getHead()); + operationMap.put(PathItem.HttpMethod.HEAD.name(), path.getHead()); } if (path.getDelete() != null) { - operationMap.put(HttpMethod.DELETE.name(), path.getDelete()); + operationMap.put(PathItem.HttpMethod.DELETE.name(), path.getDelete()); } if (path.getPatch() != null) { - operationMap.put(HttpMethod.PATCH.name(), path.getPatch()); + operationMap.put(PathItem.HttpMethod.PATCH.name(), path.getPatch()); } if (path.getOptions() != null) { - operationMap.put(HttpMethod.OPTIONS.name(), path.getOptions()); + operationMap.put(PathItem.HttpMethod.OPTIONS.name(), path.getOptions()); } return operationMap; diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java index 7a34c8360b..21d098cae2 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ContractProperties.java @@ -51,4 +51,8 @@ public interface ContractProperties { boolean isReportEnabled(); void setReportEnabled(boolean reportEnabled); + + String getName(); + + void setName(String name); } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java index f48a01d24f..b1b50f518a 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractModifier.java @@ -41,7 +41,8 @@ public PolarisContractModifier(PolarisContractProperties polarisContractProperti public void modify(ConfigurationImpl configuration) { List registerConfigs = configuration.getProvider().getRegisters(); for (RegisterConfigImpl registerConfig : registerConfigs) { - registerConfig.setReportServiceContractEnable(polarisContractProperties.isEnabled()); + registerConfig.setReportServiceContractEnable( + polarisContractProperties.isEnabled() && polarisContractProperties.isReportEnabled()); } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java index 2b43226a5e..8ac2007101 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractProperties.java @@ -17,10 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import java.util.Objects; - -import javax.annotation.Nullable; - import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -32,8 +28,6 @@ @ConfigurationProperties("spring.cloud.polaris.contract") public class PolarisContractProperties implements ContractProperties { - private final ExtendedContractProperties extendContractProperties; - private boolean enabled = true; /** * Packages to be scanned. Split by ",". @@ -46,7 +40,7 @@ public class PolarisContractProperties implements ContractProperties { /** * Group to create swagger docket. */ - private String group = "default"; + private String group = "polaris"; /** * Base paths to be scanned. Split by ",". */ @@ -57,15 +51,10 @@ public class PolarisContractProperties implements ContractProperties { @Value("${spring.cloud.polaris.contract.report.enabled:true}") private boolean reportEnabled = true; - public PolarisContractProperties(@Nullable ExtendedContractProperties extendContractProperties) { - this.extendContractProperties = extendContractProperties; - } + private String name; @Override public boolean isEnabled() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.isEnabled(); - } return enabled; } @@ -76,9 +65,6 @@ public void setEnabled(boolean enabled) { @Override public String getBasePackage() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getBasePackage(); - } return basePackage; } @@ -89,9 +75,6 @@ public void setBasePackage(String basePackage) { @Override public String getExcludePath() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getExcludePath(); - } return excludePath; } @@ -102,9 +85,6 @@ public void setExcludePath(String excludePath) { @Override public String getGroup() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getGroup(); - } return group; } @@ -115,9 +95,6 @@ public void setGroup(String group) { @Override public String getBasePath() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.getBasePath(); - } return basePath; } @@ -128,9 +105,6 @@ public void setBasePath(String basePath) { @Override public boolean isExposure() { - if (Objects.nonNull(extendContractProperties)) { - return extendContractProperties.isExposure(); - } return exposure; } @@ -148,4 +122,13 @@ public boolean isReportEnabled() { public void setReportEnabled(boolean reportEnabled) { this.reportEnabled = reportEnabled; } + + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java index d3e0edb35b..051f8bc204 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisContractPropertiesAutoConfiguration.java @@ -17,8 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import javax.annotation.Nullable; - import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -36,8 +34,8 @@ public class PolarisContractPropertiesAutoConfiguration { @Bean @ConditionalOnMissingBean - public PolarisContractProperties polarisContractProperties(@Nullable ExtendedContractProperties extendedContractProperties) { - return new PolarisContractProperties(extendedContractProperties); + public PolarisContractProperties polarisContractProperties() { + return new PolarisContractProperties(); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java index e0ace300ca..ca8c36beac 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/PolarisSwaggerAutoConfiguration.java @@ -17,11 +17,6 @@ package com.tencent.cloud.polaris.contract.config; -import java.time.LocalDate; -import java.util.Date; -import java.util.List; -import java.util.function.Predicate; - import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; @@ -30,13 +25,14 @@ import com.tencent.cloud.polaris.contract.filter.ApiDocServletFilter; import com.tencent.cloud.polaris.contract.filter.ApiDocWebFluxFilter; import com.tencent.cloud.polaris.contract.utils.PackageUtil; -import springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.service.Contact; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.DocumentationCache; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.GroupedOpenApi; +import org.springdoc.core.SpringDocConfiguration; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.MultipleOpenApiWebFluxResource; +import org.springdoc.webmvc.api.MultipleOpenApiWebMvcResource; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -45,6 +41,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +import static com.tencent.cloud.polaris.contract.utils.PackageUtil.SPLITTER; /** * Auto configuration for Polaris swagger. @@ -54,7 +54,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisEnabled @ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true) -@Import(OpenApiAutoConfiguration.class) +@Import(SpringDocConfiguration.class) public class PolarisSwaggerAutoConfiguration { static { @@ -64,65 +64,45 @@ public class PolarisSwaggerAutoConfiguration { } @Bean - public Docket polarisDocket(PolarisContractProperties polarisContractProperties) { - List> excludePathList = PackageUtil.getExcludePathPredicates(polarisContractProperties.getExcludePath()); - List> basePathList = PackageUtil.getBasePathPredicates(polarisContractProperties.getBasePath()); + public GroupedOpenApi polarisGroupedOpenApi(PolarisContractProperties polarisContractProperties) { String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage()); - - Predicate basePathListOr = null; - for (Predicate basePathPredicate : basePathList) { - if (basePathListOr == null) { - basePathListOr = basePathPredicate; - } - else { - basePathListOr = basePathListOr.or(basePathPredicate); - } - } - - Predicate excludePathListOr = null; - for (Predicate excludePathPredicate : excludePathList) { - if (excludePathListOr == null) { - excludePathListOr = excludePathPredicate; - } - else { - excludePathListOr = excludePathListOr.or(excludePathPredicate); - } + String[] basePaths = {}; + if (StringUtils.hasText(polarisContractProperties.getBasePath())) { + basePaths = polarisContractProperties.getBasePath().split(SPLITTER); } - - Predicate pathsPredicate = basePathListOr; - - if (excludePathListOr != null) { - excludePathListOr = excludePathListOr.negate(); - pathsPredicate = pathsPredicate.and(excludePathListOr); + String[] excludePaths = {}; + if (StringUtils.hasText(polarisContractProperties.getExcludePath())) { + excludePaths = polarisContractProperties.getExcludePath().split(SPLITTER); } + return GroupedOpenApi.builder() + .packagesToScan(basePackage) + .pathsToMatch(basePaths) + .pathsToExclude(excludePaths) + .group(polarisContractProperties.getGroup()) + .build(); + } - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(PackageUtil.basePackage(basePackage)) - .paths(pathsPredicate) - .build() - .groupName(polarisContractProperties.getGroup()) - .enable(polarisContractProperties.isEnabled()) - .directModelSubstitute(LocalDate.class, Date.class) - .apiInfo(new ApiInfoBuilder() - .title("Polaris Swagger API") - .description("This is to show polaris api description.") - .license("BSD-3-Clause") - .licenseUrl("https://opensource.org/licenses/BSD-3-Clause") - .termsOfServiceUrl("") - .version("1.0.0") - .contact(new Contact("", "", "")) - .build()); + @Bean + @ConditionalOnMissingBean + public OpenAPI polarisOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("Polaris Contract") + .description("This is to show polaris contract description.") + .license(new License().name("BSD-3-Clause").url("https://opensource.org/licenses/BSD-3-Clause")) + .version("1.0.0")); } @Bean - @ConditionalOnBean(Docket.class) + @ConditionalOnBean(OpenAPI.class) @ConditionalOnMissingBean - public PolarisContractReporter polarisContractReporter(DocumentationCache documentationCache, - ServiceModelToSwagger2Mapper swagger2Mapper, PolarisContractProperties polarisContractProperties, - PolarisSDKContextManager polarisSDKContextManager, PolarisDiscoveryProperties polarisDiscoveryProperties) { - return new PolarisContractReporter(documentationCache, swagger2Mapper, polarisContractProperties, - polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties); + public PolarisContractReporter polarisContractReporter( + @Nullable MultipleOpenApiWebMvcResource multipleOpenApiWebMvcResource, + @Nullable MultipleOpenApiWebFluxResource multipleOpenApiWebFluxResource, + PolarisContractProperties polarisContractProperties, PolarisSDKContextManager polarisSDKContextManager, + PolarisDiscoveryProperties polarisDiscoveryProperties, ObjectMapperProvider springdocObjectMapperProvider) { + return new PolarisContractReporter(multipleOpenApiWebMvcResource, multipleOpenApiWebFluxResource, + polarisContractProperties, polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties, springdocObjectMapperProvider); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java index 38aa3d7c9a..98e925024c 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocServletFilter.java @@ -26,7 +26,6 @@ import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; -import org.springframework.lang.NonNull; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX; @@ -51,11 +50,9 @@ public ApiDocServletFilter(PolarisContractProperties polarisContractProperties) } @Override - public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, - @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) - throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (!polarisContractProperties.isExposure()) { - String path = httpServletRequest.getServletPath(); + String path = request.getServletPath(); if (path.startsWith(SWAGGER_V2_API_DOC_URL) || path.startsWith(SWAGGER_V3_API_DOC_URL) || path.startsWith(SWAGGER_UI_V2_URL) || @@ -63,11 +60,11 @@ public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, path.startsWith(SWAGGER_RESOURCE_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) || path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) { - httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); return; } } - filterChain.doFilter(httpServletRequest, httpServletResponse); + filterChain.doFilter(request, response); } } diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java index 7e7ea199ad..ac9c23d8ad 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/filter/ApiDocWebFluxFilter.java @@ -17,13 +17,13 @@ package com.tencent.cloud.polaris.contract.filter; - import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.NonNull; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; @@ -42,6 +42,7 @@ * @author Haotian Zhang */ public class ApiDocWebFluxFilter implements WebFilter { + private final PolarisContractProperties polarisContractProperties; public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) { @@ -49,7 +50,7 @@ public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) } @Override - public Mono filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { + public Mono filter(ServerWebExchange serverWebExchange, @NonNull WebFilterChain webFilterChain) { if (!polarisContractProperties.isExposure()) { String path = serverWebExchange.getRequest().getURI().getPath(); if (path.startsWith(SWAGGER_V2_API_DOC_URL) || diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java new file mode 100644 index 0000000000..4278d7093e --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfApiMetadataGrapher.java @@ -0,0 +1,137 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.contract.tsf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.tencent.cloud.common.util.GzipUtil; +import io.swagger.v3.oas.models.OpenAPI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springdoc.api.AbstractOpenApiResource; +import org.springdoc.api.AbstractOpenApiResourceUtil; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.OpenApiWebFluxUtil; +import org.springdoc.webmvc.api.OpenApiWebMvcUtil; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.SmartLifecycle; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +public class TsfApiMetadataGrapher implements SmartLifecycle { + + private final AtomicBoolean isRunning = new AtomicBoolean(false); + private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource; + private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; + private final ObjectMapperProvider springdocObjectMapperProvider; + private Logger logger = LoggerFactory.getLogger(TsfApiMetadataGrapher.class); + private ApplicationContext applicationContext; + private String groupName; + + public TsfApiMetadataGrapher(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, + String groupName, ApplicationContext applicationContext, ObjectMapperProvider springdocObjectMapperProvider) { + this.applicationContext = applicationContext; + this.multipleOpenApiWebMvcResource = multipleOpenApiWebMvcResource; + this.multipleOpenApiWebFluxResource = multipleOpenApiWebFluxResource; + this.groupName = groupName; + this.springdocObjectMapperProvider = springdocObjectMapperProvider; + } + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void stop(Runnable runnable) { + runnable.run(); + stop(); + } + + @Override + public void start() { + if (!isRunning.compareAndSet(false, true)) { + return; + } + try { + AbstractOpenApiResource openApiResource = null; + if (multipleOpenApiWebMvcResource != null) { + openApiResource = OpenApiWebMvcUtil.getOpenApiResourceOrThrow(multipleOpenApiWebMvcResource, groupName); + } + else if (multipleOpenApiWebFluxResource != null) { + openApiResource = OpenApiWebFluxUtil.getOpenApiResourceOrThrow(multipleOpenApiWebFluxResource, groupName); + } + OpenAPI openAPI = null; + if (openApiResource != null) { + openAPI = AbstractOpenApiResourceUtil.getOpenApi(openApiResource); + } + String jsonValue; + if (springdocObjectMapperProvider != null && springdocObjectMapperProvider.jsonMapper() != null) { + jsonValue = springdocObjectMapperProvider.jsonMapper().writeValueAsString(openAPI); + } + else { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + jsonValue = mapper.writeValueAsString(openAPI); + } + if (openAPI != null && !StringUtils.isEmpty(jsonValue)) { + String serviceApiMeta = GzipUtil.compressBase64Encode(jsonValue, "utf-8"); + Environment environment = applicationContext.getEnvironment(); + String tsfToken = environment.getProperty("tsf_token"); + String tsfGroupId = environment.getProperty("tsf_group_id"); + if (StringUtils.isEmpty(tsfGroupId) || StringUtils.isEmpty(tsfToken)) { + logger.info("[tsf-swagger] auto smart check application start with local consul, api registry not work"); + return; + } + logger.info("[tsf-swagger] api_meta len: {}", serviceApiMeta.length()); + String applicationName = environment.getProperty("spring.application.name"); + if (logger.isDebugEnabled()) { + logger.debug("[tsf-swagger] service: {} openApi json data: {}", applicationName, jsonValue); + logger.debug("[tsf-swagger] service: {} api_meta info: {}", applicationName, serviceApiMeta); + } + + System.setProperty(String.format("$%s", "api_metas"), serviceApiMeta); + } + else { + logger.warn("[tsf-swagger] swagger or json is null, openApiResource keys:{}, group:{}", openApiResource, groupName); + } + } + catch (Throwable t) { + logger.error("[tsf swagger] init TsfApiMetadataGrapher failed. occur exception: ", t); + } + } + + @Override + public void stop() { + isRunning.set(true); + } + + @Override + public boolean isRunning() { + return isRunning.get(); + } + + @Override + public int getPhase() { + return -2; + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.java new file mode 100644 index 0000000000..65322d1d83 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/tsf/TsfSwaggerAutoConfiguration.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.polaris.contract.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; +import io.swagger.v3.oas.models.OpenAPI; +import org.springdoc.core.providers.ObjectMapperProvider; +import org.springdoc.webflux.api.MultipleOpenApiWebFluxResource; +import org.springdoc.webmvc.api.MultipleOpenApiWebMvcResource; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; + +@Configuration +@ConditionalOnTsfConsulEnabled +@ConditionalOnProperty(value = "tsf.swagger.enabled", havingValue = "true", matchIfMissing = true) +public class TsfSwaggerAutoConfiguration { + + @Bean + @ConditionalOnBean(OpenAPI.class) + public TsfApiMetadataGrapher tsfApiMetadataGrapher(@Nullable MultipleOpenApiWebMvcResource multipleOpenApiWebMvcResource, + @Nullable MultipleOpenApiWebFluxResource multipleOpenApiWebFluxResource, ApplicationContext context, + PolarisContractProperties polarisContractProperties, ObjectMapperProvider springdocObjectMapperProvider) { + return new TsfApiMetadataGrapher(multipleOpenApiWebMvcResource, multipleOpenApiWebFluxResource, + polarisContractProperties.getGroup(), context, springdocObjectMapperProvider); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java index 1ce380cf50..1afcb709de 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/utils/PackageUtil.java @@ -17,26 +17,17 @@ package com.tencent.cloud.polaris.contract.utils; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.function.Predicate; -import com.google.common.base.Function; -import com.google.common.base.Optional; import com.tencent.cloud.polaris.contract.SwaggerContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import springfox.documentation.RequestHandler; -import springfox.documentation.builders.PathSelectors; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.util.StringUtils; -import static com.google.common.base.Optional.fromNullable; - /** * Util for package processing. * @@ -44,87 +35,15 @@ */ public final class PackageUtil { + /** + * splitter for property. + */ + public static final String SPLITTER = ","; private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class); - private static final String SPLITTER = ","; - private PackageUtil() { } - public static Predicate basePackage(String basePackage) { - return input -> declaringClass(input).transform(handlerPackage(basePackage, SPLITTER)).or(false); - } - - public static Optional> declaringClass(RequestHandler input) { - if (input == null) { - return Optional.absent(); - } - return fromNullable(input.declaringClass()); - } - - public static Function, Boolean> handlerPackage(String basePackage, String splitter) { - return input -> { - try { - if (StringUtils.isEmpty(basePackage)) { - return false; - } - String[] packages = basePackage.trim().split(splitter); - // Loop to determine matching - for (String strPackage : packages) { - if (input == null) { - continue; - } - Package pkg = input.getPackage(); - if (pkg == null) { - continue; - } - String name = pkg.getName(); - if (StringUtils.isEmpty(name)) { - continue; - } - boolean isMatch = name.startsWith(strPackage); - if (isMatch) { - return true; - } - } - } - catch (Exception e) { - LOG.error("handler package error", e); - } - return false; - }; - } - - public static List> getExcludePathPredicates(String excludePath) { - List> excludePathList = new ArrayList<>(); - if (StringUtils.isEmpty(excludePath)) { - return excludePathList; - } - String[] exs = excludePath.split(SPLITTER); - for (String ex : exs) { - if (!StringUtils.isEmpty(ex)) { - excludePathList.add(PathSelectors.ant(ex)); - } - } - return excludePathList; - } - - public static List> getBasePathPredicates(String basePath) { - List> basePathList = new ArrayList<>(); - if (!StringUtils.isEmpty(basePath)) { - String[] bps = basePath.split(SPLITTER); - for (String bp : bps) { - if (!StringUtils.isEmpty(bp)) { - basePathList.add(PathSelectors.ant(bp)); - } - } - } - if (basePathList.isEmpty()) { - basePathList.add(PathSelectors.ant("/**")); - } - return basePathList; - } - public static String scanPackage(String configBasePackage) { String validScanPackage; // Externally configured scan package diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java new file mode 100644 index 0000000000..8ef24531ce --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/api/AbstractOpenApiResourceUtil.java @@ -0,0 +1,37 @@ +/* + * 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 org.springdoc.api; + +import java.util.Locale; + +import io.swagger.v3.oas.models.OpenAPI; + +/** + * Util for {@link AbstractOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class AbstractOpenApiResourceUtil { + + private AbstractOpenApiResourceUtil() { + } + + public static OpenAPI getOpenApi(AbstractOpenApiResource openApiResource) { + return openApiResource.getOpenApi(Locale.getDefault()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java new file mode 100644 index 0000000000..8f146bff48 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webflux/api/OpenApiWebFluxUtil.java @@ -0,0 +1,36 @@ +/* + * 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 org.springdoc.webflux.api; + +import org.springdoc.api.AbstractOpenApiResource; + +/** + * Util for {@link MultipleOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class OpenApiWebFluxUtil { + + private OpenApiWebFluxUtil() { + } + + public static AbstractOpenApiResource getOpenApiResourceOrThrow( + org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, String groupName) { + return multipleOpenApiWebFluxResource.getOpenApiResourceOrThrow(groupName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java new file mode 100644 index 0000000000..6e4967cfb3 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/java/org/springdoc/webmvc/api/OpenApiWebMvcUtil.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package org.springdoc.webmvc.api; + +import org.springdoc.api.AbstractOpenApiResource; + +/** + * Util for {@link MultipleOpenApiResource}. + * + * @author Haotian Zhang + */ +public final class OpenApiWebMvcUtil { + private OpenApiWebMvcUtil() { + } + + public static AbstractOpenApiResource getOpenApiResourceOrThrow( + org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, String groupName) { + return multipleOpenApiWebMvcResource.getOpenApiResourceOrThrow(groupName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories index 86a23f5be9..e831b84ced 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-contract/src/main/resources/META-INF/spring.factories @@ -1,7 +1,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.contract.config.PolarisSwaggerAutoConfiguration,\ - com.tencent.cloud.polaris.contract.config.PolarisContractProperties + com.tencent.cloud.polaris.contract.config.PolarisContractProperties,\ + com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesAutoConfiguration,\ + com.tencent.cloud.polaris.contract.tsf.TsfSwaggerAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesAutoConfiguration + com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesBootstrapConfiguration org.springframework.context.ApplicationListener=\ com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener diff --git a/spring-cloud-starter-tencent-polaris-discovery/pom.xml b/spring-cloud-starter-tencent-polaris-discovery/pom.xml index 7b881c93e3..261f2e6c76 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/pom.xml +++ b/spring-cloud-starter-tencent-polaris-discovery/pom.xml @@ -23,6 +23,10 @@ com.tencent.cloud spring-cloud-tencent-rpc-enhancement + + com.tencent.cloud + spring-cloud-tencent-lossless-plugin + @@ -32,12 +36,6 @@ test - - com.tencent.polaris - connector-consul - test - - com.tencent.polaris connector-nacos @@ -92,6 +90,17 @@ true + + joda-time + joda-time + + + + org.mockito + mockito-inline + test + + io.projectreactor reactor-test diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java index 1725519f38..73f4e10715 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryConfigModifier.java @@ -51,6 +51,10 @@ public void modify(ConfigurationImpl configuration) { // Set ServiceRefreshInterval configuration.getConsumer().getLocalCache() .setServiceListRefreshInterval(polarisDiscoveryProperties.getServiceListRefreshInterval()); + + configuration.getConsumer().getZeroProtection().setEnable(polarisDiscoveryProperties.isZeroProtectionEnabled()); + configuration.getConsumer().getZeroProtection() + .setNeedTestConnectivity(polarisDiscoveryProperties.isZeroProtectionNeedTestConnectivity()); } @Override diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java index 43ca4b99a1..8839880f15 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java @@ -17,18 +17,25 @@ */ package com.tencent.cloud.polaris; +import com.tencent.cloud.common.util.inet.PolarisInetUtils; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.extend.consul.ConsulConfigModifier; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryConfigModifier; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulHeartbeatProperties; import com.tencent.cloud.polaris.extend.nacos.NacosConfigModifier; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; /** * Common configuration of discovery. @@ -45,12 +52,6 @@ public PolarisDiscoveryProperties polarisDiscoveryProperties() { return new PolarisDiscoveryProperties(); } - @Bean - @ConditionalOnMissingBean - public ConsulContextProperties consulContextProperties() { - return new ConsulContextProperties(); - } - @Bean @ConditionalOnMissingBean public NacosContextProperties nacosContextProperties() { @@ -70,12 +71,6 @@ public DiscoveryConfigModifier discoveryConfigModifier(PolarisDiscoveryPropertie return new DiscoveryConfigModifier(polarisDiscoveryProperties); } - @Bean - @ConditionalOnMissingBean - public ConsulConfigModifier consulConfigModifier(@Autowired(required = false) ConsulContextProperties consulContextProperties) { - return new ConsulConfigModifier(consulContextProperties); - } - @Bean @ConditionalOnMissingBean public PolarisDiscoveryConfigModifier polarisDiscoveryConfigModifier(PolarisDiscoveryProperties polarisDiscoveryProperties) { @@ -87,4 +82,34 @@ public PolarisDiscoveryConfigModifier polarisDiscoveryConfigModifier(PolarisDisc public NacosConfigModifier nacosConfigModifier(@Autowired(required = false) NacosContextProperties nacosContextProperties) { return new NacosConfigModifier(nacosContextProperties); } + + /** + * Create when consul is enabled. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnProperty(value = "spring.cloud.consul.enabled", havingValue = "true") + protected static class ConsulDiscoveryConfiguration { + + @Bean + @ConditionalOnMissingBean + public ConsulDiscoveryProperties consulDiscoveryProperties(PolarisInetUtils polarisInetUtils) { + return new ConsulDiscoveryProperties(polarisInetUtils); + } + + @Bean + @ConditionalOnMissingBean + public ConsulHeartbeatProperties consulHeartbeatProperties() { + return new ConsulHeartbeatProperties(); + } + + @Bean + @ConditionalOnMissingBean + public ConsulDiscoveryConfigModifier consulDiscoveryConfigModifier( + PolarisDiscoveryProperties polarisDiscoveryProperties, ConsulProperties consulProperties, + ConsulDiscoveryProperties consulContextProperties, ConsulHeartbeatProperties consulHeartbeatProperties, + @Nullable TsfCoreProperties tsfCoreProperties, ApplicationContext applicationContext) { + return new ConsulDiscoveryConfigModifier(polarisDiscoveryProperties, consulProperties, consulContextProperties, + consulHeartbeatProperties, tsfCoreProperties, applicationContext); + } + } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java index 0477ebfb9e..83c089e5aa 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java @@ -101,6 +101,18 @@ public class PolarisDiscoveryProperties { */ private Long serviceListRefreshInterval = 60000L; + /** + * Zero protection switch. + */ + @Value("${spring.cloud.polaris.discovery.zero-protection.enabled:false}") + private boolean zeroProtectionEnabled = false; + + /** + * Zero protection test connectivity switch. + */ + @Value("${spring.cloud.polaris.discovery.zero-protection.is-need-test-connectivity:false}") + private boolean zeroProtectionNeedTestConnectivity = false; + public String getInstanceId() { return instanceId; } @@ -192,6 +204,22 @@ public void setHeartbeatInterval(Integer heartbeatInterval) { this.heartbeatInterval = heartbeatInterval; } + public boolean isZeroProtectionEnabled() { + return zeroProtectionEnabled; + } + + public void setZeroProtectionEnabled(boolean zeroProtectionEnabled) { + this.zeroProtectionEnabled = zeroProtectionEnabled; + } + + public boolean isZeroProtectionNeedTestConnectivity() { + return zeroProtectionNeedTestConnectivity; + } + + public void setZeroProtectionNeedTestConnectivity(boolean zeroProtectionNeedTestConnectivity) { + this.zeroProtectionNeedTestConnectivity = zeroProtectionNeedTestConnectivity; + } + public Boolean getEnabled() { return enabled; } @@ -227,6 +255,8 @@ public String toString() { ", heartbeatInterval=" + heartbeatInterval + ", healthCheckUrl='" + healthCheckUrl + '\'' + ", serviceListRefreshInterval=" + serviceListRefreshInterval + + ", zeroProtectionEnabled=" + zeroProtectionEnabled + + ", zeroProtectionNeedTestConnectivity=" + zeroProtectionNeedTestConnectivity + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java index 78f95ae9ac..82ae9d5d86 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/ConditionalOnPolarisDiscoveryEnabled.java @@ -33,7 +33,7 @@ * @author Haotian Zhang, Andrew Shan, Jie Cheng */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ElementType.TYPE, ElementType.METHOD}) @ConditionalOnDiscoveryEnabled @ConditionalOnPolarisEnabled @Conditional(DiscoveryEnabledCondition.class) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java index 7cbc84f50a..379c7dff3d 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java @@ -69,7 +69,7 @@ public List getInstances(String serviceId) throws PolarisExcept InstancesResponse filteredInstances = polarisDiscoveryHandler.getHealthyInstances(serviceId); ServiceInstances serviceInstances = filteredInstances.toServiceInstances(); for (Instance instance : serviceInstances.getInstances()) { - instances.add(new PolarisServiceInstance(instance)); + instances.add(new PolarisServiceInstance(instance, filteredInstances.getMetadata())); } return instances; } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java index 70140f1bca..a3e7b9fe4f 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClient.java @@ -38,9 +38,9 @@ */ public class PolarisReactiveDiscoveryClient implements ReactiveDiscoveryClient { - private static final Logger LOG = LoggerFactory.getLogger(PolarisReactiveDiscoveryClient.class); + private static final Logger log = LoggerFactory.getLogger(PolarisReactiveDiscoveryClient.class); - private final PolarisServiceDiscovery polarisServiceDiscovery; + private PolarisServiceDiscovery polarisServiceDiscovery; public PolarisReactiveDiscoveryClient(PolarisServiceDiscovery polarisServiceDiscovery) { this.polarisServiceDiscovery = polarisServiceDiscovery; @@ -53,6 +53,7 @@ public String description() { @Override public Flux getInstances(String serviceId) { + return Mono.justOrEmpty(serviceId).flatMapMany(loadInstancesFromPolaris()) .subscribeOn(Schedulers.boundedElastic()); } @@ -63,7 +64,7 @@ private Function> loadInstancesFromPolaris() return Flux.fromIterable(polarisServiceDiscovery.getInstances(serviceId)); } catch (PolarisException e) { - LOG.error("get service instance[{}] from polaris error!", serviceId, e); + log.error("get service instance[{}] from polaris error!", serviceId, e); return Flux.empty(); } }; @@ -76,7 +77,7 @@ public Flux getServices() { return Flux.fromIterable(polarisServiceDiscovery.getServices()); } catch (Exception e) { - LOG.error("get services from polaris server fail,", e); + log.error("get services from polaris server fail,", e); return Flux.empty(); } }).subscribeOn(Schedulers.boundedElastic()); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java index 048b5c1473..68852aacd8 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/refresh/PolarisServiceStatusChangeListener.java @@ -81,10 +81,8 @@ else if (newValue.getEventType() == ServiceEventKey.EventType.INSTANCE) { LOG.debug("receive service instances={} change event", svcEventKey); ServiceInstancesByProto oldIns = (ServiceInstancesByProto) oldValue; ServiceInstancesByProto newIns = (ServiceInstancesByProto) newValue; - if ((CollectionUtils.isEmpty(oldIns.getInstances()) - && !CollectionUtils.isEmpty(newIns.getInstances())) || - (!CollectionUtils.isEmpty(oldIns.getInstances()) - && CollectionUtils.isEmpty(newIns.getInstances()))) { + if ((CollectionUtils.isEmpty(oldIns.getInstances()) && !CollectionUtils.isEmpty(newIns.getInstances())) || + (!CollectionUtils.isEmpty(oldIns.getInstances()) && CollectionUtils.isEmpty(newIns.getInstances()))) { LOG.info("Service status of {} is update.", newIns.getService()); // Trigger reload of gateway route cache. diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java index 248e7943ba..80e6491081 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpoint.java @@ -38,7 +38,7 @@ * * @author shuiqingliu */ -@Endpoint(id = "polaris-discovery") +@Endpoint(id = "polarisdiscovery") public class PolarisDiscoveryEndpoint { private final PolarisDiscoveryProperties polarisDiscoveryProperties; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java deleted file mode 100644 index af8431a5cc..0000000000 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulConfigModifier.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.extend.consul; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; - -import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.polaris.context.PolarisConfigModifier; -import com.tencent.polaris.api.config.plugin.DefaultPlugins; -import com.tencent.polaris.factory.config.ConfigurationImpl; -import com.tencent.polaris.factory.config.consumer.DiscoveryConfigImpl; -import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; -import com.tencent.polaris.factory.config.provider.RegisterConfigImpl; -import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.CollectionUtils; - -/** - * @author lingxiao.wlx - */ -public class ConsulConfigModifier implements PolarisConfigModifier { - - private static final Logger LOGGER = LoggerFactory.getLogger(ConsulConfigModifier.class); - - private static final String ID = "consul"; - - private final ConsulContextProperties consulContextProperties; - - public ConsulConfigModifier(ConsulContextProperties consulContextProperties) { - this.consulContextProperties = consulContextProperties; - } - - @Override - public void modify(ConfigurationImpl configuration) { - if (consulContextProperties != null && consulContextProperties.isEnabled()) { - // Check if Consul client Available - boolean consulAvailable = false; - try { - consulAvailable = null != Class.forName("com.ecwid.consul.v1.ConsulClient"); - } - catch (Throwable ignored) { - - } - if (!consulAvailable) { - LOGGER.error("Please import \"connector-consul\" dependency when enabling consul service registration and discovery.\n" - + "Add dependency configuration below to pom.xml:\n" - + "\n" - + "\tcom.tencent.polaris\n" - + "\tconnector-consul\n" - + ""); - throw new RuntimeException("Dependency \"connector-consul\" not found."); - } - if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) { - configuration.getGlobal().setServerConnectors(new ArrayList<>()); - } - if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors()) - && null != configuration.getGlobal().getServerConnector()) { - configuration.getGlobal().getServerConnectors().add(configuration.getGlobal().getServerConnector()); - } - ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl(); - serverConnectorConfig.setId(ID); - serverConnectorConfig.setAddresses( - Collections.singletonList(consulContextProperties.getHost() + ":" + consulContextProperties.getPort())); - serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL); - Map metadata = serverConnectorConfig.getMetadata(); - if (StringUtils.isNotBlank(consulContextProperties.getServiceName())) { - metadata.put(ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY, consulContextProperties.getServiceName()); - } - if (StringUtils.isNotBlank(consulContextProperties.getInstanceId())) { - metadata.put(ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY, consulContextProperties.getInstanceId()); - } - if (consulContextProperties.isPreferIpAddress() - && StringUtils.isNotBlank(consulContextProperties.getIpAddress())) { - metadata.put(ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY, - String.valueOf(consulContextProperties.isPreferIpAddress())); - metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulContextProperties.getIpAddress()); - } - configuration.getGlobal().getServerConnectors().add(serverConnectorConfig); - - DiscoveryConfigImpl discoveryConfig = new DiscoveryConfigImpl(); - discoveryConfig.setServerConnectorId(ID); - discoveryConfig.setEnable(consulContextProperties.isDiscoveryEnabled()); - configuration.getConsumer().getDiscoveries().add(discoveryConfig); - - RegisterConfigImpl registerConfig = new RegisterConfigImpl(); - registerConfig.setServerConnectorId(ID); - registerConfig.setEnable(consulContextProperties.isRegister()); - configuration.getProvider().getRegisters().add(registerConfig); - } - } - - @Override - public int getOrder() { - return OrderConstant.Modifier.CONSUL_DISCOVERY_CONFIG_ORDER; - } -} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java deleted file mode 100644 index ad98e009b5..0000000000 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulContextProperties.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.polaris.extend.consul; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.ConfigurationProperties; - -/** - * Discovery configuration of Consul. - * - * @author Haotian Zhang - */ -@ConfigurationProperties("spring.cloud.consul") -public class ConsulContextProperties { - - /** - * Host of consul(or consul agent). - */ - private String host; - - private int port; - - private boolean enabled = false; - - @Value("${spring.cloud.consul.discovery.register:#{'true'}}") - private boolean register; - - @Value("${spring.cloud.consul.discovery.enabled:#{'true'}}") - private boolean discoveryEnabled; - - @Value("${spring.cloud.consul.discovery.instance-id:}") - private String instanceId; - - @Value("${spring.cloud.consul.discovery.service-name:${spring.application.name:}}") - private String serviceName; - - @Value("${spring.cloud.consul.discovery.ip-address:}") - private String ipAddress; - - @Value("${spring.cloud.consul.discovery.prefer-ip-address:#{'false'}}") - private boolean preferIpAddress; - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isRegister() { - return register; - } - - public boolean isDiscoveryEnabled() { - return discoveryEnabled; - } - - public void setRegister(boolean register) { - this.register = register; - } - - public void setDiscoveryEnabled(boolean discoveryEnabled) { - this.discoveryEnabled = discoveryEnabled; - } - - public String getInstanceId() { - return instanceId; - } - - public void setInstanceId(String instanceId) { - this.instanceId = instanceId; - } - - public String getServiceName() { - return serviceName; - } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public String getIpAddress() { - return ipAddress; - } - - public void setIpAddress(String ipAddress) { - this.ipAddress = ipAddress; - } - - public boolean isPreferIpAddress() { - return preferIpAddress; - } - - public void setPreferIpAddress(boolean preferIpAddress) { - this.preferIpAddress = preferIpAddress; - } -} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java new file mode 100644 index 0000000000..f737949581 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryConfigModifier.java @@ -0,0 +1,157 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.extend.consul; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.PolarisDiscoveryProperties; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.polaris.api.config.plugin.DefaultPlugins; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.consumer.DiscoveryConfigImpl; +import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; +import com.tencent.polaris.factory.config.provider.RegisterConfigImpl; +import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.lang.Nullable; +import org.springframework.util.CollectionUtils; + +/** + * Modifier for Consul discovery. + * + * @author lingxiao.wlx, Haotian Zhang + */ +public class ConsulDiscoveryConfigModifier implements PolarisConfigModifier { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulDiscoveryConfigModifier.class); + + private final PolarisDiscoveryProperties polarisDiscoveryProperties; + + private final ConsulProperties consulProperties; + + private final ConsulDiscoveryProperties consulDiscoveryProperties; + + private final ConsulHeartbeatProperties consulHeartbeatProperties; + + private final ApplicationContext context; + + private final TsfCoreProperties tsfCoreProperties; + + public ConsulDiscoveryConfigModifier(PolarisDiscoveryProperties polarisDiscoveryProperties, ConsulProperties consulProperties, + ConsulDiscoveryProperties consulDiscoveryProperties, ConsulHeartbeatProperties consulHeartbeatProperties, + @Nullable TsfCoreProperties tsfCoreProperties, ApplicationContext context) { + this.polarisDiscoveryProperties = polarisDiscoveryProperties; + this.consulProperties = consulProperties; + this.consulDiscoveryProperties = consulDiscoveryProperties; + this.consulHeartbeatProperties = consulHeartbeatProperties; + this.tsfCoreProperties = tsfCoreProperties; + this.context = context; + } + + @Override + public void modify(ConfigurationImpl configuration) { + // init server connectors. + if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) { + configuration.getGlobal().setServerConnectors(new ArrayList<>()); + } + + // init consul connector. + ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl(); + serverConnectorConfig.setId(ConsulDiscoveryUtil.ID); + serverConnectorConfig.setAddresses( + Collections.singletonList(consulProperties.getHost() + ":" + consulProperties.getPort())); + LOGGER.info("Will register to consul server: [" + consulProperties.getHost() + ":" + consulProperties.getPort() + "]"); + serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL); + // set consul connector metadata. + Map metadata = serverConnectorConfig.getMetadata(); + // namespace + if (StringUtils.isNotBlank(polarisDiscoveryProperties.getNamespace())) { + metadata.put(ConsulConstant.MetadataMapKey.NAMESPACE_KEY, polarisDiscoveryProperties.getNamespace()); + } + // service name + String appName = ConsulDiscoveryUtil.getAppName(consulDiscoveryProperties, context.getEnvironment()); + if (StringUtils.isNotBlank(appName)) { + metadata.put(ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY, ConsulDiscoveryUtil.normalizeForDns(appName)); + } + // instance ID + String instanceId = ConsulDiscoveryUtil.getInstanceId(consulDiscoveryProperties, context); + if (StringUtils.isNotBlank(instanceId)) { + metadata.put(ConsulConstant.MetadataMapKey.INSTANCE_ID_KEY, instanceId); + } + // token + if (StringUtils.isNotBlank(consulProperties.getAclToken())) { + serverConnectorConfig.setToken(consulProperties.getAclToken()); + } + // default query tag + if (StringUtils.isNotBlank(consulDiscoveryProperties.getDefaultQueryTag())) { + metadata.put(ConsulConstant.MetadataMapKey.QUERY_TAG_KEY, consulDiscoveryProperties.getDefaultQueryTag()); + } + // query passing + metadata.put(ConsulConstant.MetadataMapKey.QUERY_PASSING_KEY, String.valueOf(consulDiscoveryProperties.isQueryPassing())); + // prefer ip address + if (consulDiscoveryProperties.isPreferIpAddress() + && StringUtils.isNotBlank(consulDiscoveryProperties.getIpAddress())) { + metadata.put(ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY, + String.valueOf(consulDiscoveryProperties.isPreferIpAddress())); + metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulDiscoveryProperties.getIpAddress()); + } + // is not prefer agent address + if (!consulDiscoveryProperties.isPreferAgentAddress()) { + metadata.put(ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY, + String.valueOf(consulDiscoveryProperties.isPreferIpAddress())); + metadata.put(ConsulConstant.MetadataMapKey.IP_ADDRESS_KEY, consulDiscoveryProperties.getHostname()); + } + if (tsfCoreProperties != null) { + // tags + metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags())); + } + configuration.getGlobal().getServerConnectors().add(serverConnectorConfig); + + // discovery + DiscoveryConfigImpl discoveryConfig = new DiscoveryConfigImpl(); + discoveryConfig.setServerConnectorId(ConsulDiscoveryUtil.ID); + discoveryConfig.setEnable(consulDiscoveryProperties.isEnabled()); + configuration.getConsumer().getDiscoveries().add(discoveryConfig); + + // register + RegisterConfigImpl registerConfig = new RegisterConfigImpl(); + registerConfig.setServerConnectorId(ConsulDiscoveryUtil.ID); + registerConfig.setEnable(consulDiscoveryProperties.isRegister()); + configuration.getProvider().getRegisters().add(registerConfig); + + // heartbeat + polarisDiscoveryProperties.setHeartbeatInterval(Long.valueOf( + consulHeartbeatProperties.computeHeartbeatInterval().toStandardDuration().getMillis()).intValue()); + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.CONSUL_DISCOVERY_CONFIG_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java new file mode 100644 index 0000000000..1782b63f29 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryProperties.java @@ -0,0 +1,679 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.extend.consul; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.ecwid.consul.v1.ConsistencyMode; +import com.tencent.cloud.common.util.inet.PolarisInetUtils; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.commons.util.InetUtils.HostInfo; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.core.style.ToStringCreator; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Copy from org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties. + * Defines configuration for service discovery and registration. + * + * @author Spencer Gibb + * @author Donnabell Dmello + * @author Venil Noronha + * @author Richard Kettelerij + */ +@ConfigurationProperties(ConsulDiscoveryProperties.PREFIX) +public class ConsulDiscoveryProperties { + + /** + * Consul discovery properties prefix. + */ + public static final String PREFIX = "spring.cloud.consul.discovery"; + + protected static final String MANAGEMENT = "management"; + + private HostInfo hostInfo; + + /** Tags to use when registering service. */ + private List tags = new ArrayList<>(); + + /** Metadata to use when registering service. */ + private Map metadata = new LinkedHashMap<>(); + + /** Enable tag override for the registered service. */ + private Boolean enableTagOverride; + + /** Is service discovery enabled? */ + private boolean enabled = true; + + /** Tags to use when registering management service. */ + private List managementTags = new ArrayList<>(); + + /** Enable tag override for the registered management service. */ + private Boolean managementEnableTagOverride; + + /** Metadata to use when registering management service. */ + private Map managementMetadata; + + /** Alternate server path to invoke for health checking. */ + private String healthCheckPath = "/actuator/health"; + + /** Custom health check url to override default. */ + private String healthCheckUrl; + + /** Headers to be applied to the Health Check calls. */ + private Map> healthCheckHeaders = new HashMap<>(); + + /** How often to perform the health check (e.g. 10s), defaults to 10s. */ + private String healthCheckInterval = "10s"; + + /** Timeout for health check (e.g. 10s). */ + private String healthCheckTimeout; + + /** + * Timeout to deregister services critical for longer than timeout (e.g. 30m). + * Requires consul version 7.x or higher. + */ + private String healthCheckCriticalTimeout; + + /** + * IP address to use when accessing service (must also set preferIpAddress to use). + */ + private String ipAddress; + + /** Hostname to use when accessing server. */ + private String hostname; + + /** Port to register the service under (defaults to listening port). */ + private Integer port; + + /** Port to register the management service under (defaults to management port). */ + private Integer managementPort; + + private Lifecycle lifecycle = new Lifecycle(); + + /** Use ip address rather than hostname during registration. */ + private boolean preferIpAddress = true; + + /** Source of how we will determine the address to use. */ + private boolean preferAgentAddress = false; + + /** The delay between calls to watch consul catalog in millis, default is 1000. */ + private int catalogServicesWatchDelay = 1000; + + /** The number of seconds to block while watching consul catalog, default is 2. */ + private int catalogServicesWatchTimeout = 55; + + /** Service name. */ + private String serviceName; + + /** Unique service instance id. */ + private String instanceId; + + /** Service instance zone. */ + private String instanceZone; + + /** Service instance group. */ + private String instanceGroup; + + /** + * Whether hostname is included into the default instance id when registering service. + */ + private boolean includeHostnameInInstanceId = false; + + /** + * Consistency mode for health service request. + */ + private ConsistencyMode consistencyMode = ConsistencyMode.DEFAULT; + + /** + * Service instance zone comes from metadata. This allows changing the metadata tag + * name. + */ + private String defaultZoneMetadataName = "zone"; + + /** Whether to register an http or https service. */ + private String scheme = "http"; + + /** Suffix to use when registering management service. */ + private String managementSuffix = MANAGEMENT; + + /** + * Map of serviceId's -> tag to query for in server list. This allows filtering + * services by one more tags. Multiple tags can be specified with a comma separated + * value. + */ + private Map serverListQueryTags = new HashMap<>(); + + /** + * Map of serviceId's -> datacenter to query for in server list. This allows looking + * up services in another datacenters. + */ + private Map datacenters = new HashMap<>(); + + /** + * Tag to query for in service list if one is not listed in serverListQueryTags. + * Multiple tags can be specified with a comma separated value. + */ + private String defaultQueryTag; + + /** + * Add the 'passing` parameter to /v1/health/service/serviceName. This pushes health + * check passing to the server. + */ + private boolean queryPassing = true; + + /** Register as a service in consul. */ + private boolean register = true; + + /** Disable automatic de-registration of service in consul. */ + private boolean deregister = true; + + /** Register health check in consul. Useful during development of a service. */ + private boolean registerHealthCheck = true; + + /** + * Throw exceptions during service registration if true, otherwise, log warnings + * (defaults to true). + */ + private boolean failFast = true; + + /** + * Skips certificate verification during service checks if true, otherwise runs + * certificate verification. + */ + private Boolean healthCheckTlsSkipVerify; + + /** + * Order of the discovery client used by `CompositeDiscoveryClient` for sorting + * available clients. + */ + private int order = 0; + + @SuppressWarnings("unused") + private ConsulDiscoveryProperties() { + this(new PolarisInetUtils(new InetUtilsProperties())); + } + + public ConsulDiscoveryProperties(PolarisInetUtils polarisInetUtils) { + this.managementTags.add(MANAGEMENT); + this.hostInfo = polarisInetUtils.findFirstNonLoopbackHostInfo(); + this.ipAddress = this.hostInfo.getIpAddress(); + this.hostname = this.hostInfo.getHostname(); + } + + /** + * Gets the tag to use when looking up the instances for a particular service. If the + * service has an entry in {@link #serverListQueryTags} that will be used. Otherwise + * the content of {@link #defaultQueryTag} will be used. + * @param serviceId the service whose instances are being looked up + * @return the tag to filter the service instances by or null if no tags are + * configured for the service and the default query tag is not configured + */ + public String getQueryTagForService(String serviceId) { + String tag = this.serverListQueryTags.get(serviceId); + return tag != null ? tag : this.defaultQueryTag; + } + + /** + * Gets the array of tags to use when looking up the instances for a particular + * service. If the service has an entry in {@link #serverListQueryTags} that will be + * used. Otherwise the content of {@link #defaultQueryTag} will be used. This differs + * from {@link #getQueryTagForService(String)} in that it assumes the configured tag + * property value may represent multiple tags when separated by commas. When the tag + * property is set to a single tag then this method behaves identical to its + * aforementioned counterpart except that it returns a single element array with the + * single tag value. + *

+ * The expected format of the tag property value is {@code tag1,tag2,..,tagN}. + * Whitespace will be trimmed off each entry. + * @param serviceId the service whose instances are being looked up + * @return the array of tags to filter the service instances by - it will be null if + * no tags are configured for the service and the default query tag is not configured + * or if a single tag is configured and it is the empty string + */ + @Nullable + public String[] getQueryTagsForService(String serviceId) { + String queryTagStr = getQueryTagForService(serviceId); + if (queryTagStr == null || queryTagStr.isEmpty()) { + return null; + } + return StringUtils.tokenizeToStringArray(queryTagStr, ","); + } + + public String getHostname() { + return this.preferIpAddress ? this.ipAddress : this.hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + this.hostInfo.override = true; + } + + private HostInfo getHostInfo() { + return this.hostInfo; + } + + private void setHostInfo(HostInfo hostInfo) { + this.hostInfo = hostInfo; + } + + public List getTags() { + return this.tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public boolean isEnableTagOverride() { + return enableTagOverride; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public List getManagementTags() { + return this.managementTags; + } + + public void setManagementTags(List managementTags) { + this.managementTags = managementTags; + } + + public String getHealthCheckPath() { + return this.healthCheckPath; + } + + public void setHealthCheckPath(String healthCheckPath) { + this.healthCheckPath = healthCheckPath; + } + + public String getHealthCheckUrl() { + return this.healthCheckUrl; + } + + public void setHealthCheckUrl(String healthCheckUrl) { + this.healthCheckUrl = healthCheckUrl; + } + + public Map> getHealthCheckHeaders() { + return this.healthCheckHeaders; + } + + public void setHealthCheckHeaders(Map> healthCheckHeaders) { + this.healthCheckHeaders = healthCheckHeaders; + } + + public String getHealthCheckInterval() { + return this.healthCheckInterval; + } + + public void setHealthCheckInterval(String healthCheckInterval) { + this.healthCheckInterval = healthCheckInterval; + } + + public String getHealthCheckTimeout() { + return this.healthCheckTimeout; + } + + public void setHealthCheckTimeout(String healthCheckTimeout) { + this.healthCheckTimeout = healthCheckTimeout; + } + + public String getHealthCheckCriticalTimeout() { + return this.healthCheckCriticalTimeout; + } + + public void setHealthCheckCriticalTimeout(String healthCheckCriticalTimeout) { + this.healthCheckCriticalTimeout = healthCheckCriticalTimeout; + } + + public String getIpAddress() { + return this.ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + this.hostInfo.override = true; + } + + public Integer getPort() { + return this.port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Integer getManagementPort() { + return this.managementPort; + } + + public void setManagementPort(Integer managementPort) { + this.managementPort = managementPort; + } + + public Lifecycle getLifecycle() { + return this.lifecycle; + } + + public void setLifecycle(Lifecycle lifecycle) { + this.lifecycle = lifecycle; + } + + public boolean isPreferIpAddress() { + return this.preferIpAddress; + } + + public void setPreferIpAddress(boolean preferIpAddress) { + this.preferIpAddress = preferIpAddress; + } + + public boolean isPreferAgentAddress() { + return this.preferAgentAddress; + } + + public void setPreferAgentAddress(boolean preferAgentAddress) { + this.preferAgentAddress = preferAgentAddress; + } + + public int getCatalogServicesWatchDelay() { + return this.catalogServicesWatchDelay; + } + + public void setCatalogServicesWatchDelay(int catalogServicesWatchDelay) { + this.catalogServicesWatchDelay = catalogServicesWatchDelay; + } + + public int getCatalogServicesWatchTimeout() { + return this.catalogServicesWatchTimeout; + } + + public void setCatalogServicesWatchTimeout(int catalogServicesWatchTimeout) { + this.catalogServicesWatchTimeout = catalogServicesWatchTimeout; + } + + public String getServiceName() { + return this.serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getInstanceId() { + return this.instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getInstanceZone() { + return this.instanceZone; + } + + public void setInstanceZone(String instanceZone) { + this.instanceZone = instanceZone; + } + + public String getInstanceGroup() { + return this.instanceGroup; + } + + public void setInstanceGroup(String instanceGroup) { + this.instanceGroup = instanceGroup; + } + + public boolean isIncludeHostnameInInstanceId() { + return includeHostnameInInstanceId; + } + + public void setIncludeHostnameInInstanceId(boolean includeHostnameInInstanceId) { + this.includeHostnameInInstanceId = includeHostnameInInstanceId; + } + + public ConsistencyMode getConsistencyMode() { + return consistencyMode; + } + + public void setConsistencyMode(ConsistencyMode consistencyMode) { + this.consistencyMode = consistencyMode; + } + + public String getDefaultZoneMetadataName() { + return this.defaultZoneMetadataName; + } + + public void setDefaultZoneMetadataName(String defaultZoneMetadataName) { + this.defaultZoneMetadataName = defaultZoneMetadataName; + } + + public String getScheme() { + return this.scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getManagementSuffix() { + return this.managementSuffix; + } + + public void setManagementSuffix(String managementSuffix) { + this.managementSuffix = managementSuffix; + } + + public Map getServerListQueryTags() { + return this.serverListQueryTags; + } + + public void setServerListQueryTags(Map serverListQueryTags) { + this.serverListQueryTags = serverListQueryTags; + } + + public Map getDatacenters() { + return this.datacenters; + } + + public void setDatacenters(Map datacenters) { + this.datacenters = datacenters; + } + + public String getDefaultQueryTag() { + return this.defaultQueryTag; + } + + public void setDefaultQueryTag(String defaultQueryTag) { + this.defaultQueryTag = defaultQueryTag; + } + + public boolean isQueryPassing() { + return this.queryPassing; + } + + public void setQueryPassing(boolean queryPassing) { + this.queryPassing = queryPassing; + } + + public boolean isRegister() { + return this.register; + } + + public void setRegister(boolean register) { + this.register = register; + } + + public boolean isDeregister() { + return this.deregister; + } + + public void setDeregister(boolean deregister) { + this.deregister = deregister; + } + + public boolean isRegisterHealthCheck() { + return this.registerHealthCheck; + } + + public void setRegisterHealthCheck(boolean registerHealthCheck) { + this.registerHealthCheck = registerHealthCheck; + } + + public boolean isFailFast() { + return this.failFast; + } + + public void setFailFast(boolean failFast) { + this.failFast = failFast; + } + + public Boolean getHealthCheckTlsSkipVerify() { + return this.healthCheckTlsSkipVerify; + } + + public void setHealthCheckTlsSkipVerify(Boolean healthCheckTlsSkipVerify) { + this.healthCheckTlsSkipVerify = healthCheckTlsSkipVerify; + } + + public int getOrder() { + return this.order; + } + + public void setOrder(int order) { + this.order = order; + } + + public Map getManagementMetadata() { + return this.managementMetadata; + } + + public void setManagementMetadata(Map managementMetadata) { + this.managementMetadata = managementMetadata; + } + + public Boolean getEnableTagOverride() { + return this.enableTagOverride; + } + + public void setEnableTagOverride(boolean enableTagOverride) { + this.enableTagOverride = enableTagOverride; + } + + public void setEnableTagOverride(Boolean enableTagOverride) { + this.enableTagOverride = enableTagOverride; + } + + public Boolean getManagementEnableTagOverride() { + return this.managementEnableTagOverride; + } + + public void setManagementEnableTagOverride(Boolean managementEnableTagOverride) { + this.managementEnableTagOverride = managementEnableTagOverride; + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("catalogServicesWatchDelay", this.catalogServicesWatchDelay) + .append("catalogServicesWatchTimeout", this.catalogServicesWatchTimeout) + .append("consistencyMode", this.consistencyMode) + .append("datacenters", this.datacenters) + .append("defaultQueryTag", this.defaultQueryTag) + .append("defaultZoneMetadataName", this.defaultZoneMetadataName) + .append("deregister", this.deregister) + .append("enabled", this.enabled) + .append("enableTagOverride", this.enableTagOverride) + .append("failFast", this.failFast) + .append("hostInfo", this.hostInfo) + .append("healthCheckCriticalTimeout", this.healthCheckCriticalTimeout) + .append("healthCheckHeaders", this.healthCheckHeaders) + .append("healthCheckInterval", this.healthCheckInterval) + .append("healthCheckPath", this.healthCheckPath) + .append("healthCheckTimeout", this.healthCheckTimeout) + .append("healthCheckTlsSkipVerify", this.healthCheckTlsSkipVerify) + .append("healthCheckUrl", this.healthCheckUrl) + .append("hostname", this.hostname) + .append("includeHostnameInInstanceId", this.includeHostnameInInstanceId) + .append("instanceId", this.instanceId) + .append("instanceGroup", this.instanceGroup) + .append("instanceZone", this.instanceZone) + .append("ipAddress", this.ipAddress) + .append("lifecycle", this.lifecycle) + .append("metadata", this.metadata) + .append("managementEnableTagOverride", this.managementEnableTagOverride) + .append("managementMetadata", this.managementMetadata) + .append("managementPort", this.managementPort) + .append("managementSuffix", this.managementSuffix) + .append("managementTags", this.managementTags) + .append("order", this.order) + .append("port", this.port) + .append("preferAgentAddress", this.preferAgentAddress) + .append("preferIpAddress", this.preferIpAddress) + .append("queryPassing", this.queryPassing) + .append("register", this.register) + .append("registerHealthCheck", this.registerHealthCheck) + .append("scheme", this.scheme) + .append("serviceName", this.serviceName) + .append("serverListQueryTags", this.serverListQueryTags) + .append("tags", this.tags) + .toString(); + } + + /** + * Properties releated to the lifecycle. + */ + public static class Lifecycle { + + private boolean enabled = true; + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public String toString() { + return "Lifecycle{" + "enabled=" + this.enabled + '}'; + } + + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java new file mode 100644 index 0000000000..27f07d95a8 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryUtil.java @@ -0,0 +1,186 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.extend.consul; + +import java.util.Map; + +import com.ecwid.consul.v1.agent.model.NewService; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.polaris.api.config.Configuration; +import com.tencent.polaris.api.utils.IPAddressUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.factory.config.global.ServerConnectorConfigImpl; +import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.discovery.ManagementServerPortUtils; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.cloud.commons.util.IdUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; + +/** + * TSF registration utils. + * + * @author Haotian Zhang + */ +public final class ConsulDiscoveryUtil { + /** + * - 分隔符. + */ + public static final char SEPARATOR = '-'; + + /** + * Server connector ID. + */ + public static final String ID = "consul"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulDiscoveryUtil.class); + + private ConsulDiscoveryUtil() { + } + + public static String getAppName(ConsulDiscoveryProperties properties, Environment env) { + String appName = properties.getServiceName(); + if (StringUtils.isNotBlank(appName)) { + return appName; + } + return env.getProperty("spring.application.name", "application"); + } + + public static String getInstanceId(ConsulDiscoveryProperties properties, ApplicationContext context) { + // tsf consul 不支持 dns,所以这里不需要 normalize,并且由于优雅下线,readiness probe 联动都是依赖 service id 的,normalize 后两边对不上,所以需要去掉 normalize + if (StringUtils.isBlank(properties.getInstanceId())) { + return IdUtils.getDefaultInstanceId(context.getEnvironment(), false); + } + else { + return properties.getInstanceId(); + } + } + + public static String normalizeForDns(String s) { + if (s == null) { + throw new IllegalArgumentException("Consul service ids must not be empty"); + } + + StringBuilder normalized = new StringBuilder(); + Character prev = null; + for (char curr : s.toCharArray()) { + Character toAppend = null; + if (Character.isLetterOrDigit(curr)) { + toAppend = curr; + } + else if (prev == null || !(prev == SEPARATOR)) { + toAppend = SEPARATOR; + } + if (toAppend != null) { + normalized.append(toAppend); + prev = toAppend; + } + } + + return normalized.toString(); + } + + public static void setCheck(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, TsfCoreProperties tsfCoreProperties, ApplicationContext context, + ConsulHeartbeatProperties consulHeartbeatProperties, Registration registration, Configuration configuration) { + if (properties.isRegisterHealthCheck()) { + Integer checkPort; + if (shouldRegisterManagement(autoServiceRegistrationProperties, properties, context)) { + checkPort = getManagementPort(properties, context); + } + else { + checkPort = registration.getPort(); + } + Assert.notNull(checkPort, "checkPort may not be null"); + + for (ServerConnectorConfigImpl config : configuration.getGlobal().getServerConnectors()) { + if (org.apache.commons.lang.StringUtils.equals(config.getId(), ID)) { + Map metadata = config.getMetadata(); + NewService.Check check = createCheck(checkPort, consulHeartbeatProperties, properties, tsfCoreProperties); + String checkJson = JacksonUtils.serialize2Json(check); + LOGGER.debug("Check is : {}", checkJson); + metadata.put(ConsulConstant.MetadataMapKey.CHECK_KEY, checkJson); + } + } + + } + } + + public static NewService.Check createCheck(Integer port, ConsulHeartbeatProperties ttlConfig, + ConsulDiscoveryProperties properties, TsfCoreProperties tsfCoreProperties) { + NewService.Check check = new NewService.Check(); + if (ttlConfig.isEnabled()) { + check.setTtl(ttlConfig.getTtl()); + return check; + } + + Assert.notNull(port, "createCheck port must not be null"); + Assert.isTrue(port > 0, "createCheck port must be greater than 0"); + + if (properties.getHealthCheckUrl() != null) { + check.setHttp(properties.getHealthCheckUrl()); + } + else { + check.setHttp(String.format("%s://%s:%s%s", tsfCoreProperties.getScheme(), + IPAddressUtils.getIpCompatible(properties.getHostname()), port, + properties.getHealthCheckPath())); + } + check.setInterval(properties.getHealthCheckInterval()); + check.setTimeout(properties.getHealthCheckTimeout()); + if (StringUtils.isNotBlank(properties.getHealthCheckCriticalTimeout())) { + check.setDeregisterCriticalServiceAfter(properties.getHealthCheckCriticalTimeout()); + } + check.setTlsSkipVerify(properties.getHealthCheckTlsSkipVerify()); + return check; + } + + /** + * + * @param autoServiceRegistrationProperties auto service registration properties + * @param properties consul discovery properties + * @param context application context + * @return if the management service should be registered with the {@link ServiceRegistry} + */ + public static boolean shouldRegisterManagement(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ConsulDiscoveryProperties properties, ApplicationContext context) { + return autoServiceRegistrationProperties.isRegisterManagement() + && getManagementPort(properties, context) != null + && ManagementServerPortUtils.isDifferent(context); + } + + /** + * + * @param properties consul discovery properties + * @param context application context + * @return the port of the Management Service + */ + public static Integer getManagementPort(ConsulDiscoveryProperties properties, ApplicationContext context) { + // If an alternate external port is specified, use it instead + if (properties.getManagementPort() != null) { + return properties.getManagementPort(); + } + return ManagementServerPortUtils.getPort(context); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java new file mode 100644 index 0000000000..ef709e4ea3 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/extend/consul/ConsulHeartbeatProperties.java @@ -0,0 +1,118 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.extend.consul; + +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +import org.joda.time.Period; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.style.ToStringCreator; +import org.springframework.validation.annotation.Validated; + +/** + * Copy from org.springframework.cloud.consul.discovery.HeartbeatProperties. + * Properties related to heartbeat verification. + * + * @author Spencer Gibb + * @author Chris Bono + */ +@ConfigurationProperties(prefix = "spring.cloud.consul.discovery.heartbeat") +@Validated +public class ConsulHeartbeatProperties { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsulHeartbeatProperties.class); + // TODO: change enabled to default to true when I stop seeing messages like + // [WARN] agent: Check 'service:testConsulApp:xtest:8080' missed TTL, is now critical + boolean enabled = true; + + @Min(1) + private int ttlValue = 30; + + @NotNull + private String ttlUnit = "s"; + + @DecimalMin("0.1") + @DecimalMax("0.9") + private double intervalRatio = 2.0 / 3.0; + + //TODO: did heartbeatInterval need to be a field? + + protected Period computeHeartbeatInterval() { + // heartbeat rate at ratio * ttl, but no later than ttl -1s and, (under lesser + // priority), no sooner than 1s from now + double interval = ttlValue * intervalRatio; + double max = Math.max(interval, 1); + int ttlMinus1 = ttlValue - 1; + double min = Math.min(ttlMinus1, max); + Period heartbeatInterval = new Period(Math.round(1000 * min)); + LOGGER.debug("Computed heartbeatInterval: " + heartbeatInterval); + return heartbeatInterval; + } + + public String getTtl() { + return ttlValue + ttlUnit; + } + + public boolean isEnabled() { + return this.enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public @Min(1) int getTtlValue() { + return this.ttlValue; + } + + public void setTtlValue(@Min(1) int ttlValue) { + this.ttlValue = ttlValue; + } + + public @NotNull String getTtlUnit() { + return this.ttlUnit; + } + + public void setTtlUnit(@NotNull String ttlUnit) { + this.ttlUnit = ttlUnit; + } + + public @DecimalMin("0.1") @DecimalMax("0.9") double getIntervalRatio() { + return this.intervalRatio; + } + + public void setIntervalRatio(@DecimalMin("0.1") @DecimalMax("0.9") double intervalRatio) { + this.intervalRatio = intervalRatio; + } + + @Override + public String toString() { + return new ToStringCreator(this) + .append("enabled", enabled) + .append("ttlValue", ttlValue) + .append("ttlUnit", ttlUnit) + .append("intervalRatio", intervalRatio) + .toString(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java index 3b186d27a6..2d7391ff82 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/ConditionalOnPolarisRegisterEnabled.java @@ -32,7 +32,7 @@ * @author Haotian Zhang, Andrew Shan, Jie Cheng */ @Retention(RetentionPolicy.RUNTIME) -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ElementType.TYPE, ElementType.METHOD}) @ConditionalOnPolarisEnabled @Conditional(RegisterEnabledCondition.class) public @interface ConditionalOnPolarisRegisterEnabled { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java index 1c81588acf..c7dad59f80 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistration.java @@ -17,9 +17,7 @@ package com.tencent.cloud.polaris.registry; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; -import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.assembly.api.AssemblyAPI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,9 +71,6 @@ protected void register() { log.debug("Registration disabled."); return; } - if (assemblyAPI != null) { - assemblyAPI.initService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); - } super.register(); } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java index 0a3d09ae88..2dfb364042 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java @@ -26,7 +26,7 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.polaris.client.api.SDKContext; import org.apache.commons.lang.StringUtils; @@ -48,8 +48,6 @@ */ public class PolarisRegistration implements Registration { - private static final String METADATA_KEY_IP = "internal-ip"; - private static final String METADATA_KEY_ADDRESS = "internal-address"; private static final String GROUP_SERVER_ID_FORMAT = "%s__%s"; private static final String NACOS_CLUSTER = "nacos.cluster"; @@ -67,13 +65,14 @@ public class PolarisRegistration implements Registration { private final List customizers; private boolean registerEnabled = false; private Map metadata; + private Map> extendedMetadata; private int port; private String instanceId; public PolarisRegistration( PolarisDiscoveryProperties polarisDiscoveryProperties, @Nullable PolarisContextProperties polarisContextProperties, - @Nullable ConsulContextProperties consulContextProperties, + @Nullable ConsulDiscoveryProperties consulDiscoveryProperties, SDKContext context, StaticMetadataManager staticMetadataManager, @Nullable NacosContextProperties nacosContextProperties, @Nullable ServletWebServerApplicationContext servletWebServerApplicationContext, @@ -115,10 +114,6 @@ public PolarisRegistration( if (CollectionUtils.isEmpty(metadata)) { Map instanceMetadata = new HashMap<>(); - // put internal metadata - instanceMetadata.put(METADATA_KEY_IP, host); - instanceMetadata.put(METADATA_KEY_ADDRESS, host + ":" + port); - // put internal-nacos-cluster if necessary if (Objects.nonNull(nacosContextProperties)) { String clusterName = nacosContextProperties.getClusterName(); @@ -132,12 +127,14 @@ public PolarisRegistration( this.metadata = instanceMetadata; } + this.extendedMetadata = new HashMap<>(); + // generate registerEnabled if (null != polarisDiscoveryProperties) { registerEnabled = polarisDiscoveryProperties.isRegisterEnabled(); } - if (null != consulContextProperties && consulContextProperties.isEnabled()) { - registerEnabled |= consulContextProperties.isRegister(); + if (null != consulDiscoveryProperties) { + registerEnabled |= consulDiscoveryProperties.isRegister(); } if (null != nacosContextProperties && nacosContextProperties.isEnabled()) { registerEnabled |= nacosContextProperties.isRegisterEnabled(); @@ -146,7 +143,7 @@ public PolarisRegistration( public static PolarisRegistration registration(PolarisDiscoveryProperties polarisDiscoveryProperties, @Nullable PolarisContextProperties polarisContextProperties, - @Nullable ConsulContextProperties consulContextProperties, + @Nullable ConsulDiscoveryProperties consulContextProperties, SDKContext context, StaticMetadataManager staticMetadataManager, @Nullable NacosContextProperties nacosContextProperties, @Nullable ServletWebServerApplicationContext servletWebServerApplicationContext, @@ -217,6 +214,13 @@ public Map getMetadata() { return metadata; } + public Map> getExtendedMetadata() { + if (extendedMetadata == null) { + extendedMetadata = new HashMap<>(); + } + return extendedMetadata; + } + @Override public String getInstanceId() { return instanceId; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java index d610340896..582f801988 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java @@ -44,6 +44,9 @@ import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.client.util.NamedThreadFactory; import com.tencent.polaris.factory.config.provider.ServiceConfigImpl; +import com.tencent.polaris.metadata.core.TransitiveType; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -96,7 +99,8 @@ public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryPropert @Override public void register(PolarisRegistration registration) { - if (StringUtils.isEmpty(registration.getServiceId())) { + + if (StringUtils.isBlank(registration.getServiceId())) { LOGGER.warn("No service to register for polaris client..."); return; } @@ -116,9 +120,18 @@ public void register(PolarisRegistration registration) { instanceRegisterRequest.setCampus(staticMetadataManager.getCampus()); instanceRegisterRequest.setTtl(polarisDiscoveryProperties.getHeartbeatInterval()); instanceRegisterRequest.setMetadata(registration.getMetadata()); + instanceRegisterRequest.setExtendedMetadata(registration.getExtendedMetadata()); instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol()); instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion()); instanceRegisterRequest.setInstanceId(polarisDiscoveryProperties.getInstanceId()); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_NAMESPACE, polarisDiscoveryProperties.getNamespace(), TransitiveType.DISPOSABLE); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_SERVICE, serviceId, TransitiveType.DISPOSABLE); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_IP, registration.getHost(), TransitiveType.DISPOSABLE); + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .putMetadataStringValue(MetadataConstants.LOCAL_PORT, String.valueOf(registration.getPort()), TransitiveType.DISPOSABLE); try { ProviderAPI providerClient = polarisSDKContextManager.getProviderAPI(); InstanceRegisterResponse instanceRegisterResponse; @@ -129,12 +142,14 @@ public void register(PolarisRegistration registration) { instanceRegisterResponse = providerClient.register(instanceRegisterRequest); InstanceHeartbeatRequest heartbeatRequest = new InstanceHeartbeatRequest(); BeanUtils.copyProperties(instanceRegisterRequest, heartbeatRequest); + heartbeatRequest.setInstanceID(instanceRegisterResponse.getInstanceId()); // Start the heartbeat thread after the registration is successful. heartbeat(heartbeatRequest); } registration.setInstanceId(instanceRegisterResponse.getInstanceId()); - LOGGER.info("polaris registry, {} {} {}:{} {} register finished", polarisDiscoveryProperties.getNamespace(), - registration.getServiceId(), registration.getHost(), registration.getPort(), + LOGGER.info("polaris registry, {} {} {} {}:{} {} {} {} {} register finished", polarisDiscoveryProperties.getNamespace(), + registration.getServiceId(), registration.getInstanceId(), registration.getHost(), registration.getPort(), + staticMetadataManager.getRegion(), staticMetadataManager.getZone(), staticMetadataManager.getCampus(), staticMetadataManager.getMergedStaticMetadata()); if (Objects.nonNull(polarisStatProperties) && polarisStatProperties.isEnabled()) { try { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index 1cf7a83a91..126678ae4b 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -25,7 +25,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties; @@ -68,7 +68,7 @@ public PolarisServiceRegistry polarisServiceRegistry( public PolarisRegistration polarisRegistration( PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisContextProperties polarisContextProperties, - @Autowired(required = false) ConsulContextProperties consulContextProperties, + @Autowired(required = false) ConsulDiscoveryProperties consulContextProperties, PolarisSDKContextManager polarisSDKContextManager, StaticMetadataManager staticMetadataManager, NacosContextProperties nacosContextProperties, @Autowired(required = false) ServletWebServerApplicationContext servletWebServerApplicationContext, diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java index a8386a0ec1..310110d42d 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/RegisterEnabledCondition.java @@ -30,8 +30,8 @@ public class RegisterEnabledCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { - boolean isRegisterEnabled = Boolean.parseBoolean(conditionContext.getEnvironment() - .getProperty("spring.cloud.polaris.discovery.register", "true")); + boolean isRegisterEnabled = Boolean.parseBoolean( + conditionContext.getEnvironment().getProperty("spring.cloud.polaris.discovery.register", "true")); boolean isConsulRegisterEnabled = Boolean.parseBoolean( conditionContext.getEnvironment().getProperty("spring.cloud.consul.enabled", "false")) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java new file mode 100644 index 0000000000..c193f06c3d --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfApiPolarisRegistrationCustomizer.java @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.tsf.registry; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.context.ApplicationContext; +import org.springframework.util.StringUtils; + +import static com.tencent.polaris.api.config.plugin.DefaultPlugins.SERVER_CONNECTOR_CONSUL; + +/** + * Set API data to registration metadata. + * + * @author Haotian Zhang + */ +public class TsfApiPolarisRegistrationCustomizer implements PolarisRegistrationCustomizer { + private static final Logger LOG = LoggerFactory.getLogger(TsfApiPolarisRegistrationCustomizer.class); + + private static final String API_META_KEY = "TSF_API_METAS"; + private final ApplicationContext context; + + public TsfApiPolarisRegistrationCustomizer(ApplicationContext context) { + this.context = context; + } + + @Override + public void customize(PolarisRegistration registration) { + String apiMetaData = context.getEnvironment().getProperty("$api_metas"); + Map> metadata = registration.getExtendedMetadata(); + if (StringUtils.hasText(apiMetaData)) { + if (!metadata.containsKey(SERVER_CONNECTOR_CONSUL)) { + metadata.put(SERVER_CONNECTOR_CONSUL, new HashMap<>()); + } + metadata.get(SERVER_CONNECTOR_CONSUL).put(API_META_KEY, apiMetaData); + } + else { + LOG.warn("apiMetaData is null, service:{}", registration.getServiceId()); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java new file mode 100644 index 0000000000..dc4e9caba6 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfDiscoveryRegistryAutoConfiguration.java @@ -0,0 +1,71 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.tsf.registry; +import javax.servlet.ServletContext; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulHeartbeatProperties; +import com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Auto configuration for TSF discovery. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +@AutoConfigureBefore(PolarisServiceRegistryAutoConfiguration.class) +public class TsfDiscoveryRegistryAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfPortPolarisRegistrationCustomizer tsfPortPolarisRegistrationCustomizer( + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ApplicationContext context, ConsulDiscoveryProperties consulDiscoveryProperties, TsfCoreProperties tsfCoreProperties, + ConsulHeartbeatProperties consulHeartbeatProperties, PolarisSDKContextManager polarisSDKContextManager) { + return new TsfPortPolarisRegistrationCustomizer(autoServiceRegistrationProperties, context, + consulDiscoveryProperties, tsfCoreProperties, consulHeartbeatProperties, polarisSDKContextManager.getSDKContext()); + } + + @Bean + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) + @ConditionalOnMissingBean + public TsfServletRegistrationCustomizer tsfServletConsulCustomizer(ObjectProvider servletContext) { + return new TsfServletRegistrationCustomizer(servletContext); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(value = "tsf.swagger.enabled", havingValue = "true", matchIfMissing = true) + public TsfApiPolarisRegistrationCustomizer tsfApiPolarisRegistrationCustomizer(ApplicationContext context) { + return new TsfApiPolarisRegistrationCustomizer(context); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java new file mode 100644 index 0000000000..68a13a3652 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfPortPolarisRegistrationCustomizer.java @@ -0,0 +1,65 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.tsf.registry; + +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryUtil; +import com.tencent.cloud.polaris.extend.consul.ConsulHeartbeatProperties; +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; +import com.tencent.polaris.client.api.SDKContext; + +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.context.ApplicationContext; + +/** + * 服务注册时端口相关逻辑. + * + * @author Haotian Zhang + */ +public class TsfPortPolarisRegistrationCustomizer implements PolarisRegistrationCustomizer { + + private final AutoServiceRegistrationProperties autoServiceRegistrationProperties; + private final ApplicationContext context; + private final ConsulDiscoveryProperties consulDiscoveryProperties; + private final TsfCoreProperties tsfCoreProperties; + private final ConsulHeartbeatProperties consulHeartbeatProperties; + private final SDKContext sdkContext; + + public TsfPortPolarisRegistrationCustomizer(AutoServiceRegistrationProperties autoServiceRegistrationProperties, + ApplicationContext context, ConsulDiscoveryProperties consulDiscoveryProperties, TsfCoreProperties tsfCoreProperties, + ConsulHeartbeatProperties consulHeartbeatProperties, SDKContext sdkContext) { + this.autoServiceRegistrationProperties = autoServiceRegistrationProperties; + this.context = context; + this.consulDiscoveryProperties = consulDiscoveryProperties; + this.tsfCoreProperties = tsfCoreProperties; + this.consulHeartbeatProperties = consulHeartbeatProperties; + this.sdkContext = sdkContext; + } + + @Override + public void customize(PolarisRegistration registration) { + if (consulDiscoveryProperties.getPort() != null) { + registration.setPort(consulDiscoveryProperties.getPort()); + } + // we know the port and can set the check + ConsulDiscoveryUtil.setCheck(autoServiceRegistrationProperties, consulDiscoveryProperties, tsfCoreProperties, context, + consulHeartbeatProperties, registration, sdkContext.getConfig()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java new file mode 100644 index 0000000000..f4321b7438 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/tsf/registry/TsfServletRegistrationCustomizer.java @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.tsf.registry; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; + +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.polaris.registry.PolarisRegistration; +import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer; +import com.tencent.polaris.plugins.connector.common.constant.ConsulConstant; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.util.StringUtils; + +import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.TAGS_KEY; + +/** + * @author Piotr Wielgolaski + */ +public class TsfServletRegistrationCustomizer implements PolarisRegistrationCustomizer { + private final ObjectProvider servletContext; + + public TsfServletRegistrationCustomizer(ObjectProvider servletContext) { + this.servletContext = servletContext; + } + + @Override + public void customize(PolarisRegistration registration) { + if (servletContext == null) { + return; + } + ServletContext sc = servletContext.getIfAvailable(); + if (sc != null + && StringUtils.hasText(sc.getContextPath()) + && StringUtils.hasText(sc.getContextPath().replaceAll("/", ""))) { + Map metadata = registration.getMetadata(); + + List tags = Arrays.asList(JacksonUtils.deserialize(metadata.get(TAGS_KEY), String[].class)); + if (tags == null) { + tags = new ArrayList<>(); + } + tags.add("contextPath=" + sc.getContextPath()); + metadata.put(ConsulConstant.MetadataMapKey.TAGS_KEY, JacksonUtils.serialize2Json(tags)); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 947982852a..a8ebda0643 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -66,6 +66,18 @@ "defaultValue": 60000, "description": "Millis interval of refresh of service info list. Default: 60000." }, + { + "name": "spring.cloud.polaris.discovery.zero-protection.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "Zero protection switch. Default: false." + }, + { + "name": "spring.cloud.polaris.discovery.zero-protection.is-need-test-connectivity", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "Zero protection test connectivity switch. Default: false." + }, { "name": "spring.cloud.nacos.discovery.enabled", "type": "java.lang.Boolean", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories index e8deb25e8c..dc65b01e03 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/spring.factories @@ -1,8 +1,9 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration,\ com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\ - com.tencent.cloud.polaris.ribbon.PolarisDiscoveryRibbonAutoConfiguration,\ com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration,\ - com.tencent.cloud.polaris.endpoint.PolarisDiscoveryEndpointAutoConfiguration + com.tencent.cloud.polaris.endpoint.PolarisDiscoveryEndpointAutoConfiguration,\ + com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerAutoConfiguration,\ + com.tencent.cloud.polaris.tsf.registry.TsfDiscoveryRegistryAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.tencent.cloud.polaris.DiscoveryPropertiesBootstrapAutoConfiguration diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java similarity index 96% rename from spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java rename to spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java index 6870415401..126f7228a0 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspectTest.java @@ -73,9 +73,10 @@ public class LosslessRegistryAspectTest { PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryAutoConfiguration.class)) .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=") - .withPropertyValues("spring.cloud.polaris.lossless.port=" + LOSSLESS_PORT_1) + .withPropertyValues("spring.cloud.polaris.admin.port=" + LOSSLESS_PORT_1) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + APPLICATION_PORT) .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) @@ -93,9 +94,10 @@ public class LosslessRegistryAspectTest { PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryAutoConfiguration.class)) .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=1000") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/test") - .withPropertyValues("spring.cloud.polaris.lossless.port=28082") + .withPropertyValues("spring.cloud.polaris.admin.port=28082") .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + APPLICATION_PORT) .withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST) @@ -138,7 +140,7 @@ public void testRegister() { assertThatCode(() -> { assertThat(OkHttpUtil.checkUrl(HOST, LOSSLESS_PORT_1, "/online", Collections.EMPTY_MAP)).isFalse(); }).doesNotThrowAnyException(); - // delay register after 5s + // delay register after 10s Thread.sleep(10000); PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); PolarisRegistration registration = context.getBean(PolarisRegistration.class); diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java similarity index 68% rename from spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java rename to spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java index 0b0d847ff5..ef4f9bb811 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/com/tencent/cloud/plugin/lossless/LosslessConfigModifierTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifierTest.java @@ -15,11 +15,11 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.plugin.lossless; +package com.tencent.cloud.plugin.lossless.config; -import com.tencent.cloud.plugin.lossless.config.LosslessConfigModifier; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.polaris.api.config.provider.LosslessConfig; +import com.tencent.polaris.specification.api.v1.traffic.manage.LosslessProto; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,14 +36,23 @@ */ public class LosslessConfigModifierTest { - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private final ApplicationContextRunner delayRegisterContextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(TestApplication.class)) .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") - .withPropertyValues("spring.cloud.polaris.lossless.port=20000") - .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") + .withPropertyValues("spring.cloud.polaris.admin.port=20000") .withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=10") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + + private final ApplicationContextRunner healthCheckContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.lossless.enabled=true") + .withPropertyValues("spring.cloud.polaris.admin.port=20000") + .withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=/xxx") .withPropertyValues("spring.cloud.polaris.lossless.healthCheckInterval=5") .withPropertyValues("spring.application.name=test") .withPropertyValues("spring.cloud.gateway.enabled=false"); @@ -61,15 +70,25 @@ void setUp() { } @Test - void testModify() { - contextRunner.run(context -> { + void testDelayRegister() { + delayRegisterContextRunner.run(context -> { PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). getConfig().getProvider().getLossless(); - assertThat(losslessConfig.getHost()).isEqualTo("0.0.0.0"); - assertThat(losslessConfig.getPort()).isEqualTo(20000); assertThat(losslessConfig.getDelayRegisterInterval()).isEqualTo(10); + assertThat(losslessConfig.getStrategy()).isEqualTo(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_TIME); + }); + } + + @Test + void testHealthCheck() { + healthCheckContextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + LosslessConfig losslessConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getProvider().getLossless(); + assertThat(losslessConfig.getHealthCheckPath()).isEqualTo("/xxx"); assertThat(losslessConfig.getHealthCheckInterval()).isEqualTo(5); + assertThat(losslessConfig.getStrategy()).isEqualTo(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_HEALTH_CHECK); }); } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java new file mode 100644 index 0000000000..c097a04a42 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifierTest.java @@ -0,0 +1,86 @@ +/* + * 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.plugin.lossless.config; + +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.config.consumer.WeightAdjustConfig; +import com.tencent.polaris.plugin.lossless.warmup.WarmupWeightAdjuster; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link WarmupConfigModifier}. + * + * @author Shedfree Wu + */ +public class WarmupConfigModifierTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.warmup.enabled=true") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + private final ApplicationContextRunner disabledContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TestApplication.class)) + .withPropertyValues("spring.cloud.nacos.discovery.enabled=false") + .withPropertyValues("spring.cloud.polaris.enabled=true") + .withPropertyValues("spring.cloud.polaris.warmup.enabled=false") + .withPropertyValues("spring.application.name=test") + .withPropertyValues("spring.cloud.gateway.enabled=false"); + + @BeforeEach + void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + void testModify() { + contextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + WeightAdjustConfig weightAdjustConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getConsumer().getWeightAdjust(); + assertThat(weightAdjustConfig.isEnable()).isTrue(); + assertThat(weightAdjustConfig.getChain().contains(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME)).isTrue(); + }); + } + + + @Test + void testDisabled() { + disabledContextRunner.run(context -> { + PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); + WeightAdjustConfig weightAdjustConfig = polarisSDKContextManager.getSDKContext(). + getConfig().getConsumer().getWeightAdjust(); + assertThat(weightAdjustConfig.isEnable()).isTrue(); + assertThat(weightAdjustConfig.getChain().contains(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME)).isFalse(); + }); + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java index eb1aedb50c..3dee04d671 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfigurationTest.java @@ -19,13 +19,11 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; @@ -45,26 +43,9 @@ public void testDefaultInitialization() { applicationContextRunner.run(context -> { assertThat(context).hasSingleBean(DiscoveryPropertiesAutoConfiguration.class); assertThat(context).hasSingleBean(PolarisDiscoveryProperties.class); - assertThat(context).hasSingleBean(ConsulContextProperties.class); + assertThat(context).doesNotHaveBean(ConsulDiscoveryProperties.class); assertThat(context).hasSingleBean(PolarisDiscoveryHandler.class); assertThat(context).hasSingleBean(DiscoveryConfigModifier.class); }); } - - @Configuration - static class TestConfiguration { - @Bean - public PolarisDiscoveryProperties polarisDiscoveryProperties() { - PolarisDiscoveryProperties polarisDiscoveryProperties = new PolarisDiscoveryProperties(); - polarisDiscoveryProperties.setEnabled(false); - return polarisDiscoveryProperties; - } - - @Bean - public ConsulContextProperties consulContextProperties() { - ConsulContextProperties consulContextProperties = new ConsulContextProperties(); - consulContextProperties.setEnabled(true); - return consulContextProperties; - } - } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java index dc0149295b..0618ab3d1b 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/DiscoveryPropertiesBootstrapAutoConfigurationTest.java @@ -35,8 +35,7 @@ public class DiscoveryPropertiesBootstrapAutoConfigurationTest { @Test public void testDefaultInitialization() { ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner().withConfiguration( - AutoConfigurations.of( - PolarisContextAutoConfiguration.class, + AutoConfigurations.of(PolarisContextAutoConfiguration.class, DiscoveryPropertiesBootstrapAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.enabled=true"); applicationContextRunner.run(context -> { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java index 1a5e875dcc..0345bf43fe 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java @@ -101,6 +101,8 @@ public void testGetAndSet() { + ", registerEnabled=true" + ", heartbeatInterval=20" + ", healthCheckUrl='/health'" - + ", serviceListRefreshInterval=1000}"); + + ", serviceListRefreshInterval=1000" + + ", zeroProtectionEnabled=false" + + ", zeroProtectionNeedTestConnectivity=false}"); } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java index 895fd05a89..88279eda2f 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryAutoConfigurationTest.java @@ -49,7 +49,8 @@ public class PolarisDiscoveryAutoConfigurationTest { .withConfiguration(AutoConfigurations.of( PolarisContextAutoConfiguration.class, PolarisDiscoveryAutoConfiguration.class, - PolarisDiscoveryClientConfiguration.class)) + PolarisDiscoveryClientConfiguration.class, + PolarisContextAutoConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + PORT) .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java index c50e1a60ed..262d89b346 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/PolarisDiscoveryClientTest.java @@ -51,6 +51,7 @@ public class PolarisDiscoveryClientTest { @Test public void testGetInstances() { + when(polarisServiceDiscovery.getInstances(anyString())) .thenReturn(singletonList(mock(PolarisServiceInstance.class))); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java index 3c0156cbc4..d4efe34e72 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientConfigurationTest.java @@ -74,8 +74,7 @@ void setUp() { @Test public void testDefaultInitialization() { - this.contextRunner.run(context -> assertThat(context) - .hasSingleBean(PolarisReactiveDiscoveryClient.class)); + this.contextRunner.run(context -> assertThat(context).hasSingleBean(PolarisReactiveDiscoveryClient.class)); } @Test diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java index 95724e79c3..b4d41f9031 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/discovery/reactive/PolarisReactiveDiscoveryClientTest.java @@ -57,6 +57,7 @@ public class PolarisReactiveDiscoveryClientTest { @Test public void testGetInstances() throws PolarisException { + when(serviceDiscovery.getInstances(anyString())).thenAnswer(invocation -> { String serviceName = invocation.getArgument(0); if (SERVICE_PROVIDER.equalsIgnoreCase(serviceName)) { @@ -78,6 +79,7 @@ public void testGetInstances() throws PolarisException { @Test public void testGetServices() throws PolarisException { + when(serviceDiscovery.getServices()).thenAnswer(invocation -> { if (count == 0) { count++; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java index dc9b41d9d5..bb1bbb481b 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/endpoint/PolarisDiscoveryEndpointTest.java @@ -53,7 +53,7 @@ public class PolarisDiscoveryEndpointTest { private static NamingServer namingServer; - private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( PolarisPropertiesConfiguration.class, PolarisDiscoveryClientConfiguration.class, diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulContextPropertiesTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryPropertiesTest.java similarity index 81% rename from spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulContextPropertiesTest.java rename to spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryPropertiesTest.java index 1d545b4e55..ac096d8627 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulContextPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/extend/consul/ConsulDiscoveryPropertiesTest.java @@ -37,21 +37,20 @@ import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.PREFER_IP_ADDRESS_KEY; import static com.tencent.polaris.plugins.connector.common.constant.ConsulConstant.MetadataMapKey.SERVICE_NAME_KEY; import static com.tencent.polaris.test.common.Consts.HOST; -import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link ConsulContextProperties}. + * Test for {@link ConsulDiscoveryPropertiesTest}. * * @author Haotian Zhang */ @ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ConsulContextPropertiesTest.TestApplication.class) +@SpringBootTest(classes = ConsulDiscoveryPropertiesTest.TestApplication.class) @ActiveProfiles("test") -public class ConsulContextPropertiesTest { +public class ConsulDiscoveryPropertiesTest { @Autowired - private ConsulContextProperties consulContextProperties; + private ConsulDiscoveryProperties consulDiscoveryProperties; @Autowired private PolarisSDKContextManager polarisSDKContextManager; @@ -63,12 +62,9 @@ void setUp() { @Test public void testDefaultInitialization() { - assertThat(consulContextProperties).isNotNull(); - assertThat(consulContextProperties.isEnabled()).isTrue(); - assertThat(consulContextProperties.getHost()).isEqualTo("127.0.0.1"); - assertThat(consulContextProperties.getPort()).isEqualTo(8500); - assertThat(consulContextProperties.isRegister()).isTrue(); - assertThat(consulContextProperties.isDiscoveryEnabled()).isTrue(); + assertThat(consulDiscoveryProperties).isNotNull(); + assertThat(consulDiscoveryProperties.isRegister()).isTrue(); + assertThat(consulDiscoveryProperties.isEnabled()).isTrue(); } @Test @@ -84,7 +80,7 @@ public void testModify() { } } assertThat(metadata).isNotNull(); - assertThat(metadata.get(SERVICE_NAME_KEY)).isEqualTo(SERVICE_PROVIDER); + assertThat(metadata.get(SERVICE_NAME_KEY)).isEqualTo("java-provider-test"); assertThat(metadata.get(INSTANCE_ID_KEY)).isEqualTo("ins-test"); assertThat(metadata.get(PREFER_IP_ADDRESS_KEY)).isEqualTo("true"); assertThat(metadata.get(IP_ADDRESS_KEY)).isEqualTo(HOST); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java index 9d78c9033b..e1c04a29b9 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisAutoServiceRegistrationTest.java @@ -71,6 +71,7 @@ public class PolarisAutoServiceRegistrationTest { @BeforeEach void setUp() { doNothing().when(serviceRegistry).register(nullable(PolarisRegistration.class)); + doNothing().when(serviceRegistry).deregister(nullable(PolarisRegistration.class)); polarisAutoServiceRegistration = new PolarisAutoServiceRegistration(serviceRegistry, autoServiceRegistrationProperties, registration, @@ -111,6 +112,32 @@ public void testRegisterManagement() { }).doesNotThrowAnyException(); } + @Test + public void testDeregister() { + doReturn(false).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.registerManagement(); + }).doesNotThrowAnyException(); + + doReturn(true).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.deregister(); + }).doesNotThrowAnyException(); + } + + @Test + public void testDeregisterManagement() { + doReturn(false).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.registerManagement(); + }).doesNotThrowAnyException(); + + doReturn(true).when(registration).isRegisterEnabled(); + assertThatCode(() -> { + polarisAutoServiceRegistration.deregisterManagement(); + }).doesNotThrowAnyException(); + } + @Test public void testGetAppName() { doReturn("application").when(environment).getProperty(anyString(), anyString()); diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java index cd60b31b6d..f9b62d3314 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java @@ -23,7 +23,7 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; +import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.config.global.APIConfig; @@ -76,9 +76,8 @@ void setUp() { PolarisContextProperties polarisContextProperties = mock(PolarisContextProperties.class); doReturn(testLocalPort).when(polarisContextProperties).getLocalPort(); - // mock ConsulContextProperties - ConsulContextProperties consulContextProperties = mock(ConsulContextProperties.class); - doReturn(true).when(consulContextProperties).isEnabled(); + // mock ConsulDiscoveryProperties + ConsulDiscoveryProperties consulContextProperties = mock(ConsulDiscoveryProperties.class); doReturn(true).when(consulContextProperties).isRegister(); // mock NacosContextProperties @@ -180,7 +179,7 @@ public void testGetMetadata() { Map metadata = polarisRegistration1.getMetadata(); assertThat(metadata).isNotNull(); assertThat(metadata).isNotEmpty(); - assertThat(metadata.size()).isEqualTo(4); + assertThat(metadata.size()).isEqualTo(2); assertThat(metadata.get("key1")).isEqualTo("value1"); } @@ -210,7 +209,7 @@ public void testGetNacosMetadata() { Map metadata = polarisRegistration1.getMetadata(); assertThat(metadata).isNotNull(); assertThat(metadata).isNotEmpty(); - assertThat(metadata.size()).isEqualTo(4); + assertThat(metadata.size()).isEqualTo(2); assertThat(metadata.get("nacos.cluster")).isEqualTo(clusterName); } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java index 2d96a99044..e51d9facc3 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryTest.java @@ -122,7 +122,8 @@ public void testRegister() { @Test public void testDeRegister() { this.contextRunner.run(context -> { - PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class); + PolarisServiceRegistry registry = context + .getBean(PolarisServiceRegistry.class); PolarisRegistration registration = Mockito.mock(PolarisRegistration.class); doReturn(null).when(registration).getServiceId(); assertThatCode(() -> { diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java similarity index 91% rename from spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java rename to spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java index 1c8e09f916..4c9d481eda 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/org/springframework/cloud/client/serviceregistry/AutoServiceRegistrationUtils.java @@ -17,7 +17,11 @@ package org.springframework.cloud.client.serviceregistry; -public class AutoServiceRegistrationUtils { +public final class AutoServiceRegistrationUtils { + + private AutoServiceRegistrationUtils() { + + } public static void register(AbstractAutoServiceRegistration autoServiceRegistration) { autoServiceRegistration.register(); diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml index 0b08cd790a..642ef93227 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml +++ b/spring-cloud-starter-tencent-polaris-ratelimit/pom.xml @@ -19,6 +19,11 @@ com.tencent.cloud spring-cloud-tencent-rpc-enhancement + + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + @@ -34,6 +39,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-canary diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java deleted file mode 100644 index f51b6f0b87..0000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolver.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.ratelimit; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.polaris.specification.api.v1.model.ModelProto; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; - -import org.springframework.util.CollectionUtils; - -/** - * resolve labels from rate limit rule. - * - *@author lepdou 2022-05-13 - */ -@Deprecated -public class RateLimitRuleLabelResolver { - - private final ServiceRuleManager serviceRuleManager; - - public RateLimitRuleLabelResolver(ServiceRuleManager serviceRuleManager) { - this.serviceRuleManager = serviceRuleManager; - } - - public Set getExpressionLabelKeys(String namespace, String service) { - RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service); - if (rateLimitRule == null) { - return Collections.emptySet(); - } - - List rules = rateLimitRule.getRulesList(); - if (CollectionUtils.isEmpty(rules)) { - return Collections.emptySet(); - } - - Set expressionLabels = new HashSet<>(); - for (RateLimitProto.Rule rule : rules) { - Map labels = rule.getLabelsMap(); - if (CollectionUtils.isEmpty(labels)) { - return Collections.emptySet(); - } - for (String key : labels.keySet()) { - if (ExpressionLabelUtils.isExpressionLabel(key)) { - expressionLabels.add(key); - } - } - } - return expressionLabels; - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java index 72d46d23aa..a034e4049a 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfiguration.java @@ -20,14 +20,9 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; -import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import org.springframework.beans.factory.annotation.Autowired; @@ -63,20 +58,13 @@ public class PolarisRateLimitAutoConfiguration { @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) protected static class QuotaCheckFilterConfig { - @Bean - public RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver(ServiceRuleManager serviceRuleManager, - @Autowired(required = false) PolarisRateLimiterLabelServletResolver labelResolver) { - return new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver); - } - @Bean @ConditionalOnMissingBean public QuotaCheckServletFilter quotaCheckFilter(PolarisSDKContextManager polarisSDKContextManager, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver, @Autowired(required = false) PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { - return new QuotaCheckServletFilter(polarisSDKContextManager.getLimitAPI(), polarisRateLimitProperties, - rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback); + return new QuotaCheckServletFilter(polarisSDKContextManager.getLimitAPI(), polarisSDKContextManager.getAssemblyAPI(), + polarisRateLimitProperties, polarisRateLimiterLimitedFallback); } @Bean @@ -97,21 +85,14 @@ public FilterRegistrationBean quotaFilterRegistrationBe */ @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) - protected static class MetadataReactiveFilterConfig { - - @Bean - public RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver(ServiceRuleManager serviceRuleManager, - @Autowired(required = false) PolarisRateLimiterLabelReactiveResolver labelResolver) { - return new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver); - } + protected static class QuotaCheckReactiveFilterConfig { @Bean public QuotaCheckReactiveFilter quotaCheckReactiveFilter(PolarisSDKContextManager polarisSDKContextManager, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver, @Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { - return new QuotaCheckReactiveFilter(polarisSDKContextManager.getLimitAPI(), polarisRateLimitProperties, - rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback); + return new QuotaCheckReactiveFilter(polarisSDKContextManager.getLimitAPI(), polarisSDKContextManager.getAssemblyAPI(), + polarisRateLimitProperties, polarisRateLimiterLimitedFallback); } } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java index ac820aa9e0..ebb9d75535 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitPropertiesAutoConfiguration.java @@ -28,8 +28,8 @@ * @author Haotian Zhang */ @Configuration(proxyBeanMethods = false) -@ConditionalOnPolarisRateLimitEnabled @EnableConfigurationProperties(PolarisRateLimitProperties.class) +@ConditionalOnPolarisRateLimitEnabled public class PolarisRateLimitPropertiesAutoConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java index 1d6cee8788..d062171cfb 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/config/RateLimitConfigModifier.java @@ -37,11 +37,13 @@ public RateLimitConfigModifier(PolarisRateLimitProperties polarisRateLimitProper @Override public void modify(ConfigurationImpl configuration) { // Update MaxQueuingTime. - configuration.getProvider().getRateLimit().setMaxQueuingTime(polarisRateLimitProperties.getMaxQueuingTime()); + configuration.getProvider().getRateLimit() + .setMaxQueuingTime(polarisRateLimitProperties.getMaxQueuingTime()); } @Override public int getOrder() { return OrderConstant.Modifier.RATE_LIMIT_ORDER; } + } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java index 8c28449283..a6218b27ac 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpoint.java @@ -41,7 +41,7 @@ * * @author shuiqingliu **/ -@Endpoint(id = "polaris-ratelimit") +@Endpoint(id = "polarisratelimit") public class PolarisRateLimitRuleEndpoint { private static final Logger LOG = LoggerFactory.getLogger(PolarisRateLimitRuleEndpoint.class); diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java index f6bf047060..d68a765a8c 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java @@ -23,7 +23,6 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Objects; -import java.util.Set; import javax.annotation.PostConstruct; @@ -31,13 +30,13 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils; import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils; import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.ratelimit.api.core.LimitAPI; -import com.tencent.polaris.ratelimit.api.rpc.Argument; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import org.slf4j.Logger; @@ -54,11 +53,12 @@ import org.springframework.web.server.WebFilterChain; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static org.springframework.core.io.buffer.DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY; /** * Reactive filter to check quota. * - * @author Haotian Zhang, lepdou, cheese8, kaiy + * @author Haotian Zhang, lepdou, kaiy, cheese8 */ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { @@ -66,22 +66,20 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { private final LimitAPI limitAPI; - private final PolarisRateLimitProperties polarisRateLimitProperties; + private final AssemblyAPI assemblyAPI; - private final RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver; + private final PolarisRateLimitProperties polarisRateLimitProperties; private final PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback; - private String rejectTips; - public QuotaCheckReactiveFilter(LimitAPI limitAPI, + public QuotaCheckReactiveFilter(LimitAPI limitAPI, AssemblyAPI assemblyAPI, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentResolver, @Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { this.limitAPI = limitAPI; + this.assemblyAPI = assemblyAPI; this.polarisRateLimitProperties = polarisRateLimitProperties; - this.rateLimitRuleArgumentResolver = rateLimitRuleArgumentResolver; this.polarisRateLimiterLimitedFallback = polarisRateLimiterLimitedFallback; } @@ -100,31 +98,41 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; - Set arguments = rateLimitRuleArgumentResolver.getArguments(exchange, localNamespace, localService); long waitMs = -1; + QuotaResponse quotaResponse = null; try { String path = exchange.getRequest().getURI().getPath(); - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota( - limitAPI, localNamespace, localService, 1, arguments, path); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, path); if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { ServerHttpResponse response = exchange.getResponse(); DataBuffer dataBuffer; - if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { + if (Objects.nonNull(quotaResponse.getActiveRule()) + && StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) { + response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode()); + response.getHeaders().setContentType(MediaType.TEXT_PLAIN); + dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY) + .write(quotaResponse.getActiveRule().getCustomResponse().getBody() + .getBytes(StandardCharsets.UTF_8)); + } + else if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { response.setRawStatusCode(polarisRateLimiterLimitedFallback.rejectHttpCode()); response.getHeaders().setContentType(polarisRateLimiterLimitedFallback.mediaType()); - dataBuffer = response.bufferFactory().allocateBuffer() + dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY) .write(polarisRateLimiterLimitedFallback.rejectTips() .getBytes(polarisRateLimiterLimitedFallback.charset())); } else { response.setRawStatusCode(polarisRateLimitProperties.getRejectHttpCode()); response.getHeaders().setContentType(MediaType.TEXT_HTML); - dataBuffer = response.bufferFactory().allocateBuffer() + dataBuffer = response.bufferFactory().allocateBuffer(DEFAULT_INITIAL_CAPACITY) .write(rejectTips.getBytes(StandardCharsets.UTF_8)); } + // set flow control to header response.getHeaders() .add(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); + // set trace span + RateLimitUtils.reportTrace(assemblyAPI, quotaResponse.getActiveRule().getId().getValue()); if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( @@ -136,6 +144,7 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { quotaResponse.getActiveRuleName(), e); } } + RateLimitUtils.release(quotaResponse); return response.writeWith(Mono.just(dataBuffer)); } // Unirate @@ -150,11 +159,13 @@ public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { LOG.error("fail to invoke getQuota, service is " + localService, t); } + QuotaResponse finalQuotaResponse = quotaResponse; if (waitMs > 0) { - return Mono.delay(Duration.ofMillis(waitMs)).flatMap(e -> chain.filter(exchange)); + return Mono.delay(Duration.ofMillis(waitMs)) + .flatMap(e -> chain.filter(exchange).doFinally((v) -> RateLimitUtils.release(finalQuotaResponse))); } else { - return chain.filter(exchange); + return chain.filter(exchange).doFinally((v) -> RateLimitUtils.release(finalQuotaResponse)); } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java index 7266e5b544..74282fc08a 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java @@ -22,7 +22,6 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Objects; -import java.util.Set; import javax.annotation.PostConstruct; import javax.servlet.FilterChain; @@ -34,13 +33,13 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.cloud.polaris.ratelimit.utils.QuotaCheckUtils; import com.tencent.cloud.polaris.ratelimit.utils.RateLimitUtils; import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.ratelimit.api.core.LimitAPI; -import com.tencent.polaris.ratelimit.api.rpc.Argument; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import org.slf4j.Logger; @@ -69,21 +68,20 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class); private final LimitAPI limitAPI; - private final PolarisRateLimitProperties polarisRateLimitProperties; + private final AssemblyAPI assemblyAPI; - private final RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver; + private final PolarisRateLimitProperties polarisRateLimitProperties; private final PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback; private String rejectTips; - public QuotaCheckServletFilter(LimitAPI limitAPI, + public QuotaCheckServletFilter(LimitAPI limitAPI, AssemblyAPI assemblyAPI, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver, @Nullable PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { this.limitAPI = limitAPI; + this.assemblyAPI = assemblyAPI; this.polarisRateLimitProperties = polarisRateLimitProperties; - this.rateLimitRuleArgumentResolver = rateLimitRuleArgumentResolver; this.polarisRateLimiterLimitedFallback = polarisRateLimiterLimitedFallback; } @@ -94,19 +92,20 @@ public void init() { @Override protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain) - throws ServletException, IOException { + @NonNull FilterChain filterChain) throws ServletException, IOException { String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localService = MetadataContext.LOCAL_SERVICE; - - Set arguments = rateLimitRuleArgumentResolver.getArguments(request, localNamespace, localService); - + QuotaResponse quotaResponse = null; try { - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, - localNamespace, localService, 1, arguments, request.getRequestURI()); - + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, request.getRequestURI()); if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { - if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { + if (Objects.nonNull(quotaResponse.getActiveRule()) + && StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) { + response.setStatus(polarisRateLimitProperties.getRejectHttpCode()); + response.setContentType("text/plain;charset=UTF-8"); + response.getWriter().write(quotaResponse.getActiveRule().getCustomResponse().getBody()); + } + else if (!Objects.isNull(polarisRateLimiterLimitedFallback)) { response.setStatus(polarisRateLimiterLimitedFallback.rejectHttpCode()); String contentType = new MediaType(polarisRateLimiterLimitedFallback.mediaType(), polarisRateLimiterLimitedFallback.charset()).toString(); response.setContentType(contentType); @@ -117,7 +116,10 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht response.setContentType("text/html;charset=UTF-8"); response.getWriter().write(rejectTips); } + // set flow control to header response.addHeader(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); + // set trace span + RateLimitUtils.reportTrace(assemblyAPI, quotaResponse.getActiveRule().getId().getValue()); if (Objects.nonNull(quotaResponse.getActiveRule())) { try { String encodedActiveRuleName = URLEncoder.encode( @@ -129,6 +131,7 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht quotaResponse.getActiveRuleName(), e); } } + RateLimitUtils.release(quotaResponse); return; } // Unirate @@ -144,7 +147,12 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht LOG.error("fail to invoke getQuota, service is " + localService, t); } - filterChain.doFilter(request, response); + try { + filterChain.doFilter(request, response); + } + finally { + RateLimitUtils.release(quotaResponse); + } } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java deleted file mode 100644 index 13c57d8179..0000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolver.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.ratelimit.resolver; - -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.CollectionUtils; -import org.springframework.web.server.ServerWebExchange; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; - -/** - * resolve arguments from rate limit rule for Reactive. - * - * @author seansyyu 2023-03-09 - */ -public class RateLimitRuleArgumentReactiveResolver { - - private static final Logger LOG = LoggerFactory.getLogger(RateLimitRuleArgumentReactiveResolver.class); - - private final ServiceRuleManager serviceRuleManager; - - private final PolarisRateLimiterLabelReactiveResolver labelResolver; - - public RateLimitRuleArgumentReactiveResolver(ServiceRuleManager serviceRuleManager, PolarisRateLimiterLabelReactiveResolver labelResolver) { - this.serviceRuleManager = serviceRuleManager; - this.labelResolver = labelResolver; - } - - public Set getArguments(ServerWebExchange request, String namespace, String service) { - RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service); - if (rateLimitRule == null) { - return Collections.emptySet(); - } - List rules = rateLimitRule.getRulesList(); - if (CollectionUtils.isEmpty(rules)) { - return Collections.emptySet(); - } - return rules.stream() - .flatMap(rule -> rule.getArgumentsList().stream()) - .map(matchArgument -> { - String matchKey = matchArgument.getKey(); - Argument argument = null; - switch (matchArgument.getType()) { - case CUSTOM: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)) - .orElse(StringUtils.EMPTY)); - break; - case METHOD: - argument = Argument.buildMethod(request.getRequest().getMethodValue()); - break; - case HEADER: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildHeader(matchKey, Optional.ofNullable(request.getRequest().getHeaders() - .getFirst(matchKey)).orElse(StringUtils.EMPTY)); - break; - case QUERY: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildQuery(matchKey, Optional.ofNullable(request.getRequest().getQueryParams() - .getFirst(matchKey)).orElse(StringUtils.EMPTY)); - break; - case CALLER_SERVICE: - String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true) - .orElse(StringUtils.EMPTY); - String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true) - .orElse(StringUtils.EMPTY); - if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) { - argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName); - } - break; - case CALLER_IP: - InetSocketAddress remoteAddress = request.getRequest().getRemoteAddress(); - argument = Argument.buildCallerIP(remoteAddress != null ? remoteAddress.getAddress() - .getHostAddress() : StringUtils.EMPTY); - break; - default: - break; - } - return argument; - }).filter(Objects::nonNull).collect(Collectors.toSet()); - } - - private Map getCustomResolvedLabels(ServerWebExchange request) { - if (labelResolver != null) { - try { - return labelResolver.resolve(request); - } - catch (Throwable e) { - LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e); - } - } - return Collections.emptyMap(); - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java deleted file mode 100644 index e384d03336..0000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolver.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.ratelimit.resolver; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; - -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.util.CollectionUtils; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; - -/** - * resolve arguments from rate limit rule for Servlet. - * - * @author seansyyu 2023-03-09 - */ -public class RateLimitRuleArgumentServletResolver { - - private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class); - - private final ServiceRuleManager serviceRuleManager; - - private final PolarisRateLimiterLabelServletResolver labelResolver; - - public RateLimitRuleArgumentServletResolver(ServiceRuleManager serviceRuleManager, PolarisRateLimiterLabelServletResolver labelResolver) { - this.serviceRuleManager = serviceRuleManager; - this.labelResolver = labelResolver; - } - - public Set getArguments(HttpServletRequest request, String namespace, String service) { - RateLimitProto.RateLimit rateLimitRule = serviceRuleManager.getServiceRateLimitRule(namespace, service); - if (rateLimitRule == null) { - return Collections.emptySet(); - } - List rules = rateLimitRule.getRulesList(); - if (CollectionUtils.isEmpty(rules)) { - return Collections.emptySet(); - } - return rules.stream() - .flatMap(rule -> rule.getArgumentsList().stream()) - .map(matchArgument -> { - String matchKey = matchArgument.getKey(); - Argument argument = null; - switch (matchArgument.getType()) { - case CUSTOM: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildCustom(matchKey, Optional.ofNullable(getCustomResolvedLabels(request).get(matchKey)).orElse(StringUtils.EMPTY)); - break; - case METHOD: - argument = Argument.buildMethod(request.getMethod()); - break; - case HEADER: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildHeader(matchKey, Optional.ofNullable(request.getHeader(matchKey)).orElse(StringUtils.EMPTY)); - break; - case QUERY: - argument = StringUtils.isBlank(matchKey) ? null : - Argument.buildQuery(matchKey, Optional.ofNullable(request.getParameter(matchKey)).orElse(StringUtils.EMPTY)); - break; - case CALLER_SERVICE: - String sourceServiceNamespace = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, true).orElse(StringUtils.EMPTY); - String sourceServiceName = MetadataContextHolder.getDisposableMetadata(DEFAULT_METADATA_SOURCE_SERVICE_NAME, true).orElse(StringUtils.EMPTY); - if (!StringUtils.isEmpty(sourceServiceNamespace) && !StringUtils.isEmpty(sourceServiceName)) { - argument = Argument.buildCallerService(sourceServiceNamespace, sourceServiceName); - } - break; - case CALLER_IP: - argument = Argument.buildCallerIP(Optional.ofNullable(request.getRemoteAddr()).orElse(StringUtils.EMPTY)); - break; - default: - break; - } - return argument; - }).filter(Objects::nonNull).collect(Collectors.toSet()); - } - - private Map getCustomResolvedLabels(HttpServletRequest request) { - if (labelResolver != null) { - try { - return labelResolver.resolve(request); - } - catch (Throwable e) { - LOG.error("resolve custom label failed. resolver = {}", labelResolver.getClass().getName(), e); - } - } - return Collections.emptyMap(); - } - -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.java new file mode 100644 index 0000000000..c4a4aaebe7 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitAutoConfiguration.java @@ -0,0 +1,44 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.ratelimit.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +/** + * Auto configuration of TSF rate limit. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +public class TsfRateLimitAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfRateLimitConfigModifier tsfRateLimitConfigModifier(TsfCoreProperties tsfCoreProperties, + ConsulProperties consulProperties, Environment environment) { + return new TsfRateLimitConfigModifier(tsfCoreProperties, consulProperties, environment); + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitBootstrapConfiguration.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitBootstrapConfiguration.java new file mode 100644 index 0000000000..f71c1d0e4c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitBootstrapConfiguration.java @@ -0,0 +1,34 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.ratelimit.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * Bootstrap configuration for TSF rate limit. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnTsfConsulEnabled +@Import(TsfRateLimitAutoConfiguration.class) +public class TsfRateLimitBootstrapConfiguration { +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.java new file mode 100644 index 0000000000..682559c23a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/tsf/TsfRateLimitConfigModifier.java @@ -0,0 +1,68 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.ratelimit.tsf; + +import java.util.Map; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextUtils; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.ratelimit.client.sync.tsf.TsfRateLimitConstants; + +import org.springframework.core.env.Environment; + +/** + * Config modifier for TSF rate limit. + * + * @author Haotian Zhang + */ +public class TsfRateLimitConfigModifier implements PolarisConfigModifier { + + private final TsfCoreProperties tsfCoreProperties; + + private final ConsulProperties consulProperties; + + private final Environment environment; + + public TsfRateLimitConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties, + Environment environment) { + this.tsfCoreProperties = tsfCoreProperties; + this.consulProperties = consulProperties; + this.environment = environment; + } + + @Override + public void modify(ConfigurationImpl configuration) { + if (TsfContextUtils.isTsfConsulEnabled(environment)) { + Map metadata = configuration.getProvider().getRateLimit().getMetadata(); + metadata.put(TsfRateLimitConstants.RATE_LIMIT_MASTER_IP_KEY, tsfCoreProperties.getRatelimitMasterIp()); + metadata.put(TsfRateLimitConstants.RATE_LIMIT_MASTER_PORT_KEY, String.valueOf(tsfCoreProperties.getRatelimitMasterPort())); + metadata.put(TsfRateLimitConstants.SERVICE_NAME_KEY, tsfCoreProperties.getServiceName()); + metadata.put(TsfRateLimitConstants.INSTANCE_ID_KEY, tsfCoreProperties.getInstanceId()); + metadata.put(TsfRateLimitConstants.TOKEN_KEY, consulProperties.getAclToken()); + } + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.RATE_LIMIT_ORDER; + } +} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java index 3adcee5e4a..a3ea944468 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtils.java @@ -17,12 +17,9 @@ package com.tencent.cloud.polaris.ratelimit.utils; -import java.util.Map; -import java.util.Set; - +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; -import com.tencent.polaris.ratelimit.api.rpc.Argument; import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import org.slf4j.Logger; @@ -40,34 +37,13 @@ public final class QuotaCheckUtils { private QuotaCheckUtils() { } - @Deprecated - public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, - Map labels, String method) { - // build quota request - QuotaRequest quotaRequest = new QuotaRequest(); - quotaRequest.setNamespace(namespace); - quotaRequest.setService(service); - quotaRequest.setCount(count); - quotaRequest.setLabels(labels); - quotaRequest.setMethod(method); - - try { - return limitAPI.getQuota(quotaRequest); - } - catch (Throwable throwable) { - LOG.error("fail to invoke getQuota of LimitAPI with QuotaRequest[{}].", quotaRequest, throwable); - return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "get quota failed")); - } - } - - public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, - Set arguments, String method) { + public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count, String method) { // build quota request QuotaRequest quotaRequest = new QuotaRequest(); quotaRequest.setNamespace(namespace); quotaRequest.setService(service); quotaRequest.setCount(count); - quotaRequest.setArguments(arguments); + quotaRequest.setMetadataContext(MetadataContextHolder.get()); quotaRequest.setMethod(method); try { diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java index 6ddcad9317..1b90b1beb5 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/utils/RateLimitUtils.java @@ -18,9 +18,17 @@ package com.tencent.cloud.polaris.ratelimit.utils; +import java.util.HashMap; +import java.util.Map; + import com.tencent.cloud.common.util.ResourceFileUtils; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant; +import com.tencent.polaris.api.plugin.stat.TraceConstants; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; +import com.tencent.polaris.assembly.api.pojo.TraceAttributes; +import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,17 +44,18 @@ public final class RateLimitUtils { private static final Logger LOG = LoggerFactory.getLogger(RateLimitUtils.class); private RateLimitUtils() { + } public static String getRejectTips(PolarisRateLimitProperties polarisRateLimitProperties) { String tips = polarisRateLimitProperties.getRejectRequestTips(); - if (!StringUtils.isEmpty(tips)) { + if (StringUtils.hasText(tips)) { return tips; } String rejectFilePath = polarisRateLimitProperties.getRejectRequestTipsFilePath(); - if (!StringUtils.isEmpty(rejectFilePath)) { + if (StringUtils.hasText(rejectFilePath)) { try { tips = ResourceFileUtils.readFile(rejectFilePath); } @@ -56,10 +65,39 @@ public static String getRejectTips(PolarisRateLimitProperties polarisRateLimitPr } } - if (!StringUtils.isEmpty(tips)) { + if (StringUtils.hasText(tips)) { return tips; } return RateLimitConstant.QUOTA_LIMITED_INFO; } + + public static void reportTrace(AssemblyAPI assemblyAPI, String ruleId) { + try { + if (assemblyAPI != null) { + Map attributes = new HashMap<>(); + attributes.put(TraceConstants.RateLimitRuleId, ruleId); + TraceAttributes traceAttributes = new TraceAttributes(); + traceAttributes.setAttributes(attributes); + traceAttributes.setAttributeLocation(TraceAttributes.AttributeLocation.SPAN); + assemblyAPI.updateTraceAttributes(traceAttributes); + } + } + catch (Throwable throwable) { + LOG.warn("[RateLimit] Report rule id {} to trace error.", ruleId, throwable); + } + } + + public static void release(QuotaResponse quotaResponse) { + if (quotaResponse != null && CollectionUtils.isNotEmpty(quotaResponse.getReleaseList())) { + for (Runnable release : quotaResponse.getReleaseList()) { + try { + release.run(); + } + catch (Throwable throwable) { + LOG.warn("[RateLimit] Release error.", throwable); + } + } + } + } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories index 563704410a..7a4abe837c 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/resources/META-INF/spring.factories @@ -3,4 +3,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesAutoConfiguration,\ com.tencent.cloud.polaris.ratelimit.endpoint.PolarisRateLimitRuleEndpointAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesBootstrapConfiguration + com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitPropertiesBootstrapConfiguration,\ + com.tencent.cloud.polaris.ratelimit.tsf.TsfRateLimitBootstrapConfiguration diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java index d4296c7709..660611c18f 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/CalleeControllerTests.java @@ -17,15 +17,16 @@ package com.tencent.cloud.polaris.context; +import com.google.protobuf.StringValue; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaResponse; import com.tencent.polaris.ratelimit.api.rpc.QuotaResultCode; import com.tencent.polaris.ratelimit.factory.LimitAPIFactory; +import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; import com.tencent.polaris.test.mock.discovery.NamingServer; import com.tencent.polaris.test.mock.discovery.NamingService; import org.junit.jupiter.api.AfterAll; @@ -63,10 +64,9 @@ */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = { CalleeControllerTests.Config.class, TestController.class }, - properties = { "spring.application.name=java_provider_test", - "spring.cloud.polaris.discovery.namespace=Test", - "spring.cloud.polaris.address=grpc://127.0.0.1:10081" }) + classes = {CalleeControllerTests.Config.class, TestController.class}, + properties = {"spring.application.name=java_provider_test", "spring.cloud.polaris.discovery.namespace=Test", + "spring.cloud.polaris.address=grpc://127.0.0.1:10081"}) public class CalleeControllerTests { private static NamingServer namingServer; @@ -90,8 +90,7 @@ static void beforeAll() throws Exception { instanceParameter.setIsolated(false); instanceParameter.setWeight(100); ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER); - namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, - instanceParameter); + namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, instanceParameter); } @AfterAll @@ -120,6 +119,13 @@ public void test1() { QuotaResponse quotaResponse = mock(QuotaResponse.class); when(quotaResponse.getCode()).thenReturn(QuotaResultCode.QuotaResultLimited); when(quotaResponse.getInfo()).thenReturn("Testing rate limit after 10 times success."); + RateLimitProto.Rule rule = mock(RateLimitProto.Rule.class); + when(rule.getId()).thenReturn(StringValue.of("rate-test")); + RateLimitProto.CustomResponse customResponse = mock(RateLimitProto.CustomResponse.class); + when(customResponse.getBody()).thenReturn("limited"); + when(rule.getCustomResponse()).thenReturn(customResponse); + when(quotaResponse.getActiveRule()).thenReturn(rule); + when(quotaResponse.getActiveRuleName()).thenReturn("rate-test"); when(limitAPI.getQuota(any())).thenReturn(quotaResponse); } String result = restTemplate.getForObject(url, String.class); @@ -128,7 +134,7 @@ public void test1() { } catch (RestClientException e) { if (e instanceof TooManyRequests) { - System.out.println(((TooManyRequests) e).getResponseBodyAsString()); + assertThat(((TooManyRequests) e).getResponseBodyAsString()).isEqualTo("limited"); hasLimited = true; } else { @@ -159,10 +165,8 @@ public LimitAPI limitAPI(PolarisSDKContextManager polarisSDKContextManager) { @Primary public QuotaCheckServletFilter quotaCheckFilter(LimitAPI limitAPI, PolarisRateLimitProperties polarisRateLimitProperties, - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentResolver, @Autowired(required = false) PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback) { - return new QuotaCheckServletFilter(limitAPI, polarisRateLimitProperties, - rateLimitRuleArgumentResolver, polarisRateLimiterLimitedFallback); + return new QuotaCheckServletFilter(limitAPI, null, polarisRateLimitProperties, polarisRateLimiterLimitedFallback); } } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java index c4e99a4d5a..f56db9b4b3 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/context/TestController.java @@ -31,7 +31,7 @@ public class TestController { @GetMapping("/info") - public String info() { + public String info() throws Exception { return "hello service info"; } } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java deleted file mode 100644 index 4d39e0c39c..0000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/RateLimitRuleLabelResolverTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.polaris.ratelimit; - -import java.util.Set; - -import com.google.protobuf.StringValue; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.polaris.specification.api.v1.model.ModelProto; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Test for {@link RateLimitRuleLabelResolver}. - * - * @author Haotian Zhang - */ -@ExtendWith(MockitoExtension.class) -public class RateLimitRuleLabelResolverTest { - - private RateLimitRuleLabelResolver rateLimitRuleLabelResolver; - - @BeforeEach - void setUp() { - ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - when(serviceRuleManager.getServiceRateLimitRule(any(), anyString())).thenAnswer(invocationOnMock -> { - String serviceName = invocationOnMock.getArgument(1).toString(); - if (serviceName.equals("TestApp1")) { - return null; - } - else if (serviceName.equals("TestApp2")) { - return RateLimitProto.RateLimit.newBuilder().build(); - } - else if (serviceName.equals("TestApp3")) { - RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder().build(); - return RateLimitProto.RateLimit.newBuilder().addRules(rule).build(); - } - else { - ModelProto.MatchString matchString = ModelProto.MatchString.newBuilder() - .setType(ModelProto.MatchString.MatchStringType.EXACT) - .setValue(StringValue.of("value")) - .setValueType(ModelProto.MatchString.ValueType.TEXT).build(); - RateLimitProto.Rule rule = RateLimitProto.Rule.newBuilder() - .putLabels("${http.method}", matchString).build(); - return RateLimitProto.RateLimit.newBuilder().addRules(rule).build(); - } - }); - - rateLimitRuleLabelResolver = new RateLimitRuleLabelResolver(serviceRuleManager); - } - - @Test - public void testGetExpressionLabelKeys() { - // rateLimitRule == null - String serviceName = "TestApp1"; - Set labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isEmpty(); - - // CollectionUtils.isEmpty(rules) - serviceName = "TestApp2"; - labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isEmpty(); - - // CollectionUtils.isEmpty(labels) - serviceName = "TestApp3"; - labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isEmpty(); - - // Has labels - serviceName = "TestApp4"; - labelKeys = rateLimitRuleLabelResolver.getExpressionLabelKeys(null, serviceName); - assertThat(labelKeys).isNotEmpty(); - assertThat(labelKeys).contains("${http.method}"); - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java index 9a959e511e..668df07b39 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/config/PolarisRateLimitAutoConfigurationTest.java @@ -20,8 +20,6 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckReactiveFilter; import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilter; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -43,8 +41,7 @@ public class PolarisRateLimitAutoConfigurationTest { private final WebApplicationContextRunner webApplicationContextRunner = new WebApplicationContextRunner(); - private final ReactiveWebApplicationContextRunner reactiveWebApplicationContextRunner = - new ReactiveWebApplicationContextRunner(); + private final ReactiveWebApplicationContextRunner reactiveWebApplicationContextRunner = new ReactiveWebApplicationContextRunner(); @Test public void testNoWebApplication() { @@ -54,12 +51,10 @@ public void testNoWebApplication() { PolarisRateLimitProperties.class, PolarisRateLimitAutoConfiguration.class)) .run(context -> { - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentServletResolver.class); - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentReactiveResolver.class); assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class); assertThat(context).doesNotHaveBean(FilterRegistrationBean.class); - assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class); + assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class); }); } @@ -67,33 +62,31 @@ public void testNoWebApplication() { @Test public void testServletWebApplication() { this.webApplicationContextRunner - .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of( + PolarisContextAutoConfiguration.class, PolarisRateLimitProperties.class, PolarisRateLimitAutoConfiguration.class)) .run(context -> { - assertThat(context).hasSingleBean(RateLimitRuleArgumentServletResolver.class); assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class); assertThat(context).hasSingleBean(QuotaCheckServletFilter.class); assertThat(context).hasSingleBean(FilterRegistrationBean.class); - assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class); + assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckReactiveFilter.class); - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentReactiveResolver.class); }); } @Test public void testReactiveWebApplication() { this.reactiveWebApplicationContextRunner - .withConfiguration(AutoConfigurations.of(PolarisContextAutoConfiguration.class, + .withConfiguration(AutoConfigurations.of( + PolarisContextAutoConfiguration.class, PolarisRateLimitProperties.class, PolarisRateLimitAutoConfiguration.class)) .run(context -> { - assertThat(context).doesNotHaveBean(RateLimitRuleArgumentServletResolver.class); - assertThat(context).hasSingleBean(RateLimitRuleArgumentReactiveResolver.class); assertThat(context).doesNotHaveBean(PolarisRateLimitAutoConfiguration.QuotaCheckFilterConfig.class); assertThat(context).doesNotHaveBean(QuotaCheckServletFilter.class); assertThat(context).doesNotHaveBean(FilterRegistrationBean.class); - assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.MetadataReactiveFilterConfig.class); + assertThat(context).hasSingleBean(PolarisRateLimitAutoConfiguration.QuotaCheckReactiveFilterConfig.class); assertThat(context).hasSingleBean(QuotaCheckReactiveFilter.class); }); } diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java index dd4e43a681..acc1438aae 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/endpoint/PolarisRateLimitRuleEndpointTests.java @@ -51,7 +51,7 @@ @ExtendWith(MockitoExtension.class) public class PolarisRateLimitRuleEndpointTests { - private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( PolarisRateLimitRuleEndpointTests.PolarisRateLimitAutoConfiguration.class, PolarisRateLimitRuleEndpointAutoConfiguration.class, @@ -60,8 +60,7 @@ public class PolarisRateLimitRuleEndpointTests { .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("server.port=" + PORT) .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") - .withPropertyValues( - "spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) + .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST) .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); private ServiceRuleManager serviceRuleManager; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java index 812ebb1e87..f99e5d0afd 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java @@ -27,13 +27,13 @@ import java.util.stream.Collectors; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.StringValue; import com.google.protobuf.util.JsonFormat; +import com.tencent.cloud.common.constant.HeaderConstant; import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentReactiveResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; @@ -67,15 +67,13 @@ /** * Test for {@link QuotaCheckReactiveFilter}. * - * @author Haotian Zhang, cheese8, kaiy + * @author Haotian Zhang, kaiy */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) @SpringBootTest(classes = QuotaCheckReactiveFilterTest.TestApplication.class, properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"}) public class QuotaCheckReactiveFilterTest { - private final PolarisRateLimiterLabelReactiveResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); private QuotaCheckReactiveFilter quotaCheckReactiveFilter; private QuotaCheckReactiveFilter quotaCheckWithRateLimiterLimitedFallbackReactiveFilter; private PolarisRateLimiterLimitedFallback polarisRateLimiterLimitedFallback; @@ -95,11 +93,12 @@ else if (serviceName.equals("TestApp2")) { } else if (serviceName.equals("TestApp3")) { QuotaResponse response = new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited")); - response.setActiveRule(RateLimitProto.Rule.newBuilder().build()); + response.setActiveRule(RateLimitProto.Rule.newBuilder() + .setName(StringValue.newBuilder().setValue("MOCK_RULE").build()).build()); return response; } else { - return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, null)); + return new QuotaResponse(new QuotaResult(null, 0, null)); } }); @@ -123,10 +122,10 @@ else if (serviceName.equals("TestApp3")) { RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver); - this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, polarisRateLimitProperties, rateLimitRuleArgumentReactiveResolver, null); + this.quotaCheckReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, null, polarisRateLimitProperties, null); this.polarisRateLimiterLimitedFallback = new JsonPolarisRateLimiterLimitedFallback(); - this.quotaCheckWithRateLimiterLimitedFallbackReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentReactiveResolver, polarisRateLimiterLimitedFallback); + this.quotaCheckWithRateLimiterLimitedFallbackReactiveFilter = new QuotaCheckReactiveFilter(limitAPI, null, + polarisRateLimitWithHtmlRejectTipsProperties, polarisRateLimiterLimitedFallback); } @Test @@ -185,6 +184,8 @@ public void testFilter() { ServerHttpResponse response = testApp3Exchange.getResponse(); assertThat(response.getRawStatusCode()).isEqualTo(419); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INSUFFICIENT_SPACE_ON_RESOURCE); + assertThat(response.getHeaders() + .get(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)).isEqualTo(Collections.singletonList("MOCK_RULE")); // Exception MetadataContext.LOCAL_SERVICE = "TestApp4"; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java index 13065c92b5..d6a760ad61 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilterTest.java @@ -23,19 +23,18 @@ import java.io.InputStreamReader; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; -import java.util.Collections; import java.util.stream.Collectors; import javax.servlet.FilterChain; import javax.servlet.ServletException; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.StringValue; import com.google.protobuf.util.JsonFormat; +import com.tencent.cloud.common.constant.HeaderConstant; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties; -import com.tencent.cloud.polaris.ratelimit.resolver.RateLimitRuleArgumentServletResolver; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLimitedFallback; import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; @@ -69,12 +68,10 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = QuotaCheckServletFilterTest.TestApplication.class, properties = { - "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" -}) + "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" + }) public class QuotaCheckServletFilterTest { - private final PolarisRateLimiterLabelServletResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); private QuotaCheckServletFilter quotaCheckServletFilter; private QuotaCheckServletFilter quotaCheckWithHtmlRejectTipsServletFilter; private QuotaCheckServletFilter quotaCheckWithRateLimiterLimitedFallbackFilter; @@ -95,7 +92,8 @@ else if (serviceName.equals("TestApp2")) { } else if (serviceName.equals("TestApp3")) { QuotaResponse response = new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultLimited, 0, "QuotaResultLimited")); - response.setActiveRule(RateLimitProto.Rule.newBuilder().build()); + response.setActiveRule(RateLimitProto.Rule.newBuilder() + .setName(StringValue.newBuilder().setValue("MOCK_RULE").build()).build()); return response; } else { @@ -113,19 +111,22 @@ else if (serviceName.equals("TestApp3")) { ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); - InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); + RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); + InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader() + .getResourceAsStream("ratelimit.json"); + String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines() + .collect(Collectors.joining("")); JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder); RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build(); RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver); - this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitProperties, rateLimitRuleArgumentServletResolver, null); - this.quotaCheckWithHtmlRejectTipsServletFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentServletResolver, null); + this.quotaCheckServletFilter = new QuotaCheckServletFilter(limitAPI, null, polarisRateLimitProperties, null); + this.quotaCheckWithHtmlRejectTipsServletFilter = new QuotaCheckServletFilter(limitAPI, null, + polarisRateLimitWithHtmlRejectTipsProperties, null); this.polarisRateLimiterLimitedFallback = new JsonPolarisRateLimiterLimitedFallback(); - this.quotaCheckWithRateLimiterLimitedFallbackFilter = new QuotaCheckServletFilter(limitAPI, polarisRateLimitWithHtmlRejectTipsProperties, rateLimitRuleArgumentServletResolver, polarisRateLimiterLimitedFallback); + this.quotaCheckWithRateLimiterLimitedFallbackFilter = new QuotaCheckServletFilter(limitAPI, null, + polarisRateLimitWithHtmlRejectTipsProperties, polarisRateLimiterLimitedFallback); } @Test @@ -182,13 +183,13 @@ public void testDoFilterInternal() { quotaCheckServletFilter.doFilterInternal(request, testApp3Response, filterChain); assertThat(testApp3Response.getStatus()).isEqualTo(419); assertThat(testApp3Response.getContentAsString()).isEqualTo("RejectRequestTips提示消息"); + assertThat(testApp3Response.getHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)).isEqualTo("MOCK_RULE"); MockHttpServletResponse testApp3Response2 = new MockHttpServletResponse(); quotaCheckWithHtmlRejectTipsServletFilter.doFilterInternal(request, testApp3Response2, filterChain); assertThat(testApp3Response2.getStatus()).isEqualTo(419); assertThat(testApp3Response2.getContentAsString()).isEqualTo("

RejectRequestTips提示消息

"); - // Exception MockHttpServletResponse testApp4Response = new MockHttpServletResponse(); MetadataContext.LOCAL_SERVICE = "TestApp4"; diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java deleted file mode 100644 index 1648a96183..0000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentReactiveResolverTest.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.polaris.ratelimit.resolver; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilterTest; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.http.server.reactive.MockServerHttpRequest; -import org.springframework.mock.web.server.MockServerWebExchange; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.web.server.ServerWebExchange; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = RateLimitRuleArgumentReactiveResolverTest.TestApplication.class, - properties = { - "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" - }) -public class RateLimitRuleArgumentReactiveResolverTest { - - private final PolarisRateLimiterLabelReactiveResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); - - private final PolarisRateLimiterLabelReactiveResolver labelResolverEx = - exchange -> { - throw new RuntimeException(); - }; - - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver1; - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver2; - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver3; - private RateLimitRuleArgumentReactiveResolver rateLimitRuleArgumentReactiveResolver4; - - @BeforeEach - void setUp() throws InvalidProtocolBufferException { - MetadataContext.LOCAL_NAMESPACE = "TEST"; - - ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - - RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); - InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder); - RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build(); - RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); - when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - - // normal - this.rateLimitRuleArgumentReactiveResolver1 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolver); - // ex - this.rateLimitRuleArgumentReactiveResolver2 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager, labelResolverEx); - // null - ServiceRuleManager serviceRuleManager1 = mock(ServiceRuleManager.class); - when(serviceRuleManager1.getServiceRateLimitRule(anyString(), anyString())).thenReturn(null); - this.rateLimitRuleArgumentReactiveResolver3 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager1, labelResolver); - // null 2 - ServiceRuleManager serviceRuleManager2 = mock(ServiceRuleManager.class); - RateLimitProto.RateLimit rateLimit2 = RateLimitProto.RateLimit.newBuilder().build(); - when(serviceRuleManager2.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit2); - this.rateLimitRuleArgumentReactiveResolver4 = new RateLimitRuleArgumentReactiveResolver(serviceRuleManager2, labelResolver); - } - - @Test - public void testGetRuleArguments() { - // Mock request - MetadataContext.LOCAL_SERVICE = "Test"; - // Mock request - MockServerHttpRequest request = MockServerHttpRequest.get("http://127.0.0.1:8080/test") - .remoteAddress(new InetSocketAddress("127.0.0.1", 8080)) - .header("xxx", "xxx") - .queryParam("yyy", "yyy") - .build(); - ServerWebExchange exchange = MockServerWebExchange.from(request); - MetadataContext metadataContext = new MetadataContext(); - metadataContext.setUpstreamDisposableMetadata(new HashMap() {{ - put(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, MetadataContext.LOCAL_NAMESPACE); - put(DEFAULT_METADATA_SOURCE_SERVICE_NAME, MetadataContext.LOCAL_SERVICE); - }}); - MetadataContextHolder.set(metadataContext); - Set arguments = rateLimitRuleArgumentReactiveResolver1.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - Set exceptRes = new HashSet<>(); - exceptRes.add(Argument.buildMethod("GET")); - exceptRes.add(Argument.buildHeader("xxx", "xxx")); - exceptRes.add(Argument.buildQuery("yyy", "yyy")); - exceptRes.add(Argument.buildCallerIP("127.0.0.1")); - exceptRes.add(Argument.buildCustom("xxx", "xxx")); - exceptRes.add(Argument.buildCallerService(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); - assertThat(arguments).isEqualTo(exceptRes); - - rateLimitRuleArgumentReactiveResolver2.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentReactiveResolver3.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentReactiveResolver4.getArguments(exchange, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - } - - @SpringBootApplication - protected static class TestApplication { - } - -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java deleted file mode 100644 index 1a8b49ed7f..0000000000 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/resolver/RateLimitRuleArgumentServletResolverTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.polaris.ratelimit.resolver; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.ratelimit.filter.QuotaCheckServletFilterTest; -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; -import com.tencent.polaris.ratelimit.api.rpc.Argument; -import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAME; -import static com.tencent.cloud.common.constant.MetadataConstant.DefaultMetadata.DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - classes = RateLimitRuleArgumentServletResolverTest.TestApplication.class, - properties = { - "spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp" - }) -public class RateLimitRuleArgumentServletResolverTest { - - private final PolarisRateLimiterLabelServletResolver labelResolver = - exchange -> Collections.singletonMap("xxx", "xxx"); - private final PolarisRateLimiterLabelServletResolver labelResolverEx = - exchange -> { - throw new RuntimeException(); - }; - - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver1; - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver2; - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver3; - private RateLimitRuleArgumentServletResolver rateLimitRuleArgumentServletResolver4; - - @BeforeEach - void setUp() throws InvalidProtocolBufferException { - MetadataContext.LOCAL_NAMESPACE = "TEST"; - - ServiceRuleManager serviceRuleManager = mock(ServiceRuleManager.class); - - RateLimitProto.Rule.Builder ratelimitRuleBuilder = RateLimitProto.Rule.newBuilder(); - InputStream inputStream = QuotaCheckServletFilterTest.class.getClassLoader().getResourceAsStream("ratelimit.json"); - String json = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines().collect(Collectors.joining("")); - JsonFormat.parser().ignoringUnknownFields().merge(json, ratelimitRuleBuilder); - RateLimitProto.Rule rateLimitRule = ratelimitRuleBuilder.build(); - RateLimitProto.RateLimit rateLimit = RateLimitProto.RateLimit.newBuilder().addRules(rateLimitRule).build(); - when(serviceRuleManager.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit); - - // normal - this.rateLimitRuleArgumentServletResolver1 = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolver); - // ex - this.rateLimitRuleArgumentServletResolver2 = new RateLimitRuleArgumentServletResolver(serviceRuleManager, labelResolverEx); - // null - ServiceRuleManager serviceRuleManager1 = mock(ServiceRuleManager.class); - when(serviceRuleManager1.getServiceRateLimitRule(anyString(), anyString())).thenReturn(null); - this.rateLimitRuleArgumentServletResolver3 = new RateLimitRuleArgumentServletResolver(serviceRuleManager1, labelResolver); - // null 2 - ServiceRuleManager serviceRuleManager2 = mock(ServiceRuleManager.class); - RateLimitProto.RateLimit rateLimit2 = RateLimitProto.RateLimit.newBuilder().build(); - when(serviceRuleManager2.getServiceRateLimitRule(anyString(), anyString())).thenReturn(rateLimit2); - this.rateLimitRuleArgumentServletResolver4 = new RateLimitRuleArgumentServletResolver(serviceRuleManager2, labelResolver); - } - - @Test - public void testGetRuleArguments() { - // Mock request - MetadataContext.LOCAL_SERVICE = "Test"; - MockHttpServletRequest request = new MockHttpServletRequest(null, "GET", "/xxx"); - request.setParameter("yyy", "yyy"); - request.addHeader("xxx", "xxx"); - MetadataContext metadataContext = new MetadataContext(); - metadataContext.setUpstreamDisposableMetadata(new HashMap() {{ - put(DEFAULT_METADATA_SOURCE_SERVICE_NAMESPACE, MetadataContext.LOCAL_NAMESPACE); - put(DEFAULT_METADATA_SOURCE_SERVICE_NAME, MetadataContext.LOCAL_SERVICE); - }}); - MetadataContextHolder.set(metadataContext); - Set arguments = rateLimitRuleArgumentServletResolver1.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - Set exceptRes = new HashSet<>(); - exceptRes.add(Argument.buildMethod("GET")); - exceptRes.add(Argument.buildHeader("xxx", "xxx")); - exceptRes.add(Argument.buildQuery("yyy", "yyy")); - exceptRes.add(Argument.buildCallerIP("127.0.0.1")); - exceptRes.add(Argument.buildCustom("xxx", "xxx")); - exceptRes.add(Argument.buildCallerService(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); - assertThat(arguments).isEqualTo(exceptRes); - - rateLimitRuleArgumentServletResolver2.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentServletResolver3.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - rateLimitRuleArgumentServletResolver4.getArguments(request, MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE); - } - - @SpringBootApplication - protected static class TestApplication { - } -} diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java index ad2691f4d9..792948c882 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/utils/QuotaCheckUtilsTest.java @@ -17,9 +17,6 @@ package com.tencent.cloud.polaris.ratelimit.utils; -import java.util.HashMap; -import java.util.HashSet; - import com.tencent.polaris.api.plugin.ratelimiter.QuotaResult; import com.tencent.polaris.ratelimit.api.core.LimitAPI; import com.tencent.polaris.ratelimit.api.rpc.QuotaRequest; @@ -69,59 +66,28 @@ else if (serviceName.equals("TestApp3")) { public void testGetQuota() { // Pass String serviceName = "TestApp1"; - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); - assertThat(quotaResponse.getWaitMs()).isEqualTo(0); - assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); - - // Unirate waiting 1000ms - serviceName = "TestApp2"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); - assertThat(quotaResponse.getWaitMs()).isEqualTo(1000); - assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); - - // Rate limited - serviceName = "TestApp3"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited); - assertThat(quotaResponse.getWaitMs()).isEqualTo(0); - assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited"); - - // Exception - serviceName = "TestApp4"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashMap<>(), null); - assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); - assertThat(quotaResponse.getWaitMs()).isEqualTo(0); - assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed"); - } - - @Test - public void testGetQuota2() { - // Pass - String serviceName = "TestApp1"; - QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); assertThat(quotaResponse.getWaitMs()).isEqualTo(0); assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); // Unirate waiting 1000ms serviceName = "TestApp2"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); assertThat(quotaResponse.getWaitMs()).isEqualTo(1000); assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultOk"); // Rate limited serviceName = "TestApp3"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultLimited); assertThat(quotaResponse.getWaitMs()).isEqualTo(0); assertThat(quotaResponse.getInfo()).isEqualTo("QuotaResultLimited"); // Exception serviceName = "TestApp4"; - quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, new HashSet<>(), null); + quotaResponse = QuotaCheckUtils.getQuota(limitAPI, null, serviceName, 1, null); assertThat(quotaResponse.getCode()).isEqualTo(QuotaResultCode.QuotaResultOk); assertThat(quotaResponse.getWaitMs()).isEqualTo(0); assertThat(quotaResponse.getInfo()).isEqualTo("get quota failed"); diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 98ab742b06..3975201b49 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -50,7 +50,7 @@ com.tencent.polaris - router-lane + router-namespace diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java index 96545d6210..3b9e23c749 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java @@ -35,6 +35,7 @@ import com.netflix.loadbalancer.ZoneAvoidanceRule; import com.tencent.cloud.common.constant.RouterConstant; import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; @@ -206,6 +207,7 @@ ProcessRoutersRequest buildProcessRoutersBaseRequest(ServiceInstances serviceIns serviceInfo.setNamespace(MetadataContext.LOCAL_NAMESPACE); serviceInfo.setService(MetadataContext.LOCAL_SERVICE); processRoutersRequest.setSourceService(serviceInfo); + processRoutersRequest.setMetadataContainerGroup(MetadataContextHolder.get().getMetadataContainerGroup(false)); return processRoutersRequest; } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java index 6d380f5bb0..ef87b68cb0 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisRouterContext.java @@ -13,14 +13,13 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. + * */ package com.tencent.cloud.polaris.router; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -28,11 +27,12 @@ import org.apache.commons.lang.StringUtils; import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; /** * the context for router. * - * @author lepdou 2022-05-17 + * @author lepdou, Hoatian Zhang */ public class PolarisRouterContext { @@ -77,37 +77,19 @@ public String getLabel(String labelKey) { return routerLabels.get(labelKey); } - public Set getLabelAsSet(String labelKey) { - Map routerLabels = labels.get(RouterConstant.ROUTER_LABELS); - if (CollectionUtils.isEmpty(routerLabels)) { - return Collections.emptySet(); - } - - for (Map.Entry entry : routerLabels.entrySet()) { - if (StringUtils.equalsIgnoreCase(labelKey, entry.getKey())) { - String keysStr = entry.getValue(); - if (StringUtils.isNotBlank(keysStr)) { - String[] keysArr = StringUtils.split(keysStr, ","); - return new HashSet<>(Arrays.asList(keysArr)); - } - } - } - - return Collections.emptySet(); - } - public void putLabels(String labelType, Map subLabels) { if (this.labels == null) { this.labels = new HashMap<>(); } - labels.put(labelType, subLabels); + + Map subLabelMap = new LinkedCaseInsensitiveMap<>(); + if (!CollectionUtils.isEmpty(subLabels)) { + subLabelMap.putAll(subLabels); + } + labels.put(labelType, subLabelMap); } public Map> getLabels() { return labels; } - - public void setLabels(Map> labels) { - this.labels = labels; - } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java index 4d30dab48c..67376a187b 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/RouterConfigModifier.java @@ -22,9 +22,10 @@ import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; -import com.tencent.polaris.api.plugin.route.LocationLevel; import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; import com.tencent.polaris.plugins.router.nearby.NearbyRouterConfig; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import org.apache.commons.lang.StringUtils; /** @@ -42,8 +43,18 @@ public RouterConfigModifier(PolarisNearByRouterProperties polarisNearByRouterPro @Override public void modify(ConfigurationImpl configuration) { + // Set excludeCircuitBreakInstances to false + RecoverRouterConfig recoverRouterConfig = configuration.getConsumer().getServiceRouter() + .getPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, RecoverRouterConfig.class); + recoverRouterConfig.setExcludeCircuitBreakInstances(false); + + // Update modified config to source properties + configuration.getConsumer().getServiceRouter() + .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig); + if (StringUtils.isNotBlank(polarisNearByRouterProperties.getMatchLevel())) { - LocationLevel locationLevel = LocationLevel.valueOf(polarisNearByRouterProperties.getMatchLevel()); + RoutingProto.NearbyRoutingConfig.LocationLevel locationLevel = + RoutingProto.NearbyRoutingConfig.LocationLevel.valueOf(StringUtils.upperCase(polarisNearByRouterProperties.getMatchLevel())); NearbyRouterConfig nearbyRouterConfig = configuration.getConsumer().getServiceRouter().getPluginConfig( ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, NearbyRouterConfig.class); nearbyRouterConfig.setMatchLevel(locationLevel); diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java index 67f2aff2ae..a71c2e8d3d 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java @@ -18,21 +18,14 @@ package com.tencent.cloud.polaris.router.config; -import java.util.List; - -import com.tencent.cloud.common.metadata.StaticMetadataManager; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.lang.Nullable; /** * configuration for feign singleton components. @@ -47,12 +40,8 @@ public class FeignAutoConfiguration { @Bean - public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List routerLabelResolvers, - StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver, - PolarisContextProperties polarisContextProperties) { - return new RouterLabelFeignInterceptor(routerLabelResolvers, staticMetadataManager, - routerRuleLabelResolver, polarisContextProperties); + public RouterLabelFeignInterceptor routerLabelInterceptor() { + return new RouterLabelFeignInterceptor(); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java index 17222e23ca..9e783a2170 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java @@ -23,6 +23,7 @@ import com.tencent.cloud.polaris.router.feign.PolarisFeignLoadBalancer; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.context.annotation.Bean; @@ -40,6 +41,7 @@ public class FeignLoadBalancerConfiguration { @Bean + @ConditionalOnMissingClass("com.netflix.zuul.http.ZuulServlet") @ConditionalOnMissingBean public PolarisFeignLoadBalancer polarisFeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig, ServerIntrospector serverIntrospector) { diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java index 868d54b32a..69238fbf76 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java @@ -18,6 +18,8 @@ package com.tencent.cloud.polaris.router.config; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.tencent.cloud.common.metadata.StaticMetadataManager; @@ -28,16 +30,24 @@ import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.beanprocessor.RetryLoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNamespaceRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterceptor; +import com.tencent.cloud.polaris.router.interceptor.NamespaceRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor; import com.tencent.cloud.polaris.router.resttemplate.RouterContextFactory; +import com.tencent.cloud.polaris.router.resttemplate.RouterLabelRestTemplateInterceptor; +import com.tencent.cloud.polaris.router.scg.RouterLabelGlobalFilter; import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; import com.tencent.cloud.polaris.router.zuul.PolarisRibbonRoutingFilter; +import com.tencent.cloud.polaris.router.zuul.RouterLabelZuulFilter; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -47,8 +57,9 @@ import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.web.client.RestTemplate; import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; @@ -60,7 +71,6 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisRouterEnabled @RibbonClients(defaultConfiguration = {RibbonConfiguration.class}) -@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class}) public class RouterAutoConfiguration { @Bean @@ -93,9 +103,30 @@ public RuleBasedRouterRequestInterceptor ruleBasedRouterRequestInterceptor(Polar return new RuleBasedRouterRequestInterceptor(polarisRuleBasedRouterProperties); } + @Bean + @ConditionalOnProperty(value = "spring.cloud.polaris.router.namespace-router.enabled", matchIfMissing = true) + public NamespaceRouterRequestInterceptor namespaceRouterRequestInterceptor(PolarisNamespaceRouterProperties polarisNamespaceRouterProperties) { + return new NamespaceRouterRequestInterceptor(polarisNamespaceRouterProperties); + } + + /** + * Create when gateway application is SCG. + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(name = "org.springframework.cloud.gateway.filter.GlobalFilter") + protected static class RouterLabelScgFilterConfig { + + @Bean + public RouterLabelGlobalFilter routerLabelGlobalFilter() { + return new RouterLabelGlobalFilter(); + } + + } + @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") public static class RestTemplateAutoConfiguration { + @Bean @Order(HIGHEST_PRECEDENCE) @ConditionalOnClass(name = "org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor") @@ -125,6 +156,7 @@ public RouterContextFactory routerContextFactory(List restTemplates = Collections.emptyList(); + + @Bean + public RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor() { + return new RouterLabelRestTemplateInterceptor(); + } + + @Bean + public SmartInitializingSingleton addRouterLabelInterceptorForRestTemplate(RouterLabelRestTemplateInterceptor interceptor) { + return () -> restTemplates.forEach(restTemplate -> { + List list = new ArrayList<>(restTemplate.getInterceptors()); + int addIndex = list.size(); + for (int i = 0; i < list.size(); i++) { + if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { + addIndex = i; + } + } + list.add(addIndex, interceptor); + restTemplate.setInterceptors(list); + }); + } } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java index e1de4a37f7..c3669ab80c 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterConfigModifierAutoConfiguration.java @@ -20,6 +20,7 @@ import com.tencent.cloud.polaris.router.RouterConfigModifier; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNamespaceRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; @@ -35,7 +36,8 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisRouterEnabled -@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class}) +@Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class, + PolarisNamespaceRouterProperties.class}) public class RouterConfigModifierAutoConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java index 949edc54ae..79f1f5aaa8 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.router.config.properties; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java new file mode 100644 index 0000000000..16250b7225 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNamespaceRouterProperties.java @@ -0,0 +1,59 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.router.config.properties; + +import com.tencent.polaris.api.rpc.NamespaceRouterFailoverType; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * the configuration for namespace router. + * + * @author lepdou 2022-05-23 + */ +@ConfigurationProperties(prefix = "spring.cloud.polaris.router.namespace-router") +public class PolarisNamespaceRouterProperties { + + private boolean enabled = false; + + private NamespaceRouterFailoverType failOver = NamespaceRouterFailoverType.all; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public NamespaceRouterFailoverType getFailOver() { + return failOver; + } + + public void setFailOver(NamespaceRouterFailoverType failOver) { + this.failOver = failOver; + } + + @Override + public String toString() { + return "PolarisNamespaceRouterProperties{" + + "enabled=" + enabled + + ", failOver=" + failOver + + '}'; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java index 1c6a76a60e..226195a135 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.router.config.properties; @@ -28,7 +27,7 @@ @ConfigurationProperties(prefix = "spring.cloud.polaris.router.nearby-router") public class PolarisNearByRouterProperties { - private boolean enabled = true; + private boolean enabled = false; private String matchLevel; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java index 67a17975ff..e9ecceabfe 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java @@ -13,11 +13,12 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.router.config.properties; +import com.tencent.polaris.api.rpc.RuleBasedRouterFailoverType; + import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -30,6 +31,8 @@ public class PolarisRuleBasedRouterProperties { private boolean enabled = true; + private RuleBasedRouterFailoverType failOver = RuleBasedRouterFailoverType.all; + public boolean isEnabled() { return enabled; } @@ -38,11 +41,19 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + public RuleBasedRouterFailoverType getFailOver() { + return failOver; + } + + public void setFailOver(RuleBasedRouterFailoverType failOver) { + this.failOver = failOver; + } + @Override public String toString() { - return "PolarisNearByRouterProperties{" + + return "PolarisRuleBasedRouterProperties{" + "enabled=" + enabled + + ", failOver=" + failOver + '}'; } - } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java index eac72ba12f..b7a65e4e58 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/endpoint/PolarisRouterEndpoint.java @@ -42,7 +42,7 @@ * Router actuator endpoint. * @author lepdou 2022-07-25 */ -@Endpoint(id = "polaris-router") +@Endpoint(id = "polarisrouter") public class PolarisRouterEndpoint { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisRouterEndpoint.class); diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java deleted file mode 100644 index 849d563c61..0000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.router.feign; - -import java.net.URI; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; -import feign.RequestTemplate; -import org.apache.commons.lang.StringUtils; - -import org.springframework.util.CollectionUtils; - -/** - * Resolve rule expression label from feign request. - * - * @author lepdou 2022-05-20 - */ -public final class FeignExpressionLabelUtils { - - private FeignExpressionLabelUtils() { - } - - public static Map resolve(RequestTemplate request, Set labelKeys) { - if (CollectionUtils.isEmpty(labelKeys)) { - return Collections.emptyMap(); - } - - Map labels = new HashMap<>(); - - for (String labelKey : labelKeys) { - if (ExpressionLabelUtils.isHeaderLabel(labelKey)) { - String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey); - if (StringUtils.isBlank(headerKey)) { - continue; - } - labels.put(labelKey, getHeaderValue(request, headerKey)); - } - else if (ExpressionLabelUtils.isQueryLabel(labelKey)) { - String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey); - if (StringUtils.isBlank(queryKey)) { - continue; - } - labels.put(labelKey, getQueryValue(request, queryKey)); - } - else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { - String cookieKey = ExpressionLabelUtils.parseCookieKey(labelKey); - if (StringUtils.isBlank(cookieKey)) { - continue; - } - labels.put(labelKey, getCookieValue(request, cookieKey)); - } - else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { - labels.put(labelKey, request.method()); - } - else if (ExpressionLabelUtils.isUriLabel(labelKey)) { - URI uri = URI.create(request.request().url()); - labels.put(labelKey, uri.getPath()); - } - } - - return labels; - } - - public static String getHeaderValue(RequestTemplate request, String key) { - Map> headers = request.headers(); - return ExpressionLabelUtils.getFirstValue(headers, key); - } - - public static String getQueryValue(RequestTemplate request, String key) { - return ExpressionLabelUtils.getFirstValue(request.queries(), key); - } - - public static String getCookieValue(RequestTemplate request, String key) { - Map> headers = request.headers(); - return ExpressionLabelUtils.getCookieFirstValue(headers, key); - } -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java index dea8ff1bf3..7313908101 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancer.java @@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -36,7 +37,6 @@ import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer; -import org.springframework.util.CollectionUtils; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; @@ -65,8 +65,8 @@ protected void customizeLoadBalancerCommandBuilder(RibbonRequest request, IClien PolarisRouterContext buildRouterContext(Map> headers) { Collection labelHeaderValues = headers.get(RouterConstant.ROUTER_LABEL_HEADER); - if (CollectionUtils.isEmpty(labelHeaderValues)) { - return null; + if (labelHeaderValues == null) { + labelHeaderValues = new ArrayList<>(0); } PolarisRouterContext routerContext = new PolarisRouterContext(); diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java index 0faa26a5a3..eda50162f1 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptor.java @@ -18,63 +18,21 @@ package com.tencent.cloud.polaris.router.feign; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.constant.RouterConstant; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.metadata.StaticMetadataManager; -import com.tencent.cloud.common.util.JacksonUtils; -import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; +import com.tencent.cloud.metadata.provider.FeignRequestTemplateMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; import feign.RequestInterceptor; import feign.RequestTemplate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; -import org.springframework.util.CollectionUtils; - -import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; /** - * Resolver labels from request. + * Interceptor used for setting Feign RequestTemplate metadata provider. * - * @author lepdou, cheese8 + * @author lepdou, cheese8, Hoatian Zhang */ public class RouterLabelFeignInterceptor implements RequestInterceptor, Ordered { - private static final Logger LOGGER = LoggerFactory.getLogger(RouterLabelFeignInterceptor.class); - - private final List routerLabelResolvers; - private final StaticMetadataManager staticMetadataManager; - private final RouterRuleLabelResolver routerRuleLabelResolver; - private final PolarisContextProperties polarisContextProperties; - - public RouterLabelFeignInterceptor(List routerLabelResolvers, - StaticMetadataManager staticMetadataManager, - RouterRuleLabelResolver routerRuleLabelResolver, - PolarisContextProperties polarisContextProperties) { - if (!CollectionUtils.isEmpty(routerLabelResolvers)) { - routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder)); - this.routerLabelResolvers = routerLabelResolvers; - } - else { - this.routerLabelResolvers = null; - } - this.staticMetadataManager = staticMetadataManager; - this.routerRuleLabelResolver = routerRuleLabelResolver; - this.polarisContextProperties = polarisContextProperties; - } @Override public int getOrder() { @@ -83,62 +41,7 @@ public int getOrder() { @Override public void apply(RequestTemplate requestTemplate) { - // local service labels - Map labels = new HashMap<>(staticMetadataManager.getMergedStaticMetadata()); - - // labels from rule expression - String peerServiceName = requestTemplate.feignTarget().name(); - Set expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, - MetadataContext.LOCAL_SERVICE, peerServiceName); - - Map ruleExpressionLabels = getRuleExpressionLabels(requestTemplate, expressionLabelKeys); - labels.putAll(ruleExpressionLabels); - - // labels from custom spi - if (!CollectionUtils.isEmpty(routerLabelResolvers)) { - routerLabelResolvers.forEach(resolver -> { - try { - Map customResolvedLabels = resolver.resolve(requestTemplate, expressionLabelKeys); - if (!CollectionUtils.isEmpty(customResolvedLabels)) { - labels.putAll(customResolvedLabels); - } - } - catch (Throwable t) { - LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t); - } - }); - } - - // labels from downstream - Map transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata(); - labels.putAll(transitiveLabels); - - // pass label by header - String encodedLabelsContent; - try { - encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(labels), UTF_8); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException("unsupported charset exception " + UTF_8); - } - requestTemplate.header(RouterConstant.ROUTER_LABEL_HEADER, encodedLabelsContent); - } - - private Map getRuleExpressionLabels(RequestTemplate requestTemplate, Set labelKeys) { - if (CollectionUtils.isEmpty(labelKeys)) { - return Collections.emptyMap(); - } - - //enrich labels from request - Map labels = FeignExpressionLabelUtils.resolve(requestTemplate, labelKeys); - - //enrich caller ip label - for (String labelKey : labelKeys) { - if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) { - labels.put(labelKey, polarisContextProperties.getLocalIpAddress()); - } - } - - return labels; + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new FeignRequestTemplateMetadataProvider(requestTemplate)); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java index 8a4f7137b0..3a97f7624b 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/MetadataRouterRequestInterceptor.java @@ -18,23 +18,19 @@ package com.tencent.cloud.polaris.router.interceptor; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.tencent.cloud.common.constant.RouterConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; -import com.tencent.polaris.api.pojo.RouteArgument; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.metadata.MetadataRouter; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; -import org.springframework.util.CollectionUtils; - /** * Router request interceptor for metadata router. - * @author lepdou 2022-07-06 + * @author lepdou, Hoatian Zhang */ public class MetadataRouterRequestInterceptor implements RouterRequestInterceptor { private static final String LABEL_KEY_METADATA_ROUTER_KEYS = "system-metadata-router-keys"; @@ -51,18 +47,10 @@ public void apply(ProcessRoutersRequest request, PolarisRouterContext routerCont return; } - // 1. get metadata router label keys - Set metadataRouterKeys = routerContext.getLabelAsSet(LABEL_KEY_METADATA_ROUTER_KEYS); - // 2. get metadata router labels - Map metadataRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS, - metadataRouterKeys); - // 3. set metadata router labels to request - Set routeArguments = new HashSet<>(); - if (!CollectionUtils.isEmpty(metadataRouterKeys)) { - for (Map.Entry entry : metadataRouterLabels.entrySet()) { - routeArguments.add(RouteArgument.fromLabel(entry.getKey(), entry.getValue())); - } - } - request.putRouterArgument(MetadataRouter.ROUTER_TYPE_METADATA, routeArguments); + // set metadata router label keys + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + String metadataRouteKeys = metadataContainer.getRawMetadataStringValue(LABEL_KEY_METADATA_ROUTER_KEYS); + metadataContainer.putMetadataMapValue(MetadataRouter.ROUTER_TYPE_METADATA, MetadataRouter.KEY_METADATA_KEYS, metadataRouteKeys, TransitiveType.NONE); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java new file mode 100644 index 0000000000..e9dd95fe38 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NamespaceRouterRequestInterceptor.java @@ -0,0 +1,55 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.interceptor; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.config.properties.PolarisNamespaceRouterProperties; +import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; +import com.tencent.polaris.plugins.router.namespace.NamespaceRouter; +import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; + +/** + * Router request interceptor for namespace router. + * + * @author Hoatian Zhang + */ +public class NamespaceRouterRequestInterceptor implements RouterRequestInterceptor { + + private final PolarisNamespaceRouterProperties polarisNamespaceRouterProperties; + + public NamespaceRouterRequestInterceptor(PolarisNamespaceRouterProperties polarisNamespaceRouterProperties) { + this.polarisNamespaceRouterProperties = polarisNamespaceRouterProperties; + } + + @Override + public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { + // set namespace router enable + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataMapValue(NamespaceRouter.ROUTER_TYPE_NAMESPACE, NamespaceRouter.ROUTER_ENABLED, + String.valueOf(polarisNamespaceRouterProperties.isEnabled()), TransitiveType.NONE); + + // set namespace router fail over type. + request.setNamespaceRouterFailoverType(polarisNamespaceRouterProperties.getFailOver()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java index ca59f77883..6d40e0c552 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/NearbyRouterRequestInterceptor.java @@ -18,13 +18,13 @@ package com.tencent.cloud.polaris.router.interceptor; -import java.util.HashSet; -import java.util.Set; - +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; -import com.tencent.polaris.api.pojo.RouteArgument; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.nearby.NearbyRouter; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; @@ -42,13 +42,10 @@ public NearbyRouterRequestInterceptor(PolarisNearByRouterProperties polarisNearB @Override public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { - if (!polarisNearByRouterProperties.isEnabled()) { - return; - } - - Set routeArguments = new HashSet<>(1); - routeArguments.add(RouteArgument.buildCustom(NearbyRouter.ROUTER_ENABLED, "true")); - - request.putRouterArgument(NearbyRouter.ROUTER_TYPE_NEAR_BY, routeArguments); + // set nearby router enable + boolean nearbyRouterEnabled = polarisNearByRouterProperties.isEnabled(); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataMapValue(NearbyRouter.ROUTER_TYPE_NEAR_BY, NearbyRouter.ROUTER_ENABLED, String.valueOf(nearbyRouterEnabled), TransitiveType.NONE); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java index 64d8c913f3..39d9e37b82 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/interceptor/RuleBasedRouterRequestInterceptor.java @@ -13,28 +13,23 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.polaris.router.interceptor; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.tencent.cloud.common.constant.RouterConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.cloud.polaris.router.spi.RouterRequestInterceptor; -import com.tencent.polaris.api.pojo.RouteArgument; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; -import org.springframework.util.CollectionUtils; - /** * Router request interceptor for rule based router. - * @author lepdou 2022-07-06 + * @author lepdou, Hoatian Zhang */ public class RuleBasedRouterRequestInterceptor implements RouterRequestInterceptor { @@ -46,24 +41,12 @@ public RuleBasedRouterRequestInterceptor(PolarisRuleBasedRouterProperties polari @Override public void apply(ProcessRoutersRequest request, PolarisRouterContext routerContext) { + // set rule based router enable boolean ruleBasedRouterEnabled = polarisRuleBasedRouterProperties.isEnabled(); - - // set dynamic switch for rule based router - Set routeArguments = new HashSet<>(); - routeArguments.add(RouteArgument.buildCustom(RuleBasedRouter.ROUTER_ENABLED, String.valueOf(ruleBasedRouterEnabled))); - - // The label information that the rule based routing depends on - // is placed in the metadata of the source service for transmission. - // Later, can consider putting it in routerMetadata like other routers. - if (ruleBasedRouterEnabled) { - Map ruleRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS); - if (!CollectionUtils.isEmpty(ruleRouterLabels)) { - for (Map.Entry label : ruleRouterLabels.entrySet()) { - routeArguments.add(RouteArgument.fromLabel(label.getKey(), label.getValue())); - } - } - } - - request.putRouterArgument(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, routeArguments); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataMapValue(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, RuleBasedRouter.ROUTER_ENABLED, String.valueOf(ruleBasedRouterEnabled), TransitiveType.NONE); + // set rule based router fail over type. + request.setRuleBasedRouterFailoverType(polarisRuleBasedRouterProperties.getFailOver()); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.java new file mode 100644 index 0000000000..d079f7b876 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptor.java @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.router.resttemplate; + +import java.io.IOException; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.provider.RestTemplateMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; + +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; + +/** + * Interceptor used for setting RestTemplate HttpRequest metadata provider. + * + * @author liuye, Hoatian Zhang + */ +public class RouterLabelRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered { + + @Override + public int getOrder() { + return OrderConstant.Client.RestTemplate.ROUTER_LABEL_INTERCEPTOR_ORDER; + } + + @Override + public ClientHttpResponse intercept(@NonNull HttpRequest request, @NonNull byte[] body, + @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new RestTemplateMetadataProvider(request)); + return clientHttpRequestExecution.execute(request, body); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java new file mode 100644 index 0000000000..b0bb6ab8f1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilter.java @@ -0,0 +1,57 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.scg; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; +import reactor.core.publisher.Mono; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.web.server.ServerWebExchange; + +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; + +/** + * Interceptor used for setting SCG ServerWebExchange metadata provider. + * + * @author Hoatian Zhang + */ +public class RouterLabelGlobalFilter implements GlobalFilter, Ordered { + @Override + public int getOrder() { + return LOAD_BALANCER_CLIENT_FILTER_ORDER - 1; + } + + /** + * Copied from ReactiveLoadBalancerClientFilter, and create new RequestData for passing router labels. + */ + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new ReactiveMetadataProvider(exchange.getRequest(), + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP))); + return chain.filter(exchange); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java new file mode 100644 index 0000000000..c4170153c5 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/zuul/RouterLabelZuulFilter.java @@ -0,0 +1,66 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.zuul; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.metadata.provider.ServletMetadataProvider; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.constant.MetadataConstants; +import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup; + +import org.springframework.core.Ordered; + +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; + +/** + * Interceptor used for setting Zuul metadata provider. + * + * @author Shedfree Wu + */ +public class RouterLabelZuulFilter extends ZuulFilter { + @Override + public String filterType() { + return PRE_TYPE; + } + + @Override + public int filterOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() throws ZuulException { + RequestContext context = RequestContext.getCurrentContext(); + + MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false) + .setMetadataProvider(new ServletMetadataProvider(context.getRequest(), + CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer() + .getRawMetadataStringValue(MetadataConstants.LOCAL_IP))); + + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 631bd8e42e..92251c9163 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -9,14 +9,14 @@ { "name": "spring.cloud.polaris.router.nearby-router.enabled", "type": "java.lang.Boolean", - "defaultValue": true, - "description": "the switch for near by router." + "defaultValue": false, + "description": "the switch for nearby router." }, { "name": "spring.cloud.polaris.router.nearby-router.matchLevel", "type": "java.lang.String", - "defaultValue": "zone", - "description": "the match level for nearby router, options can be region/zone/campus." + "defaultValue": "ZONE", + "description": "the match level for nearby router, options can be REGION/ZONE/CAMPUS." }, { "name": "spring.cloud.polaris.router.rule-router.enabled", @@ -24,11 +24,48 @@ "defaultValue": true, "description": "the switch for rule based router." }, + { + "name": "spring.cloud.polaris.router.rule-router.failOver", + "type": "java.lang.String", + "defaultValue": "all", + "description": "the fail over type for rule based router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "the switch for namespace router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.failOver", + "type": "java.lang.String", + "defaultValue": "all", + "description": "the fail over type for namespace router." + }, { "name": "spring.cloud.polaris.router.enabled", "type": "java.lang.Boolean", "defaultValue": true, "description": "the switch for router module." } + ], + "hints": [ + { + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", + "values": [ + { + "value": "CAMPUS" + }, + { + "value": "ZONE" + }, + { + "value": "REGION" + }, + { + "value": "ALL" + } + ] + } ] } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories index db8b9bec4d..c350e3ff9f 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories @@ -1,6 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.polaris.router.config.RouterConfigModifierAutoConfiguration,\ com.tencent.cloud.polaris.router.config.RouterAutoConfiguration,\ com.tencent.cloud.polaris.router.config.FeignAutoConfiguration,\ com.tencent.cloud.polaris.router.endpoint.PolarisRouterEndpointAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.router.config.RouterBootstrapAutoConfiguration \ No newline at end of file + com.tencent.cloud.polaris.router.config.RouterBootstrapAutoConfiguration diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java new file mode 100644 index 0000000000..7c835c8a65 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/MockApplicationContext.java @@ -0,0 +1,262 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Map; + +import com.tencent.cloud.common.metadata.StaticMetadataManager; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.MessageSourceResolvable; +import org.springframework.context.NoSuchMessageException; +import org.springframework.core.ResolvableType; +import org.springframework.core.env.Environment; +import org.springframework.core.io.Resource; + +public class MockApplicationContext implements org.springframework.context.ApplicationContext { + @Override + public String getId() { + return null; + } + + @Override + public String getApplicationName() { + return null; + } + + @Override + public String getDisplayName() { + return null; + } + + @Override + public long getStartupDate() { + return 0; + } + + @Override + public ApplicationContext getParent() { + return null; + } + + @Override + public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { + return null; + } + + @Override + public BeanFactory getParentBeanFactory() { + return null; + } + + @Override + public boolean containsLocalBean(String name) { + return false; + } + + @Override + public boolean containsBeanDefinition(String beanName) { + return false; + } + + @Override + public int getBeanDefinitionCount() { + return 0; + } + + @Override + public String[] getBeanDefinitionNames() { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(ResolvableType type) { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(Class type) { + return new String[0]; + } + + @Override + public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) { + return new String[0]; + } + + @Override + public Map getBeansOfType(Class type) throws BeansException { + return null; + } + + @Override + public Map getBeansOfType(Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { + return null; + } + + @Override + public String[] getBeanNamesForAnnotation(Class annotationType) { + return new String[0]; + } + + @Override + public Map getBeansWithAnnotation(Class annotationType) throws BeansException { + return null; + } + + @Override + public A findAnnotationOnBean(String beanName, Class annotationType) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public Object getBean(String name) throws BeansException { + + return null; + } + + @Override + public T getBean(String name, Class requiredType) throws BeansException { + return null; + } + + @Override + public Object getBean(String name, Object... args) throws BeansException { + return null; + } + + @Override + public T getBean(Class requiredType) throws BeansException { + if (requiredType.equals(StaticMetadataManager.class)) { + return (T) new StaticMetadataManager(new MetadataLocalProperties(), new ArrayList<>()); + } + + return null; + } + + @Override + public T getBean(Class requiredType, Object... args) throws BeansException { + return null; + } + + @Override + public ObjectProvider getBeanProvider(Class requiredType) { + return null; + } + + @Override + public ObjectProvider getBeanProvider(ResolvableType requiredType) { + return null; + } + + @Override + public boolean containsBean(String name) { + return false; + } + + @Override + public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException { + return false; + } + + @Override + public Class getType(String name) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { + return null; + } + + @Override + public String[] getAliases(String name) { + return new String[0]; + } + + @Override + public void publishEvent(Object event) { + + } + + @Override + public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) { + return null; + } + + @Override + public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException { + return null; + } + + @Override + public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException { + return null; + } + + @Override + public Environment getEnvironment() { + return null; + } + + @Override + public Resource[] getResources(String locationPattern) throws IOException { + return new Resource[0]; + } + + @Override + public Resource getResource(String location) { + return null; + } + + @Override + public ClassLoader getClassLoader() { + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java index a48840ace2..41e8a17dfe 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java @@ -23,7 +23,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import com.netflix.client.config.DefaultClientConfigImpl; @@ -54,9 +53,11 @@ import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultServiceInstances; import com.tencent.polaris.api.pojo.Instance; -import com.tencent.polaris.api.pojo.RouteArgument; import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.pojo.ServiceKey; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; import com.tencent.polaris.plugins.router.metadata.MetadataRouter; import com.tencent.polaris.plugins.router.nearby.NearbyRouter; import com.tencent.polaris.plugins.router.rule.RuleBasedRouter; @@ -218,35 +219,25 @@ public void testBuildMetadataRouteRequest() { try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) .thenReturn(testCallerService); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getApplicationContext()).thenReturn(new MockApplicationContext()); setTransitiveMetadata(); PolarisLoadBalancerCompositeRule compositeRule = new PolarisLoadBalancerCompositeRule(routerAPI, polarisLoadBalancerProperties, config, requestInterceptors, null, null); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + metadataContainer.putMetadataStringValue("system-metadata-router-keys", "k2", TransitiveType.NONE); + ServiceInstances serviceInstances = assembleServiceInstances(); PolarisRouterContext routerContext = assembleRouterContext(); - Map oldRouterLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS); - Map newRouterLabels = new HashMap<>(oldRouterLabels); - newRouterLabels.put("system-metadata-router-keys", "k2"); - routerContext.putLabels(RouterConstant.ROUTER_LABELS, newRouterLabels); - ProcessRoutersRequest request = compositeRule.buildProcessRoutersBaseRequest(serviceInstances); compositeRule.processRouterRequestInterceptors(request, routerContext); - Set routerMetadata = request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA); - - AssertionsForClassTypes.assertThat(routerMetadata.size()).isEqualTo(1); - AssertionsForClassTypes.assertThat(request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()) - .isEqualTo(0); - AssertionsForClassTypes.assertThat(request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) - .size()).isEqualTo(1); - - for (RouteArgument routeArgument : request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED)) { - AssertionsForClassTypes.assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED); - AssertionsForClassTypes.assertThat(routeArgument.getValue()).isEqualTo("false"); - } + String result = metadataContainer.getRawMetadataMapValue(MetadataRouter.ROUTER_TYPE_METADATA, MetadataRouter.KEY_METADATA_KEYS); + AssertionsForClassTypes.assertThat(result).isEqualTo("k2"); } } @@ -258,6 +249,7 @@ public void testBuildNearbyRouteRequest() { try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) .thenReturn(testCallerService); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getApplicationContext()).thenReturn(new MockApplicationContext()); setTransitiveMetadata(); @@ -270,24 +262,10 @@ public void testBuildNearbyRouteRequest() { ProcessRoutersRequest request = compositeRule.buildProcessRoutersBaseRequest(serviceInstances); compositeRule.processRouterRequestInterceptors(request, routerContext); - Set routerMetadata = request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY); - - AssertionsForClassTypes.assertThat(request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA).size()) - .isEqualTo(0); - AssertionsForClassTypes.assertThat(routerMetadata.size()).isEqualTo(1); - - for (RouteArgument routeArgument : routerMetadata) { - AssertionsForClassTypes.assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED); - AssertionsForClassTypes.assertThat(routeArgument.getValue()).isEqualTo("true"); - } - - AssertionsForClassTypes.assertThat(request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED) - .size()).isEqualTo(1); - - for (RouteArgument routeArgument : request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED)) { - AssertionsForClassTypes.assertThat(routeArgument.getKey()).isEqualTo(RuleBasedRouter.ROUTER_ENABLED); - AssertionsForClassTypes.assertThat(routeArgument.getValue()).isEqualTo("false"); - } + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + String result = metadataContainer.getRawMetadataMapValue(NearbyRouter.ROUTER_TYPE_NEAR_BY, NearbyRouter.ROUTER_ENABLED); + AssertionsForClassTypes.assertThat(result).isEqualTo("true"); } } @@ -299,6 +277,7 @@ public void testBuildRuleBasedRouteRequest() { try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())). thenReturn(testCallerService); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getApplicationContext()).thenReturn(new MockApplicationContext()); setTransitiveMetadata(); @@ -311,13 +290,10 @@ public void testBuildRuleBasedRouteRequest() { ProcessRoutersRequest request = compositeRule.buildProcessRoutersBaseRequest(serviceInstances); compositeRule.processRouterRequestInterceptors(request, routerContext); - Set routerMetadata = request.getRouterArguments(RuleBasedRouter.ROUTER_TYPE_RULE_BASED); - - AssertionsForClassTypes.assertThat(routerMetadata.size()).isEqualTo(3); - AssertionsForClassTypes.assertThat(request.getRouterArguments(MetadataRouter.ROUTER_TYPE_METADATA).size()) - .isEqualTo(0); - AssertionsForClassTypes.assertThat(request.getRouterArguments(NearbyRouter.ROUTER_TYPE_NEAR_BY).size()) - .isEqualTo(0); + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.CUSTOM, false); + String result = metadataContainer.getRawMetadataMapValue(RuleBasedRouter.ROUTER_TYPE_RULE_BASED, RuleBasedRouter.ROUTER_ENABLED); + AssertionsForClassTypes.assertThat(result).isEqualTo("true"); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java index b876020879..b14415f0cf 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisRouterContextTest.java @@ -20,7 +20,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.Set; import com.google.common.collect.Sets; import com.tencent.cloud.common.constant.RouterConstant; @@ -97,20 +96,4 @@ public void testGetLabel() { String resolvedLabel = routerContext.getLabel("k1"); assertThat(resolvedLabel).isEqualTo("v1"); } - - @Test - public void testGetLabelAsSet() { - Map labels = new HashMap<>(); - labels.put("k1", "v1,v2,v3"); - - PolarisRouterContext routerContext = new PolarisRouterContext(); - routerContext.putLabels(RouterConstant.ROUTER_LABELS, labels); - - Set resolvedLabels = routerContext.getLabelAsSet("k1"); - - assertThat(resolvedLabels.size()).isEqualTo(3); - assertThat(resolvedLabels).contains("v1"); - assertThat(resolvedLabels).contains("v2"); - assertThat(resolvedLabels).contains("v3"); - } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java deleted file mode 100644 index 128d3523d5..0000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessorTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.polaris.router.beanprocessor; - -import com.tencent.cloud.common.util.BeanFactoryUtils; -import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor; -import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; -import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; -import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -/** - * Test for ${@link LoadBalancerInterceptorBeanPostProcessor}. - * - * @author lepdou 2022-05-26 - */ -@ExtendWith(MockitoExtension.class) -public class LoadBalancerInterceptorBeanPostProcessorTest { - - @Mock - private LoadBalancerClient loadBalancerClient; - @Mock - private LoadBalancerRequestFactory loadBalancerRequestFactory; - @Mock - private BeanFactory beanFactory; - - @Test - public void testWrapperLoadBalancerInterceptor() { - when(beanFactory.getBean(LoadBalancerRequestFactory.class)).thenReturn(loadBalancerRequestFactory); - when(beanFactory.getBean(LoadBalancerClient.class)).thenReturn(loadBalancerClient); - - try (MockedStatic mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) { - mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, SpringWebRouterLabelResolver.class)) - .thenReturn(null); - LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(loadBalancerClient, loadBalancerRequestFactory); - - LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor(); - processor.setBeanFactory(beanFactory); - - Object bean = processor.postProcessBeforeInitialization(loadBalancerInterceptor, ""); - - assertThat(bean).isInstanceOf(PolarisLoadBalancerInterceptor.class); - } - } - - @Test - public void testNotWrapperLoadBalancerInterceptor() { - LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor(); - processor.setBeanFactory(beanFactory); - - OtherBean otherBean = new OtherBean(); - Object bean = processor.postProcessBeforeInitialization(otherBean, ""); - assertThat(bean).isNotInstanceOf(PolarisLoadBalancerInterceptor.class); - assertThat(bean).isInstanceOf(OtherBean.class); - } - - static class OtherBean { - - } -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java index f10d9ada45..6d3323a56f 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/RouterBootstrapAutoConfigurationTest.java @@ -61,7 +61,7 @@ public void testDefaultInitialization() { routerConfigModifier.modify((ConfigurationImpl) configuration); NearbyRouterConfig nearbyRouterConfig = configuration.getConsumer().getServiceRouter().getPluginConfig( ServiceRouterConfig.DEFAULT_ROUTER_NEARBY, NearbyRouterConfig.class); - Assertions.assertEquals("campus", nearbyRouterConfig.getMatchLevel().name()); + Assertions.assertEquals("CAMPUS", nearbyRouterConfig.getMatchLevel().name()); }); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java index 379fbf7e97..7b2598f33d 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterPropertiesTest.java @@ -37,7 +37,7 @@ void setUp() { @Test public void isEnabled() { - assertThat(properties.isEnabled()).isEqualTo(true); + assertThat(properties.isEnabled()).isEqualTo(false); } @Test @@ -49,6 +49,6 @@ public void setEnabled() { @Test public void testToString() { assertThat(properties.toString()) - .isEqualTo("PolarisNearByRouterProperties{enabled=true, matchLevel='null'}"); + .isEqualTo("PolarisNearByRouterProperties{enabled=false, matchLevel='null'}"); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java index 9a8fc5697a..1cc5e43adc 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterPropertiesTest.java @@ -49,7 +49,7 @@ public void setEnabled() { @Test public void testToString() { assertThat(properties.toString()) - .isEqualTo("PolarisNearByRouterProperties{enabled=true}"); + .isEqualTo("PolarisRuleBasedRouterProperties{enabled=true, failOver=all}"); } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java deleted file mode 100644 index dc1410f5d6..0000000000 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/FeignExpressionLabelUtilsTest.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.router.feign; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; - -import feign.Request; -import feign.RequestTemplate; -import org.junit.jupiter.api.Test; - -import static java.util.stream.Collectors.toSet; -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test for {@link FeignExpressionLabelUtils}. - *@author lepdou 2022-05-26 - */ -public class FeignExpressionLabelUtilsTest { - - @Test - public void testGetHeaderLabel() { - String headerKey = "uid"; - String headerValue = "1000"; - String headerKey2 = "teacher.age"; - String headerValue2 = "1000"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.header(headerKey, headerValue); - requestTemplate.header(headerKey2, headerValue2); - - String labelKey1 = "${http.header.uid}"; - String labelKey2 = "${http.header.name}"; - String labelKey3 = "${http.headername}"; - String labelKey4 = "${http.header.}"; - String labelKey5 = "${http.header.teacher.age}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, - Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(headerValue); - assertThat(result.get(labelKey5)).isEqualTo(headerValue2); - assertThat(result.get(labelKey2)).isBlank(); - assertThat(result.get(labelKey3)).isBlank(); - assertThat(result.get(labelKey4)).isBlank(); - } - - @Test - public void testGetQueryLabel() { - String headerKey = "uid"; - String headerValue = "1000"; - String headerKey2 = "teacher.age"; - String headerValue2 = "1000"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.query(headerKey, headerValue); - requestTemplate.query(headerKey2, headerValue2); - - String labelKey1 = "${http.query.uid}"; - String labelKey2 = "${http.query.name}"; - String labelKey3 = "${http.queryname}"; - String labelKey4 = "${http.query.}"; - String labelKey5 = "${http.query.teacher.age}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, - Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(headerValue); - assertThat(result.get(labelKey5)).isEqualTo(headerValue2); - assertThat(result.get(labelKey2)).isBlank(); - assertThat(result.get(labelKey3)).isBlank(); - assertThat(result.get(labelKey4)).isBlank(); - } - - @Test - public void testGetMethod() { - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.method(Request.HttpMethod.GET); - - String labelKey1 = "${http.method}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo("GET"); - } - - @Test - public void testGetUri() { - String uri = "/user/get"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.uri(uri); - requestTemplate.method(Request.HttpMethod.GET); - requestTemplate.target("http://localhost"); - requestTemplate = requestTemplate.resolve(new HashMap<>()); - - String labelKey1 = "${http.uri}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(uri); - } - - @Test - public void testGetUri2() { - String uri = "/"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.uri(uri); - requestTemplate.method(Request.HttpMethod.GET); - requestTemplate.target("http://localhost"); - requestTemplate = requestTemplate.resolve(new HashMap<>()); - - String labelKey1 = "${http.uri}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(uri); - } - - @Test - public void testGetCookie() { - String uri = "/"; - String cookieValue = "zhangsan"; - - RequestTemplate requestTemplate = new RequestTemplate(); - requestTemplate.uri(uri); - requestTemplate.method(Request.HttpMethod.GET); - requestTemplate.target("http://localhost"); - requestTemplate = requestTemplate.resolve(new HashMap<>()); - requestTemplate.header("cookie", Collections.singleton("uid=zhangsan; auth-token=dfhuwshfy77")); - - String labelKey1 = "${http.cookie.uid}"; - Map result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1) - .collect(toSet())); - - assertThat(result).isNotEmpty(); - assertThat(result.get(labelKey1)).isEqualTo(cookieValue); - } -} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java index 6c60c6200d..0b798b1212 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/PolarisFeignLoadBalancerTest.java @@ -114,7 +114,9 @@ public void testHasNoneRouterContext() { mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); PolarisRouterContext routerContext = polarisFeignLoadBalancer.buildRouterContext(headers); - assertThat(routerContext).isNull(); + + Map routerLabels = routerContext.getLabels(RouterConstant.ROUTER_LABELS); + assertThat(routerLabels).isEmpty(); } } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java index 0e381c96ec..7fad43476e 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/feign/RouterLabelFeignInterceptorTest.java @@ -18,124 +18,82 @@ package com.tencent.cloud.polaris.router.feign; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; +import java.util.List; import java.util.Map; -import java.util.Set; import com.tencent.cloud.common.constant.OrderConstant; -import com.tencent.cloud.common.constant.RouterConstant; -import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.metadata.StaticMetadataManager; -import com.tencent.cloud.common.util.ApplicationContextAwareUtils; -import com.tencent.cloud.common.util.JacksonUtils; -import com.tencent.cloud.polaris.context.config.PolarisContextProperties; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; import feign.RequestTemplate; -import feign.Target; +import io.netty.handler.codec.http.HttpHeaderNames; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; /** * test for {@link RouterLabelFeignInterceptor}. * - * @author lepdou, cheese8 + * @author lepdou 2022-05-26 */ -@ExtendWith(MockitoExtension.class) +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = RouterLabelFeignInterceptorTest.TestApplication.class, + properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", + "spring.cloud.gateway.enabled=false", "spring.cloud.polaris.router.zuul.enabled=false"}) public class RouterLabelFeignInterceptorTest { - @Mock - private StaticMetadataManager staticMetadataManager; - @Mock - private RouterRuleLabelResolver routerRuleLabelResolver; - @Mock - private FeignRouterLabelResolver routerLabelResolver; - @Mock - private PolarisContextProperties polarisContextProperties; - @Test - public void testResolveRouterLabel() throws UnsupportedEncodingException { - RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor( - Collections.singletonList(routerLabelResolver), - staticMetadataManager, routerRuleLabelResolver, polarisContextProperties); + public void testRouterLabel() { + RouterLabelFeignInterceptor routerLabelFeignInterceptor = new RouterLabelFeignInterceptor(); assertThat(routerLabelFeignInterceptor.getOrder()).isEqualTo(OrderConstant.Client.Feign.ROUTER_LABEL_INTERCEPTOR_ORDER); // mock request template - RequestTemplate requestTemplate = new RequestTemplate(); + RequestTemplate requestTemplate = mock(RequestTemplate.class); String headerUidKey = "uid"; String headerUidValue = "1000"; - requestTemplate.header(headerUidKey, headerUidValue); - String peerService = "peerService"; - Target.EmptyTarget target = Target.EmptyTarget.create(Object.class, peerService); - requestTemplate.feignTarget(target); - - // mock ApplicationContextAwareUtils#getProperties - try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { - String testService = "callerService"; - mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) - .thenReturn(testService); - - MetadataContext metadataContext = Mockito.mock(MetadataContext.class); - - // mock transitive metadata - Map transitiveLabels = new HashMap<>(); - transitiveLabels.put("k1", "v1"); - transitiveLabels.put("k2", "v22"); - when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels); - - // mock MetadataContextHolder#get - try (MockedStatic mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class)) { - mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); - - // mock expression rule labels - Set expressionKeys = new HashSet<>(); - expressionKeys.add("${http.header.uid}"); - expressionKeys.add("${http.header.name}"); - when(routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, - MetadataContext.LOCAL_SERVICE, peerService)).thenReturn(expressionKeys); - - // mock custom resolved labels from request - Map customResolvedLabels = new HashMap<>(); - customResolvedLabels.put("k2", "v2"); - customResolvedLabels.put("k3", "v3"); - when(routerLabelResolver.resolve(requestTemplate, expressionKeys)).thenReturn(customResolvedLabels); - - Map localMetadata = new HashMap<>(); - localMetadata.put("k3", "v31"); - localMetadata.put("k4", "v4"); - when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata); - - routerLabelFeignInterceptor.apply(requestTemplate); - - Collection routerLabels = requestTemplate.headers().get(RouterConstant.ROUTER_LABEL_HEADER); + Map> headerMap = new HashMap<>(); + headerMap.put(headerUidKey, Collections.singletonList(headerUidValue)); + headerMap.put(HttpHeaderNames.COOKIE.toString(), Collections.singletonList("k1=v1")); + doReturn(headerMap).when(requestTemplate).headers(); + doReturn(Request.HttpMethod.POST.toString()).when(requestTemplate).method(); + Request request = mock(Request.class); + doReturn(request).when(requestTemplate).request(); + doReturn("http://callee/test/path").when(request).url(); + Map> queryMap = new HashMap<>(); + queryMap.put("q1", Collections.singletonList("a1")); + doReturn(queryMap).when(requestTemplate).queries(); + + routerLabelFeignInterceptor.apply(requestTemplate); + + // get message metadata container + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.MESSAGE, false); + // method + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString()); + // path + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path"); + // header + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, headerUidKey)).isEqualTo(headerUidValue); + // cookie + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1"); + // query + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1"); + } - assertThat(routerLabels).isNotNull(); - for (String value : routerLabels) { - Map labels = JacksonUtils.deserialize2Map(URLDecoder.decode(value, "UTF-8")); + @SpringBootApplication + protected static class TestApplication { - assertThat(labels.get("k1")).isEqualTo("v1"); - assertThat(labels.get("k2")).isEqualTo("v22"); - assertThat(labels.get("k3")).isEqualTo("v3"); - assertThat(labels.get("k4")).isEqualTo("v4"); - assertThat(labels.get("${http.header.uid}")).isEqualTo(headerUidValue); - assertThat(labels.get("${http.header.name}")).isEqualTo(""); - } - } - } } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java index 9e729a1822..4fc3808d9a 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterContextFactoryTest.java @@ -45,12 +45,13 @@ import org.springframework.http.HttpRequest; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** - * Test for {@link RouterContextFactory} + * Test for {@link RouterContextFactory}. * * @author lepdou 2022-10-09 */ @@ -82,7 +83,7 @@ public void testRouterContext() { Set expressionKeys = new HashSet<>(); expressionKeys.add("${http.method}"); expressionKeys.add("${http.uri}"); - when(routerRuleLabelResolver.getExpressionLabelKeys(callerService, callerService, calleeService)).thenReturn(expressionKeys); + when(routerRuleLabelResolver.getExpressionLabelKeys(any(), any(), any())).thenReturn(expressionKeys); // mock custom resolved from request Map customResolvedLabels = new HashMap<>(); @@ -111,7 +112,6 @@ public void testRouterContext() { PolarisRouterContext routerContext = routerContextFactory.create(request, null, calleeService); verify(staticMetadataManager).getMergedStaticMetadata(); - verify(routerRuleLabelResolver).getExpressionLabelKeys(callerService, callerService, calleeService); verify(springWebRouterLabelResolver).resolve(request, null, expressionKeys); assertThat(routerContext.getLabels(RouterConstant.TRANSITIVE_LABELS).get("k1")).isEqualTo("v1"); diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java new file mode 100644 index 0000000000..88ad69970c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/RouterLabelRestTemplateInterceptorTest.java @@ -0,0 +1,128 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.resttemplate; + +import java.net.URI; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; +import io.netty.handler.codec.http.HttpHeaderNames; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.mock.http.client.MockClientHttpResponse; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * Test for {@link RouterLabelRestTemplateInterceptor}. + * + * @author liuye, Haotian Zhang + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = RouterLabelRestTemplateInterceptorTest.TestApplication.class, + properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", + "spring.cloud.gateway.enabled=false", "spring.cloud.polaris.router.zuul.enabled=false"}) +public class RouterLabelRestTemplateInterceptorTest { + + @Mock + private ClientHttpRequestExecution clientHttpRequestExecution; + + @Test + public void testRouterLabel() throws Exception { + RouterLabelRestTemplateInterceptor routerLabelRestTemplateInterceptor = new RouterLabelRestTemplateInterceptor(); + + assertThat(routerLabelRestTemplateInterceptor.getOrder()).isEqualTo(OrderConstant.Client.RestTemplate.ROUTER_LABEL_INTERCEPTOR_ORDER); + + String calleeService = "calleeService"; + HttpRequest request = new MockedHttpRequest("http://" + calleeService + "/test/path?q1=a1"); + + ClientHttpResponse mockedResponse = new MockClientHttpResponse(new byte[] {}, HttpStatus.OK); + when(clientHttpRequestExecution.execute(eq(request), any())).thenReturn(mockedResponse); + + routerLabelRestTemplateInterceptor.intercept(request, null, clientHttpRequestExecution); + + // get message metadata container + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.MESSAGE, false); + // method + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString()); + // path + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path"); + // header + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000"); + // cookie + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1"); + // query + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1"); + } + + static class MockedHttpRequest implements HttpRequest { + + private final URI uri; + + private final HttpHeaders httpHeaders = new HttpHeaders(); + + MockedHttpRequest(String url) { + this.uri = URI.create(url); + this.httpHeaders.add("uid", "1000"); + this.httpHeaders.add(HttpHeaderNames.COOKIE.toString(), "k1=v1"); + } + + @Override + public HttpMethod getMethod() { + return HttpMethod.POST; + } + @Override + public String getMethodValue() { + return HttpMethod.POST.toString(); + } + @Override + public URI getURI() { + return uri; + } + + @Override + public HttpHeaders getHeaders() { + return httpHeaders; + } + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java new file mode 100644 index 0000000000..15de9c6d13 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/RouterLabelGlobalFilterTest.java @@ -0,0 +1,96 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.scg; + +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.metadata.core.MessageMetadataContainer; +import com.tencent.polaris.metadata.core.MetadataContainer; +import com.tencent.polaris.metadata.core.MetadataType; +import feign.Request; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import reactor.core.publisher.Mono; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.http.HttpCookie; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.server.ServerWebExchange; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; + +/** + * Test for ${@link RouterLabelGlobalFilter}. + * + * @author Haotian Zhang + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = RouterLabelGlobalFilterTest.TestApplication.class, + properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", + "spring.main.web-application-type=reactive", "spring.cloud.polaris.router.zuul.enabled=false"}) +public class RouterLabelGlobalFilterTest { + + @Test + public void testRouterLabel() { + RouterLabelGlobalFilter routerLabelGlobalFilter = new RouterLabelGlobalFilter(); + + assertThat(routerLabelGlobalFilter.getOrder()) + .isEqualTo(LOAD_BALANCER_CLIENT_FILTER_ORDER - 1); + + MockServerHttpRequest request = MockServerHttpRequest.post("/test/path") + .header("uid", "1000") + .cookie(new HttpCookie("k1", "v1")) + .queryParam("q1", "a1") + .build(); + MockServerWebExchange mockWebExchange = new MockServerWebExchange.Builder(request).build(); + + routerLabelGlobalFilter.filter(mockWebExchange, new EmptyGatewayFilterChain()); + + // get message metadata container + MetadataContainer metadataContainer = MetadataContextHolder.get() + .getMetadataContainer(MetadataType.MESSAGE, false); + // method + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString()); + // path + assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path"); + // header + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000"); + // cookie + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1"); + // query + assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1"); + } + + static class EmptyGatewayFilterChain implements GatewayFilterChain { + + @Override + public Mono filter(ServerWebExchange exchange) { + return Mono.empty(); + } + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java new file mode 100644 index 0000000000..0836cf1ea5 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/transformer/PolarisInstanceTransformerTest.java @@ -0,0 +1,55 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.transformer; + +import com.tencent.cloud.common.pojo.PolarisServiceInstance; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer; +import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.pojo.Instance; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * PolarisInstanceTransformerTest. + * + * @author sean yu + */ +public class PolarisInstanceTransformerTest { + + @Test + public void test() { + try ( + MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.namespace")) + .thenReturn("default"); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties("spring.cloud.polaris.service")) + .thenReturn("test"); + PolarisInstanceTransformer polarisInstanceTransformer = new PolarisInstanceTransformer(); + DefaultInstance instance = new DefaultInstance(); + instance.setZone("zone"); + PolarisServiceInstance polarisServiceInstance = new PolarisServiceInstance(instance); + Instance instance1 = polarisInstanceTransformer.transform(polarisServiceInstance); + assertThat(instance1.getZone()).isEqualTo("zone"); + } + } +} diff --git a/spring-cloud-tencent-commons/pom.xml b/spring-cloud-tencent-commons/pom.xml index d2c5477a11..6ba7d16d7f 100644 --- a/spring-cloud-tencent-commons/pom.xml +++ b/spring-cloud-tencent-commons/pom.xml @@ -14,8 +14,8 @@ Spring Cloud Tencent Commons - 2.5 - 2.7 + 2.6 + 2.11.0 @@ -50,6 +50,11 @@ spring-boot-starter-json + + org.springframework.boot + spring-boot-starter-validation + + org.springframework.cloud spring-cloud-starter @@ -79,6 +84,11 @@ true + + com.google.code.gson + gson + + org.springframework.cloud spring-cloud-starter-openfeign 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 3f8bb25550..f132920eb8 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 @@ -62,9 +62,9 @@ public static class HeaderName { public static final String CUSTOM_DISPOSABLE_METADATA = "SCT-CUSTOM-DISPOSABLE-METADATA"; /** - * System Metadata. + * Application Metadata. */ - public static final String SYSTEM_METADATA = "SCT-SYSTEM-METADATA"; + public static final String APPLICATION_METADATA = "SCT-APPLICATION-METADATA"; /** * Metadata context. 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 2ad9dbb2a8..35df6cb7f4 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 @@ -17,13 +17,14 @@ package com.tencent.cloud.common.constant; -import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter; import org.springframework.core.Ordered; +import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER; + /** * Constant for order. * @@ -36,6 +37,10 @@ public static class Client { * Order constant for Feign. */ public static class Feign { + /** + * Order of encode transfer metadata interceptor. + */ + public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; /** * Order of encode router label interceptor. @@ -47,6 +52,10 @@ public static class Feign { * Order constant for RestTemplate. */ public static class RestTemplate { + /** + * Order of encode transfer metadata interceptor. + */ + public static final int ENCODE_TRANSFER_METADATA_INTERCEPTOR_ORDER = Ordered.LOWEST_PRECEDENCE - 1; /** * Order of encode router label interceptor. @@ -58,12 +67,15 @@ public static class RestTemplate { * Order constant for Spring Cloud Gateway. */ public static class Scg { + /** + * Order of encode transfer metadata filter. + */ + public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = LOAD_BALANCER_CLIENT_FILTER_ORDER + 1; /** * Order of enhanced filter. - * {@link ReactiveLoadBalancerClientFilter}.LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150. */ - public static final int ENHANCED_FILTER_ORDER = 10150 + 1; + public static final int ENHANCED_FILTER_ORDER = LOAD_BALANCER_CLIENT_FILTER_ORDER + 1; } /** @@ -71,6 +83,11 @@ public static class Scg { */ public static class Zuul { + /** + * Order of encode transfer metadata filter. + */ + public static final int ENCODE_TRANSFER_METADATA_FILTER_ORDER = RIBBON_ROUTING_FILTER_ORDER - 1; + /** * Order of enhanced ROUTE filter. */ @@ -148,7 +165,7 @@ public static final class Modifier { /** * Address modifier order. */ - public static Integer ADDRESS_ORDER = Integer.MIN_VALUE; + public static Integer ADDRESS_ORDER = Integer.MIN_VALUE + 10; /** * Discovery config modifier order. @@ -200,9 +217,19 @@ public static final class Modifier { */ public static Integer LOSSLESS_ORDER = 2; + /** + * Order of admin configuration modifier. + */ + public static Integer ADMIN_ORDER = 2; + /** * Order of service contract configuration modifier. */ public static Integer SERVICE_CONTRACT_ORDER = Integer.MAX_VALUE - 9; + + /** + * Order of trace configuration modifier. + */ + public static Integer TRACE_ORDER = 2; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java index 00d9633a7f..b66de0100e 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/RouterConstant.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.common.constant; @@ -21,7 +20,7 @@ /** * Router constants. * - * @author lepdou 2022-05-17 + * @author lepdou, Hoatian Zhang */ public final class RouterConstant { diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java similarity index 62% rename from spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java rename to spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java index 6f63cbc935..d590e22c80 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelReactiveResolver.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/WarmupCons.java @@ -13,26 +13,26 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ -package com.tencent.cloud.polaris.ratelimit.spi; - -import java.util.Map; - -import org.springframework.web.server.ServerWebExchange; +package com.tencent.cloud.common.constant; /** - * Resolve custom label from request. The label used for rate limit params. - * - * @author lepdou 2022-03-31 + * 预热所需枚举. + * @author jiangfan */ -public interface PolarisRateLimiterLabelReactiveResolver { +public final class WarmupCons { /** - * Resolve custom label from request. - * @param exchange the http request - * @return resolved labels + * 预热保护阈值. */ - Map resolve(ServerWebExchange exchange); + public static double DEFAULT_PROTECTION_THRESHOLD_KEY = 50; + /** + * TSF 启动时间。预热开始时间. + */ + public static String TSF_START_TIME = "TSF_START_TIME"; + + private WarmupCons() { + + } } 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 b1cfaad89e..321cfa945a 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 @@ -56,6 +56,16 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M */ public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable"; + /** + * disposable Context. + */ + public static final String FRAGMENT_APPLICATION = "application"; + + /** + * upstream disposable Context. + */ + public static final String FRAGMENT_UPSTREAM_APPLICATION = "upstream-application"; + /** * the key of the header(key) list needed to be transmitted from upstream to downstream. */ @@ -93,8 +103,6 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M if (!StringUtils.hasText(namespace)) { LOG.error("namespace should not be blank. please configure spring.cloud.polaris.namespace or " + "spring.cloud.polaris.discovery.namespace"); - throw new RuntimeException("namespace should not be blank. please configure spring.cloud.polaris.namespace or " - + "spring.cloud.polaris.discovery.namespace"); } namespace = DiscoveryUtil.rewriteNamespace(namespace); LOCAL_NAMESPACE = namespace; @@ -109,8 +117,6 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M if (!StringUtils.hasText(serviceName)) { LOG.error("service name should not be blank. please configure spring.cloud.polaris.service or " + "spring.cloud.polaris.discovery.service or spring.application.name"); - throw new RuntimeException("service name should not be blank. please configure spring.cloud.polaris.service or " - + "spring.cloud.polaris.discovery.service or spring.application.name"); } serviceName = DiscoveryUtil.rewriteServiceId(serviceName); LOCAL_SERVICE = serviceName; @@ -120,8 +126,8 @@ public MetadataContext() { super(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX); } - private Map getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream) { - MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + private Map getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller); Map values = new HashMap<>(); metadataContainer.iterateMetadataValues(new BiConsumer() { @Override @@ -137,15 +143,15 @@ public void accept(String s, MetadataValue metadataValue) { return values; } - private void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream, Map values) { + public void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream, Map values) { MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); for (Map.Entry entry : values.entrySet()) { metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), transitiveType); } } - private Map getMapMetadataAsMap(MetadataType metadataType, String mapKey, TransitiveType transitiveType, boolean downstream) { - MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + private Map getMapMetadataAsMap(MetadataType metadataType, String mapKey, TransitiveType transitiveType, boolean caller) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller); Map values = new HashMap<>(); MetadataValue metadataValue = metadataContainer.getMetadataValue(mapKey); if (!(metadataValue instanceof MetadataMapValue)) { @@ -167,8 +173,8 @@ public void accept(String s, MetadataValue metadataValue) { } private void putMapMetadataAsMap(MetadataType metadataType, String mapKey, - TransitiveType transitiveType, boolean downstream, Map values) { - MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); + TransitiveType transitiveType, boolean caller, Map values) { + MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller); for (Map.Entry entry : values.entrySet()) { metadataContainer.putMetadataMapValue(mapKey, entry.getKey(), entry.getValue(), transitiveType); } @@ -178,10 +184,22 @@ public Map getDisposableMetadata() { return getFragmentContext(FRAGMENT_DISPOSABLE); } + public void setDisposableMetadata(Map disposableMetadata) { + putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); + } + public Map getTransitiveMetadata() { return getFragmentContext(FRAGMENT_TRANSITIVE); } + public void setTransitiveMetadata(Map transitiveMetadata) { + putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); + } + + public Map getApplicationMetadata() { + return getFragmentContext(FRAGMENT_APPLICATION); + } + public Map getCustomMetadata() { Map transitiveMetadata = this.getTransitiveMetadata(); Map disposableMetadata = this.getDisposableMetadata(); @@ -227,14 +245,6 @@ public void setLoadbalancer(String key, Object value) { metadataContainer.putMetadataMapObjectValue(FRAGMENT_LB_METADATA, key, value); } - public void setTransitiveMetadata(Map transitiveMetadata) { - putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(transitiveMetadata)); - } - - public void setDisposableMetadata(Map disposableMetadata) { - putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(disposableMetadata)); - } - public void setUpstreamDisposableMetadata(Map upstreamDisposableMetadata) { putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(upstreamDisposableMetadata)); } @@ -255,10 +265,14 @@ public Map getFragmentContext(String fragment) { return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, false); case FRAGMENT_UPSTREAM_DISPOSABLE: return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true); + case FRAGMENT_APPLICATION: + return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false); + case FRAGMENT_UPSTREAM_APPLICATION: + return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true); case FRAGMENT_RAW_TRANSHEADERS: return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false); case FRAGMENT_RAW_TRANSHEADERS_KV: - return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.PASS_THROUGH, false); + return getMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.NONE, false); default: return getMapMetadataAsMap(MetadataType.CUSTOM, fragment, TransitiveType.NONE, false); } @@ -289,16 +303,21 @@ public void putFragmentContext(String fragment, Map context) { case FRAGMENT_UPSTREAM_DISPOSABLE: putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true, context); break; + case FRAGMENT_APPLICATION: + putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false, context); + break; + case FRAGMENT_UPSTREAM_APPLICATION: + putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true, context); + break; case FRAGMENT_RAW_TRANSHEADERS: putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS, TransitiveType.NONE, false, context); break; case FRAGMENT_RAW_TRANSHEADERS_KV: - putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.PASS_THROUGH, false, context); + putMapMetadataAsMap(MetadataType.CUSTOM, FRAGMENT_RAW_TRANSHEADERS_KV, TransitiveType.NONE, false, context); break; default: putMapMetadataAsMap(MetadataType.CUSTOM, fragment, TransitiveType.NONE, false, context); break; } } - } 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 71e1b77546..1f220769dd 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 @@ -22,13 +22,14 @@ import java.util.Map; import java.util.Optional; -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MetadataContainer; import com.tencent.polaris.metadata.core.MetadataProvider; import com.tencent.polaris.metadata.core.MetadataType; import com.tencent.polaris.metadata.core.TransitiveType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -43,7 +44,7 @@ */ public final class MetadataContextHolder { - private static MetadataLocalProperties metadataLocalProperties; + private static final Logger LOG = LoggerFactory.getLogger(MetadataContextHolder.class); private static StaticMetadataManager staticMetadataManager; @@ -60,28 +61,44 @@ public static MetadataContext get() { private static MetadataContext createMetadataManager() { MetadataContext metadataManager = new MetadataContext(); - if (metadataLocalProperties == null) { - metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext() - .getBean(MetadataLocalProperties.class); - } if (staticMetadataManager == null) { - staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() - .getBean(StaticMetadataManager.class); + if (ApplicationContextAwareUtils.getApplicationContext() != null) { + staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext() + .getBean(StaticMetadataManager.class); + } + else { + // for junit test. + return metadataManager; + } } + // local custom metadata MetadataContainer metadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); + Map mergedStaticMetadata = staticMetadataManager.getMergedStaticMetadata(); + for (Map.Entry entry : mergedStaticMetadata.entrySet()) { + metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.NONE); + } + // local custom transitive metadata Map mergedStaticTransitiveMetadata = staticMetadataManager.getMergedStaticTransitiveMetadata(); for (Map.Entry entry : mergedStaticTransitiveMetadata.entrySet()) { metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); } + // local custom disposable metadata Map mergedStaticDisposableMetadata = staticMetadataManager.getMergedStaticDisposableMetadata(); for (Map.Entry entry : mergedStaticDisposableMetadata.entrySet()) { metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); } - + // local trans header if (StringUtils.hasText(staticMetadataManager.getTransHeader())) { String transHeader = staticMetadataManager.getTransHeader(); metadataContainer.putMetadataMapValue(MetadataContext.FRAGMENT_RAW_TRANSHEADERS, transHeader, "", TransitiveType.NONE); } + + // local application disposable metadata + MetadataContainer applicationMetadataContainer = metadataManager.getMetadataContainer(MetadataType.APPLICATION, false); + Map mergedApplicationMetadata = staticMetadataManager.getMergedStaticMetadata(); + for (Map.Entry entry : mergedApplicationMetadata.entrySet()) { + applicationMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } return metadataManager; } @@ -133,24 +150,36 @@ public static void set(MetadataContext metadataContext) { * Save metadata map to thread local. * * @param dynamicTransitiveMetadata custom metadata collection - * @param dynamicDisposableMetadata custom disposable metadata connection + * @param dynamicDisposableMetadata custom disposable metadata collection + * @param dynamicApplicationMetadata application metadata collection * @param callerMetadataProvider caller metadata provider */ public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata, - MetadataProvider callerMetadataProvider) { + Map dynamicApplicationMetadata, MetadataProvider callerMetadataProvider) { com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> { + // caller transitive metadata to local custom transitive metadata MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { for (Map.Entry entry : dynamicTransitiveMetadata.entrySet()) { metadataContainerUpstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); } } + // caller disposable metadata to caller custom disposable metadata MetadataContainer metadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, true); if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { for (Map.Entry entry : dynamicDisposableMetadata.entrySet()) { metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); } } + // caller application metadata to caller application disposable metadata + MetadataContainer applicationMetadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.APPLICATION, true); + if (!CollectionUtils.isEmpty(dynamicApplicationMetadata)) { + for (Map.Entry entry : dynamicApplicationMetadata.entrySet()) { + applicationMetadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); + } + } + + // caller message metadata if (callerMetadataProvider != null) { MessageMetadataContainer callerMessageContainer = metadataManager.getMetadataContainer(MetadataType.MESSAGE, true); callerMessageContainer.setMetadataProvider(callerMetadataProvider); 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 f0171cebb3..2a70e9f668 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 @@ -261,7 +261,8 @@ private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperti List instanceMetadataProviders) { // resolve region info if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { - Set providerRegions = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getRegion).filter(region -> !StringUtils.isBlank(region)).collect(Collectors.toSet()); + Set providerRegions = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getRegion) + .filter(region -> !StringUtils.isBlank(region)).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(providerRegions)) { if (providerRegions.size() > 1) { throw new IllegalArgumentException("Multiple Regions Provided in InstanceMetadataProviders"); @@ -278,7 +279,8 @@ private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperti // resolve zone info if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { - Set providerZones = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getZone).filter(zone -> !StringUtils.isBlank(zone)).collect(Collectors.toSet()); + Set providerZones = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getZone) + .filter(zone -> !StringUtils.isBlank(zone)).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(providerZones)) { if (providerZones.size() > 1) { throw new IllegalArgumentException("Multiple Zones Provided in InstanceMetadataProviders"); @@ -295,7 +297,8 @@ private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperti // resolve campus info if (!CollectionUtils.isEmpty(instanceMetadataProviders)) { - Set providerCampus = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getCampus).filter(campus -> !StringUtils.isBlank(campus)).collect(Collectors.toSet()); + Set providerCampus = instanceMetadataProviders.stream().map(InstanceMetadataProvider::getCampus) + .filter(campus -> !StringUtils.isBlank(campus)).collect(Collectors.toSet()); if (!CollectionUtils.isEmpty(providerCampus)) { if (providerCampus.size() > 1) { throw new IllegalArgumentException("Multiple Campus Provided in InstanceMetadataProviders"); 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 ea7954c376..b21ab2f92f 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 @@ -30,7 +30,7 @@ * * @author shuiqingliu **/ -@Endpoint(id = "polaris-metadata") +@Endpoint(id = "polarismetadata") public class PolarisMetadataEndpoint { private final StaticMetadataManager staticMetadataManager; @@ -41,7 +41,7 @@ public PolarisMetadataEndpoint(StaticMetadataManager staticMetadataManager) { @ReadOperation public Map metadata() { - Map result = new HashMap<>(); + Map result = new HashMap<>(); result.put("Env", staticMetadataManager.getAllEnvMetadata()); result.put("EnvTransitive", staticMetadataManager.getEnvTransitiveMetadata()); result.put("ConfigTransitive", staticMetadataManager.getConfigTransitiveMetadata()); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java index d5f28e5975..8af64d5e57 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/pojo/PolarisServiceInstance.java @@ -18,10 +18,12 @@ package com.tencent.cloud.common.pojo; import java.net.URI; +import java.util.HashMap; import java.util.Map; import java.util.Objects; import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.utils.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.client.DefaultServiceInstance; @@ -40,7 +42,13 @@ public class PolarisServiceInstance implements ServiceInstance { private final String scheme; + private final Map serviceMetadata; + public PolarisServiceInstance(Instance instance) { + this(instance, null); + } + + public PolarisServiceInstance(Instance instance, Map metadata) { this.instance = instance; this.isSecure = StringUtils.equalsIgnoreCase(instance.getProtocol(), "https"); if (isSecure) { @@ -49,6 +57,10 @@ public PolarisServiceInstance(Instance instance) { else { scheme = "http"; } + this.serviceMetadata = new HashMap<>(); + if (CollectionUtils.isNotEmpty(metadata)) { + this.serviceMetadata.putAll(metadata); + } } public Instance getPolarisInstance() { @@ -95,6 +107,10 @@ public String getScheme() { return this.scheme; } + public Map getServiceMetadata() { + return serviceMetadata; + } + /** * To fix loadbalancer not working bug when importing spring-retry. * @param o object @@ -116,4 +132,14 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(instance, scheme); } + + @Override + public String toString() { + return "PolarisServiceInstance{" + + "instance=" + instance + + ", isSecure=" + isSecure + + ", scheme='" + scheme + '\'' + + ", serviceMetadata=" + serviceMetadata + + '}'; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java new file mode 100644 index 0000000000..5598674195 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/tsf/ConditionalOnTsfConsulEnabled.java @@ -0,0 +1,63 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.tsf; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.tencent.polaris.api.utils.StringUtils; + +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Condition that if Polaris enabled. + * + * @author Haotian Zhang + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +@Conditional(ConditionalOnTsfConsulEnabled.OnTsfEnabledCondition.class) +public @interface ConditionalOnTsfConsulEnabled { + + class OnTsfEnabledCondition implements Condition { + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + Environment environment = conditionContext.getEnvironment(); + boolean tsfConsulEnable = false; + + String tsfAppId = environment.getProperty("tsf_app_id"); + if (StringUtils.isNotBlank(tsfAppId)) { + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + String tsePolarisAddress = environment.getProperty("polaris_address"); + if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("spring.cloud.polaris.address"))) { + tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); + } + tsfConsulEnable = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); + } + + return tsfConsulEnable; + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java index c5509312e5..880970499b 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/AddressUtils.java @@ -19,18 +19,21 @@ package com.tencent.cloud.common.util; import java.io.IOException; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.NetworkInterface; import java.net.Socket; import java.net.URI; import java.util.ArrayList; import java.util.Collections; +import java.util.Enumeration; import java.util.List; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.StringUtils; /** * the utils of parse address. @@ -43,11 +46,17 @@ public final class AddressUtils { private static final String ADDRESS_SEPARATOR = ","; + private final static Boolean hasIpv6Address; + + static { + hasIpv6Address = hasIpv6Address(); + } + private AddressUtils() { } public static List parseAddressList(String addressInfo) { - if (StringUtils.isEmpty(addressInfo)) { + if (StringUtils.isBlank(addressInfo)) { return Collections.emptyList(); } List addressList = new ArrayList<>(); @@ -77,4 +86,63 @@ public static boolean accessible(String ip, int port, int timeout) { } return true; } + + public static boolean preferIpv6() { + if (Boolean.FALSE.equals(hasIpv6Address)) { + LOGGER.debug("AddressUtils.preferIpv6 hasIpv6Address = false"); + return false; + } + if ("true".equalsIgnoreCase(System.getenv("tsf_prefer_ipv6"))) { + LOGGER.debug("AddressUtils.preferIpv6 System.getenv = true"); + return true; + } + if ("true".equalsIgnoreCase(System.getProperty("tsf_prefer_ipv6"))) { + LOGGER.debug("AddressUtils.preferIpv6 System.getProperty = true"); + return true; + } + if ("true".equalsIgnoreCase(BeanFactoryUtils.resolve("${tsf_prefer_ipv6}"))) { + LOGGER.debug("AddressUtils.preferIpv6 BeanFactoryUtils.resolve = true"); + return true; + } + LOGGER.debug("AddressUtils.preferIpv6 result = false"); + return false; + } + + /** + * Determine whether environment has an ipv6 address. + */ + private static boolean hasIpv6Address() { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + LOGGER.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } + else if (result != null) { + continue; + } + + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements(); ) { + InetAddress address = addrs.nextElement(); + if (address instanceof Inet6Address + && !address.isLinkLocalAddress() + && !address.isLoopbackAddress()) { + LOGGER.trace("Found non-loopback interface: " + ifc.getDisplayName()); + return true; + } + } + } + } + } + catch (IOException ex) { + LOGGER.error("Cannot get first non-loopback address", ex); + } + return false; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java index e7729cf184..cd982c6807 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/BeanFactoryUtils.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.common.util; @@ -22,8 +21,15 @@ import java.util.List; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.stereotype.Component; import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; @@ -31,9 +37,30 @@ * the utils for bean factory. * @author lepdou 2022-05-23 */ -public final class BeanFactoryUtils { +@Component +public final class BeanFactoryUtils implements BeanFactoryAware { + + private static final Logger LOGGER = LoggerFactory.getLogger(BeanFactoryUtils.class); - private BeanFactoryUtils() { + private static BeanFactory beanFactory; + + /** + * Dynamic parsing of spring @Value. + * + * @param value something like ${} + * @return return null if the parsing fails or the object is not found. + */ + public static String resolve(String value) { + try { + if (beanFactory instanceof ConfigurableBeanFactory) { + return ((ConfigurableBeanFactory) beanFactory).resolveEmbeddedValue(value); + } + } + catch (Exception e) { + LOGGER.error("resolve {} failed.", value, e); + } + + return null; } public static List getBeans(BeanFactory beanFactory, Class requiredType) { @@ -45,4 +72,9 @@ public static List getBeans(BeanFactory beanFactory, Class requiredTyp Map beanMap = beansOfTypeIncludingAncestors((ListableBeanFactory) beanFactory, requiredType); return new ArrayList<>(beanMap.values()); } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + BeanFactoryUtils.beanFactory = beanFactory; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java new file mode 100644 index 0000000000..a8631d1126 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/GzipUtil.java @@ -0,0 +1,90 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author kysonli + */ +public final class GzipUtil { + + private static final Logger LOG = LoggerFactory.getLogger(GzipUtil.class); + + private GzipUtil() { + } + + public static byte[] compress(String data, String charsetName) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(bos)) { + gzip.write(data.getBytes(charsetName)); + gzip.finish(); + return bos.toByteArray(); + } + catch (IOException e) { + LOG.error("compress data [{}] error", data, e); + throw e; + } + } + + public static String compressBase64Encode(String data, String charsetName) throws IOException { + byte[] compressData = compress(data, charsetName); + return new String(Base64.getEncoder().encode(compressData), charsetName); + } + + public static String compressBase64Encode(byte[] byteData, String charsetName) throws IOException { + byte[] compressData = compress(new String(byteData, charsetName), charsetName); + return Base64.getEncoder().encodeToString(compressData); + } + + + public static byte[] decompress(byte[] zipData) throws IOException { + try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData); + GZIPInputStream gzip = new GZIPInputStream(bis); + ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + byte[] buf = new byte[256]; + int num; + while ((num = gzip.read(buf)) != -1) { + bos.write(buf, 0, num); + } + bos.flush(); + return bos.toByteArray(); + } + catch (IOException e) { + LOG.error("decompress zip data error", e); + throw e; + } + } + + public static String base64DecodeDecompress(String data, String charsetName) throws IOException { + byte[] base64DecodeData = Base64.getDecoder().decode(data); + return new String(decompress(base64DecodeData), charsetName); + } + + public static String base64DecodeDecompress(String data) throws IOException { + return base64DecodeDecompress(data, "utf-8"); + } + +} 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 a6c14a0d6a..b4862ce053 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 @@ -31,7 +31,7 @@ /** * Utils for Jackson. * - * @author Haotian Zhang + * @author Haotian Zhang, cheese8 */ public final class JacksonUtils { @@ -93,7 +93,6 @@ public static T deserialize(String jsonStr, Class type) { * @param jsonStr Json String * @return Map */ - @SuppressWarnings("unchecked") public static Map deserialize2Map(String jsonStr) { try { if (StringUtils.hasText(jsonStr)) { @@ -107,7 +106,8 @@ public static Map deserialize2Map(String jsonStr) { return new HashMap<>(); } catch (JsonProcessingException e) { - LOG.error("Json to map failed. check if the format of the json string[{}] is correct.", jsonStr, e); + LOG.error( + "Json to map failed. check if the format of the json string[{}] is correct.", jsonStr, e); throw new RuntimeException("Json to map failed.", e); } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java index e34d79f56a..a65219b2ad 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/OkHttpUtil.java @@ -55,7 +55,7 @@ private OkHttpUtil() { public static boolean get(String path, Map headers) { HttpURLConnection conn = null; try { - URL url = new java.net.URL(path); + URL url = new URL(path); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java index 9c5e73b9d4..203fa47271 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionLabelUtils.java @@ -13,7 +13,6 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ package com.tencent.cloud.common.util.expresstion; @@ -138,7 +137,7 @@ public static boolean isCallerIPLabel(String expression) { } public static String getQueryValue(String queryString, String queryKey) { - return getQueryValue(queryString, queryKey, StringUtils.EMPTY); + return getQueryValue(queryString, queryKey, null); } public static String getQueryValue(String queryString, String queryKey, String defaultValue) { @@ -160,31 +159,31 @@ public static String getQueryValue(String queryString, String queryKey, String d public static String getFirstValue(Map> valueMaps, String key) { if (CollectionUtils.isEmpty(valueMaps)) { - return StringUtils.EMPTY; + return null; } Collection values = valueMaps.get(key); if (CollectionUtils.isEmpty(values)) { - return StringUtils.EMPTY; + return null; } for (String value : values) { return value; } - return StringUtils.EMPTY; + return null; } public static String getCookieFirstValue(Map> valueMaps, String key) { if (CollectionUtils.isEmpty(valueMaps)) { - return StringUtils.EMPTY; + return null; } Collection values = valueMaps.get(HttpHeaderNames.COOKIE.toString()); if (CollectionUtils.isEmpty(values)) { - return StringUtils.EMPTY; + return null; } for (String value : values) { @@ -196,6 +195,6 @@ public static String getCookieFirstValue(Map> valueMa } } } - return StringUtils.EMPTY; + return null; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java index a5f28e8fde..dff35783a3 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/ExpressionParserV1.java @@ -53,7 +53,7 @@ public boolean isHeaderLabel(String expression) { @Override public String parseHeaderKey(String expression) { - return expression.substring(LABEL_HEADER_PREFIX_LEN, expression.length() - 1); + return StringUtils.substring(expression, LABEL_HEADER_PREFIX_LEN, expression.length() - 1); } @Override @@ -63,7 +63,7 @@ public boolean isQueryLabel(String expression) { @Override public String parseQueryKey(String expression) { - return expression.substring(LABEL_QUERY_PREFIX_LEN, expression.length() - 1); + return StringUtils.substring(expression, LABEL_QUERY_PREFIX_LEN, expression.length() - 1); } @Override @@ -73,7 +73,7 @@ public boolean isCookieLabel(String expression) { @Override public String parseCookieKey(String expression) { - return expression.substring(LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); + return StringUtils.substring(expression, LABEL_COOKIE_PREFIX_LEN, expression.length() - 1); } @Override diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java index 476aeeecfa..7e4276d57b 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/expresstion/SpringWebExpressionLabelUtils.java @@ -75,7 +75,7 @@ else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { labels.put(labelKey, getCookieValue(exchange.getRequest(), cookieKey)); } else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { - labels.put(labelKey, exchange.getRequest().getMethodValue()); + labels.put(labelKey, exchange.getRequest().getMethod().toString()); } else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, exchange.getRequest().getURI().getPath()); @@ -118,7 +118,7 @@ else if (ExpressionLabelUtils.isCookieLabel(labelKey)) { labels.put(labelKey, getCookieValue(request, cookieKey)); } else if (ExpressionLabelUtils.isMethodLabel(labelKey)) { - labels.put(labelKey, request.getMethodValue()); + labels.put(labelKey, request.getMethod().toString()); } else if (ExpressionLabelUtils.isUriLabel(labelKey)) { labels.put(labelKey, request.getURI().getPath()); @@ -129,7 +129,7 @@ else if (ExpressionLabelUtils.isUriLabel(labelKey)) { } public static String getHeaderValue(ServerHttpRequest request, String key) { - return getHeaderValue(request, key, StringUtils.EMPTY); + return getHeaderValue(request, key, null); } public static String getHeaderValue(ServerHttpRequest request, String key, String defaultValue) { @@ -141,7 +141,7 @@ public static String getHeaderValue(ServerHttpRequest request, String key, Strin } public static String getQueryValue(ServerHttpRequest request, String key) { - return getQueryValue(request, key, StringUtils.EMPTY); + return getQueryValue(request, key, null); } public static String getQueryValue(ServerHttpRequest request, String key, String defaultValue) { @@ -157,7 +157,7 @@ public static String getQueryValue(ServerHttpRequest request, String key, String } public static String getCookieValue(ServerHttpRequest request, String key) { - return getCookieValue(request, key, StringUtils.EMPTY); + return getCookieValue(request, key, null); } public static String getCookieValue(ServerHttpRequest request, String key, String defaultValue) { @@ -181,7 +181,7 @@ public static String getQueryValue(HttpRequest request, String key) { public static String getCookieValue(HttpRequest request, String key) { String first = request.getHeaders().getFirst(HttpHeaders.COOKIE); if (StringUtils.isEmpty(first)) { - return StringUtils.EMPTY; + return null; } String[] cookieArray = StringUtils.split(first, ";"); for (String cookieItem : cookieArray) { @@ -190,6 +190,6 @@ public static String getCookieValue(HttpRequest request, String key) { return cookieKv[1]; } } - return StringUtils.EMPTY; + return null; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java new file mode 100644 index 0000000000..e0afb55b67 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtils.java @@ -0,0 +1,320 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.util.inet; + +import java.io.Closeable; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import com.tencent.cloud.common.util.AddressUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.commons.util.InetUtilsProperties; + + +/** + * Extend from {@link InetUtils}. + * + * @author Haotian Zhang + */ +public class PolarisInetUtils implements Closeable { + + private static final Logger logger = LoggerFactory.getLogger(PolarisInetUtils.class); + // TODO: maybe shutdown the thread pool if it isn't being used? + private final ExecutorService executorService; + private final InetUtilsProperties properties; + + public PolarisInetUtils(final InetUtilsProperties properties) { + this.properties = properties; + this.executorService = Executors + .newSingleThreadExecutor(r -> { + Thread thread = new Thread(r); + thread.setName(InetUtilsProperties.PREFIX); + thread.setDaemon(true); + return thread; + }); + } + + public static String getIpString(boolean _ipv6) { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + logger.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } + else if (result != null) { + continue; + } + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements(); ) { + InetAddress address = addrs.nextElement(); + if (_ipv6) { + if (address instanceof Inet6Address + && !address.isLinkLocalAddress() + && !address.isLoopbackAddress() + ) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + else { + if (address instanceof Inet4Address + && !address.isLoopbackAddress() + ) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + } + } + } + } + catch (IOException ex) { + logger.error("Cannot get first non-loopback address", ex); + } + + if (result == null) { + return null; + } + + if (result.getHostAddress().contains("%")) { + return result.getHostAddress().split("%")[0]; + } + else { + return result.getHostAddress(); + } + } + + @Override + public void close() { + executorService.shutdown(); + } + + public InetUtils.HostInfo findFirstNonLoopbackHostInfo() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address != null) { + return convertAddress(address); + } + InetUtils.HostInfo hostInfo = new InetUtils.HostInfo(); + hostInfo.setHostname(this.properties.getDefaultHostname()); + hostInfo.setIpAddress(this.properties.getDefaultIpAddress()); + return hostInfo; + } + + public InetAddress findFirstNonLoopbackAddress() { + boolean preferIpv6 = AddressUtils.preferIpv6(); + InetAddress result = findFirstNonLoopbackAddressByIpType(preferIpv6); + logger.debug("ipv6 before, preferIpv6:{}, result:{}", preferIpv6, result); + if (result == null) { + result = findFirstNonLoopbackAddressByIpType(!preferIpv6); + } + logger.debug("ipv6 after, preferIpv6:{}, result:{}", preferIpv6, result); + + if (result != null) { + return result; + } + + try { + return InetAddress.getLocalHost(); + } + catch (UnknownHostException e) { + logger.warn("Unable to retrieve localhost"); + } + + return null; + } + + /** for testing. */ + boolean isPreferredAddress(InetAddress address) { + + if (this.properties.isUseOnlySiteLocalInterfaces()) { + final boolean siteLocalAddress = address.isSiteLocalAddress(); + if (!siteLocalAddress) { + logger.trace("Ignoring address: " + address.getHostAddress()); + } + return siteLocalAddress; + } + final List preferredNetworks = this.properties.getPreferredNetworks(); + if (preferredNetworks.isEmpty()) { + return true; + } + for (String regex : preferredNetworks) { + final String hostAddress = address.getHostAddress(); + if (hostAddress.matches(regex) || hostAddress.startsWith(regex)) { + return true; + } + } + logger.trace("Ignoring address: " + address.getHostAddress()); + return false; + } + + /** for testing. */ + boolean ignoreInterface(String interfaceName) { + for (String regex : this.properties.getIgnoredInterfaces()) { + if (interfaceName.matches(regex)) { + logger.trace("Ignoring interface: " + interfaceName); + return true; + } + } + return false; + } + + public InetUtils.HostInfo convertAddress(final InetAddress address) { + InetUtils.HostInfo hostInfo = new InetUtils.HostInfo(); + Future result = executorService.submit(new Callable() { + @Override + public String call() throws Exception { + return address.getHostName(); + } + }); + + String hostname; + try { + hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS); + } + catch (Exception e) { + logger.info("Cannot determine local hostname"); + hostname = "localhost"; + } + if (hostname.contains("%")) { + hostInfo.setHostname(hostname.split("%")[0]); + } + else { + hostInfo.setHostname(hostname); + } + if (address.getHostAddress().contains("%")) { + hostInfo.setIpAddress(address.getHostAddress().split("%")[0]); + } + else { + hostInfo.setIpAddress(address.getHostAddress()); + } + return hostInfo; + } + + public String findIpInterface() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address.getHostAddress().contains("%")) { + return address.getHostAddress().split("%")[1]; + } + return ""; + } + + public String findIpAddress() { + InetAddress address = findFirstNonLoopbackAddress(); + return address.getHostAddress().split("%")[0]; + } + + /** + * + * @return "[ipv6]" + */ + public String findIpAddressWithBracket() { + InetAddress address = findFirstNonLoopbackAddress(); + if (address.getHostAddress().contains("%")) { + return address.getHostAddress().split("%")[0]; + } + return address.getHostAddress(); + } + + /** + * @return ipv6%eth0 + * + */ + public String findIpAddressAndInterface() { + InetAddress address = findFirstNonLoopbackAddress(); + return address.getHostAddress(); + } + + public InetAddress findFirstNonLoopbackAddressByIpType(boolean _ipv6) { + InetAddress result = null; + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface + .getNetworkInterfaces(); nics.hasMoreElements(); ) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + logger.trace("Testing interface: " + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || result == null) { + lowest = ifc.getIndex(); + } + else if (result != null) { + continue; + } + + // @formatter:off + if (!ignoreInterface(ifc.getDisplayName())) { + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements();) { + InetAddress address = addrs.nextElement(); + if (_ipv6) { + if (address instanceof Inet6Address + && !address.isLinkLocalAddress() + && !address.isLoopbackAddress() + && isPreferredAddress(address)) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + else { + if (address instanceof Inet4Address + && !address.isLoopbackAddress() + && isPreferredAddress(address)) { + logger.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + result = address; + } + } + } + } + // @formatter:on + } + } + } + catch (IOException ex) { + logger.error("Cannot get first non-loopback address", ex); + } + + if (result != null) { + return result; + } + + + return null; + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java new file mode 100644 index 0000000000..4160d7bb18 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsAutoConfiguration.java @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.util.inet; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.cloud.commons.util.UtilAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + + +/** + * Auto configuration for PolarisInetUtils. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@Import(UtilAutoConfiguration.class) +public class PolarisInetUtilsAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public PolarisInetUtils polarisInetUtils(InetUtilsProperties properties) { + return new PolarisInetUtils(properties); + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java new file mode 100644 index 0000000000..9973573d99 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/inet/PolarisInetUtilsBootstrapConfiguration.java @@ -0,0 +1,30 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.common.util.inet; + +import org.springframework.context.annotation.Import; + +/** + * Auto configuration for PolarisInetUtils. + * + * @author Haotian Zhang + */ +@Import(PolarisInetUtilsAutoConfiguration.class) +public class PolarisInetUtilsBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java new file mode 100644 index 0000000000..a97f2635c5 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/context/TsfContext.java @@ -0,0 +1,78 @@ +/* + * 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 org.springframework.tsf.core.context; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.metadata.core.MetadataType; +import com.tencent.polaris.metadata.core.TransitiveType; + +import org.springframework.tsf.core.entity.Tag; + +public final class TsfContext { + + static final int MAX_KEY_LENGTH = 32; + static final int MAX_VALUE_LENGTH = 128; + + private TsfContext() { + + } + + public static void putTags(Map tagMap, Tag.ControlFlag... flags) { + if (tagMap == null) { + return; + } + MetadataContext tsfCoreContext = MetadataContextHolder.get(); + TransitiveType transitive = TransitiveType.DISPOSABLE; + if (null != flags) { + for (Tag.ControlFlag flag : flags) { + if (flag == Tag.ControlFlag.TRANSITIVE) { + transitive = TransitiveType.PASS_THROUGH; + break; + } + } + } + for (Map.Entry entry : tagMap.entrySet()) { + validateTag(entry.getKey(), entry.getValue()); + } + tsfCoreContext.putMetadataAsMap(MetadataType.CUSTOM, transitive, false, tagMap); + } + + public static void putTag(String key, String value, Tag.ControlFlag... flags) { + putTags(Collections.singletonMap(key, value), flags); + } + + private static void validateTag(String key, String value) { + int keyLength = key.getBytes(StandardCharsets.UTF_8).length; + int valueLength = value.getBytes(StandardCharsets.UTF_8).length; + + if (keyLength > MAX_KEY_LENGTH) { + throw new RuntimeException(String.format("Key \"%s\" length (after UTF-8 encoding) exceeding limit (%d)", key, + MAX_KEY_LENGTH)); + } + if (valueLength > MAX_VALUE_LENGTH) { + throw new RuntimeException(String.format("Value \"%s\" length (after UTF-8 encoding) exceeding limit (%d)", value, + MAX_VALUE_LENGTH)); + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java new file mode 100644 index 0000000000..16d409a0c0 --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/org/springframework/tsf/core/entity/Tag.java @@ -0,0 +1,144 @@ +/* + * 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 org.springframework.tsf.core.entity; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Tag implements Serializable { + + /** + * update version whenever change the content in tag. + */ + public static final int VERSION = 1; + + public enum ControlFlag { + + /** + * tag transitive by all services. + */ + @SerializedName("0") + TRANSITIVE, + + /** + * tag not used in auth. + */ + @SerializedName("1") + NOT_IN_AUTH, + + /** + * tag not used in route. + */ + @SerializedName("2") + NOT_IN_ROUTE, + + /** + * tag not used in trace. + */ + @SerializedName("3") + NOT_IN_SLEUTH, + + /** + * tag not used in lane. + */ + @SerializedName("4") + NOT_IN_LANE, + + /** + * tag not used in unit. + */ + @SerializedName("5") + IN_UNIT + } + + @SerializedName("k") + @Expose + private String key; + + @SerializedName("v") + @Expose + private String value; + + @SerializedName("f") + @Expose + private Set flags = new HashSet<>(); + + public Tag(String key, String value, ControlFlag... flags) { + this.key = key; + this.value = value; + this.flags = new HashSet<>(Arrays.asList(flags)); + } + + public Tag() { + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public Set getFlags() { + return flags; + } + + public void setFlags(Set flags) { + this.flags = flags; + } + + @Override + public boolean equals(Object object) { + if (object instanceof Tag) { + Tag tag = (Tag) object; + return (key == null ? tag.key == null : key.equals(tag.key)) + && (flags == null ? tag.flags == null : flags.equals(tag.flags)); + } + return false; + } + + @Override + public int hashCode() { + return (key == null ? 0 : key.hashCode()) + (flags == null ? 0 : flags.hashCode()); + } + + + @Override + public String toString() { + return "Tag{" + + "key='" + key + '\'' + + ", value='" + value + '\'' + + ", flags=" + flags + + '}'; + } +} diff --git a/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories index 4c54d3372a..d99cbf89a6 100644 --- a/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-tencent-commons/src/main/resources/META-INF/spring.factories @@ -1,4 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.common.util.inet.PolarisInetUtilsAutoConfiguration,\ com.tencent.cloud.common.util.ApplicationContextAwareUtils,\ com.tencent.cloud.common.metadata.config.MetadataAutoConfiguration,\ com.tencent.cloud.common.metadata.endpoint.PolarisMetadataEndpointAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.common.util.inet.PolarisInetUtilsBootstrapConfiguration 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 c2cd05b8d0..6f54ff7ba4 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 @@ -49,7 +49,7 @@ public void test1() { metadataContext.setTransitiveMetadata(customMetadata); MetadataContextHolder.set(metadataContext); - customMetadata = MetadataContextHolder.get().getTransitiveMetadata(); + metadataContext.setTransitiveMetadata(customMetadata); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("2"); @@ -63,7 +63,7 @@ public void test1() { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - MetadataContextHolder.init(customMetadata, new HashMap<>(), null); + MetadataContextHolder.init(customMetadata, new HashMap<>(), new HashMap<>(), null); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getTransitiveMetadata(); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java index a7fcf2725d..14bfac793f 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/config/MetadataLocalPropertiesTest.java @@ -34,8 +34,7 @@ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MetadataLocalPropertiesTest.TestApplication.class, - properties = {"spring.config.location = classpath:application-test.yml", - "spring.main.web-application-type = reactive"}) + properties = {"spring.config.location = classpath:application-test.yml", "spring.main.web-application-type=reactive"}) public class MetadataLocalPropertiesTest { @Autowired diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java index 6073268aed..66d4445aab 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ExpressionLabelUtilsTest.java @@ -44,7 +44,7 @@ /** * test for {@link ExpressionLabelUtils}. * - * @author lepdou 2022-05-27, cheese8 + * @author lepdou, cheese8 */ @ExtendWith(MockitoExtension.class) public class ExpressionLabelUtilsTest { diff --git a/spring-cloud-tencent-commons/src/test/resources/application-test.yml b/spring-cloud-tencent-commons/src/test/resources/application-test.yml index bea1a05869..bf8666dddc 100644 --- a/spring-cloud-tencent-commons/src/test/resources/application-test.yml +++ b/spring-cloud-tencent-commons/src/test/resources/application-test.yml @@ -6,6 +6,8 @@ spring: - org.springframework.cloud.gateway.config.GatewayAutoConfiguration - org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration cloud: + gateway: + enabled: false tencent: metadata: content: diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 716f69b786..ec69654141 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -76,27 +76,27 @@ com.tencent.cloud - spring-cloud-tencent-featureenv-plugin + spring-cloud-starter-tencent-discovery-adapter-plugin com.tencent.cloud - spring-cloud-tencent-gateway-plugin + spring-cloud-tencent-featureenv-plugin com.tencent.cloud - spring-cloud-starter-tencent-discovery-adapter-plugin + spring-cloud-tencent-gateway-plugin com.tencent.cloud - spring-cloud-tencent-lossless-plugin + spring-cloud-starter-tencent-discovery-adapter-plugin com.tencent.cloud - spring-cloud-starter-tencent-threadlocal-plugin + spring-cloud-tencent-lossless-plugin diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 23180a90dd..578b8fe2ed 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -70,21 +70,19 @@ - - 1.14.0-Hoxton.SR12-RC3 - - - 2.0.0.0-SNAPSHOT + 2.0.0.0-Hoxton.SR12-SNAPSHOT + 2.0.0.0-SNAPSHOT 32.0.1-jre 1.2.13 - 3.0.0 + 1.7.0 1.5.24 4.5.1 1.12.10 2.12.7 3.21.7 + 2.9.9 2.0.2 @@ -104,7 +102,14 @@ import - + + polaris-dependencies + com.tencent.polaris + ${polaris.version} + pom + import + + com.tencent.cloud spring-cloud-tencent-commons @@ -135,6 +140,7 @@ ${revision} + com.tencent.cloud spring-cloud-starter-tencent-polaris-ratelimit @@ -208,6 +214,12 @@ ${revision} + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + ${revision} + + com.google.guava @@ -242,21 +254,15 @@ - io.springfox - springfox-boot-starter - ${springfox.swagger2.version} - - - - io.swagger - swagger-models - ${io.swagger.version} + org.springdoc + springdoc-openapi-ui + ${springdoc.version} - io.swagger - swagger-annotations - ${io.swagger.version} + org.springdoc + springdoc-openapi-webflux-ui + ${springdoc.version} @@ -271,6 +277,13 @@ ${byte-buddy.version} + + + joda-time + joda-time + ${joda-time.version} + + org.mockito mockito-inline @@ -292,14 +305,6 @@ test - - - polaris-dependencies - com.tencent.polaris - ${polaris.version} - pom - import - diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml index 3672717020..9117a7314f 100644 --- a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/pom.xml @@ -18,7 +18,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webflux diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml index 4e8c2a8ce4..a42bb9e9d6 100644 --- a/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/lossless-example/lossless-callee-service/src/main/resources/bootstrap.yml @@ -15,12 +15,12 @@ spring: exposure: true report: enabled: true + admin: + port: 28084 stat: enabled: true - port: 28084 lossless: enabled: true - port: 28084 #healthCheckPath: /actuator/health #healthCheckInterval: 5000 lossless: diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml index 72f7ed345d..52c29f7272 100644 --- a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/pom.xml @@ -15,7 +15,7 @@ com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery - 2.2.10-RC2 + 2022.0.0.0 @@ -24,7 +24,7 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webflux diff --git a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml index a621c8c493..8e2a7b94ca 100644 --- a/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/lossless-example/lossless-nacos-callee-service/src/main/resources/bootstrap.yml @@ -9,12 +9,13 @@ spring: server-addr: 127.0.0.1:8848 enabled: true polaris: + admin: + port: 28085 lossless: enabled: true - port: 28085 healthCheckPath: /actuator/health healthCheckInterval: 5000 lossless: healthy: delay: - second: 20 \ No newline at end of file + second: 20 diff --git a/spring-cloud-tencent-examples/lossless-example/pom.xml b/spring-cloud-tencent-examples/lossless-example/pom.xml index 02d46dabd2..2873cb7b0a 100644 --- a/spring-cloud-tencent-examples/lossless-example/pom.xml +++ b/spring-cloud-tencent-examples/lossless-example/pom.xml @@ -15,4 +15,5 @@ lossless-example pom Spring Cloud Starter Tencent Lossless Example - \ No newline at end of file + + diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java index 79948b3e7a..6d8653eeb8 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-frontend/src/main/java/com/tencent/cloud/polaris/router/grayrelease/front/GrayReleaseFrontApplication.java @@ -19,9 +19,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableDiscoveryClient @EnableFeignClients public class GrayReleaseFrontApplication { diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java index 77819ea417..a7b5a115e1 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-gateway/src/main/java/com/tencent/cloud/polaris/router/grayrelease/gateway/GrayReleaseGatewayApplication.java @@ -19,9 +19,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableDiscoveryClient @EnableFeignClients public class GrayReleaseGatewayApplication { diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java index 3003093ee1..4857030e20 100644 --- a/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-example/router-grayrelease-middle/src/main/java/com/tencent/cloud/polaris/router/grayrelease/middle/GrayReleaseMiddleApplication.java @@ -19,9 +19,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableDiscoveryClient @EnableFeignClients public class GrayReleaseMiddleApplication { diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml new file mode 100644 index 0000000000..c5c4c40721 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-callee-service/src/main/resources/application.yml @@ -0,0 +1,37 @@ +server: + port: 48093 +spring: + application: + name: LaneCalleeService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + contract: + exposure: true + report: + enabled: true + admin: + port: 28083 + stat: + enabled: true + # pushgateway: + # enabled: true + # address: 127.0.0.1:9091 + config: + address: grpc://9.134.5.52:8093 + auto-refresh: true + groups: + - name: ${spring.application.name} + files: [ "config/callee.properties" ] +management: + endpoints: + web: + exposure: + include: + - polaris-discovery + - polaris-config \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml new file mode 100644 index 0000000000..ee0cb3c2ea --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-caller-service/src/main/resources/application.yml @@ -0,0 +1,43 @@ +server: + port: 48092 +spring: + application: + name: LaneCallerService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + heartbeat: + enabled: true + health-check-url: /lane/caller/healthCheck + contract: + exposure: true + report: + enabled: true + circuitbreaker: + enabled: true + admin: + port: 28082 + stat: + enabled: true + # pushgateway: + # enabled: true + # address: 127.0.0.1:9091 + tencent: + rpc-enhancement: + enabled: true + reporter: + enabled: true + ignore-internal-server-error: true + series: server_error + statuses: gateway_timeout, bad_gateway, service_unavailable +management: + endpoints: + web: + exposure: + include: + - polaris-discovery \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml new file mode 100644 index 0000000000..044956f092 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-router-grayrelease-lane-example/router-grayrelease-lane-gateway/src/main/resources/application.yml @@ -0,0 +1,38 @@ +server: + port: 48090 +spring: + application: + name: LaneRouterGatewayService + cloud: + polaris: + address: grpc://119.91.66.223:8091 + namespace: default + enabled: true + contract: + exposure: true + report: + enabled: true + admin: + port: 28081 + stat: + enabled: true + gateway: + discovery: + locator: + enabled: true + 'predicates[0]': + name: Path + args: + patterns: '''/'' + serviceId + ''/**''' + 'filters[0]': + name: RewritePath + args: + regexp: '''/'' + serviceId + ''/(?.*)''' + replacement: '''/$\{remaining}''' + routes: + - id: LaneRouterCallerService + uri: lb://LaneCallerService + predicates: + - Path=/LaneCallerService/** + filters: + - StripPrefix=1 diff --git a/spring-cloud-tencent-examples/pom.xml b/spring-cloud-tencent-examples/pom.xml index df75f878b0..8eccfd4446 100644 --- a/spring-cloud-tencent-examples/pom.xml +++ b/spring-cloud-tencent-examples/pom.xml @@ -23,6 +23,7 @@ quickstart-example lossless-example polaris-router-grayrelease-lane-example + tsf-example diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java index bdd60f8ef4..a5090dbf02 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java @@ -36,11 +36,7 @@ public class CustomMetadata implements InstanceMetadataProvider { public Map getMetadata() { Map metadata = new HashMap<>(); metadata.put("k1", "v1"); + metadata.put("lane", "lane1"); return metadata; } - - @Override - public String getZone() { - return "shenzhen-zone-1"; - } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index a792d5a14a..88919d5ae3 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -29,7 +29,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -82,26 +81,6 @@ public String info() { return String.format("Quickstart [%s] Service [%s:%s] is called. datasource = [%s].", appName, ip, port, dataSourceProperties); } - /** - * Mock post save value. - * @return true - */ - @PostMapping("/saveValue") - public Boolean saveValue(@RequestParam int value) { - LOG.info("Quickstart [{}] Service [{}:{}] is called. Mock save value = [{}].", appName, ip, port, value); - return true; - } - - /** - * Get path echo of callee. - * @return information of callee - */ - @GetMapping("/path/echo/{param}") - public String pathEcho(@PathVariable String param) { - LOG.info("Quickstart [{}] Service [{}:{}] is called. param = [{}].", appName, ip, port, param); - return String.format("Quickstart [%s] Service [%s:%s] is called. datasource = [%s].", appName, ip, port, param); - } - /** * Get metadata in HTTP header. * @@ -144,4 +123,10 @@ public String health() { LOG.info("Quickstart Callee Service [{}:{}] is detected right.", ip, port); return String.format("Quickstart Callee Service [%s:%s] is detected right.", ip, port); } + + @GetMapping("/test/{num}/echo") + public String test(@PathVariable int num) { + LOG.info("Quickstart Callee Service [%s] is detected right.", num); + return String.format("Quickstart Callee Service [%s] is detected right.", num); + } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java deleted file mode 100644 index cdd4b97e02..0000000000 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolver.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.quickstart.callee.ratelimit; - -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; - -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelServletResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * resolver custom label from request. - * - * @author lepdou 2022-03-31 - */ -@Component -public class CustomLabelResolver implements PolarisRateLimiterLabelServletResolver { - private static final Logger LOG = LoggerFactory.getLogger(CustomLabelResolver.class); - - @Value("${label.key-value:}") - private String[] keyValues; - - @Override - public Map resolve(HttpServletRequest request) { - // rate limit by some request params. such as query params, headers .. - - return getLabels(keyValues); - } - - private Map getLabels(String[] keyValues) { - Map labels = new HashMap<>(); - for (String kv : keyValues) { - String key = kv.substring(0, kv.indexOf(":")); - String value = kv.substring(kv.indexOf(":") + 1); - labels.put(key, value); - } - - LOG.info("Current labels:{}", labels); - return labels; - } -} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml index bf4d56b8f6..d9f0131b2b 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/resources/bootstrap.yml @@ -14,10 +14,11 @@ spring: contract: exposure: true report: - enabled: false + enabled: true + admin: + port: 28083 stat: enabled: true - port: 28083 # pushgateway: # enabled: true # address: 127.0.0.1:9091 @@ -35,7 +36,7 @@ spring: metadata: content: label1: value1 - region: huanan +# region: huanan management: endpoints: web: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java index 8257f2cd54..7b4b9edef4 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/CustomMetadata.java @@ -36,11 +36,7 @@ public class CustomMetadata implements InstanceMetadataProvider { public Map getMetadata() { Map metadata = new HashMap<>(); metadata.put("k1", "v2"); + metadata.put("lane", "lane2"); return metadata; } - - @Override - public String getZone() { - return "shenzhen-zone-2"; - } } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 9f923950a2..a3dac5adbd 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -61,7 +61,7 @@ public class QuickstartCalleeController { @Autowired private DataSourceProperties dataSourceProperties; private boolean ifBadGateway = true; - private boolean ifDelay = true; + private boolean ifDelay = false; /** * Get sum of two value. diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java deleted file mode 100644 index 4a270fc62f..0000000000 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/java/com/tencent/cloud/quickstart/callee/ratelimit/CustomLabelResolverReactive.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.quickstart.callee.ratelimit; - -import java.util.HashMap; -import java.util.Map; - -import com.tencent.cloud.polaris.ratelimit.spi.PolarisRateLimiterLabelReactiveResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; - -/** - * resolver custom label from request. - * - * @author sean yu - */ -@Component -public class CustomLabelResolverReactive implements PolarisRateLimiterLabelReactiveResolver { - private static final Logger LOG = LoggerFactory.getLogger(CustomLabelResolverReactive.class); - - @Value("${label.key-value:}") - private String[] keyValues; - - @Override - public Map resolve(ServerWebExchange exchange) { - // rate limit by some request params. such as query params, headers .. - return getLabels(keyValues); - } - - private Map getLabels(String[] keyValues) { - Map labels = new HashMap<>(); - for (String kv : keyValues) { - String key = kv.substring(0, kv.indexOf(":")); - String value = kv.substring(kv.indexOf(":") + 1); - labels.put(key, value); - } - - LOG.info("Current labels:{}", labels); - return labels; - } -} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml index b5c7ec0bfe..19e7e5d5f8 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-b/src/main/resources/bootstrap.yml @@ -14,10 +14,11 @@ spring: contract: exposure: true report: - enabled: false + enabled: true + admin: + port: 28084 stat: enabled: true - port: 28084 # pushgateway: # enabled: true # address: 127.0.0.1:9091 @@ -34,7 +35,7 @@ spring: metadata: content: label1: value2 - region: huanan +# region: huanan management: endpoints: web: diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java index 9482965788..c936bef0b0 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/CustomMetadataProvider.java @@ -17,6 +17,9 @@ package com.tencent.cloud.quickstart.caller; +import java.util.HashMap; +import java.util.Map; + import com.tencent.cloud.common.spi.InstanceMetadataProvider; import org.springframework.stereotype.Component; @@ -28,7 +31,10 @@ public class CustomMetadataProvider implements InstanceMetadataProvider { @Override - public String getRegion() { - return "huadong"; + public Map getMetadata() { + Map metadata = new HashMap<>(); + metadata.put("k1", "v1"); + return metadata; } + } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java index ec939dd176..7ec58858a6 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/QuickstartCallerController.java @@ -17,20 +17,30 @@ package com.tencent.cloud.quickstart.caller; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.polaris.api.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; @@ -63,6 +73,8 @@ public class QuickstartCallerController { */ @GetMapping("/feign") public String feign(@RequestParam int value1, @RequestParam int value2) { + MetadataContext metadataContext = MetadataContextHolder.get(); + metadataContext.setTransitiveMetadata(Collections.singletonMap("feign-trace", String.format("%d+%d", value1, value2))); return quickstartCalleeService.sum(value1, value2); } @@ -71,8 +83,30 @@ public String feign(@RequestParam int value1, @RequestParam int value2) { * @return information of callee */ @GetMapping("/rest") - public String rest() { - return restTemplate.getForObject("http://QuickstartCalleeService/quickstart/callee/info", String.class); + public ResponseEntity rest(@RequestHeader Map headerMap) { + String url = "http://QuickstartCalleeService/quickstart/callee/info"; + + HttpHeaders headers = new HttpHeaders(); + for (Map.Entry entry : headerMap.entrySet()) { + if (StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue()) + && !entry.getKey().contains("sct-") + && !entry.getKey().contains("SCT-") + && !entry.getKey().contains("polaris-") + && !entry.getKey().contains("POLARIS-")) { + headers.add(entry.getKey(), entry.getValue()); + } + } + + // 创建 HttpEntity 实例并传入 HttpHeaders + HttpEntity entity = new HttpEntity<>(headers); + + // 使用 exchange 方法发送 GET 请求,并获取响应 + try { + return restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + } + catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) { + return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode()); + } } /** @@ -93,32 +127,33 @@ public Mono webclient() { * Get information 30 times per 1 second. * * @return result of 30 calls. - * @throws InterruptedException exception */ @GetMapping("/ratelimit") - public String invokeInfo() throws InterruptedException { - StringBuffer builder = new StringBuffer(); - CountDownLatch count = new CountDownLatch(30); + public String invokeInfo() { + StringBuilder builder = new StringBuilder(); AtomicInteger index = new AtomicInteger(0); for (int i = 0; i < 30; i++) { - new Thread(() -> { + try { + ResponseEntity entity = restTemplate.getForEntity( + "http://QuickstartCalleeService/quickstart/callee/info", String.class); + builder.append(entity.getBody() + "\n"); try { - ResponseEntity entity = restTemplate.getForEntity( - "http://QuickstartCalleeService/quickstart/callee/info", String.class); - builder.append(entity.getBody() + "\n"); + Thread.sleep(30); } - catch (RestClientException e) { - if (e instanceof HttpClientErrorException.TooManyRequests) { - builder.append("TooManyRequests " + index.incrementAndGet() + "\n"); - } - else { - throw e; - } + catch (InterruptedException e) { + throw new RuntimeException(e); } - count.countDown(); - }).start(); + } + catch (RestClientException e) { + if (e instanceof HttpClientErrorException.TooManyRequests) { + builder.append("TooManyRequests " + index.incrementAndGet() + "\n"); + } + else { + throw e; + } + } } - count.await(); + return builder.toString(); } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java index 5b348144b2..837b5ec0c1 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/circuitbreaker/CircuitBreakerController.java @@ -17,6 +17,7 @@ package com.tencent.cloud.quickstart.caller.circuitbreaker; +import com.tencent.cloud.common.metadata.MetadataContext; import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +29,8 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; @@ -110,19 +113,44 @@ public String circuitBreakFeignFallbackFromCodeWildcard(@PathVariable String uid @GetMapping("/rest") public String circuitBreakRestTemplate() { return circuitBreakerFactory - .create("QuickstartCalleeService#/quickstart/callee/circuitBreak") + .create(MetadataContext.LOCAL_NAMESPACE + "#QuickstartCalleeService#/quickstart/callee/circuitBreak#http#GET") .run(() -> defaultRestTemplate.getForObject("/quickstart/callee/circuitBreak", String.class), throwable -> "trigger the refuse for service callee." ); } + /** + * RestTemplate wildcard circuit breaker with fallback from Polaris. + * @return circuit breaker information of callee + */ + @GetMapping("/rest/fallbackFromPolaris/wildcard/{uid}") + public ResponseEntity circuitBreakRestTemplateFallbackFromPolarisWildcard(@PathVariable String uid) { + String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid); + return restTemplateFallbackFromPolaris.getForEntity(path, String.class); + } + + /** + * RestTemplate wildcard circuit breaker with fallback from code. + * @return circuit breaker information of callee + */ + @GetMapping("/rest/fallbackFromCode/wildcard/{uid}") + public ResponseEntity circuitBreakRestTemplateFallbackFromCodeWildcard(@PathVariable String uid) { + String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid); + return restTemplateFallbackFromCode.getForEntity(path, String.class); + } + /** * RestTemplate circuit breaker with fallback from Polaris. * @return circuit breaker information of callee */ @GetMapping("/rest/fallbackFromPolaris") public ResponseEntity circuitBreakRestTemplateFallbackFromPolaris() { - return restTemplateFallbackFromPolaris.getForEntity("/quickstart/callee/circuitBreak", String.class); + try { + return restTemplateFallbackFromPolaris.getForEntity("/quickstart/callee/circuitBreak", String.class); + } + catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) { + return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode()); + } } /** @@ -131,7 +159,12 @@ public ResponseEntity circuitBreakRestTemplateFallbackFromPolaris() { */ @GetMapping("/rest/fallbackFromCode") public ResponseEntity circuitBreakRestTemplateFallbackFromCode() { - return restTemplateFallbackFromCode.getForEntity("/quickstart/callee/circuitBreak", String.class); + try { + return restTemplateFallbackFromCode.getForEntity("/quickstart/callee/circuitBreak", String.class); + } + catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) { + return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode()); + } } /** @@ -148,7 +181,7 @@ public Mono webclient() { .bodyToMono(String.class) .transform(it -> reactiveCircuitBreakerFactory - .create("QuickstartCalleeService#/quickstart/callee/circuitBreak") + .create(MetadataContext.LOCAL_NAMESPACE + "QuickstartCalleeService#/quickstart/callee/circuitBreak#http#GET") .run(it, throwable -> Mono.just("fallback: trigger the refuse for service callee")) ); } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml index b51cbdec52..89f73c3c54 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/resources/bootstrap.yml @@ -14,15 +14,19 @@ spring: heartbeat: enabled: true health-check-url: /quickstart/caller/healthCheck + zero-protection: + enabled: true + is-need-test-connectivity: true contract: exposure: true report: - enabled: false + enabled: true circuitbreaker: enabled: true + admin: + port: 28082 stat: enabled: true - port: 28082 # pushgateway: # enabled: true # address: 127.0.0.1:9091 diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml index 9013c29d49..9bfb76041a 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/pom.xml @@ -28,11 +28,6 @@ org.springframework.cloud spring-cloud-starter-gateway - - - org.springframework.boot - spring-boot-starter-actuator - diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml index 0db7fd89ad..b30f39da4c 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-gateway-service/src/main/resources/bootstrap.yml @@ -18,13 +18,16 @@ spring: address: grpc://119.91.66.223:8091 namespace: default enabled: true + circuitbreaker: + enabled: true contract: exposure: true report: - enabled: false + enabled: true + admin: + port: 28081 stat: enabled: true - port: 28081 gateway: discovery: locator: diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml b/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml new file mode 100644 index 0000000000..44abeeb31f --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + tsf-example + com.tencent.cloud + ${revision} + ../pom.xml + + consumer-demo + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-contract + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-circuitbreaker + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java new file mode 100644 index 0000000000..999d198d3b --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/ConsumerApplication.java @@ -0,0 +1,44 @@ +/* + * 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.tsf.demo.consumer; + +import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreaker; + +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.tsf.annotation.EnableTsf; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +@EnableFeignClients // 使用Feign微服务调用时请启用 +@EnableTsf +public class ConsumerApplication { + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + + @LoadBalanced + @Bean + @PolarisCircuitBreaker + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java new file mode 100644 index 0000000000..1a7e71983d --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/controller/ConsumerController.java @@ -0,0 +1,102 @@ +/* + * 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.tsf.demo.consumer.controller; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderDemoService; +import com.tencent.cloud.tsf.demo.consumer.proxy.ProviderService; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.tsf.core.context.TsfContext; +import org.springframework.tsf.core.entity.Tag; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +@RestController +public class ConsumerController { + @Autowired + private RestTemplate restTemplate; + @Autowired + private ProviderService providerService; + @Autowired + private ProviderDemoService providerDemoService; + + @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) + public String restProvider(@PathVariable String str, + @RequestParam(required = false) String tagName, + @RequestParam(required = false) String tagValue) { + if (StringUtils.isNotBlank(tagName)) { + TsfContext.putTag(tagName, tagValue); + } + TsfContext.putTag("operation", "rest"); + Map mTags = new HashMap<>(); + mTags.put("rest-trace-key1", "value1"); + mTags.put("rest-trace-key2", "value2"); + TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE); + try { + return restTemplate.getForObject("http://provider-demo/echo/" + str, String.class); + } + catch (CallAbortedException callAbortedException) { + return callAbortedException.getMessage(); + } + + } + + @RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET) + public String feignProvider(@PathVariable String str, + @RequestParam(required = false) String tagName, + @RequestParam(required = false) String tagValue) { + if (StringUtils.isNotBlank(tagName)) { + TsfContext.putTag(tagName, tagValue); + } + TsfContext.putTag("operation", "feign"); + Map mTags = new HashMap<>(); + mTags.put("feign-trace-key1", "value1"); + mTags.put("feign-trace-key2", "value2"); + TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE); + try { + return providerDemoService.echo(str); + } + catch (CallAbortedException callAbortedException) { + return callAbortedException.getMessage(); + } + } + + @RequestMapping(value = "/echo-feign-url/{str}", method = RequestMethod.GET) + public String feignUrlProvider(@PathVariable String str, + @RequestParam(required = false) String tagName, + @RequestParam(required = false) String tagValue) { + if (StringUtils.isNotBlank(tagName)) { + TsfContext.putTag(tagName, tagValue); + } + TsfContext.putTag("operation", "feignUrl"); + Map mTags = new HashMap<>(); + mTags.put("feignUrl-trace-key1", "value1"); + mTags.put("feignUrl-trace-key2", "value2"); + TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE); + return providerService.echo(str); + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java new file mode 100644 index 0000000000..47a38b4758 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/entity/CustomMetadata.java @@ -0,0 +1,32 @@ +/* + * 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.tsf.demo.consumer.entity; + +/** + * 用户自定义 Metadata. + */ +public class CustomMetadata { + + private String name; + private String value; + + public CustomMetadata(String name, String value) { + this.name = name; + this.value = value; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java new file mode 100644 index 0000000000..c102fc84e0 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderDemoService.java @@ -0,0 +1,36 @@ +/* + * 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.tsf.demo.consumer.proxy; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = "provider-demo") +public interface ProviderDemoService { + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); + + @RequestMapping(value = "/echo/error/{str}", method = RequestMethod.GET) + String echoError(@PathVariable("str") String str); + + @RequestMapping(value = "/echo/slow/{str}", method = RequestMethod.GET) + String echoSlow(@PathVariable("str") String str, @RequestParam("delay") int delay); +} diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.java similarity index 52% rename from spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java rename to spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.java index 18f3d0cacb..ac540217a4 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-caller-service/src/main/java/com/tencent/cloud/quickstart/caller/router/CustomRouterLabelResolver.java +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/java/com/tencent/cloud/tsf/demo/consumer/proxy/ProviderService.java @@ -13,42 +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.quickstart.caller.router; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.google.gson.Gson; -import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver; -import feign.RequestTemplate; +package com.tencent.cloud.tsf.demo.consumer.proxy; +import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; /** - * - * Customize the business tag information obtained from the request - * - *@author lepdou 2022-05-12 + * 测试通过URL配置FeignClient + * 使用时修改provider-ip:provider-port配置 */ -@Component -public class CustomRouterLabelResolver implements FeignRouterLabelResolver { - private final Gson gson = new Gson(); +@FeignClient(name = "provider", url = "http://127.0.0.1:18081", fallback = FeignClientFallback.class) +public interface ProviderService { - @Override - public Map resolve(RequestTemplate requestTemplate, Set expressionLabelKeys) { - Map labels = new HashMap<>(); - - labels.put("label1", "value1"); + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); - return labels; - } +} +@Component +class FeignClientFallback implements ProviderService { @Override - public int getOrder() { - return 0; + public String echo(String str) { + return "tsf-fault-tolerance-" + str; } } diff --git a/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml new file mode 100644 index 0000000000..b7cd3ee201 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/consumer-demo/src/main/resources/bootstrap.yml @@ -0,0 +1,17 @@ +server: + port: 18083 +spring: + application: + name: consumer-demo +feign: + tsf: + enabled: true + +#本地测试时打开 +#tsf_namespace_id: default_namespace + +logging: + file: + name: /tsf-demo-logs/${spring.application.name}/root.log + level: + root: INFO diff --git a/spring-cloud-tencent-examples/tsf-example/pom.xml b/spring-cloud-tencent-examples/tsf-example/pom.xml new file mode 100644 index 0000000000..41379d9301 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/pom.xml @@ -0,0 +1,41 @@ + + + + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + tsf-example + Spring Cloud Tencent TSF Examples + pom + + + true + + + + provider-demo + consumer-demo + + diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml b/spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml new file mode 100644 index 0000000000..e1ccfd1c08 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + tsf-example + com.tencent.cloud + ${revision} + ../pom.xml + + provider-demo + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-contract + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + + + com.tencent.cloud + spring-cloud-starter-tencent-trace-plugin + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java new file mode 100644 index 0000000000..accc1811e6 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderApplication.java @@ -0,0 +1,31 @@ +/* + * 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.tsf.demo.provider; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.tsf.annotation.EnableTsf; + +@SpringBootApplication +@EnableTsf +public class ProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(ProviderApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java new file mode 100644 index 0000000000..bfd49ba5ff --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderConfigController.java @@ -0,0 +1,36 @@ +/* + * 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.tsf.demo.provider; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RefreshScope +public class ProviderConfigController { + + @Value("${provider.name:default}") + private String name; + + @GetMapping("/config/name") + public String getConfig() { + return name; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java new file mode 100644 index 0000000000..b2f80e1b41 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/ProviderController.java @@ -0,0 +1,154 @@ +/* + * 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.tsf.demo.provider; + + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + +import javax.servlet.http.HttpServletResponse; + +import com.tencent.cloud.tsf.demo.provider.config.ProviderNameConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + + +/** + * @Author leoziltong@tencent.com + * @Date: 2021/5/11 17:10 + */ +@RestController +public class ProviderController { + + private static final Logger LOG = LoggerFactory.getLogger(ProviderController.class); + + @Value("${spring.application.name:}") + private String applicationName; + + @Autowired + private ProviderNameConfig providerNameConfig; + + // 获取本机ip + public static String getInet4Address() { + Enumeration nis; + String ip = null; + try { + nis = NetworkInterface.getNetworkInterfaces(); + for (; nis.hasMoreElements(); ) { + NetworkInterface ni = nis.nextElement(); + Enumeration ias = ni.getInetAddresses(); + for (; ias.hasMoreElements(); ) { + InetAddress ia = ias.nextElement(); + if (ia instanceof Inet4Address && !ia.getHostAddress().equals("127.0.0.1")) { + ip = ia.getHostAddress(); + } + } + } + } + catch (SocketException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return ip; + } + + @RequestMapping(value = "/hello", method = RequestMethod.GET) + public String hello() { + String echoHello = "say hello"; + LOG.info(echoHello); + return echoHello; + } + + @RequestMapping(value = "/echo/{param}", method = RequestMethod.GET) + public ResponseEntity echo(@PathVariable String param) { + int status; + String responseBody; + + switch (param) { + case "1xx": + status = HttpServletResponse.SC_CONTINUE; + responseBody = "mock 1xx return."; + break; + case "3xx": + status = HttpServletResponse.SC_FOUND; + responseBody = "mock 3xx return."; + break; + case "4xx": + status = HttpServletResponse.SC_NOT_FOUND; + responseBody = "mock 4xx return."; + break; + case "5xx": + status = HttpServletResponse.SC_BAD_GATEWAY; + responseBody = "mock 5xx return."; + break; + default: + responseBody = String.format("from host-ip: %s, request param: %s, response from %s", + getInet4Address(), param, providerNameConfig.getName()); + status = HttpServletResponse.SC_OK; + break; + } + + return ResponseEntity.status(status).body(responseBody); + } + + @RequestMapping(value = "/echo/error/{param}", method = RequestMethod.GET) + public String echoError(@PathVariable String param) { + LOG.info("Error request param: [" + param + "], throw exception"); + + throw new RuntimeException("mock-ex"); + } + + /** + * 延迟返回. + * @param param 参数 + * @param delay 延时时间,单位毫秒 + * @throws InterruptedException InterruptedException + */ + @RequestMapping(value = "/echo/slow/{param}", method = RequestMethod.GET) + public String echoSlow(@PathVariable String param, @RequestParam(required = false) Integer delay) throws InterruptedException { + int sleepTime = delay == null ? 1000 : delay; + LOG.info("slow request param: [" + param + "], Start sleep: [" + sleepTime + "]ms"); + Thread.sleep(sleepTime); + LOG.info("slow request param: [" + param + "], End sleep: [" + sleepTime + "]ms"); + + String result = "request param: " + param + + ", slow response from " + applicationName + + ", sleep: [" + sleepTime + "]ms"; + return result; + } + + @RequestMapping(value = "/echo/unit/{param}", method = RequestMethod.GET) + public String echoUnit(@PathVariable String param) { + LOG.info("provider-demo -- unit request param: [" + param + "]"); + String result = "request param: " + param + ", response from " + applicationName; + LOG.info("provider-demo -- unit provider config name: [" + applicationName + ']'); + LOG.info("provider-demo -- unit response info: [" + result + "]"); + return result; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java new file mode 100644 index 0000000000..45c04f22cb --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfig.java @@ -0,0 +1,37 @@ +/* + * 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.tsf.demo.provider.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +@Component +@RefreshScope +@ConfigurationProperties(prefix = "provider.config") +public class ProviderNameConfig { + private String name = "echo-provider-default-name"; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.java new file mode 100644 index 0000000000..1493c91058 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/config/ProviderNameConfigChangeListener.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.tsf.demo.provider.config; + +import com.tencent.tsf.consul.config.watch.ConfigChangeCallback; +import com.tencent.tsf.consul.config.watch.ConfigChangeListener; +import com.tencent.tsf.consul.config.watch.ConfigProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.stereotype.Component; + +@Component +@ConfigChangeListener(prefix = "provider.config", value = {"name"}) +public class ProviderNameConfigChangeListener implements ConfigChangeCallback { + + private static final Logger log = LoggerFactory.getLogger(ProviderNameConfigChangeListener.class); + + @Override + public void callback(ConfigProperty lastConfigProperty, ConfigProperty newConfigProperty) { + log.info("[TSF SDK] Configuration Change Listener: key: {}, old value: {}, new value: {}", + lastConfigProperty.getKey(), lastConfigProperty.getValue(), newConfigProperty.getValue()); + } + +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java new file mode 100644 index 0000000000..be6cc6cd6b --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/controller/SwaggerApiController.java @@ -0,0 +1,145 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.tsf.demo.provider.swagger.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.tsf.demo.provider.swagger.model.MessageBox; +import com.tencent.cloud.tsf.demo.provider.swagger.model.MessageModel; +import com.tencent.cloud.tsf.demo.provider.swagger.model.MessageUser; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController("/swagger") +@Tag(description = "swagger 测试", name = "swaggerValue1") +public class SwaggerApiController { + + @RequestMapping(value = "/swagger/findMessages", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @Operation(method = "POST", + summary = "根据任务ID查询任务列表", + description = "根据任务ID查询任务列表Note") + public List findMessages(@RequestBody + @Parameter(name = "msgIds", description = "消息ID列表") List msgIds) { + List messageModels = new ArrayList<>(); + MessageModel messageModel = new MessageModel(); + messageModel.setMsgContent("test1"); + messageModel.setMsgId("1"); + messageModel.setSendTime(System.currentTimeMillis()); + MessageUser messageSender = new MessageUser(); + messageSender.setEmail("abc@xxxx.com"); + messageSender.setName("特朗普"); + messageSender.setOfficeAddress("华盛顿白宫"); + messageSender.setPhoneNum("911911911"); + messageModel.setSendUser(messageSender); + MessageUser messageReceiver = new MessageUser(); + messageReceiver.setEmail("abc@xxxx.com"); + messageReceiver.setName("拜登"); + messageReceiver.setOfficeAddress("华盛顿白宫"); + messageReceiver.setPhoneNum("911911911"); + messageModel.setReceiveUsers(Lists.newArrayList(messageReceiver)); + messageModels.add(messageModel); + return messageModels; + } + + //虽然这些@ExampleProperty和@Example属性已经在Swagger中实现,但Springfox还没有支持它们。问题仍然存在: + //https://github.com/springfox/springfox/issues/853 + //https://github.com/springfox/springfox/issues/1536 + + @Operation(summary = "获取消息内容", method = "GET", description = "获取消息内容Note") + @ApiResponse(responseCode = "200", description = "abcdef", content = @Content(schema = @Schema(implementation = String.class))) + @RequestMapping("/swagger/getMessageContent") + public String getMessageContent(@RequestParam(name = "id") + @Parameter(description = "消息ID", name = "id") String msgId) { + return "abcdefg"; + } + + @Operation(summary = "获取消息详情", method = "GET", description = "获取消息内容Note") + @ApiResponses({@ApiResponse(responseCode = "200", description = "abcdef", content = @Content(schema = @Schema(implementation = MessageModel.class)))}) + @RequestMapping(value = "/swagger/getMessageDetail", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public MessageModel getMessageDetail(@RequestParam(name = "id") + @Parameter(description = "消息ID", name = "id") String msgId) { + MessageModel messageModel = new MessageModel(); + messageModel.setMsgContent("test1"); + messageModel.setMsgId("1"); + messageModel.setSendTime(System.currentTimeMillis()); + MessageUser messageSender = new MessageUser(); + messageSender.setEmail("abc@xxxx.com"); + messageSender.setName("特朗普"); + messageSender.setOfficeAddress("华盛顿白宫"); + messageSender.setPhoneNum("911911911"); + messageModel.setSendUser(messageSender); + MessageUser messageReceiver = new MessageUser(); + messageReceiver.setEmail("abc@xxxx.com"); + messageReceiver.setName("拜登"); + messageReceiver.setOfficeAddress("华盛顿白宫"); + messageReceiver.setPhoneNum("911911911"); + messageModel.setReceiveUsers(Lists.newArrayList(messageReceiver)); + return messageModel; + } + + @Operation(summary = "获取投递箱详情", method = "GET", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "获取投递箱成功", content = @Content(schema = @Schema(implementation = MessageBox.class)))}) + @RequestMapping(value = "/swagger/getMessageBox", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public MessageBox getMessageBox(@RequestParam @Parameter(required = true, description = "投递箱ID") String boxId, + @RequestParam @Parameter(name = "sizeLimit", example = "10", description = "投递箱最大投递数") int maxSizeLimit) { + return new MessageBox(); + } + + @Operation(summary = "获取投递箱详情V2", method = "POST", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "获取投递箱成功", content = @Content(schema = @Schema(implementation = MessageBox.class)))}) + @RequestMapping(value = "/swagger/v2/getMessageBox", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public MessageBox getMessageBoxV2(@RequestBody + @Parameter(required = true, name = "messageBox", example = "投递箱信息") MessageBox messageBox) { + return new MessageBox(); + } + + @Operation(summary = "获取投递箱详情V3", method = "POST", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "获取投递箱成功", content = @Content(schema = @Schema(implementation = Map.class)))}) + @RequestMapping(value = "/swagger/v3/getMessageBox", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public Map queryMessageBoxV3(@RequestBody + @Parameter(required = true, name = "messageBox", example = "投递箱信息") MessageBox messageBox) { + + return new HashMap<>(); + } + + + @Operation(summary = "获取投递箱地址", method = "GET", description = "") + @ApiResponses({@ApiResponse(responseCode = "200", description = "投递箱地址", content = @Content(schema = @Schema(implementation = String.class)))}) + @RequestMapping(value = "/swagger/getMessageBoxAddress", produces = MediaType.TEXT_PLAIN_VALUE) + public String queryMessageBoxAddress(@RequestParam(name = "boxId") + @Parameter(description = "投递箱ID", name = "boxId", example = "box-qvp9htm5", required = true) String id) { + return "华盛顿白宫"; + + } + +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java new file mode 100644 index 0000000000..ec0a4ff056 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageBox.java @@ -0,0 +1,102 @@ +/* + * 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.tsf.demo.provider.swagger.model; + + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "消息投递箱") +public class MessageBox { + + @Schema(title = "默认失效天数", required = false) + private int expiredDays; + + @Schema(title = "最大失效天数", required = false) + private Integer maxExpiredDays; + + @Schema(title = "容量大小", required = false) + private Float capacity; + + @Schema(title = "最大容量大小", required = false) + private float maxCapacity; + + @Schema(title = "接受的信息数量", required = false) + private Double size; + + @Schema(title = "最大接受的信息数量", required = false) + private double maxSize; + + @Schema(title = "消息(循环测试嵌套对象)", required = false) + private MessageModel messageModel; + + public int getExpiredDays() { + return expiredDays; + } + + public void setExpiredDays(int expiredDays) { + this.expiredDays = expiredDays; + } + + public Integer getMaxExpiredDays() { + return maxExpiredDays; + } + + public void setMaxExpiredDays(Integer maxExpiredDays) { + this.maxExpiredDays = maxExpiredDays; + } + + public Float getCapacity() { + return capacity; + } + + public void setCapacity(Float capacity) { + this.capacity = capacity; + } + + public float getMaxCapacity() { + return maxCapacity; + } + + public void setMaxCapacity(float maxCapacity) { + this.maxCapacity = maxCapacity; + } + + public Double getSize() { + return size; + } + + public void setSize(Double size) { + this.size = size; + } + + public double getMaxSize() { + return maxSize; + } + + public void setMaxSize(double maxSize) { + this.maxSize = maxSize; + } + + public MessageModel getMessageModel() { + return messageModel; + } + + public void setMessageModel(MessageModel messageModel) { + this.messageModel = messageModel; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java new file mode 100644 index 0000000000..08d3a528ea --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageModel.java @@ -0,0 +1,92 @@ +/* + * 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.tsf.demo.provider.swagger.model; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "消息", title = "messageModel") +public class MessageModel { + + @Schema(name = "id", title = "消息ID", required = true, description = "消息ID notes") + private String msgId; + + @Schema(title = "消息内容", required = false) + private String msgContent; + + @Schema(title = "消息发送者", required = true) + private MessageUser sendUser; + + @Schema(title = "消息接收者", required = true) + private List receiveUsers; + + @Schema(title = "消息发送时间", required = true) + private long sendTime; + + @Schema(title = "消息投递箱", required = false) + private MessageBox messageBox; + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public String getMsgContent() { + return msgContent; + } + + public void setMsgContent(String msgContent) { + this.msgContent = msgContent; + } + + public MessageUser getSendUser() { + return sendUser; + } + + public void setSendUser(MessageUser sendUser) { + this.sendUser = sendUser; + } + + public List getReceiveUsers() { + return receiveUsers; + } + + public void setReceiveUsers(List receiveUsers) { + this.receiveUsers = receiveUsers; + } + + public long getSendTime() { + return sendTime; + } + + public void setSendTime(long sendTime) { + this.sendTime = sendTime; + } + + public MessageBox getMessageBox() { + return messageBox; + } + + public void setMessageBox(MessageBox messageBox) { + this.messageBox = messageBox; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java new file mode 100644 index 0000000000..9bd2f06edf --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/java/com/tencent/cloud/tsf/demo/provider/swagger/model/MessageUser.java @@ -0,0 +1,69 @@ +/* + * 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.tsf.demo.provider.swagger.model; + + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "消息发送/接收者") +public class MessageUser { + + @Schema(title = "用户姓名", name = "name") + private String name; + + @Schema(title = "邮箱地址") + private String email; + + @Schema(title = "电话号码") + private String phoneNum; + + @Schema(title = "办公地址") + private String officeAddress; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhoneNum() { + return phoneNum; + } + + public void setPhoneNum(String phoneNum) { + this.phoneNum = phoneNum; + } + + public String getOfficeAddress() { + return officeAddress; + } + + public void setOfficeAddress(String officeAddress) { + this.officeAddress = officeAddress; + } +} diff --git a/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml new file mode 100644 index 0000000000..018fc95105 --- /dev/null +++ b/spring-cloud-tencent-examples/tsf-example/provider-demo/src/main/resources/bootstrap.yml @@ -0,0 +1,29 @@ +server: + port: 18081 +spring: + application: + name: provider-demo + cloud: + polaris: + namespace: default + enabled: true + stat: + enabled: true + loadbalancer: + strategy: polarisWeightedRandom + tencent: + rpc-enhancement: + reporter: + enabled: true + +logging: + file: + name: /tsf-demo-logs/${spring.application.name}/root.log + level: + root: INFO +management: + endpoints: + web: + exposure: + include: + - polaris-config diff --git a/spring-cloud-tencent-plugin-starters/pom.xml b/spring-cloud-tencent-plugin-starters/pom.xml index 5debf63608..702dfeca45 100644 --- a/spring-cloud-tencent-plugin-starters/pom.xml +++ b/spring-cloud-tencent-plugin-starters/pom.xml @@ -20,6 +20,7 @@ spring-cloud-starter-tencent-discovery-adapter-plugin spring-cloud-tencent-lossless-plugin spring-cloud-starter-tencent-threadlocal-plugin + spring-cloud-starter-tencent-trace-plugin diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java index 4f82638ad7..34f9300008 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosDiscoveryAdapterAutoConfiguration.java @@ -21,7 +21,7 @@ import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosRegistrationTransformer; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerAutoConfiguration; -import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; +import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import org.springframework.boot.autoconfigure.AutoConfigureBefore; @@ -43,7 +43,7 @@ public class NacosDiscoveryAdapterAutoConfiguration { @Bean @ConditionalOnMissingBean - @ConditionalOnClass(name = "com.alibaba.cloud.nacos.NacosServiceInstance") + @ConditionalOnClass(name = "com.alibaba.cloud.nacos.ribbon.NacosServer") public InstanceTransformer instanceTransformer() { return new NacosInstanceTransformer(); } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java index dbcc1c8bca..db10472962 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosInstanceTransformer.java @@ -18,11 +18,10 @@ package com.tencent.cloud.plugin.discovery.adapter.transformer; -import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer; +import com.alibaba.cloud.nacos.ribbon.NacosServer; +import com.netflix.loadbalancer.Server; +import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer; import com.tencent.polaris.api.pojo.DefaultInstance; -import org.apache.commons.lang.StringUtils; - -import org.springframework.cloud.client.ServiceInstance; /** * NacosInstanceTransformer. @@ -32,20 +31,12 @@ public class NacosInstanceTransformer implements InstanceTransformer { @Override - public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) { - if ("com.alibaba.cloud.nacos.NacosServiceInstance".equals(serviceInstance.getClass().getName())) { - String nacosWeight = serviceInstance.getMetadata().get("nacos.weight"); - instance.setWeight( - StringUtils.isBlank(nacosWeight) ? 100 : (int) Double.parseDouble(nacosWeight) * 100 - ); - String nacosHealthy = serviceInstance.getMetadata().get("nacos.healthy"); - instance.setHealthy( - !StringUtils.isBlank(nacosHealthy) && Boolean.parseBoolean(nacosHealthy) - ); - String nacosInstanceId = serviceInstance.getMetadata().get("nacos.instanceId"); - instance.setId(nacosInstanceId); - + public void transformCustom(DefaultInstance instance, Server server) { + if ("com.alibaba.cloud.nacos.ribbon.NacosServer".equals(server.getClass().getName())) { + NacosServer nacosServer = (NacosServer) server; + instance.setWeight((int) (nacosServer.getInstance().getWeight() * 100)); + instance.setHealthy(nacosServer.getInstance().isHealthy()); + instance.setMetadata(nacosServer.getMetadata()); } } - } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java index d82558d272..9d2f44cf6e 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/main/java/com/tencent/cloud/plugin/discovery/adapter/transformer/NacosRegistrationTransformer.java @@ -36,8 +36,7 @@ public String getRegistry() { @Override public void transformCustom(DefaultInstance instance, Registration registration) { if (registration instanceof NacosRegistration) { - NacosRegistration nacosRegistration = (NacosRegistration) registration; - NacosDiscoveryProperties nacosDiscoveryProperties = nacosRegistration.getNacosDiscoveryProperties(); + NacosDiscoveryProperties nacosDiscoveryProperties = ((NacosRegistration) registration).getNacosDiscoveryProperties(); String namespace = nacosDiscoveryProperties.getNamespace(); if (StringUtils.isBlank(namespace)) { namespace = "default"; diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java index 8320d6d902..00dd8be77f 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-discovery-adapter-plugin/src/test/java/com/tencent/cloud/plugin/discovery/adapter/config/NacosInstanceTransformerTest.java @@ -18,12 +18,10 @@ package com.tencent.cloud.plugin.discovery.adapter.config; -import java.util.HashMap; - -import com.alibaba.cloud.nacos.NacosServiceInstance; +import com.alibaba.cloud.nacos.ribbon.NacosServer; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer; -import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.api.pojo.DefaultInstance; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -53,13 +51,14 @@ public static void beforeAll() { @Test public void test() { NacosInstanceTransformer nacosInstanceTransformer = new NacosInstanceTransformer(); - NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); - nacosServiceInstance.setMetadata(new HashMap() {{ - put("nacos.weight", "0.01"); - put("nacos.healthy", "true"); - put("nacos.instanceId", "xxx"); - }}); - Instance instance = nacosInstanceTransformer.transform(nacosServiceInstance); + + com.alibaba.nacos.api.naming.pojo.Instance nacosInstance = new com.alibaba.nacos.api.naming.pojo.Instance(); + nacosInstance.setHealthy(true); + NacosServer nacosServer = new NacosServer(nacosInstance); + + + DefaultInstance instance = new DefaultInstance(); + nacosInstanceTransformer.transformCustom(instance, nacosServer); assertThat(instance.isHealthy()).isEqualTo(true); } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java index b56215f963..15dd313c62 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-threadlocal-plugin/src/test/java/com/tencent/cloud/plugin/threadlocal/TaskExecutorWrapperTest.java @@ -20,7 +20,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml new file mode 100644 index 0000000000..99fe4f187e --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/pom.xml @@ -0,0 +1,24 @@ + + + spring-cloud-tencent-plugin-starters + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + spring-cloud-starter-tencent-trace-plugin + Spring Cloud Tencent Trace Plugin + + + + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + + com.tencent.polaris + trace-otel + + + diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java similarity index 63% rename from spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java rename to spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java index 1ec3a7a0c7..ed7b2d4590 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/spi/PolarisRateLimiterLabelServletResolver.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/SpanAttributesProvider.java @@ -16,23 +16,13 @@ * */ -package com.tencent.cloud.polaris.ratelimit.spi; +package com.tencent.cloud.plugin.trace; import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; -/** - * Resolve custom label from request. The label used for rate limit params. - * - * @author lepdou 2022-03-31 - */ -public interface PolarisRateLimiterLabelServletResolver { +public interface SpanAttributesProvider { - /** - * Resolve custom label from request. - * @param request the http request - * @return resolved labels - */ - Map resolve(HttpServletRequest request); + Map getConsumerSpanAttributes(EnhancedPluginContext context); } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java new file mode 100644 index 0000000000..6525ec8e45 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/TraceServerMetadataEnhancedPlugin.java @@ -0,0 +1,84 @@ +/* + * 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.plugin.trace; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +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.api.utils.CollectionUtils; +import com.tencent.polaris.assembly.api.AssemblyAPI; +import com.tencent.polaris.assembly.api.pojo.TraceAttributes; + +public class TraceServerMetadataEnhancedPlugin implements EnhancedPlugin { + + private final PolarisSDKContextManager polarisSDKContextManager; + + private final SpanAttributesProvider spanAttributesProvider; + + public TraceServerMetadataEnhancedPlugin(PolarisSDKContextManager polarisSDKContextManager, SpanAttributesProvider spanAttributesProvider) { + this.polarisSDKContextManager = polarisSDKContextManager; + this.spanAttributesProvider = spanAttributesProvider; + } + + @Override + public EnhancedPluginType getType() { + return EnhancedPluginType.Server.PRE; + } + + @Override + public void run(EnhancedPluginContext context) throws Throwable { + AssemblyAPI assemblyAPI = polarisSDKContextManager.getAssemblyAPI(); + Map attributes = new HashMap<>(); + if (null != spanAttributesProvider) { + Map additionalAttributes = spanAttributesProvider.getConsumerSpanAttributes(context); + if (CollectionUtils.isNotEmpty(additionalAttributes)) { + attributes.putAll(additionalAttributes); + } + } + MetadataContext metadataContext = MetadataContextHolder.get(); + Map transitiveCustomAttributes = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + if (CollectionUtils.isNotEmpty(transitiveCustomAttributes)) { + for (Map.Entry entry : transitiveCustomAttributes.entrySet()) { + attributes.put("custom." + entry.getKey(), entry.getValue()); + } + } + Map disposableCustomAttributes = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + if (CollectionUtils.isNotEmpty(disposableCustomAttributes)) { + for (Map.Entry entry : disposableCustomAttributes.entrySet()) { + attributes.put("custom." + entry.getKey(), entry.getValue()); + } + } + TraceAttributes traceAttributes = new TraceAttributes(); + traceAttributes.setAttributes(attributes); + traceAttributes.setAttributeLocation(TraceAttributes.AttributeLocation.SPAN); + assemblyAPI.updateTraceAttributes(traceAttributes); + } + + @Override + public int getOrder() { + return PluginOrderConstant.ServerPluginOrder.PROVIDER_TRACE_METADATA_PLUGIN_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java new file mode 100644 index 0000000000..72370839a2 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifier.java @@ -0,0 +1,41 @@ +/* + * 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.plugin.trace.config; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; + +/** + * Spring Cloud Tencent config Override polaris trace config. + * + * @author andrew 2024-06-18 + */ +public class TraceConfigModifier implements PolarisConfigModifier { + + @Override + public void modify(ConfigurationImpl configuration) { + configuration.getGlobal().getTraceReporter().setEnable(true); + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.TRACE_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java new file mode 100644 index 0000000000..c9e3540481 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierAutoConfiguration.java @@ -0,0 +1,37 @@ +/* + * 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.plugin.trace.config; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) +public class TraceConfigModifierAutoConfiguration { + + @Bean + public TraceConfigModifier traceConfigModifier() { + return new TraceConfigModifier(); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java new file mode 100644 index 0000000000..4f0a87bc7a --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceConfigModifierBootstrapAutoConfiguration.java @@ -0,0 +1,30 @@ +/* + * 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.plugin.trace.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(TraceConfigModifierAutoConfiguration.class) +public class TraceConfigModifierBootstrapAutoConfiguration { + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java new file mode 100644 index 0000000000..9eb8970a42 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/config/TraceEnhancedPluginAutoConfiguration.java @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.trace.config; + +import com.tencent.cloud.plugin.trace.SpanAttributesProvider; +import com.tencent.cloud.plugin.trace.TraceServerMetadataEnhancedPlugin; +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) +public class TraceEnhancedPluginAutoConfiguration { + + @Bean + public TraceServerMetadataEnhancedPlugin traceServerMetadataEnhancedPlugin( + PolarisSDKContextManager polarisSDKContextManager, @Autowired(required = false) SpanAttributesProvider spanAttributesProvider) { + return new TraceServerMetadataEnhancedPlugin(polarisSDKContextManager, spanAttributesProvider); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java new file mode 100644 index 0000000000..311fbc65a8 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfSpanAttributesProvider.java @@ -0,0 +1,58 @@ +/* + * 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.plugin.trace.tsf; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.plugin.trace.SpanAttributesProvider; +import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; +import com.tencent.polaris.api.utils.CollectionUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants; + +import org.springframework.cloud.client.ServiceInstance; + +public class TsfSpanAttributesProvider implements SpanAttributesProvider { + + @Override + public Map getConsumerSpanAttributes(EnhancedPluginContext context) { + Map attributes = new HashMap<>(); + if (null != context.getRequest().getUrl()) { + attributes.put("remoteInterface", context.getRequest().getUrl().getPath()); + } + ServiceInstance targetServiceInstance = context.getTargetServiceInstance(); + if (null != targetServiceInstance && CollectionUtils.isNotEmpty(targetServiceInstance.getMetadata())) { + if (targetServiceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_NAMESPACE_ID)) { + attributes.put("remote.namespace-id", StringUtils.defaultString( + targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_NAMESPACE_ID))); + } + if (targetServiceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_GROUP_ID)) { + attributes.put("remote.group-id", StringUtils.defaultString( + targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_GROUP_ID))); + } + if (targetServiceInstance.getMetadata().containsKey(TsfMetadataConstants.TSF_APPLICATION_ID)) { + attributes.put("remote.application-id", StringUtils.defaultString( + targetServiceInstance.getMetadata().get(TsfMetadataConstants.TSF_APPLICATION_ID))); + } + } + return attributes; + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java new file mode 100644 index 0000000000..6bfed4541e --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/java/com/tencent/cloud/plugin/trace/tsf/TsfTracePropertiesAutoConfiguration.java @@ -0,0 +1,36 @@ +/* + * 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.plugin.trace.tsf; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty(value = "spring.cloud.polaris.trace.enabled", matchIfMissing = true) +public class TsfTracePropertiesAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfSpanAttributesProvider tsfClientSpanAttributesProvider() { + return new TsfSpanAttributesProvider(); + } + +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..eb958b7e9d --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-starter-tencent-trace-plugin/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.plugin.trace.config.TraceConfigModifierAutoConfiguration,\ + com.tencent.cloud.plugin.trace.config.TraceEnhancedPluginAutoConfiguration,\ + com.tencent.cloud.plugin.trace.tsf.TsfTracePropertiesAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.plugin.trace.config.TraceConfigModifierBootstrapAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml index 59a313be94..2cd2864210 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/pom.xml @@ -1,6 +1,6 @@ - spring-cloud-tencent-plugin-starters @@ -17,22 +17,22 @@ com.tencent.cloud - spring-cloud-tencent-polaris-context + spring-cloud-tencent-rpc-enhancement - com.tencent.cloud - spring-cloud-tencent-commons + com.tencent.polaris + lossless-register com.tencent.polaris - lossless-register + lossless-deregister com.tencent.polaris - lossless-deregister + lossless-warmup @@ -52,12 +52,6 @@ test - - com.tencent.cloud - spring-cloud-starter-tencent-polaris-discovery - true - - com.tencent.polaris polaris-test-mock-discovery diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java index 9dab0f2436..37cfca588a 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/LosslessRegistryAspect.java @@ -22,6 +22,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; import com.tencent.polaris.api.pojo.BaseInstance; +import com.tencent.polaris.plugin.lossless.common.HttpLosslessActionProvider; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -78,12 +79,13 @@ public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable { } // web started, get port from registration - BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, registrationTransformer); + BaseInstance instance = getBaseInstance(registration, registrationTransformer); Runnable registerAction = () -> executeJoinPoint(joinPoint); - - SpringCloudLosslessActionProvider losslessActionProvider = - new SpringCloudLosslessActionProvider(serviceRegistry, registration, losslessProperties, registerAction); + Runnable deregisterAction = () -> serviceRegistry.deregister(registration); + HttpLosslessActionProvider losslessActionProvider = + new HttpLosslessActionProvider(registerAction, deregisterAction, registration.getPort(), + instance, polarisSDKContextManager.getSDKContext().getExtensions()); polarisSDKContextManager.getLosslessAPI().setLosslessActionProvider(instance, losslessActionProvider); polarisSDKContextManager.getLosslessAPI().losslessRegister(instance); @@ -104,4 +106,8 @@ public void executeJoinPoint(ProceedingJoinPoint joinPoint) { throw new RuntimeException(e); } } + + public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { + return registrationTransformer.transform(registration); + } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java deleted file mode 100644 index a97df5960b..0000000000 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/SpringCloudLosslessActionProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - -package com.tencent.cloud.plugin.lossless; - -import java.util.HashMap; -import java.util.Map; - -import com.tencent.cloud.common.util.OkHttpUtil; -import com.tencent.cloud.plugin.lossless.config.LosslessProperties; -import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer; -import com.tencent.polaris.api.plugin.lossless.InstanceProperties; -import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider; -import com.tencent.polaris.api.pojo.BaseInstance; -import com.tencent.polaris.api.utils.StringUtils; - -import org.springframework.cloud.client.serviceregistry.Registration; -import org.springframework.cloud.client.serviceregistry.ServiceRegistry; -import org.springframework.http.HttpHeaders; - -/** - * LosslessActionProvider for Spring Cloud. - * - * @author Shedfree Wu - */ -public class SpringCloudLosslessActionProvider implements LosslessActionProvider { - private ServiceRegistry serviceRegistry; - - private LosslessProperties losslessProperties; - - private Runnable originalRegisterAction; - - private Registration registration; - - public SpringCloudLosslessActionProvider(ServiceRegistry serviceRegistry, Registration registration, - LosslessProperties losslessProperties, Runnable originalRegisterAction) { - this.serviceRegistry = serviceRegistry; - this.registration = registration; - this.losslessProperties = losslessProperties; - this.originalRegisterAction = originalRegisterAction; - } - - @Override - public String getName() { - return "spring-cloud"; - } - - @Override - public void doRegister(InstanceProperties instanceProperties) { - // use lambda to do original register - originalRegisterAction.run(); - } - - @Override - public void doDeregister() { - serviceRegistry.deregister(registration); - } - - /** - * Check whether health check is enable. - * @return true: register after passing doHealthCheck, false: register after delayRegisterInterval. - */ - @Override - public boolean isEnableHealthCheck() { - return StringUtils.isNotBlank(losslessProperties.getHealthCheckPath()); - } - - @Override - public boolean doHealthCheck() { - Map headers = new HashMap<>(1); - headers.put(HttpHeaders.USER_AGENT, "polaris"); - - return OkHttpUtil.checkUrl("localhost", registration.getPort(), - losslessProperties.getHealthCheckPath(), headers); - } - - public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) { - return registrationTransformer.transform(registration); - } - -} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java index f5049df761..56a06c27ff 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessConfigModifier.java @@ -21,8 +21,10 @@ import com.tencent.cloud.common.constant.OrderConstant.Modifier; import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.api.utils.StringUtils; import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.factory.config.provider.LosslessConfigImpl; +import com.tencent.polaris.specification.api.v1.traffic.manage.LosslessProto; /** * Config modifier for lossless. @@ -39,17 +41,27 @@ public LosslessConfigModifier(LosslessProperties losslessProperties) { @Override public void modify(ConfigurationImpl configuration) { + LosslessConfigImpl losslessConfig = (LosslessConfigImpl) configuration.getProvider().getLossless(); if (losslessProperties.isEnabled()) { - LosslessConfigImpl losslessConfig = (LosslessConfigImpl) configuration.getProvider().getLossless(); losslessConfig.setEnable(true); - losslessConfig.setPort(losslessProperties.getPort()); if (Objects.nonNull(losslessProperties.getDelayRegisterInterval())) { losslessConfig.setDelayRegisterInterval(losslessProperties.getDelayRegisterInterval()); } - if (Objects.nonNull(losslessProperties.getHealthCheckInterval())) { - losslessConfig.setHealthCheckInterval(losslessProperties.getHealthCheckInterval()); + if (StringUtils.isNotEmpty(losslessProperties.getHealthCheckPath())) { + losslessConfig.setHealthCheckPath(losslessProperties.getHealthCheckPath()); + losslessConfig.setStrategy(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_HEALTH_CHECK); + + if (Objects.nonNull(losslessProperties.getHealthCheckInterval())) { + losslessConfig.setHealthCheckInterval(losslessProperties.getHealthCheckInterval()); + } + } + else { + losslessConfig.setStrategy(LosslessProto.DelayRegister.DelayStrategy.DELAY_BY_TIME); } } + else { + losslessConfig.setEnable(false); + } } @Override diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java index 3f29608836..288e0bf962 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessProperties.java @@ -23,9 +23,7 @@ @ConfigurationProperties("spring.cloud.polaris.lossless") public class LosslessProperties { - private boolean enabled = true; - - private int port = 28080; + private boolean enabled = false; private String healthCheckPath; @@ -41,14 +39,6 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - public String getHealthCheckPath() { return healthCheckPath; } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java index 5d104704f3..96e3fbee18 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/LosslessPropertiesAutoConfiguration.java @@ -32,7 +32,7 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnPolarisEnabled -@EnableConfigurationProperties(LosslessProperties.class) +@EnableConfigurationProperties({LosslessProperties.class, WarmupProperties.class}) public class LosslessPropertiesAutoConfiguration { @Bean @@ -40,4 +40,10 @@ public class LosslessPropertiesAutoConfiguration { public LosslessConfigModifier losslessConfigModifier(LosslessProperties losslessProperties) { return new LosslessConfigModifier(losslessProperties); } + + @Bean + @ConditionalOnMissingBean + public WarmupConfigModifier warmupConfigModifier(WarmupProperties warmupProperties) { + return new WarmupConfigModifier(warmupProperties); + } } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java new file mode 100644 index 0000000000..4547ffd0e7 --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupConfigModifier.java @@ -0,0 +1,66 @@ +/* + * 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.plugin.lossless.config; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; + +import com.tencent.cloud.common.constant.OrderConstant.Modifier; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.consumer.WeightAdjustConfigImpl; +import com.tencent.polaris.plugin.lossless.warmup.WarmupWeightAdjuster; + +/** + * Config modifier for warmup. + * + * @author Shedfree Wu + */ +public class WarmupConfigModifier implements PolarisConfigModifier { + + private final WarmupProperties warmupProperties; + + public WarmupConfigModifier(WarmupProperties warmupProperties) { + this.warmupProperties = warmupProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + WeightAdjustConfigImpl weightAdjustConfig = (WeightAdjustConfigImpl) configuration.getConsumer().getWeightAdjust(); + if (warmupProperties.isEnabled()) { + Set chainSet = new TreeSet<>( + Optional.ofNullable(weightAdjustConfig.getChain()).orElse(Collections.emptyList())); + chainSet.add(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME); + weightAdjustConfig.setChain(new ArrayList<>(chainSet)); + } + else { + Set chainSet = new TreeSet<>( + Optional.ofNullable(weightAdjustConfig.getChain()).orElse(Collections.emptyList())); + chainSet.remove(WarmupWeightAdjuster.WARMUP_WEIGHT_ADJUSTER_NAME); + weightAdjustConfig.setChain(new ArrayList<>(chainSet)); + } + } + + @Override + public int getOrder() { + return Modifier.LOSSLESS_ORDER; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java new file mode 100644 index 0000000000..1b8d8d4f9e --- /dev/null +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/java/com/tencent/cloud/plugin/lossless/config/WarmupProperties.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.plugin.lossless.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("spring.cloud.polaris.warmup") +public class WarmupProperties { + + private boolean enabled = false; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 48a31c1cd7..c4e339832c 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-lossless-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -3,7 +3,7 @@ { "name": "spring.cloud.polaris.lossless.enabled", "type": "java.lang.Boolean", - "defaultValue": true, + "defaultValue": false, "description": "the switch for lossless plugin." } ] diff --git a/spring-cloud-tencent-polaris-context/pom.xml b/spring-cloud-tencent-polaris-context/pom.xml index 972fe0046f..82e881630d 100644 --- a/spring-cloud-tencent-polaris-context/pom.xml +++ b/spring-cloud-tencent-polaris-context/pom.xml @@ -34,6 +34,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata @@ -108,6 +112,10 @@ com.tencent.polaris router-nearby + + com.tencent.polaris + router-namespace + com.tencent.polaris router-metadata @@ -177,7 +185,16 @@ com.tencent.polaris polaris-router-factory - + + + com.tencent.polaris + polaris-circuitbreaker-factory + + + + com.tencent.polaris + polaris-ratelimit-factory + com.tencent.polaris @@ -193,6 +210,11 @@ com.tencent.polaris polaris-assembly-factory + + + com.tencent.polaris + event-tsf + diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java index 68e9f2c4c8..bb830b80d4 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.context; +import java.util.ArrayList; import java.util.List; import com.tencent.cloud.common.constant.OrderConstant; @@ -26,6 +27,8 @@ import com.tencent.polaris.factory.config.ConfigurationImpl; import org.apache.commons.lang.StringUtils; +import org.springframework.util.CollectionUtils; + /** * Modify polaris server address. * @@ -48,6 +51,13 @@ public void modify(ConfigurationImpl configuration) { List addresses = AddressUtils.parseAddressList(properties.getAddress()); configuration.getGlobal().getServerConnector().setAddresses(addresses); + if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) { + configuration.getGlobal().setServerConnectors(new ArrayList<>()); + } + if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors()) + && null != configuration.getGlobal().getServerConnector()) { + configuration.getGlobal().getServerConnectors().add(configuration.getGlobal().getServerConnector()); + } } @Override diff --git a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java similarity index 80% rename from spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java rename to spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java index 22830fa811..f627d46eda 100644 --- a/spring-cloud-starter-tencent-polaris-contract/src/main/java/com/tencent/cloud/polaris/contract/config/ExtendedContractProperties.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisConfigurationConfigModifier.java @@ -15,12 +15,12 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.contract.config; +package com.tencent.cloud.polaris.context; /** - * Extend contract properties. + * Config modifier interface for Polaris configuration. * * @author Haotian Zhang */ -public interface ExtendedContractProperties extends ContractProperties { +public interface PolarisConfigurationConfigModifier extends PolarisConfigModifier { } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java index 143b6fbb7a..8138aeb5c2 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PolarisSDKContextManager.java @@ -17,14 +17,17 @@ package com.tencent.cloud.polaris.context; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.config.Configuration; import com.tencent.polaris.api.control.Destroyable; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.LosslessAPI; import com.tencent.polaris.api.core.ProviderAPI; +import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.assembly.api.AssemblyAPI; import com.tencent.polaris.assembly.factory.AssemblyAPIFactory; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; @@ -53,7 +56,8 @@ public class PolarisSDKContextManager { * Constant for checking before destroy SDK context. */ public volatile static boolean isRegistered = false; - private volatile static SDKContext sdkContext; + private volatile static SDKContext configSDKContext; + private volatile static SDKContext serviceSdkContext; private volatile static ProviderAPI providerAPI; private volatile static ConsumerAPI consumerAPI; private volatile static LosslessAPI losslessAPI; @@ -75,7 +79,7 @@ public PolarisSDKContextManager(PolarisContextProperties properties, Environment * Don't call this method directly. */ public static void innerDestroy() { - if (Objects.nonNull(sdkContext)) { + if (Objects.nonNull(serviceSdkContext)) { try { // destroy ProviderAPI if (Objects.nonNull(providerAPI)) { @@ -119,9 +123,9 @@ public static void innerDestroy() { assemblyAPI = null; } - if (Objects.nonNull(sdkContext)) { - sdkContext.destroy(); - sdkContext = null; + if (Objects.nonNull(serviceSdkContext)) { + serviceSdkContext.destroy(); + serviceSdkContext = null; } LOG.info("Polaris SDK context is destroyed."); } @@ -131,35 +135,129 @@ public static void innerDestroy() { } } + /** + * Used for config data. + * @return configSDKContext + */ + public static SDKContext innerGetConfigSDKContext() { + if (configSDKContext == null) { + throw new IllegalArgumentException("configSDKContext is not initialized."); + } + return configSDKContext; + } + + public static void innerConfigDestroy() { + try { + if (Objects.nonNull(configSDKContext)) { + configSDKContext.destroy(); + configSDKContext = null; + } + LOG.info("Polaris SDK config context is destroyed."); + } + catch (Throwable throwable) { + LOG.info("Polaris SDK config context is destroyed failed.", throwable); + } + } + public void init() { - if (null == sdkContext) { + initService(); + initConfig(); + } + + public SDKContext getSDKContext() { + initService(); + return serviceSdkContext; + } + + public ProviderAPI getProviderAPI() { + initService(); + return providerAPI; + } + + public LosslessAPI getLosslessAPI() { + initService(); + return losslessAPI; + } + + public ConsumerAPI getConsumerAPI() { + initService(); + return consumerAPI; + } + + public RouterAPI getRouterAPI() { + initService(); + return routerAPI; + } + + public CircuitBreakAPI getCircuitBreakAPI() { + initService(); + return circuitBreakAPI; + } + + public LimitAPI getLimitAPI() { + initService(); + return limitAPI; + } + + public AssemblyAPI getAssemblyAPI() { + return assemblyAPI; + } + + public SDKContext getConfigSDKContext() { + initConfig(); + return configSDKContext; + } + + /** + * Used for config data. + * @param context sdk context + */ + public static void setConfigSDKContext(SDKContext context) { + if (configSDKContext == null) { + configSDKContext = context; + // add shutdown hook + Runtime.getRuntime().addShutdownHook(new Thread(PolarisSDKContextManager::innerConfigDestroy)); + LOG.info("create Polaris config SDK context successfully."); + } + } + + public void initService() { + if (null == serviceSdkContext) { try { + // get modifiers for service. + List serviceModifierList = new ArrayList<>(); + for (PolarisConfigModifier modifier : modifierList) { + if (!(modifier instanceof PolarisConfigurationConfigModifier)) { + serviceModifierList.add(modifier); + } + } // init SDKContext - sdkContext = SDKContext.initContextByConfig(properties.configuration(modifierList, + Configuration configuration = properties.configuration(serviceModifierList, () -> environment.getProperty("spring.cloud.client.ip-address"), - () -> environment.getProperty("spring.cloud.polaris.local-port", Integer.class, 0))); - sdkContext.init(); + () -> environment.getProperty("spring.cloud.polaris.local-port", Integer.class, 0)); + serviceSdkContext = SDKContext.initContextByConfig(configuration); + serviceSdkContext.init(); // init ProviderAPI - providerAPI = DiscoveryAPIFactory.createProviderAPIByContext(sdkContext); + providerAPI = DiscoveryAPIFactory.createProviderAPIByContext(serviceSdkContext); // init losslessAPI - losslessAPI = DiscoveryAPIFactory.createLosslessAPIByContext(sdkContext); + losslessAPI = DiscoveryAPIFactory.createLosslessAPIByContext(serviceSdkContext); // init ConsumerAPI - consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(sdkContext); + consumerAPI = DiscoveryAPIFactory.createConsumerAPIByContext(serviceSdkContext); // init RouterAPI - routerAPI = RouterAPIFactory.createRouterAPIByContext(sdkContext); + routerAPI = RouterAPIFactory.createRouterAPIByContext(serviceSdkContext); // init CircuitBreakAPI - circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByContext(sdkContext); + circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPIByContext(serviceSdkContext); // init LimitAPI - limitAPI = LimitAPIFactory.createLimitAPIByContext(sdkContext); + limitAPI = LimitAPIFactory.createLimitAPIByContext(serviceSdkContext); // init AssemblyAPI - assemblyAPI = AssemblyAPIFactory.createAssemblyAPIByContext(sdkContext); + assemblyAPI = AssemblyAPIFactory.createAssemblyAPIByContext(serviceSdkContext); // add shutdown hook Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -175,51 +273,40 @@ public void init() { } } })); - LOG.info("create Polaris SDK context successfully. properties: {}", properties); + LOG.info("create Polaris SDK context successfully. properties: {}, configuration: {}", properties, configuration); } catch (Throwable throwable) { - LOG.error("create Polaris SDK context failed. properties: {}", properties, throwable); + LOG.error("create Polaris SDK context failed. properties: {}, ", properties, throwable); throw throwable; } } } - public SDKContext getSDKContext() { - init(); - return sdkContext; - } - - public ProviderAPI getProviderAPI() { - init(); - return providerAPI; - } - - public LosslessAPI getLosslessAPI() { - init(); - return losslessAPI; - } - - public ConsumerAPI getConsumerAPI() { - init(); - return consumerAPI; - } - - public RouterAPI getRouterAPI() { - init(); - return routerAPI; - } - - public CircuitBreakAPI getCircuitBreakAPI() { - init(); - return circuitBreakAPI; - } - - public LimitAPI getLimitAPI() { - init(); - return limitAPI; - } + public void initConfig() { + // get modifiers for configuration. + List configModifierList = new ArrayList<>(); + for (PolarisConfigModifier modifier : modifierList) { + if (modifier instanceof PolarisConfigurationConfigModifier) { + configModifierList.add(modifier); + } + } + if (null == configSDKContext && CollectionUtils.isNotEmpty(configModifierList)) { + try { + // init config SDKContext + Configuration configuration = properties.configuration(configModifierList, + () -> environment.getProperty("spring.cloud.client.ip-address"), + () -> environment.getProperty("spring.cloud.polaris.local-port", Integer.class, 0)); + configSDKContext = SDKContext.initContextByConfig(configuration); + configSDKContext.init(); - public AssemblyAPI getAssemblyAPI() { - return assemblyAPI; + // add shutdown hook + Runtime.getRuntime().addShutdownHook(new Thread(PolarisSDKContextManager::innerConfigDestroy)); + LOG.info("create Polaris config SDK context successfully. properties: {}, configuration: {}", properties, configuration); + } + catch (Throwable throwable) { + LOG.error("create Polaris config SDK context failed. properties: {}, ", properties, throwable); + throw throwable; + } + } } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java index bf41c50bd5..132d9e618c 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContext.java @@ -20,8 +20,8 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.polaris.api.plugin.common.ValueContext; -import com.tencent.polaris.api.plugin.route.LocationLevel; import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import org.apache.commons.lang.StringUtils; /** @@ -39,13 +39,13 @@ public PostInitPolarisSDKContext(SDKContext sdkContext, StaticMetadataManager st ValueContext valueContext = sdkContext.getValueContext(); if (StringUtils.isNotBlank(region)) { - valueContext.setValue(LocationLevel.region.name(), region); + valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.REGION.name(), region); } if (StringUtils.isNotBlank(zone)) { - valueContext.setValue(LocationLevel.zone.name(), zone); + valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.ZONE.name(), zone); } if (StringUtils.isNotBlank(campus)) { - valueContext.setValue(LocationLevel.campus.name(), campus); + valueContext.setValue(RoutingProto.NearbyRoutingConfig.LocationLevel.CAMPUS.name(), campus); } } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java new file mode 100644 index 0000000000..6929db5c5a --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminConfigModifier.java @@ -0,0 +1,47 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.admin; + +import com.tencent.cloud.common.constant.OrderConstant.Modifier; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; + +/** + * Config modifier for admin. + * + * @author Haotian Zhang + */ +public class PolarisAdminConfigModifier implements PolarisConfigModifier { + + private final PolarisAdminProperties polarisAdminProperties; + + public PolarisAdminConfigModifier(PolarisAdminProperties polarisAdminProperties) { + this.polarisAdminProperties = polarisAdminProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + configuration.getGlobal().getAdmin().setHost(this.polarisAdminProperties.getHost()); + configuration.getGlobal().getAdmin().setPort(this.polarisAdminProperties.getPort()); + } + + @Override + public int getOrder() { + return Modifier.ADMIN_ORDER; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.java new file mode 100644 index 0000000000..6d7c5f58d0 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/admin/PolarisAdminProperties.java @@ -0,0 +1,63 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.admin; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties for Polaris Admin. + * + * @author Haotian Zhang + */ +@ConfigurationProperties(prefix = "spring.cloud.polaris.admin") +public class PolarisAdminProperties { + + /** + * Admin host. + */ + private String host = "0.0.0.0"; + + /** + * Admin port. + */ + private int port = 28080; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + @Override + public String toString() { + return "PolarisAdminProperties{" + + "host='" + host + '\'' + + ", port=" + port + + '}'; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java index 080b0bf4fa..30ef485f04 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java @@ -25,6 +25,11 @@ import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.context.admin.PolarisAdminConfigModifier; +import com.tencent.cloud.polaris.context.admin.PolarisAdminProperties; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties; +import com.tencent.cloud.polaris.context.config.extend.tsf.TsfInstanceMetadataProvider; import com.tencent.cloud.polaris.context.listener.PolarisContextApplicationEventListener; import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.client.api.SDKContext; @@ -64,4 +69,34 @@ public ServiceRuleManager serviceRuleManager(PolarisSDKContextManager polarisSDK public PolarisContextApplicationEventListener contextApplicationEventListener(PolarisSDKContextManager polarisSDKContextManager) { return new PolarisContextApplicationEventListener(polarisSDKContextManager); } + + @Bean + @ConditionalOnMissingBean + public PolarisAdminProperties polarisAdminProperties() { + return new PolarisAdminProperties(); + } + + @Bean + @ConditionalOnMissingBean + public PolarisAdminConfigModifier polarisAdminConfigModifier(PolarisAdminProperties polarisAdminProperties) { + return new PolarisAdminConfigModifier(polarisAdminProperties); + } + + @Bean + @ConditionalOnMissingBean + public ConsulProperties consulProperties() { + return new ConsulProperties(); + } + + @Bean + @ConditionalOnMissingBean + public TsfCoreProperties tsfCoreProperties() { + return new TsfCoreProperties(); + } + + @Bean + @ConditionalOnMissingBean + public TsfInstanceMetadataProvider tsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) { + return new TsfInstanceMetadataProvider(tsfCoreProperties); + } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java new file mode 100644 index 0000000000..dfe1661130 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextEnvironmentPostProcessor.java @@ -0,0 +1,105 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +/** + * Read Polaris env. + * + * @author Haotian Zhang + */ +public final class PolarisContextEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { + /** + * order before TsfCoreEnvironmentPostProcessor. + */ + public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 8; + + private final Logger LOGGER = LoggerFactory.getLogger(PolarisContextEnvironmentPostProcessor.class); + + private PolarisContextEnvironmentPostProcessor() { + + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + Map polarisEnvProperties = new HashMap<>(); + + // polaris_address + String polarisAddress = environment.getProperty("polaris_address"); + if (StringUtils.isNotBlank(polarisAddress)) { + polarisEnvProperties.put("spring.cloud.polaris.address", polarisAddress); + } + + // polaris_address + String polarisNamespace = environment.getProperty("polaris_namespace"); + if (StringUtils.isNotBlank(polarisNamespace)) { + polarisEnvProperties.put("spring.cloud.polaris.namespace", polarisNamespace); + } + + // polaris_config_address + String polarisConfigAddress = environment.getProperty("polaris_config_address"); + if (StringUtils.isNotBlank(polarisConfigAddress)) { + polarisEnvProperties.put("spring.cloud.polaris.config.address", polarisConfigAddress); + } + + // polaris_admin_port + String polarisAdminPort = environment.getProperty("polaris_admin_port"); + if (StringUtils.isNotBlank(polarisAdminPort)) { + polarisEnvProperties.put("spring.cloud.polaris.admin.port", polarisAdminPort); + } + + // application_version + String applicationVersion = environment.getProperty("tsf_prog_version"); + if (StringUtils.isNotBlank(applicationVersion)) { + polarisEnvProperties.put("spring.cloud.polaris.discovery.version", applicationVersion); + } + + // region + String region = environment.getProperty("tsf_region"); + if (StringUtils.isNotBlank(region)) { + polarisEnvProperties.put("spring.cloud.tencent.metadata.content.region", region); + } + + // zone + String zone = environment.getProperty("tsf_zone"); + if (StringUtils.isNotBlank(zone)) { + polarisEnvProperties.put("spring.cloud.tencent.metadata.content.zone", zone); + } + + LOGGER.debug("polaris-env-properties:{}", polarisEnvProperties); + MapPropertySource propertySource = new MapPropertySource("polaris-env-properties", polarisEnvProperties); + environment.getPropertySources().addFirst(propertySource); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java index 498af60d13..f92d065fbe 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java @@ -65,7 +65,7 @@ public class PolarisContextProperties { * If polaris enabled. */ @Value("${spring.cloud.polaris.enabled:#{'true'}}") - private Boolean enabled; + private Boolean enabled = true; /** * polaris namespace. @@ -76,6 +76,7 @@ public class PolarisContextProperties { /** * polaris service name. */ + @Value("${spring.cloud.polaris.service:${spring.application.name:}}") private String service; public Configuration configuration(List modifierList, Supplier ipAddressSupplier, Supplier portSupplier) { diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java new file mode 100644 index 0000000000..f5fba11380 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulProperties.java @@ -0,0 +1,106 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.consul; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.validation.annotation.Validated; + +/** + * Copy from org.springframework.cloud.consul.ConsulProperties. + * + * @author Spencer Gibb + */ +@ConfigurationProperties(ConsulProperties.PREFIX) +@Validated +public class ConsulProperties { + + /** + * Prefix for configuration properties. + */ + public static final String PREFIX = "spring.cloud.consul"; + + /** Consul agent hostname. Defaults to 'localhost'. */ + private String host = "localhost"; + + /** + * Consul agent scheme (HTTP/HTTPS). If there is no scheme in address - client + * will use HTTP. + */ + private String scheme; + + /** Consul agent port. Defaults to '8500'. */ + private int port = 8500; + + /** Is spring cloud consul enabled. */ + private boolean enabled = false; + + @Value("${consul.token:${CONSUL_TOKEN:${spring.cloud.consul.token:${SPRING_CLOUD_CONSUL_TOKEN:}}}}") + private String aclToken; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getScheme() { + return scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getAclToken() { + return aclToken; + } + + public void setAclToken(String aclToken) { + this.aclToken = aclToken; + } + + @Override + public String toString() { + return "ConsulProperties{" + + "host='" + host + '\'' + + ", scheme='" + scheme + '\'' + + ", port=" + port + + ", enabled=" + enabled + + ", aclToken='" + aclToken + '\'' + + '}'; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.java new file mode 100644 index 0000000000..9cfbf98929 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextAutoConfiguration.java @@ -0,0 +1,44 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; +import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * TSF context auto configuration. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter(PolarisContextAutoConfiguration.class) +@ConditionalOnTsfConsulEnabled +public class TsfContextAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public TsfContextConfigModifier tsfConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties) { + return new TsfContextConfigModifier(tsfCoreProperties, consulProperties); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java new file mode 100644 index 0000000000..2c452f00e4 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextBootstrapConfiguration.java @@ -0,0 +1,32 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * TSF context bootstrap configuration. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@Import(TsfContextAutoConfiguration.class) +public class TsfContextBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java new file mode 100644 index 0000000000..18c55bcb70 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextConfigModifier.java @@ -0,0 +1,65 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import com.tencent.cloud.common.constant.OrderConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.extend.consul.ConsulProperties; +import com.tencent.polaris.api.config.plugin.DefaultPlugins; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.event.tsf.TsfEventReporterConfig; + +/** + * Config modifier for TSF. + * + * @author Haotian Zhang + */ +public class TsfContextConfigModifier implements PolarisConfigModifier { + + private final TsfCoreProperties tsfCoreProperties; + + private final ConsulProperties consulProperties; + + public TsfContextConfigModifier(TsfCoreProperties tsfCoreProperties, ConsulProperties consulProperties) { + this.tsfCoreProperties = tsfCoreProperties; + this.consulProperties = consulProperties; + } + + @Override + public void modify(ConfigurationImpl configuration) { + configuration.getGlobal().getEventReporter().getReporters().add(DefaultPlugins.TSF_EVENT_REPORTER_TYPE); + + TsfEventReporterConfig tsfEventReporterConfig = new TsfEventReporterConfig(); + tsfEventReporterConfig.setEventMasterIp(tsfCoreProperties.getEventMasterIp()); + tsfEventReporterConfig.setEventMasterPort(tsfCoreProperties.getEventMasterPort()); + tsfEventReporterConfig.setAppId(tsfCoreProperties.getAppId()); + tsfEventReporterConfig.setRegion(tsfCoreProperties.getTsfRegion()); + tsfEventReporterConfig.setInstanceId(tsfCoreProperties.getInstanceId()); + tsfEventReporterConfig.setTsfNamespaceId(tsfCoreProperties.getTsfNamespaceId()); + tsfEventReporterConfig.setServiceName(tsfCoreProperties.getServiceName()); + tsfEventReporterConfig.setToken(consulProperties.getAclToken()); + tsfEventReporterConfig.setApplicationId(tsfCoreProperties.getTsfApplicationId()); + configuration.getGlobal().getEventReporter() + .setPluginConfig(DefaultPlugins.TSF_EVENT_REPORTER_TYPE, tsfEventReporterConfig); + } + + @Override + public int getOrder() { + return OrderConstant.Modifier.CIRCUIT_BREAKER_ORDER - 1; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.java new file mode 100644 index 0000000000..b940cfd747 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfContextUtils.java @@ -0,0 +1,58 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import java.util.concurrent.atomic.AtomicBoolean; + +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.core.env.Environment; + +/** + * Utils for TSF. + * + * @author Haotian Zhang + */ +public final class TsfContextUtils { + + private static final Logger LOG = LoggerFactory.getLogger(TsfContextUtils.class); + + private static final AtomicBoolean isFirstConfiguration = new AtomicBoolean(true); + + private static boolean tsfConsulEnabled = false; + + private TsfContextUtils() { + } + + public static boolean isTsfConsulEnabled(Environment environment) { + if (environment != null && isFirstConfiguration.compareAndSet(true, false)) { + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + String tsePolarisAddress = environment.getProperty("polaris_address"); + if (StringUtils.isBlank(tsePolarisAddress) && StringUtils.isNotBlank(environment.getProperty("spring.cloud.polaris.address"))) { + tsePolarisAddress = environment.getProperty("spring.cloud.polaris.address"); + } + tsfConsulEnabled = StringUtils.isNotBlank(tsfConsulIp) && StringUtils.isBlank(tsePolarisAddress); + if (tsfConsulEnabled) { + LOG.info("Tsf Consul is enabled: {}", tsfConsulIp); + } + } + return tsfConsulEnabled; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java new file mode 100644 index 0000000000..558a9e31ea --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreEnvironmentPostProcessor.java @@ -0,0 +1,160 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.polaris.api.utils.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; + +/** + * Read TSF env. + * + * @author Haotian Zhang + */ +public final class TsfCoreEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { + /** + * order after PolarisContextEnvironmentPostProcessor. + */ + public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 9; + + private final Logger LOGGER = LoggerFactory.getLogger(TsfCoreEnvironmentPostProcessor.class); + + private TsfCoreEnvironmentPostProcessor() { + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + String tsfAppId = environment.getProperty("tsf_app_id"); + // TSF deploy + if (StringUtils.isNotBlank(tsfAppId)) { + Map defaultProperties = new HashMap<>(); + + // lossless + String polarisAdminPort = environment.getProperty("polaris_admin_port"); + if (StringUtils.isNotBlank(polarisAdminPort)) { + defaultProperties.put("spring.cloud.polaris.lossless.enabled", true); + } + + if (TsfContextUtils.isTsfConsulEnabled(environment)) { + // tsf_consul_ip + String tsfConsulIp = environment.getProperty("tsf_consul_ip"); + if (StringUtils.isBlank(tsfConsulIp)) { + LOGGER.error("tsf_consul_ip is empty"); + } + // tsf_consul_port + String tsfConsulPort = environment.getProperty("tsf_consul_port"); + if (StringUtils.isBlank(tsfConsulPort)) { + LOGGER.error("tsf_consul_port is empty"); + } + // tsf_token + String tsfConsulToken = environment.getProperty("tsf_token"); + if (StringUtils.isBlank(tsfConsulToken)) { + LOGGER.error("tsf_token is empty"); + } + // tsf_instance_id + String tsfInstanceId = environment.getProperty("tsf_instance_id"); + if (StringUtils.isBlank(tsfInstanceId)) { + LOGGER.error("tsf_instance_id is empty"); + } + // tsf_application_id + String tsfApplicationId = environment.getProperty("tsf_application_id"); + if (StringUtils.isBlank(tsfApplicationId)) { + LOGGER.error("tsf_application_id is empty"); + } + + // tsf_group_id + String tsfGroupId = environment.getProperty("tsf_group_id"); + if (StringUtils.isBlank(tsfGroupId)) { + LOGGER.error("tsf_group_id is empty"); + } + + // tsf_namespace_id + String tsfNamespaceId = environment.getProperty("tsf_namespace_id"); + if (StringUtils.isBlank(tsfNamespaceId)) { + LOGGER.error("tsf_namespace_id is empty"); + } + + // context + defaultProperties.put("spring.cloud.polaris.enabled", "true"); + defaultProperties.put("spring.cloud.polaris.discovery.enabled", "false"); + defaultProperties.put("spring.cloud.polaris.discovery.register", "false"); + defaultProperties.put("spring.cloud.consul.enabled", "true"); + defaultProperties.put("spring.cloud.consul.host", tsfConsulIp); + defaultProperties.put("spring.cloud.consul.port", tsfConsulPort); + defaultProperties.put("spring.cloud.consul.token", tsfConsulToken); + + // discovery + defaultProperties.put("spring.cloud.consul.discovery.enabled", "true"); + defaultProperties.put("spring.cloud.consul.discovery.register", "true"); + defaultProperties.put("spring.cloud.consul.discovery.instance-id", tsfInstanceId); + defaultProperties.put("spring.cloud.polaris.discovery.instance-id", tsfInstanceId); + defaultProperties.put("spring.cloud.polaris.discovery.zero-protection.enabled", "true"); + defaultProperties.put("spring.cloud.polaris.discovery.zero-protection.is-need-test-connectivity", "true"); + defaultProperties.put("spring.cloud.discovery.client.health-indicator.enabled", "false"); + + // contract + defaultProperties.put("spring.cloud.polaris.contract.enabled", environment.getProperty("tsf.swagger.enabled", "true")); + if (StringUtils.isNotBlank(environment.getProperty("tsf.swagger.basePackage"))) { + defaultProperties.put("spring.cloud.polaris.contract.base-package", environment.getProperty("tsf.swagger.basePackage")); + } + if (StringUtils.isNotBlank(environment.getProperty("tsf.swagger.excludePath"))) { + defaultProperties.put("spring.cloud.polaris.contract.exclude-path", environment.getProperty("tsf.swagger.excludePath")); + } + defaultProperties.put("spring.cloud.polaris.contract.group", environment.getProperty("tsf.swagger.group", "polaris")); + defaultProperties.put("spring.cloud.polaris.contract.base-path", environment.getProperty("tsf.swagger.basePath", "/**")); + defaultProperties.put("spring.cloud.polaris.contract.exposure", environment.getProperty("tsf.swagger.doc.auto-startup", "true")); + defaultProperties.put("spring.cloud.polaris.contract.report.enabled", environment.getProperty("tsf.swagger.enabled", "true")); + defaultProperties.put("spring.cloud.polaris.contract.name", tsfApplicationId); + + // configuration + defaultProperties.put("spring.cloud.polaris.config.enabled", "true"); + defaultProperties.put("spring.cloud.polaris.config.internal-enabled", "false"); + defaultProperties.put("spring.cloud.polaris.config.data-source", "consul"); + defaultProperties.put("spring.cloud.polaris.config.address", "http://" + tsfConsulIp + ":" + tsfConsulPort); + defaultProperties.put("spring.cloud.polaris.config.port", tsfConsulPort); + defaultProperties.put("spring.cloud.polaris.config.token", tsfConsulToken); + defaultProperties.put("spring.cloud.polaris.config.groups[0].namespace", "config"); + defaultProperties.put("spring.cloud.polaris.config.groups[0].name", "application"); + defaultProperties.put("spring.cloud.polaris.config.groups[0].files[0]", tsfApplicationId + "/" + tsfGroupId + "/"); + defaultProperties.put("spring.cloud.polaris.config.groups[0].files[1]", tsfNamespaceId + "/"); + defaultProperties.put("spring.cloud.polaris.config.refresh-type", "refresh_context"); + + // router + defaultProperties.put("spring.cloud.polaris.router.rule-router.fail-over", "none"); + defaultProperties.put("spring.cloud.polaris.router.namespace-router.enabled", "true"); + } + + MapPropertySource propertySource = new MapPropertySource("tsf-polaris-properties", defaultProperties); + environment.getPropertySources().addFirst(propertySource); + } + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java new file mode 100644 index 0000000000..39c29baaf4 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfCoreProperties.java @@ -0,0 +1,318 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Core properties. + * + * @author Haotian Zhang + */ +@ConfigurationProperties("tsf") +public class TsfCoreProperties { + + @Value("${tsf_app_id:}") + private String appId; + + /** + * Unique service instance id. + */ + @Value("${tsf_instance_id:${spring.cloud.consul.discovery.instanceId:${SPRING_CLOUD_CONSUL_DISCOVERY_INSTANCEID:}}}") + private String instanceId; + + /** + * tsf service consul registration tags. + *

+ * applicationId 应用Id + */ + @Value("${tsf_application_id:}") + private String tsfApplicationId; + + /** + * tsf service consul registration tags. + *

+ * groupId 部署组Id + */ + @Value("${tsf_group_id:}") + private String tsfGroupId; + + /** + * tsf service consul registration tags. + * + * progVersion 包版本 + */ + @Value("${tsf_prog_version:}") + private String tsfProgVersion; + + /** + * 仅本地测试时使用. + */ + @Value("${tsf_namespace_id:}") + private String tsfNamespaceId; + + @Value("${spring.application.name:}") + private String serviceName; + + /** + * tsf service consul registration tags. + * + * 地域信息 + */ + @Value("${tsf_region:}") + private String tsfRegion; + + /** + * tsf service consul registration tags. + * + * 可用区信息 + */ + @Value("${tsf_zone:}") + private String tsfZone; + + /** + * Tags to use when registering service. + */ + @Value("${tsf.discovery.tags:}") + private List tags = new ArrayList<>(); + + /** + * Service instance zone. + */ + @Value("${tsf.discovery.instanceZone:}") + private String instanceZone; + + /** + * Service instance group. + */ + @Value("${tsf.discovery.instanceGroup:}") + private String instanceGroup; + + /** + * Service instance zone comes from metadata. + * This allows changing the metadata tag name. + */ + @Value("${tsf.discovery.defaultZoneMetadataName:zone}") + private String defaultZoneMetadataName = "zone"; + + /** + * Whether to register an http or https service. + */ + @Value("${tsf.discovery.scheme:http}") + private String scheme = "http"; + + @Value("${tsf_event_master_ip:}") + private String eventMasterIp; + + @Value("${tsf_event_master_port:15200}") + private Integer eventMasterPort; + + @Value("${tsf_ratelimit_master_ip:}") + private String ratelimitMasterIp; + + @Value("${tsf_ratelimit_master_port:7000}") + private Integer ratelimitMasterPort; + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getTsfApplicationId() { + return tsfApplicationId; + } + + public void setTsfApplicationId(final String tsfApplicationId) { + this.tsfApplicationId = tsfApplicationId; + } + + public String getTsfGroupId() { + return tsfGroupId; + } + + public void setTsfGroupId(final String tsfGroupId) { + this.tsfGroupId = tsfGroupId; + } + + public String getTsfProgVersion() { + return tsfProgVersion; + } + + public void setTsfProgVersion(final String tsfProgVersion) { + this.tsfProgVersion = tsfProgVersion; + } + + public String getTsfNamespaceId() { + return tsfNamespaceId; + } + + public void setTsfNamespaceId(String tsfNamespaceId) { + this.tsfNamespaceId = tsfNamespaceId; + } + + public String getServiceName() { + return serviceName; + } + + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + public String getTsfRegion() { + return tsfRegion; + } + + public void setTsfRegion(String tsfRegion) { + this.tsfRegion = tsfRegion; + } + + public String getTsfZone() { + return tsfZone; + } + + public void setTsfZone(String tsfZone) { + this.tsfZone = tsfZone; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public List getTsfTags() { + List tags = new LinkedList<>(getTags()); + if (StringUtils.isNotBlank(getInstanceZone())) { + tags.add(getDefaultZoneMetadataName() + "=" + getInstanceZone()); + } + if (StringUtils.isNotBlank(getInstanceGroup())) { + tags.add("group=" + getInstanceGroup()); + } + //store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically + tags.add("secure=" + getScheme().equalsIgnoreCase("https")); + return tags; + } + + public String getInstanceZone() { + return instanceZone; + } + + public void setInstanceZone(String instanceZone) { + this.instanceZone = instanceZone; + } + + public String getInstanceGroup() { + return instanceGroup; + } + + public void setInstanceGroup(String instanceGroup) { + this.instanceGroup = instanceGroup; + } + + public String getDefaultZoneMetadataName() { + return defaultZoneMetadataName; + } + + public void setDefaultZoneMetadataName(String defaultZoneMetadataName) { + this.defaultZoneMetadataName = defaultZoneMetadataName; + } + + public String getScheme() { + return scheme; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getEventMasterIp() { + return eventMasterIp; + } + + public void setEventMasterIp(String eventMasterIp) { + this.eventMasterIp = eventMasterIp; + } + + public Integer getEventMasterPort() { + return eventMasterPort; + } + + public void setEventMasterPort(Integer eventMasterPort) { + this.eventMasterPort = eventMasterPort; + } + + public String getRatelimitMasterIp() { + return ratelimitMasterIp; + } + + public void setRatelimitMasterIp(String ratelimitMasterIp) { + this.ratelimitMasterIp = ratelimitMasterIp; + } + + public Integer getRatelimitMasterPort() { + return ratelimitMasterPort; + } + + public void setRatelimitMasterPort(Integer ratelimitMasterPort) { + this.ratelimitMasterPort = ratelimitMasterPort; + } + + @Override + public String toString() { + return "TsfCoreProperties{" + + "appId='" + appId + '\'' + + ", instanceId='" + instanceId + '\'' + + ", tsfApplicationId='" + tsfApplicationId + '\'' + + ", tsfGroupId='" + tsfGroupId + '\'' + + ", tsfProgVersion='" + tsfProgVersion + '\'' + + ", tsfNamespaceId='" + tsfNamespaceId + '\'' + + ", serviceName='" + serviceName + '\'' + + ", tsfRegion='" + tsfRegion + '\'' + + ", tsfZone='" + tsfZone + '\'' + + ", tags=" + tags + + ", instanceZone='" + instanceZone + '\'' + + ", instanceGroup='" + instanceGroup + '\'' + + ", defaultZoneMetadataName='" + defaultZoneMetadataName + '\'' + + ", scheme='" + scheme + '\'' + + ", eventMasterIp='" + eventMasterIp + '\'' + + ", eventMasterPort=" + eventMasterPort + + ", ratelimitMasterIp='" + ratelimitMasterIp + '\'' + + ", ratelimitMasterPort=" + ratelimitMasterPort + + '}'; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java new file mode 100644 index 0000000000..e30ade6a14 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/extend/tsf/TsfInstanceMetadataProvider.java @@ -0,0 +1,89 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.tsf; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.constant.SdkVersion; +import com.tencent.cloud.common.constant.WarmupCons; +import com.tencent.cloud.common.spi.InstanceMetadataProvider; +import com.tencent.cloud.common.util.JacksonUtils; +import com.tencent.cloud.common.util.inet.PolarisInetUtils; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants; + + +/** + * InstanceMetadataProvider for TSF. + * + * @author Hoatian Zhang + */ +public class TsfInstanceMetadataProvider implements InstanceMetadataProvider { + + private final TsfCoreProperties tsfCoreProperties; + + public TsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) { + this.tsfCoreProperties = tsfCoreProperties; + } + + @Override + public Map getMetadata() { + HashMap tsfMetadata = new HashMap<>(); + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfApplicationId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfProgVersion())) { + tsfMetadata.put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfGroupId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfNamespaceId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getInstanceId())) { + tsfMetadata.put(TsfMetadataConstants.TSF_INSTNACE_ID, tsfCoreProperties.getInstanceId()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfRegion())) { + tsfMetadata.put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion()); + } + + if (StringUtils.isNotBlank(tsfCoreProperties.getTsfZone())) { + tsfMetadata.put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone()); + } + + tsfMetadata.put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis())); + tsfMetadata.put(TsfMetadataConstants.TSF_SDK_VERSION, SdkVersion.get()); + tsfMetadata.put(TsfMetadataConstants.TSF_TAGS, JacksonUtils.serialize2Json(tsfCoreProperties.getTsfTags())); + String ipv4Address = PolarisInetUtils.getIpString(false); + if (StringUtils.isNotBlank(ipv4Address)) { + tsfMetadata.put(TsfMetadataConstants.TSF_ADDRESS_IPV4, ipv4Address); + } + String ipv6Address = PolarisInetUtils.getIpString(true); + if (StringUtils.isNotBlank(ipv6Address)) { + tsfMetadata.put(TsfMetadataConstants.TSF_ADDRESS_IPV6, ipv6Address); + } + return tsfMetadata; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java index d01ef8a7fb..67ad30a8b4 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java @@ -23,6 +23,7 @@ import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.logging.LoggingApplicationListener; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.GenericApplicationListener; import org.springframework.core.ResolvableType; @@ -45,7 +46,8 @@ public boolean supportsEventType(ResolvableType resolvableType) { return false; } return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type) - || ApplicationFailedEvent.class.isAssignableFrom(type); + || ApplicationFailedEvent.class.isAssignableFrom(type) + || EnvironmentChangeEvent.class.isAssignableFrom(type); } @Override diff --git a/spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.java b/spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.java new file mode 100644 index 0000000000..364695e73b --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/org/springframework/tsf/annotation/EnableTsf.java @@ -0,0 +1,45 @@ +/* + * 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 org.springframework.tsf.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * Compatible with old versions TSF SDK. + * + * @author Haotian Zhang + */ + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@EnableAutoConfiguration +@EnableDiscoveryClient // 服务注册发现 +@EnableConfigurationProperties // 分布式配置 +public @interface EnableTsf { +} diff --git a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories index a121e3c265..ac093c2972 100644 --- a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories @@ -1,7 +1,12 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration,\ - com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration + com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration,\ + com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration + com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration,\ + com.tencent.cloud.polaris.context.config.extend.tsf.TsfContextBootstrapConfiguration org.springframework.context.ApplicationListener=\ com.tencent.cloud.polaris.context.logging.PolarisLoggingApplicationListener +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tencent.cloud.polaris.context.config.PolarisContextEnvironmentPostProcessor,\ + com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreEnvironmentPostProcessor diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java index e2d33f0492..b6fd8a8d2e 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PolarisContextGetHostTest.java @@ -20,6 +20,7 @@ import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.polaris.client.api.SDKContext; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.platform.commons.util.StringUtils; @@ -38,8 +39,8 @@ */ @ExtendWith(SpringExtension.class) @SpringBootTest(classes = PolarisContextApplication.class, - properties = { "spring.config.location = classpath:bootstrap.yml" }) -@ImportAutoConfiguration({ PolarisContextAutoConfiguration.class }) + properties = {"spring.config.location = classpath:bootstrap.yml"}) +@ImportAutoConfiguration({PolarisContextAutoConfiguration.class}) public class PolarisContextGetHostTest { @Autowired @@ -48,6 +49,11 @@ public class PolarisContextGetHostTest { @Autowired private PolarisContextProperties polarisContextProperties; + @BeforeEach + public void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + @Test public void testGetConfigHost() { String bindIP = polarisSDKContextManager.getSDKContext().getConfig().getGlobal().getAPI().getBindIP(); @@ -58,5 +64,6 @@ public void testGetConfigHost() { assertThat(polarisContextProperties.getEnabled()).isTrue(); assertThat(polarisContextProperties.getNamespace()).isEqualTo("dev"); assertThat(polarisContextProperties.getService()).isEqualTo("TestApp"); + assertThat(polarisContextProperties.getLocalPort()).isEqualTo(9090); } } diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java index a5567c7643..c6d06f8a55 100644 --- a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/PostInitPolarisSDKContextTest.java @@ -19,8 +19,8 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.polaris.api.plugin.common.ValueContext; -import com.tencent.polaris.api.plugin.route.LocationLevel; import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -55,9 +55,9 @@ public void testConstructor() { when(staticMetadataManager.getCampus()).thenReturn(CAMPUS); new PostInitPolarisSDKContext(sdkContext, staticMetadataManager); - String regionName = valueContext.getValue(LocationLevel.region.name()); - String zoneName = valueContext.getValue(LocationLevel.zone.name()); - String campusName = valueContext.getValue(LocationLevel.campus.name()); + String regionName = valueContext.getValue(RoutingProto.NearbyRoutingConfig.LocationLevel.REGION.name()); + String zoneName = valueContext.getValue(RoutingProto.NearbyRoutingConfig.LocationLevel.ZONE.name()); + String campusName = valueContext.getValue(RoutingProto.NearbyRoutingConfig.LocationLevel.CAMPUS.name()); Assertions.assertThat(regionName).isEqualTo(REGION); Assertions.assertThat(zoneName).isEqualTo(ZONE); diff --git a/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.java b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.java new file mode 100644 index 0000000000..77ef87b5da --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/test/java/com/tencent/cloud/polaris/context/config/extend/consul/ConsulPropertiesTest.java @@ -0,0 +1,72 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.context.config.extend.consul; + +import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link ConsulPropertiesTest}. + * + * @author Haotian Zhang + */ +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = ConsulPropertiesTest.TestApplication.class) +@ActiveProfiles("test") +public class ConsulPropertiesTest { + + @Autowired + private ConsulProperties consulProperties; + + @BeforeEach + public void setUp() { + PolarisSDKContextManager.innerDestroy(); + } + + @AfterEach + public void tearDown() { + PolarisSDKContextManager.innerDestroy(); + } + + @Test + public void testDefaultInitialization() { + assertThat(consulProperties).isNotNull(); + assertThat(consulProperties.isEnabled()).isFalse(); + assertThat(consulProperties.getHost()).isEqualTo("localhost"); + assertThat(consulProperties.getPort()).isEqualTo(8500); + } + + @SpringBootApplication + protected static class TestApplication { + + static { + PolarisSDKContextManager.innerDestroy(); + } + } +} diff --git a/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml b/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml index 843279bfbc..de73a15d75 100644 --- a/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml +++ b/spring-cloud-tencent-polaris-context/src/test/resources/bootstrap.yml @@ -6,5 +6,6 @@ spring: namespace: dev service: TestApp enabled: true + local-port: 9090 logging: path: /tmp/polaris/logs diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java index d9b138343a..d18bca83b8 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancer.java @@ -76,7 +76,7 @@ public void addServers(List servers) { @Override public List getReachableServers() { - // Get servers first from the thread context. When routers filter all instances, getReachableServersWithoutCache function cannot be executed. + // Get servers first from the thread context if (THREAD_CACHE_SERVERS.get() != null) { return THREAD_CACHE_SERVERS.get(); } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java index 8156b6c733..bb8f021d2b 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRibbonClientConfiguration.java @@ -56,7 +56,7 @@ public ILoadBalancer polarisLoadBalancer(IClientConfig iClientConfig, IRule iRul @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "roundRobin", matchIfMissing = true) + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "roundRobin") public IRule roundRobinRule() { return new RoundRobinRule(); } @@ -77,7 +77,7 @@ public IRule polarisWeightedRandomRule(PolarisSDKContextManager polarisSDKContex @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRoundRobin") + @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRoundRobin", matchIfMissing = true) public IRule polarisWeightedRoundRobinRule(PolarisSDKContextManager polarisSDKContextManager) { return new PolarisWeightedRoundRobinRule(polarisSDKContextManager.getRouterAPI()); } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 9235e861d0..92251c9163 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-polaris-loadbalancer/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,47 +1,69 @@ { "properties": [ { - "name": "spring.cloud.polaris.loadbalancer.enabled", + "name": "spring.cloud.polaris.router.metadata-router.enabled", "type": "java.lang.Boolean", - "defaultValue": "true", - "description": "polaris loadbalancer." + "defaultValue": true, + "description": "the switch for metadata router." }, { - "name": "spring.cloud.polaris.loadbalancer.discoveryType", + "name": "spring.cloud.polaris.router.nearby-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "the switch for nearby router." + }, + { + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", "type": "java.lang.String", - "defaultValue": "POLARIS", - "description": "Type of discovery server." + "defaultValue": "ZONE", + "description": "the match level for nearby router, options can be REGION/ZONE/CAMPUS." }, { - "name": "spring.cloud.polaris.loadbalancer.strategy", + "name": "spring.cloud.polaris.router.rule-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "the switch for rule based router." + }, + { + "name": "spring.cloud.polaris.router.rule-router.failOver", "type": "java.lang.String", - "defaultValue": "roundRobin", - "description": "loadbalancer strategy." + "defaultValue": "all", + "description": "the fail over type for rule based router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "the switch for namespace router." + }, + { + "name": "spring.cloud.polaris.router.namespace-router.failOver", + "type": "java.lang.String", + "defaultValue": "all", + "description": "the fail over type for namespace router." + }, + { + "name": "spring.cloud.polaris.router.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "the switch for router module." } ], "hints": [ { - "name": "spring.cloud.polaris.loadbalancer.strategy", + "name": "spring.cloud.polaris.router.nearby-router.matchLevel", "values": [ { - "value": "roundRobin", - "description": "round robin load balancer." - }, - { - "value": "random", - "description": "random load balancer." + "value": "CAMPUS" }, { - "value": "polarisWeightedRandom", - "description": "polaris weighted random load balancer." + "value": "ZONE" }, { - "value": "polarisWeightedRoundRobin", - "description": "polaris weighted round robin load balancer." + "value": "REGION" }, { - "value": "polarisRingHash", - "description": "polaris ring hash load balancer." + "value": "ALL" } ] } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java index ec0e239702..0735a90df2 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java @@ -70,8 +70,10 @@ public Response execute(Request request, Options options) throws IOException { enhancedPluginContext.setOriginRequest(request); enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance()); - DefaultServiceInstance serviceInstance = new DefaultServiceInstance(request.requestTemplate().feignTarget() - .name(), url.getHost(), url.getPort(), url.getScheme().equals("https")); + String svcName = request.requestTemplate().feignTarget().name(); + DefaultServiceInstance serviceInstance = new DefaultServiceInstance( + String.format("%s-%s-%d", svcName, url.getHost(), url.getPort()), + svcName, url.getHost(), url.getPort(), url.getScheme().equals("https")); // -1 means access directly by url if (serviceInstance.getPort() == -1) { enhancedPluginContext.setTargetServiceInstance(null, url); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java index eff88f13ad..f839e1dc57 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PluginOrderConstant.java @@ -20,6 +20,7 @@ import org.springframework.core.Ordered; + /** * PluginOrderConstant. * @@ -58,5 +59,21 @@ public static class ClientPluginOrder { * {@link com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateEnhancedPlugin}. */ public static final int CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 10; + + /** + * order for + * {@link com.tencent.cloud.plugin.trace.TraceClientMetadataEnhancedPlugin}. + */ + public static final int CONSUMER_TRACE_METADATA_PLUGIN_ORDER = CONSUMER_TRANSFER_METADATA_PLUGIN_ORDER - 1; + } + + public static class ServerPluginOrder { + + /** + * order for + * {@link com.tencent.cloud.plugin.trace.TraceServerMetadataEnhancedPlugin}. + */ + public static final int PROVIDER_TRACE_METADATA_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 1; } + } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java index 2ad8e5de0e..41865379a5 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java @@ -33,16 +33,6 @@ public class PolarisStatProperties { */ private boolean enabled = true; - /** - * Local host for prometheus to pull. - */ - private String host; - - /** - * Port for prometheus to pull. 0 for random from 20000 to 65535. - */ - private int port = 0; - /** * Path for prometheus to pull. */ @@ -67,6 +57,12 @@ public class PolarisStatProperties { @Value("${spring.cloud.polaris.stat.pushgateway.push-interval:#{30000}}") private Long pushGatewayPushInterval = 30 * 1000L; + /** + * If push gateway gzip open. default false. + */ + @Value("${spring.cloud.polaris.stat.pushgateway.open-gzip:#{false}}") + private Boolean openGzip = false; + public boolean isEnabled() { return enabled; } @@ -75,22 +71,6 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - public String getPath() { return path; } @@ -122,4 +102,12 @@ public Long getPushGatewayPushInterval() { public void setPushGatewayPushInterval(Long pushGatewayPushInterval) { this.pushGatewayPushInterval = pushGatewayPushInterval; } + + public Boolean getOpenGzip() { + return openGzip; + } + + public void setOpenGzip(Boolean openGzip) { + this.openGzip = openGzip; + } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java index 36c21680b4..53db6a75d2 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java @@ -23,7 +23,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; /** * Autoconfiguration of stat reporter. @@ -37,7 +36,7 @@ public class PolarisStatPropertiesAutoConfiguration { @Bean @ConditionalOnMissingBean - public StatConfigModifier statReporterConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) { - return new StatConfigModifier(polarisStatProperties, environment); + public StatConfigModifier statReporterConfigModifier(PolarisStatProperties polarisStatProperties) { + return new StatConfigModifier(polarisStatProperties); } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java index abaac1c935..6d166fd6a4 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java @@ -20,11 +20,9 @@ import com.tencent.cloud.common.constant.OrderConstant; import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.factory.config.global.StatReporterConfigImpl; import com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandlerConfig; -import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; - import static com.tencent.polaris.api.config.global.StatReporterConfig.DEFAULT_REPORTER_PROMETHEUS; /** @@ -36,43 +34,31 @@ public class StatConfigModifier implements PolarisConfigModifier { private final PolarisStatProperties polarisStatProperties; - private final Environment environment; - - public StatConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) { + public StatConfigModifier(PolarisStatProperties polarisStatProperties) { this.polarisStatProperties = polarisStatProperties; - this.environment = environment; } @Override public void modify(ConfigurationImpl configuration) { // Turn on stat reporter configuration. configuration.getGlobal().getStatReporter().setEnable(polarisStatProperties.isEnabled()); - PrometheusHandlerConfig prometheusHandlerConfig = configuration.getGlobal().getStatReporter() - .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); + StatReporterConfigImpl statReporterConfig = configuration.getGlobal().getStatReporter(); + statReporterConfig.setEnable(polarisStatProperties.isEnabled()); + PrometheusHandlerConfig prometheusHandlerConfig = statReporterConfig.getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); // Set prometheus plugin. if (polarisStatProperties.isEnabled()) { - if (polarisStatProperties.isPushGatewayEnabled()) { // push gateway prometheusHandlerConfig.setType("push"); prometheusHandlerConfig.setAddress(polarisStatProperties.getPushGatewayAddress()); prometheusHandlerConfig.setPushInterval(polarisStatProperties.getPushGatewayPushInterval()); + prometheusHandlerConfig.setOpenGzip(polarisStatProperties.getOpenGzip()); } else { // pull metrics prometheusHandlerConfig.setType("pull"); - if (!StringUtils.hasText(polarisStatProperties.getHost())) { - polarisStatProperties.setHost(environment.getProperty("spring.cloud.client.ip-address")); - } - prometheusHandlerConfig.setHost(polarisStatProperties.getHost()); - prometheusHandlerConfig.setPort(polarisStatProperties.getPort()); prometheusHandlerConfig.setPath(polarisStatProperties.getPath()); } - - } - else { - // Set port to -1 to disable stat plugin. - prometheusHandlerConfig.setPort(-1); } configuration.getGlobal().getStatReporter() .setPluginConfig(DEFAULT_REPORTER_PROMETHEUS, prometheusHandlerConfig); diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java index a44ef3a56f..81e8beb23d 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/transformer/PolarisInstanceTransformer.java @@ -20,6 +20,7 @@ import com.tencent.cloud.common.pojo.PolarisServiceInstance; import com.tencent.polaris.api.pojo.DefaultInstance; +import com.tencent.polaris.api.utils.CollectionUtils; import org.springframework.cloud.client.ServiceInstance; @@ -38,6 +39,9 @@ public void transformCustom(DefaultInstance instance, ServiceInstance serviceIns instance.setZone(polarisServiceInstance.getPolarisInstance().getZone()); instance.setCampus(polarisServiceInstance.getPolarisInstance().getCampus()); instance.setWeight(polarisServiceInstance.getPolarisInstance().getWeight()); + if (CollectionUtils.isNotEmpty(polarisServiceInstance.getServiceMetadata())) { + instance.setServiceMetadata(polarisServiceInstance.getServiceMetadata()); + } } } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json index a2a449b33e..7c6745ba81 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -57,20 +57,28 @@ "name": "spring.cloud.polaris.stat.pushgateway.address", "type": "java.lang.String", "description": "PushGateway address.", - "sourceType": "com.tencent.cloud.plugin.pushgateway.PolarisStatPushGatewayProperties" + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties" }, { "name": "spring.cloud.polaris.stat.pushgateway.enabled", "type": "java.lang.Boolean", "description": "If state pushGateway reporter enabled.", - "sourceType": "com.tencent.cloud.plugin.pushgateway.PolarisStatPushGatewayProperties", + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties", "defaultValue": false }, { "name": "spring.cloud.polaris.stat.pushgateway.push-interval", "type": "java.lang.Long", "description": "Push metrics interval. unit: milliseconds default 30s.", - "sourceType": "com.tencent.cloud.plugin.pushgateway.PolarisStatPushGatewayProperties" + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties", + "defaultValue": 30000 + }, + { + "name": "spring.cloud.polaris.stat.pushgateway.open-gzip", + "type": "java.lang.Boolean", + "description": "If push gateway gzip open. default false.", + "sourceType": "com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties", + "defaultValue": false } ] } diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java index 86c0c74a7a..2244b10ab3 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java @@ -35,8 +35,6 @@ public class PolarisStatPropertiesTest { .withConfiguration(AutoConfigurations.of(PolarisStatPropertiesAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.stat.enabled=true") - .withPropertyValues("spring.cloud.polaris.stat.host=127.0.0.1") - .withPropertyValues("spring.cloud.polaris.stat.port=20000") .withPropertyValues("spring.cloud.polaris.stat.path=/xxx") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.enabled=true") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.address=127.0.0.1:9091") @@ -50,8 +48,6 @@ public void testDefaultInitialization() { assertThat(polarisStatProperties).isNotNull(); assertThat(polarisStatProperties.isEnabled()).isTrue(); - assertThat(polarisStatProperties.getHost()).isNotBlank(); - assertThat(polarisStatProperties.getPort()).isEqualTo(20000); assertThat(polarisStatProperties.getPath()).isEqualTo("/xxx"); assertThat(polarisStatProperties.isPushGatewayEnabled()).isTrue(); assertThat(polarisStatProperties.getPushGatewayAddress()).isEqualTo("127.0.0.1:9091"); diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java index 52c125ebf4..0321271572 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifierTest.java @@ -18,6 +18,7 @@ package com.tencent.cloud.rpc.enhancement.stat.config; import com.tencent.cloud.polaris.context.PolarisSDKContextManager; +import com.tencent.polaris.api.config.global.StatReporterConfig; import com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandlerConfig; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,6 +54,7 @@ public class StatConfigModifierTest { .withPropertyValues("spring.cloud.polaris.stat.pushgateway.enabled=true") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.address=127.0.0.1:9091") .withPropertyValues("spring.cloud.polaris.stat.pushgateway.push-interval=1000") + .withPropertyValues("spring.cloud.polaris.stat.pushgateway.open-gzip=true") .withPropertyValues("spring.application.name=test") .withPropertyValues("spring.cloud.gateway.enabled=false"); @@ -76,8 +78,6 @@ void testPull() { .getGlobal().getStatReporter() .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); assertThat(prometheusHandlerConfig.getType()).isEqualTo("pull"); - assertThat(prometheusHandlerConfig.getHost()).isEqualTo("127.0.0.1"); - assertThat(prometheusHandlerConfig.getPort()).isEqualTo(20000); assertThat(prometheusHandlerConfig.getPath()).isEqualTo("/xxx"); }); } @@ -92,6 +92,7 @@ void testPush() { assertThat(prometheusHandlerConfig.getType()).isEqualTo("push"); assertThat(prometheusHandlerConfig.getAddress()).isEqualTo("127.0.0.1:9091"); assertThat(prometheusHandlerConfig.getPushInterval()).isEqualTo(1000); + assertThat(prometheusHandlerConfig.isOpenGzip()).isTrue(); }); } @@ -99,10 +100,9 @@ void testPush() { void testDisabled() { disabledContextRunner.run(context -> { PolarisSDKContextManager polarisSDKContextManager = context.getBean(PolarisSDKContextManager.class); - PrometheusHandlerConfig prometheusHandlerConfig = polarisSDKContextManager.getSDKContext().getConfig() - .getGlobal().getStatReporter() - .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); - assertThat(prometheusHandlerConfig.getPort()).isEqualTo(-1); + StatReporterConfig statReporterConfig = polarisSDKContextManager.getSDKContext().getConfig() + .getGlobal().getStatReporter(); + assertThat(statReporterConfig.isEnable()).isFalse(); }); }