hoxton 2.0.0.0 (#1458)
* fix:fix restTemplateCustomizer bean conflict causing service to fail to start properly. * fix:fix NullPointerException when properties contain kv with null value. * fix: memory not released while using wildcard api call with circuitbreaker (#1361) * fix: memory not released while using wildcard api call with circuitbreaker enabled * fix: change version 1.13.3-Hoxton.SR12-SNAPSHOT * fix: update polaris verion to 1.15.9 release * Update CHANGELOG.md * release 1.13.3-Hoxton.SR12 (#1362) * fix: memory not released while using wildcard api call with circuitbreaker enabled * fix: change version 1.13.3-Hoxton.SR12-SNAPSHOT * fix: update polaris verion to 1.15.9 release * Update CHANGELOG.md * release: 1.13.3-Hoxton.SR12 * fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoke by wildcard apis (#1392) * fix: CHANGE VERSION TO 1.13.4-Hoxton.SR12-SNAPSHOT (#1407) * fix: fix PolarisCircuitBreakerConfiguration not clear when gateway invoked by wildcard apis * Update CHANGELOG.md * fix: restore PolarisCircuitBreakerUtils and use ThreadPoolUtils.waitAndStopThreadPools instead * fix: 修复命名不一致问题 * fix: CHANGE VERSION TO 1.13.4-Hoxton.SR12-SNAPSHOT * Update polaris version to 1.15.10-SNAPSHOT * fix:fix rate limit window update bug. * fix: fix npe when feign.hystrix.enabled=false (#1436) * feat: support 2.0.0 feature * fix * feat: support lossless config from console & support warmup (#1435) feat:add admin http handler. (#1448) feat:support concurrency rate limit. (#1454) * fix * add changelog * fix * fix changelog * fix * fix checkstyle * fix ut --------- Co-authored-by: 码匠君 <pointer_v@qq.com> Co-authored-by: Haotian Zhang <928016560@qq.com> Co-authored-by: andrew shan <45474304+andrewshan@users.noreply.github.com> Co-authored-by: shedfreewu <shedfreewu@tencent.com>hoxton
parent
eab382b371
commit
84a98de136
@ -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<String, Collection<String>> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, String> 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<String, String> 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 {
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<TsfCallbackParam> 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<String> interestedKeys = new HashSet<>();
|
||||
Set<String> 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<TsfCallbackParam> parseConfigChangeEventToTsfCallbackParam(ConfigChangeEvent event) {
|
||||
List<TsfCallbackParam> result = new ArrayList<>();
|
||||
Set<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue