feat:support smooth upgrade from tsf. (#1542)

pull/1542/head
fishtailfu 5 months ago
parent 853202b1f9
commit 50fba76b38

@ -59,6 +59,17 @@
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-auth</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-fault-tolerance</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>

@ -27,8 +27,8 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.instrument.scg.EnhancedGatewayGlobalFilter;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter;
import org.assertj.core.util.Maps;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;

@ -0,0 +1,42 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.auth.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfAuth {
}

@ -1,2 +1,5 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.auth.config.PolarisAuthPropertiesAutoConfiguration,\
com.tencent.cloud.polaris.auth.config.PolarisAuthAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.auth.config.PolarisAuthPropertiesBootstrapConfiguration

@ -1,2 +0,0 @@
com.tencent.cloud.polaris.auth.config.PolarisAuthPropertiesAutoConfiguration
com.tencent.cloud.polaris.auth.config.PolarisAuthAutoConfiguration

@ -0,0 +1,45 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.auth.config;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link PolarisAuthProperties}.
*
* @author Haotian Zhang
*/
public class PolarisAuthPropertiesTest {
private final ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisAuthPropertiesAutoConfiguration.class))
.withPropertyValues("spring.cloud.polaris.auth.enabled=false");
@Test
public void testGetAndSet() {
this.applicationContextRunner.run(context -> {
PolarisAuthProperties properties = context.getBean(PolarisAuthProperties.class);
assertThat(properties.isEnabled()).isFalse();
});
}
}

@ -17,8 +17,8 @@
package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisCircuitBreakerNameResolver;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignCircuitBreaker;
import com.tencent.cloud.polaris.circuitbreaker.instrument.feign.PolarisCircuitBreakerNameResolver;
import com.tencent.cloud.polaris.circuitbreaker.instrument.feign.PolarisFeignCircuitBreaker;
import feign.Feign;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.feign;
package com.tencent.cloud.polaris.circuitbreaker.instrument.feign;
import java.io.IOException;
import java.lang.reflect.Method;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.feign;
package com.tencent.cloud.polaris.circuitbreaker.instrument.feign;
import java.lang.reflect.Method;
import java.net.URI;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.feign;
package com.tencent.cloud.polaris.circuitbreaker.instrument.feign;
import java.lang.reflect.Field;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.feign;
package com.tencent.cloud.polaris.circuitbreaker.instrument.feign;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.reactor;
package com.tencent.cloud.polaris.circuitbreaker.instrument.reactor;
import com.tencent.polaris.circuitbreak.api.InvokeHandler;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.reactor;
package com.tencent.cloud.polaris.circuitbreaker.instrument.reactor;
import com.tencent.polaris.circuitbreak.api.InvokeHandler;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.reactor;
package com.tencent.cloud.polaris.circuitbreaker.instrument.reactor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.reactor;
package com.tencent.cloud.polaris.circuitbreaker.instrument.reactor;
import java.util.function.Function;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.resttemplate;
package com.tencent.cloud.polaris.circuitbreaker.instrument.resttemplate;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -28,12 +28,15 @@ import java.lang.annotation.Target;
* if coded fallback or fallbackClass provided, RestTemplate will always return fallback when any exception occurs,
* if none coded fallback or fallbackClass provided, RestTemplate will return fallback response from Polaris server when fallback occurs.
* fallback and fallbackClass cannot provide at same time.
* <p>
* Deprecated since 2.0.0.0.
*
* @author sean yu
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Deprecated
public @interface PolarisCircuitBreaker {
/**

@ -15,13 +15,16 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.resttemplate;
package com.tencent.cloud.polaris.circuitbreaker.instrument.resttemplate;
/**
* PolarisCircuitBreakerFallback.
* <p>
* Deprecated since 2.0.0.0.
*
* @author sean yu
*/
@Deprecated
public interface PolarisCircuitBreakerFallback {
PolarisCircuitBreakerHttpResponse fallback();

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.resttemplate;
package com.tencent.cloud.polaris.circuitbreaker.instrument.resttemplate;
import java.io.ByteArrayInputStream;
import java.io.IOException;

@ -21,7 +21,7 @@ import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreaker;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerHttpResponse;
import com.tencent.cloud.polaris.circuitbreaker.instrument.resttemplate.PolarisCircuitBreakerHttpResponse;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;

@ -17,7 +17,7 @@
package org.springframework.cloud.openfeign;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignCircuitBreaker;
import com.tencent.cloud.polaris.circuitbreaker.instrument.feign.PolarisFeignCircuitBreaker;
import feign.Feign;
import feign.Target;

@ -0,0 +1,40 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.cloud.tsf.circuitbreaker.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfCircuitBreaker {
}

@ -1,5 +1,6 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.GatewayPolarisCircuitBreakerAutoConfiguration,\
org.springframework.cloud.openfeign.PolarisFeignCircuitBreakerTargeterAutoConfiguration,\

@ -18,7 +18,7 @@
package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisCircuitBreakerNameResolver;
import com.tencent.cloud.polaris.circuitbreaker.instrument.feign.PolarisCircuitBreakerNameResolver;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import org.junit.jupiter.api.Test;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.feign;
package com.tencent.cloud.polaris.circuitbreaker.instrument.feign;
import java.lang.reflect.Method;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.circuitbreaker.feign;
package com.tencent.cloud.polaris.circuitbreaker.instrument.feign;
import feign.Feign;
import feign.RequestLine;

@ -57,7 +57,7 @@ import org.springframework.util.CollectionUtils;
*/
public class PolarisContractReporter implements ApplicationListener<ApplicationReadyEvent> {
private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class);
private static final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class);
private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource;
private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource;

@ -38,13 +38,13 @@ import org.springframework.util.StringUtils;
public class TsfApiMetadataGrapher implements SmartLifecycle {
private static final Logger logger = LoggerFactory.getLogger(TsfApiMetadataGrapher.class);
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;
private final ApplicationContext applicationContext;
private final String groupName;
public TsfApiMetadataGrapher(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource,
org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource,

@ -17,8 +17,8 @@
package com.tencent.cloud.polaris.discovery.refresh;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.discovery.ConditionalOnPolarisDiscoveryEnabled;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
@ -30,13 +30,19 @@ import org.springframework.context.annotation.Configuration;
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisEnabled
@ConditionalOnPolarisDiscoveryEnabled
public class PolarisRefreshConfiguration {
@Bean
@ConditionalOnMissingBean
public PolarisServiceStatusChangeListener polarisServiceChangeListener() {
return new PolarisServiceStatusChangeListener();
public PolarisServiceStatusChangeListener polarisServiceChangeListener(ServiceInstanceChangeCallbackManager serviceInstanceChangeCallbackManager) {
return new PolarisServiceStatusChangeListener(serviceInstanceChangeCallbackManager);
}
@Bean
@ConditionalOnMissingBean
public ServiceInstanceChangeCallbackManager serviceInstanceChangeCallbackManager() {
return new ServiceInstanceChangeCallbackManager();
}
@Bean

@ -17,14 +17,18 @@
package com.tencent.cloud.polaris.discovery.refresh;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import com.google.common.collect.Sets;
import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.RegistryCacheValue;
import com.tencent.polaris.api.pojo.ServiceEventKey;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.client.pojo.ServiceInstancesByProto;
import com.tencent.polaris.client.pojo.ServicesByProto;
import org.slf4j.Logger;
@ -34,7 +38,6 @@ import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;
/**
* Change listener of Polaris service info. When service info is created or deleted, or, instance of service is from
@ -42,7 +45,8 @@ import org.springframework.util.CollectionUtils;
*
* @author Haotian Zhang
*/
public class PolarisServiceStatusChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware {
public class PolarisServiceStatusChangeListener extends AbstractResourceEventListener
implements ApplicationEventPublisherAware {
/**
* Index of service info status.
@ -50,9 +54,13 @@ public class PolarisServiceStatusChangeListener extends AbstractResourceEventLis
public static final AtomicLong INDEX = new AtomicLong(0);
private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceStatusChangeListener.class);
private final ServiceInstanceChangeCallbackManager serviceInstanceChangeCallbackManager;
private ApplicationEventPublisher publisher;
public PolarisServiceStatusChangeListener(ServiceInstanceChangeCallbackManager serviceInstanceChangeCallbackManager) {
this.serviceInstanceChangeCallbackManager = serviceInstanceChangeCallbackManager;
}
@Override
public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue,
RegistryCacheValue newValue) {
@ -88,6 +96,22 @@ public class PolarisServiceStatusChangeListener extends AbstractResourceEventLis
// Trigger reload of gateway route cache.
this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement()));
}
List<Instance> oldInstances = new ArrayList<>();
List<Instance> newInstances = new ArrayList<>();
if (CollectionUtils.isNotEmpty(oldIns.getInstances())) {
oldInstances.addAll(oldIns.getInstances());
}
if (CollectionUtils.isNotEmpty(newIns.getInstances())) {
newInstances.addAll(newIns.getInstances());
}
try {
this.serviceInstanceChangeCallbackManager.handle(svcEventKey.getService(), oldInstances, newInstances);
}
catch (Throwable throwable) {
LOG.error("Service[{}] instance status change callback failed.", svcEventKey.getService(), throwable);
}
}
}
}

@ -0,0 +1,32 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.discovery.refresh;
import java.util.List;
import com.tencent.polaris.api.pojo.Instance;
/**
* Callback for service instance change.
*
* @author Haotian Zhang
*/
public interface ServiceInstanceChangeCallback {
void callback(List<Instance> currentServiceInstances, List<Instance> addServiceInstances, List<Instance> deleteServiceInstances);
}

@ -0,0 +1,145 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.discovery.refresh;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClient;
import com.tencent.cloud.polaris.discovery.reactive.PolarisReactiveDiscoveryClient;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.client.util.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.util.annotation.NonNull;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.util.CollectionUtils;
/**
* Call back manager for service instance change.
*
* @author Haotian Zhang
*/
public class ServiceInstanceChangeCallbackManager implements ApplicationListener<ApplicationReadyEvent>, BeanPostProcessor {
private static final Logger LOG = LoggerFactory.getLogger(ServiceInstanceChangeCallbackManager.class);
private final ConcurrentHashMap<String, List<ServiceInstanceChangeCallback>> callbackMap = new ConcurrentHashMap<>();
private final ScheduledThreadPoolExecutor serviceChangeListenerExecutor;
public ServiceInstanceChangeCallbackManager() {
this.serviceChangeListenerExecutor = new ScheduledThreadPoolExecutor(4, new NamedThreadFactory("service-change-listener"));
}
public void handle(String serviceName, List<Instance> oldInstances, List<Instance> newInstances) {
List<Instance> addInstances = new ArrayList<>();
List<Instance> deleteInstances = new ArrayList<>();
// calculate add instances.
for (Instance instance : newInstances) {
if (!oldInstances.contains(instance)) {
addInstances.add(instance);
}
}
// calculate delete instances.
for (Instance instance : oldInstances) {
if (!newInstances.contains(instance)) {
deleteInstances.add(instance);
}
}
if ((!CollectionUtils.isEmpty(addInstances) || !CollectionUtils.isEmpty(deleteInstances))
&& callbackMap.containsKey(serviceName)) {
List<ServiceInstanceChangeCallback> callbacks = callbackMap.get(serviceName);
for (ServiceInstanceChangeCallback callback : callbacks) {
serviceChangeListenerExecutor.execute(() -> {
try {
callback.callback(newInstances, addInstances, deleteInstances);
}
catch (Exception e) {
LOG.error("exception in callback, service name:{}, ", serviceName, e);
}
});
}
}
}
@Override
public synchronized Object postProcessAfterInitialization(Object bean, String beanName) {
Class<?> clz = bean.getClass();
if (!ServiceInstanceChangeCallback.class.isAssignableFrom(clz)) {
return bean;
}
String serviceName = null;
if (clz.isAnnotationPresent(ServiceInstanceChangeListener.class)) {
ServiceInstanceChangeListener serviceInstanceChangeListener = clz.getAnnotation(ServiceInstanceChangeListener.class);
serviceName = serviceInstanceChangeListener.serviceName();
}
if (StringUtils.isBlank(serviceName)) {
return bean;
}
// process callback
if (callbackMap.containsKey(serviceName)) {
List<ServiceInstanceChangeCallback> callbacks = callbackMap.get(serviceName);
callbacks.add((ServiceInstanceChangeCallback) bean);
}
else {
List<ServiceInstanceChangeCallback> callbacks = new ArrayList<>();
callbacks.add((ServiceInstanceChangeCallback) bean);
callbackMap.put(serviceName, callbacks);
}
return bean;
}
@Override
public void onApplicationEvent(@NonNull ApplicationReadyEvent event) {
PolarisDiscoveryClient polarisDiscoveryClient = ApplicationContextAwareUtils.getBeanIfExists(PolarisDiscoveryClient.class);
PolarisReactiveDiscoveryClient polarisReactiveDiscoveryClient = ApplicationContextAwareUtils.getBeanIfExists(PolarisReactiveDiscoveryClient.class);
for (String serviceName : callbackMap.keySet()) {
try {
if (polarisDiscoveryClient != null) {
polarisDiscoveryClient.getInstances(serviceName);
}
else if (polarisReactiveDiscoveryClient != null) {
polarisReactiveDiscoveryClient.getInstances(serviceName).subscribe();
}
else {
LOG.warn("[{}] no discovery client found.", serviceName);
}
}
catch (Throwable throwable) {
LOG.error("Get instances of service [{}] failed.", serviceName, throwable);
}
}
}
}

@ -15,29 +15,28 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.quickstart.caller.circuitbreaker;
package com.tencent.cloud.polaris.discovery.refresh;
import java.util.HashMap;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerFallback;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerHttpResponse;
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;
/**
* CustomFallback.
*
* @author sean yu
* @author Haotian Zhang
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public class CustomFallback implements PolarisCircuitBreakerFallback {
@Override
public PolarisCircuitBreakerHttpResponse fallback() {
return new PolarisCircuitBreakerHttpResponse(
200,
new HashMap<String, String>() {{
put("Content-Type", "application/json");
}},
"{\"msg\": \"this is a fallback class\"}");
}
public @interface ServiceInstanceChangeListener {
/**
* listen service name.
* @return service name
*/
String serviceName();
}

@ -0,0 +1,44 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.eager.config;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClient;
import com.tencent.cloud.polaris.discovery.reactive.PolarisReactiveDiscoveryClient;
import com.tencent.cloud.polaris.eager.instrument.feign.FeignEagerLoadSmartLifecycle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnProperty(name = "spring.cloud.polaris.discovery.eager-load.enabled", havingValue = "true")
public class PolarisEagerLoadAutoConfiguration {
@Bean
@ConditionalOnClass(name = "feign.Feign")
@ConditionalOnProperty(name = "spring.cloud.polaris.discovery.eager-load.feign.enabled", havingValue = "true", matchIfMissing = true)
public FeignEagerLoadSmartLifecycle feignEagerLoadSmartLifecycle(
ApplicationContext applicationContext, @Autowired(required = false) PolarisDiscoveryClient polarisDiscoveryClient,
@Autowired(required = false) PolarisReactiveDiscoveryClient polarisReactiveDiscoveryClient) {
return new FeignEagerLoadSmartLifecycle(applicationContext, polarisDiscoveryClient, polarisReactiveDiscoveryClient);
}
}

@ -0,0 +1,94 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.eager.instrument.feign;
import com.tencent.cloud.common.util.FeignUtil;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClient;
import com.tencent.cloud.polaris.discovery.reactive.PolarisReactiveDiscoveryClient;
import com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.SmartLifecycle;
public class FeignEagerLoadSmartLifecycle implements SmartLifecycle {
private static final Logger LOG = LoggerFactory.getLogger(FeignEagerLoadSmartLifecycle.class);
private final ApplicationContext applicationContext;
private final PolarisDiscoveryClient polarisDiscoveryClient;
private final PolarisReactiveDiscoveryClient polarisReactiveDiscoveryClient;
public FeignEagerLoadSmartLifecycle(ApplicationContext applicationContext, PolarisDiscoveryClient polarisDiscoveryClient,
PolarisReactiveDiscoveryClient polarisReactiveDiscoveryClient) {
this.applicationContext = applicationContext;
this.polarisDiscoveryClient = polarisDiscoveryClient;
this.polarisReactiveDiscoveryClient = polarisReactiveDiscoveryClient;
}
@Override
public void start() {
LOG.info("feign eager-load start");
for (String name : applicationContext.getBeanDefinitionNames()) {
try {
if (name.contains(FeignUtil.FEIGN_CLIENT_SPECIF) && !name.startsWith(FeignUtil.FEIGN_CLIENT_DEFAULT)) {
String feignName = FeignUtil.analysisFeignName(name, applicationContext);
if (StringUtils.isNotBlank(feignName)) {
LOG.info("[{}] eager-load start", feignName);
if (polarisDiscoveryClient != null) {
polarisDiscoveryClient.getInstances(feignName);
}
else if (polarisReactiveDiscoveryClient != null) {
polarisReactiveDiscoveryClient.getInstances(feignName).subscribe();
}
else {
LOG.warn("[{}] no discovery client found.", feignName);
}
LOG.info("[{}] eager-load end", feignName);
}
else {
LOG.warn("feign name is blank.");
}
}
}
catch (Exception e) {
LOG.error("[{}] eager-load failed.", name, e);
}
}
LOG.info("feign eager-load end");
}
@Override
public void stop() {
}
@Override
public boolean isRunning() {
return false;
}
@Override
public int getPhase() {
return 10;
}
}

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.tsf.registry;
package com.tencent.cloud.polaris.registry.tsf;
import java.util.HashMap;
import java.util.Map;

@ -14,8 +14,8 @@
* 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.registry.tsf;
package com.tencent.cloud.polaris.tsf.registry;
import javax.servlet.ServletContext;
import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.tsf.registry;
package com.tencent.cloud.polaris.registry.tsf;
import com.tencent.cloud.polaris.context.config.extend.tsf.TsfCoreProperties;
import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.tsf.registry;
package com.tencent.cloud.polaris.registry.tsf;
import java.util.ArrayList;
import java.util.Arrays;

@ -0,0 +1,40 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.serviceregistry.watch;
import java.util.List;
import com.ecwid.consul.v1.health.model.HealthService;
/**
* Not working anymore. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
public interface ConsulServiceChangeCallback {
/** Service change callback function.
* @param currentServices Currently available services list
* @param addServices Newly added services list
* @param deleteServices Removed services list
*/
void callback(List<HealthService> currentServices, List<HealthService> addServices, List<HealthService> deleteServices);
}

@ -0,0 +1,53 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.serviceregistry.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ConsulServiceChangeListener {
/**
* .
* @return
*/
String serviceName();
/**
* true false .
* @return
*/
boolean global() default false;
}

@ -0,0 +1,47 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.serviceregistry.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface LocalServiceChangeListener {
/**
* currentServices .
* @return .
*/
boolean excludeLocalInstance() default false;
}

@ -78,6 +78,18 @@
"defaultValue": false,
"description": "Zero protection test connectivity switch. Default: false."
},
{
"name": "spring.cloud.polaris.discovery.eager-load.enabled",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "Eager load switch. Default: false."
},
{
"name": "spring.cloud.polaris.discovery.eager-load.feign.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "Feign eager load switch. Default: true."
},
{
"name": "spring.cloud.nacos.discovery.enabled",
"type": "java.lang.Boolean",

@ -3,6 +3,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\
com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration,\
com.tencent.cloud.polaris.endpoint.PolarisDiscoveryEndpointAutoConfiguration,\
com.tencent.cloud.polaris.tsf.registry.TsfDiscoveryRegistryAutoConfiguration
com.tencent.cloud.polaris.registry.tsf.TsfDiscoveryRegistryAutoConfiguration,\
com.tencent.cloud.polaris.eager.config.PolarisEagerLoadAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.DiscoveryPropertiesBootstrapAutoConfiguration

@ -61,7 +61,7 @@ public class PolarisServiceStatusChangeListenerTest {
@Test
public void testOnResourceUpdated() {
PolarisServiceStatusChangeListener polarisServiceStatusChangeListener = new PolarisServiceStatusChangeListener();
PolarisServiceStatusChangeListener polarisServiceStatusChangeListener = new PolarisServiceStatusChangeListener(mock(ServiceInstanceChangeCallbackManager.class));
polarisServiceStatusChangeListener.setApplicationEventPublisher(publisher);
// Service update event

@ -0,0 +1,40 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.ratelimit.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfRateLimit {
}

@ -23,7 +23,7 @@ import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.util.BeanFactoryUtils;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.scg.PolarisLoadBalancerClientFilter;
import com.tencent.cloud.polaris.router.instrument.scg.PolarisLoadBalancerClientFilter;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.springframework.beans.BeansException;

@ -17,8 +17,8 @@
package com.tencent.cloud.polaris.router.beanprocessor;
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor;
import com.tencent.cloud.polaris.router.resttemplate.RouterContextFactory;
import com.tencent.cloud.polaris.router.instrument.resttemplate.PolarisLoadBalancerInterceptor;
import com.tencent.cloud.polaris.router.instrument.resttemplate.RouterContextFactory;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import org.springframework.beans.BeansException;

@ -17,8 +17,8 @@
package com.tencent.cloud.polaris.router.beanprocessor;
import com.tencent.cloud.polaris.router.resttemplate.PolarisRetryLoadBalancerInterceptor;
import com.tencent.cloud.polaris.router.resttemplate.RouterContextFactory;
import com.tencent.cloud.polaris.router.instrument.resttemplate.PolarisRetryLoadBalancerInterceptor;
import com.tencent.cloud.polaris.router.instrument.resttemplate.RouterContextFactory;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import org.springframework.beans.BeansException;

@ -17,8 +17,8 @@
package com.tencent.cloud.polaris.router.config;
import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory;
import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor;
import com.tencent.cloud.polaris.router.instrument.feign.PolarisCachingSpringLoadBalanceFactory;
import com.tencent.cloud.polaris.router.instrument.feign.RouterLabelFeignInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.netflix.ribbon.RibbonClients;

@ -19,7 +19,7 @@ package com.tencent.cloud.polaris.router.config;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.tencent.cloud.polaris.router.feign.PolarisFeignLoadBalancer;
import com.tencent.cloud.polaris.router.instrument.feign.PolarisFeignLoadBalancer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;

@ -32,13 +32,13 @@ import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterP
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.instrument.resttemplate.RouterContextFactory;
import com.tencent.cloud.polaris.router.instrument.resttemplate.RouterLabelRestTemplateInterceptor;
import com.tencent.cloud.polaris.router.instrument.scg.RouterLabelGlobalFilter;
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;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import java.util.Map;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import com.tencent.cloud.polaris.router.PolarisRouterContext;

@ -15,14 +15,14 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.io.IOException;
import java.net.URI;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.rpc.enhancement.instrument.resttemplate.EnhancedRestTemplateWrapInterceptor;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateWrapInterceptor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;

@ -15,14 +15,14 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.io.IOException;
import java.net.URI;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.rpc.enhancement.instrument.resttemplate.EnhancedRestTemplateWrapInterceptor;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateWrapInterceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.util.Collections;
import java.util.Comparator;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.io.IOException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.scg;
package com.tencent.cloud.polaris.router.instrument.scg;
import java.net.URI;
import java.util.Collections;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.scg;
package com.tencent.cloud.polaris.router.instrument.scg;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider;

@ -0,0 +1,41 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.lane.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfLane {
}

@ -0,0 +1,41 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.femas.adaptor.tsf.governance.zonefilter;
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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfZoneFilter {
}

@ -0,0 +1,41 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.unit.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfUnit {
}

@ -0,0 +1,46 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.unit.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TsfUnitCall {
// 单元化下的业务系统名
String systemName() default "";
// 单元化下的是否调用GDU服务
boolean global() default false;
}

@ -0,0 +1,40 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.unit.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TsfUnitCustomerIdentifier {
}

@ -0,0 +1,44 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.unit.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TsfUnitLocalCall {
String className() default "";
String methodName() default "";
}

@ -0,0 +1,41 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.cloud.tsf.route.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;
/**
* Empty annotation. Compatible with old versions TSF SDK.
* <p>
* Deprecated since 2.0.0.0.
*
* @author Haotian Zhang
*/
@Deprecated
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableTsfRoute {
}

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.loadbalancer.ILoadBalancer;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import java.util.ArrayList;
import java.util.Collection;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import java.util.Collections;
import java.util.HashMap;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.feign;
package com.tencent.cloud.polaris.router.instrument.feign;
import java.util.Collections;
import java.util.List;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.net.URI;
import java.util.Collections;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.resttemplate;
package com.tencent.cloud.polaris.router.instrument.resttemplate;
import java.net.URI;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.scg;
package com.tencent.cloud.polaris.router.instrument.scg;
import java.net.URI;
import java.util.HashMap;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.scg;
package com.tencent.cloud.polaris.router.instrument.scg;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.polaris.metadata.core.MessageMetadataContainer;

@ -0,0 +1,83 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.async;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import com.tencent.cloud.plugin.threadlocal.TaskExecutorWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Role;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_CONSUMER;
import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_SUPPLIER;
/**
* polaris async executor for @Async .
*
* @author Haotian Zhang
*/
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnProperty(name = "spring.cloud.tencent.async.enabled")
public class PolarisAsyncConfiguration implements AsyncConfigurer {
private static final Logger logger = LoggerFactory.getLogger(PolarisAsyncConfiguration.class);
@Primary
@Bean("polarisAsyncExecutor")
public TaskExecutor polarisAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int corePoolSize = 10;
executor.setCorePoolSize(corePoolSize);
int maxPoolSize = 50;
executor.setMaxPoolSize(maxPoolSize);
int queueCapacity = 10;
executor.setQueueCapacity(queueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
String threadNamePrefix = "polaris-async-executor-";
executor.setThreadNamePrefix(threadNamePrefix);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(5);
executor.initialize();
TaskExecutor executorWrapper = new TaskExecutorWrapper<>(executor, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER);
logger.info("Created async executor with corePoolSize:{}, maxPoolSize:{}, queueCapacity:{}", corePoolSize, maxPoolSize, queueCapacity);
return executorWrapper;
}
@Override
public Executor getAsyncExecutor() {
return polarisAsyncExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> logger.error("Execute asynchronous tasks '{}' failed.", method, ex);
}
}

@ -0,0 +1,68 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.common.metadata;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.tencent.cloud.common.util.JacksonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Metadata Context for cross thread.
*
* @author Haotian Zhang
*/
public class CrossThreadMetadataContext {
private static final Logger LOG = LoggerFactory.getLogger(CrossThreadMetadataContext.class);
/**
* Get metadata context from previous thread.
*/
public static final Supplier<CrossThreadMetadataContext> CROSS_THREAD_METADATA_CONTEXT_SUPPLIER = () -> {
CrossThreadMetadataContext crossThreadMetadataContext = new CrossThreadMetadataContext();
crossThreadMetadataContext.setMetadataContext(MetadataContextHolder.get());
if (LOG.isDebugEnabled()) {
LOG.debug("Context map is got: {}", JacksonUtils.serialize2Json(crossThreadMetadataContext));
}
return crossThreadMetadataContext;
};
/**
* Set metadata context to current thread.
*/
public static final Consumer<CrossThreadMetadataContext> CROSS_THREAD_METADATA_CONTEXT_CONSUMER = crossThreadMetadataContext -> {
MetadataContextHolder.set(crossThreadMetadataContext.getMetadataContext());
if (LOG.isDebugEnabled()) {
LOG.debug("Context map is set: {}", JacksonUtils.serialize2Json(crossThreadMetadataContext));
}
};
private MetadataContext metadataContext;
public MetadataContext getMetadataContext() {
return metadataContext;
}
public void setMetadataContext(MetadataContext metadataContext) {
this.metadataContext = metadataContext;
}
}

@ -142,8 +142,8 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
return values;
}
public void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream, Map<String, String> values) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream);
public void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller, Map<String, String> values) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
for (Map.Entry<String, String> entry : values.entrySet()) {
metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), transitiveType);
}

@ -84,4 +84,18 @@ public class ApplicationContextAwareUtils implements ApplicationContextAware {
}
return property;
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static <T> T getBeanIfExists(Class<T> requiredType) {
try {
return applicationContext.getBean(requiredType);
}
catch (Throwable e) {
LOGGER.warn("get bean failed, bean type: {}", requiredType.getName());
return null;
}
}
}

@ -0,0 +1,83 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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 org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
/**
* @author heihuliliu
*/
public final class FeignUtil {
/**
* Feign client spec.
*/
public static final String FEIGN_CLIENT_SPECIF = ".FeignClientSpecification";
/**
* Default Feign client spec.
*/
public static final String FEIGN_CLIENT_DEFAULT = "default.";
/**
* regular expression that parses ${xxx} .
*/
public static final String REGEX = "^[$][{](.*)[}]$";
/**
* replacement of ${xxx}.
*/
public static final String REPLACEMENT = "$1";
private FeignUtil() {
}
/**
* TODO If @FeignClient specifies contextId, the service name will not be obtained correctly, but the contextId will be obtained.
*
* @param name feign name.
* @param context application context.
* @return service name.
*/
public static String analysisFeignName(String name, ApplicationContext context) {
String feignName = "";
String feignPath = name.substring(0, name.indexOf(FEIGN_CLIENT_SPECIF));
// Handle the case where the service name is a variable
if (feignPath.matches(REGEX)) {
feignPath = context.getEnvironment().getProperty(feignPath.replaceAll(REGEX, REPLACEMENT));
}
if (StringUtils.hasText(feignPath)) {
// The case of multi-level paths
String[] feignNames = feignPath.split("/");
if (feignNames.length > 1) {
for (int i = 0; i < feignNames.length; i++) {
if (StringUtils.hasText(feignNames[i])) {
feignName = feignNames[i];
break;
}
}
}
else {
feignName = feignNames[0];
}
}
return feignName;
}
}

@ -0,0 +1,45 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import com.tencent.polaris.threadlocal.cross.CompletableFutureUtils;
import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_CONSUMER;
import static com.tencent.cloud.common.metadata.CrossThreadMetadataContext.CROSS_THREAD_METADATA_CONTEXT_SUPPLIER;
/**
* Polaris CompletableFuture Utils.
*
* @author Haotian Zhang
*/
public final class PolarisCompletableFutureUtils {
private PolarisCompletableFutureUtils() {
}
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return CompletableFutureUtils.supplyAsync(supplier, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER);
}
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return CompletableFutureUtils.runAsync(runnable, CROSS_THREAD_METADATA_CONTEXT_SUPPLIER, CROSS_THREAD_METADATA_CONTEXT_CONSUMER);
}
}

@ -15,10 +15,11 @@
* specific language governing permissions and limitations under the License.
*/
package org.springframework.tsf.core.context;
package org.springframework.tsf.core;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.metadata.MetadataContext;
@ -32,6 +33,7 @@ public final class TsfContext {
static final int MAX_KEY_LENGTH = 32;
static final int MAX_VALUE_LENGTH = 128;
private static final String CUSTOM_METADATA = "tsf-custom-metadata";
private TsfContext() {
@ -74,4 +76,19 @@ public final class TsfContext {
MAX_VALUE_LENGTH));
}
}
public static void putCustomMetadata(Object customMetadata) {
if (customMetadata == null) {
return;
}
MetadataContext tsfCoreContext = MetadataContextHolder.get();
Map<String, String> tagMap = new HashMap<>();
try {
tagMap.put(CUSTOM_METADATA, customMetadata.toString());
}
catch (Throwable throwable) {
throw new RuntimeException("Failed to parse custom metadata", throwable);
}
tsfCoreContext.putMetadataAsMap(MetadataType.CUSTOM, TransitiveType.NONE, false, tagMap);
}
}

@ -0,0 +1,52 @@
package org.springframework.tsf.core.util;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
/**
* Spring context utils.
* <p>
* Deprecated since 2.0.0.0.
*
* @author hongweizhu
*/
@Deprecated
public class TsfSpringContextAware {
/**
* Get application context.
* @return application context
*/
public static ApplicationContext getApplicationContext() {
return ApplicationContextAwareUtils.getApplicationContext();
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// do nothing.
}
/**
* Get application property.
* @param key property name
* @return property value
*/
public static String getProperties(String key) {
return ApplicationContextAwareUtils.getProperties(key);
}
/**
* Get application property. If null, return default.
* @param key property name
* @param defaultValue default value
* @return property value
*/
public static String getProperties(String key, String defaultValue) {
return ApplicationContextAwareUtils.getProperties(key, defaultValue);
}
public static <T> T getBean(Class<T> requiredType) {
return ApplicationContextAwareUtils.getBean(requiredType);
}
}

@ -19,6 +19,12 @@
"name": "spring.cloud.tencent.metadata.headers",
"type": "java.util.List",
"description": "Custom transitive http header key list."
},
{
"name": "spring.cloud.tencent.async.enabled",
"type": "java.lang.Boolean",
"defaultValue": false,
"description": "Async support switch. Default: false."
}
]
}

@ -232,6 +232,12 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-fault-tolerance</artifactId>
<version>${revision}</version>
</dependency>
<!-- third part framework dependencies -->
<dependency>
<groupId>com.google.guava</groupId>

@ -22,6 +22,7 @@ import java.net.URLDecoder;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.quickstart.callee.config.DataSourceProperties;
import com.tencent.cloud.quickstart.callee.service.FaultToleranceService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -59,6 +60,9 @@ public class QuickstartCalleeController {
@Autowired
private DataSourceProperties dataSourceProperties;
@Autowired
private FaultToleranceService faultToleranceService;
/**
* Get sum of two value.
* @param value1 value 1
@ -126,7 +130,22 @@ public class QuickstartCalleeController {
@GetMapping("/test/{num}/echo")
public String test(@PathVariable int num) {
LOG.info("Quickstart Callee Service [%s] is detected right.", num);
LOG.info("Quickstart Callee Service [{}] is detected right.", num);
return String.format("Quickstart Callee Service [%s] is detected right.", num);
}
@GetMapping("/faultTolerance/failFast")
public String faultToleranceFailFast() {
return faultToleranceService.failFast();
}
@GetMapping("/faultTolerance/failOver")
public String faultToleranceFailOver() {
return faultToleranceService.failOver();
}
@GetMapping("/faultTolerance/forking")
public String faultToleranceForking() {
return faultToleranceService.forking();
}
}

@ -0,0 +1,60 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.service;
import java.util.List;
import com.tencent.cloud.polaris.discovery.refresh.ServiceInstanceChangeCallback;
import com.tencent.cloud.polaris.discovery.refresh.ServiceInstanceChangeListener;
import com.tencent.polaris.api.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* Call back for QuickstartCalleeService.
*
* @author Haotian Zhang
*/
@Component
@ServiceInstanceChangeListener(serviceName = "QuickstartCalleeService")
public class CalleeServiceChangeCallback implements ServiceInstanceChangeCallback {
private static final Logger LOG = LoggerFactory.getLogger(CalleeServiceChangeCallback.class);
@Override
public void callback(List<Instance> currentServiceInstances, List<Instance> addServiceInstances, List<Instance> deleteServiceInstances) {
String current = generateNodeList(currentServiceInstances);
String add = generateNodeList(addServiceInstances);
String delete = generateNodeList(deleteServiceInstances);
LOG.info("current: {}, add: {}, delete: {}", current, add, delete);
}
private String generateNodeList(List<Instance> deleteServiceInstances) {
StringBuilder nodeListStr = new StringBuilder("[");
for (Instance instance : deleteServiceInstances) {
if (nodeListStr.length() > 1) {
nodeListStr.append(", ");
}
nodeListStr.append(instance.getHost()).append(":").append(instance.getPort());
}
nodeListStr.append("]");
return nodeListStr.toString();
}
}

@ -0,0 +1,62 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.service;
import java.util.concurrent.atomic.AtomicInteger;
import com.tencent.cloud.plugin.faulttolerance.annotation.FaultTolerance;
import com.tencent.cloud.plugin.faulttolerance.model.FaultToleranceStrategy;
import org.springframework.stereotype.Service;
/**
* Service for fault tolerance.
*
* @author Haotian Zhang
*/
@Service
public class FaultToleranceService {
private final AtomicInteger failOverCount = new AtomicInteger(0);
private final AtomicInteger forkingCount = new AtomicInteger(0);
@FaultTolerance(strategy = FaultToleranceStrategy.FAIL_FAST, fallbackMethod = "fallback")
public String failFast() {
throw new RuntimeException("NO");
}
public String fallback() {
return "fallback";
}
@FaultTolerance(strategy = FaultToleranceStrategy.FAIL_OVER, maxAttempts = 3)
public String failOver() {
if (failOverCount.incrementAndGet() % 4 == 0) {
return "OK";
}
throw new RuntimeException("NO");
}
@FaultTolerance(strategy = FaultToleranceStrategy.FORKING, parallelism = 4)
public String forking() {
if (forkingCount.incrementAndGet() % 4 == 0) {
return "OK";
}
throw new RuntimeException("NO");
}
}

@ -17,9 +17,6 @@
package com.tencent.cloud.quickstart.caller;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreaker;
import com.tencent.cloud.quickstart.caller.circuitbreaker.CustomFallback;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
@ -50,27 +47,7 @@ public class QuickstartCallerApplication {
@Bean
@LoadBalanced
public RestTemplate defaultRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
@Bean
@LoadBalanced
@PolarisCircuitBreaker
public RestTemplate restTemplateFallbackFromPolaris() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
@Bean
@LoadBalanced
@PolarisCircuitBreaker(fallbackClass = CustomFallback.class)
public RestTemplate restTemplateFallbackFromCode() {
public RestTemplate calleeRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);

@ -49,16 +49,8 @@ public class CircuitBreakerController {
private CircuitBreakerQuickstartCalleeServiceWithFallback circuitBreakerQuickstartCalleeServiceWithFallback;
@Autowired
@Qualifier("defaultRestTemplate")
private RestTemplate defaultRestTemplate;
@Autowired
@Qualifier("restTemplateFallbackFromPolaris")
private RestTemplate restTemplateFallbackFromPolaris;
@Autowired
@Qualifier("restTemplateFallbackFromCode")
private RestTemplate restTemplateFallbackFromCode;
@Qualifier("calleeRestTemplate")
private RestTemplate calleeRestTemplate;
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
@ -110,7 +102,7 @@ public class CircuitBreakerController {
public String circuitBreakRestTemplate() {
return circuitBreakerFactory
.create(MetadataContext.LOCAL_NAMESPACE + "#QuickstartCalleeService#/quickstart/callee/circuitBreak#http#GET")
.run(() -> defaultRestTemplate.getForObject("/quickstart/callee/circuitBreak", String.class),
.run(() -> calleeRestTemplate.getForObject("/quickstart/callee/circuitBreak", String.class),
throwable -> "trigger the refuse for service callee."
);
}
@ -122,17 +114,7 @@ public class CircuitBreakerController {
@GetMapping("/rest/fallbackFromPolaris/wildcard/{uid}")
public ResponseEntity<String> 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<String> circuitBreakRestTemplateFallbackFromCodeWildcard(@PathVariable String uid) {
String path = String.format("/quickstart/callee/circuitBreak/wildcard/%s", uid);
return restTemplateFallbackFromCode.getForEntity(path, String.class);
return calleeRestTemplate.getForEntity(path, String.class);
}
/**
@ -142,21 +124,7 @@ public class CircuitBreakerController {
@GetMapping("/rest/fallbackFromPolaris")
public ResponseEntity<String> circuitBreakRestTemplateFallbackFromPolaris() {
try {
return restTemplateFallbackFromPolaris.getForEntity("/quickstart/callee/circuitBreak", String.class);
}
catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) {
return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode());
}
}
/**
* RestTemplate circuit breaker with fallback from code.
* @return circuit breaker information of callee
*/
@GetMapping("/rest/fallbackFromCode")
public ResponseEntity<String> circuitBreakRestTemplateFallbackFromCode() {
try {
return restTemplateFallbackFromCode.getForEntity("/quickstart/callee/circuitBreak", String.class);
return calleeRestTemplate.getForEntity("/quickstart/callee/circuitBreak", String.class);
}
catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) {
return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode());

@ -14,27 +14,7 @@
<dependencies>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
<artifactId>spring-cloud-starter-tencent-all</artifactId>
</dependency>
<dependency>
@ -46,16 +26,6 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-trace-plugin</artifactId>
</dependency>
</dependencies>
<build>

@ -17,8 +17,6 @@
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;
@ -37,7 +35,6 @@ public class ConsumerApplication {
@LoadBalanced
@Bean
@PolarisCircuitBreaker
public RestTemplate restTemplate() {
return new RestTemplate();
}

@ -19,14 +19,17 @@ package com.tencent.cloud.tsf.demo.consumer.controller;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import com.tencent.cloud.common.util.PolarisCompletableFutureUtils;
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.TsfContext;
import org.springframework.tsf.core.entity.Tag;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@ -62,7 +65,30 @@ public class ConsumerController {
catch (CallAbortedException callAbortedException) {
return callAbortedException.getMessage();
}
}
@RequestMapping(value = "/echo-rest-async/{str}", method = RequestMethod.GET)
public String restAsync(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) throws ExecutionException, InterruptedException {
if (StringUtils.isNotBlank(tagName)) {
TsfContext.putTag(tagName, tagValue);
}
TsfContext.putTag("operation", "rest");
Map<String, String> mTags = new HashMap<>();
mTags.put("rest-trace-key1", "value1");
mTags.put("rest-trace-key2", "value2");
TsfContext.putTags(mTags, Tag.ControlFlag.TRANSITIVE);
CompletableFuture<String> echoFuture = PolarisCompletableFutureUtils.supplyAsync(() -> {
try {
return restTemplate.getForObject("http://provider-demo/echo/" + str, String.class);
}
catch (CallAbortedException callAbortedException) {
return callAbortedException.getMessage();
}
});
return echoFuture.get();
}
@RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET)

@ -0,0 +1,54 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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 com.tencent.polaris.api.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.tsf.core.TsfContext;
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 SdkBaseTest {
private static final Logger LOG = LoggerFactory.getLogger(SdkBaseTest.class);
@Autowired
private RestTemplate restTemplate;
// 调用一次provider接口
@RequestMapping(value = "/echo-once/{str}", method = RequestMethod.GET)
public String restOnceProvider(@PathVariable String str,
@RequestParam(required = false) String tagName,
@RequestParam(required = false) String tagValue) {
if (!StringUtils.isEmpty(tagName)) {
TsfContext.putTag(tagName, tagValue);
}
LOG.info("start call echo-once");
String result = restTemplate.getForObject("http://provider-demo/echo/" + str, String.class);
LOG.info("end call echo-once, the result is : " + result);
return result;
}
}

@ -21,6 +21,7 @@
<module>spring-cloud-tencent-lossless-plugin</module>
<module>spring-cloud-starter-tencent-threadlocal-plugin</module>
<module>spring-cloud-starter-tencent-trace-plugin</module>
<module>spring-cloud-starter-tencent-fault-tolerance</module>
</modules>
</project>

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tencent-plugin-starters</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-starter-tencent-fault-tolerance</artifactId>
<name>Spring Cloud Starter Tencent Fault Tolerance Plugin</name>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,95 @@
/*
* Tencent is pleased to support the open source community by making spring-cloud-tencent available.
*
* Copyright (C) 2021 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.faulttolerance.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 com.tencent.cloud.plugin.faulttolerance.model.FaultToleranceStrategy;
/**
* Annotation for Fault Tolerance.
*
* @author Haotian Zhang
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface FaultTolerance {
/**
* Specifies a method to process fallback logic.
* A fallback method should be defined in the same class where is @FaultTolerance.
* Also, a fallback method should have same signature to a method.
* for example:
* <p>
* <pre>@FaultTolerance(fallbackMethod = "getByIdFallback").
* public String getById(String id) {
* // original method implementation
* }
* public String getByIdFallback(String id) {
* // fallback method implementation
* }
* </pre>
* </p>
* @return method name
*/
String fallbackMethod() default "";
/**
* Defines exceptions which should be ignored.
*
* @return exceptions to ignore
*/
Class<? extends Throwable>[] ignoreExceptions() default {};
/**
* Defines exceptions which should be retried.
* Default is all exceptions.
*
* @return exceptions to wrap
*/
Class<? extends Throwable>[] raisedExceptions() default {};
/**
* Defines the fault tolerance strategy, the default is fast fail strategy.
* @see FaultToleranceStrategy
*
* @return the fault tolerance strategy
*/
FaultToleranceStrategy strategy() default FaultToleranceStrategy.FAIL_FAST;
/**
* Number of retries, only used under {@link FaultToleranceStrategy}.FAIL_OVER strategy. Default is 0.
*
* @return the maximum number of retry attempts
*/
int maxAttempts() default 0;
/**
* The parallelism of forking is only used under the {@link FaultToleranceStrategy}.FORKING strategy.
*
* @return the parallelism level
*/
int parallelism() default 1;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save