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

Co-authored-by: Haotian Zhang <skyebefreeman@qq.com>
pull/1543/head
Fishtail 4 months ago committed by SkyeBeFreeman
parent 853202b1f9
commit 7e6c55e35f

@ -25,3 +25,4 @@
- [docs:update circuit breaker examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1521) - [docs:update circuit breaker examples.](https://github.com/Tencent/spring-cloud-tencent/pull/1521)
- [feat:support zuul circuit breaker fallback response.](https://github.com/Tencent/spring-cloud-tencent/pull/1522) - [feat:support zuul circuit breaker fallback response.](https://github.com/Tencent/spring-cloud-tencent/pull/1522)
- [feat:support auth.](https://github.com/Tencent/spring-cloud-tencent/pull/1541) - [feat:support auth.](https://github.com/Tencent/spring-cloud-tencent/pull/1541)
- [feat:support smooth upgrade from tsf. ](https://github.com/Tencent/spring-cloud-tencent/pull/1542)

@ -59,6 +59,17 @@
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-auth</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-auth</artifactId>
</dependency> </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> </dependencies>
<build> <build>

@ -15,11 +15,6 @@
<dependencies> <dependencies>
<!-- Spring Cloud Tencent dependencies start --> <!-- Spring Cloud Tencent dependencies start -->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-commons</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-rpc-enhancement</artifactId> <artifactId>spring-cloud-tencent-rpc-enhancement</artifactId>

@ -27,8 +27,8 @@ import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; 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.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter;
import org.assertj.core.util.Maps; import org.assertj.core.util.Maps;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; 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=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.auth.config.PolarisAuthPropertiesBootstrapConfiguration 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; package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisCircuitBreakerNameResolver; import com.tencent.cloud.polaris.circuitbreaker.instrument.feign.PolarisCircuitBreakerNameResolver;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignCircuitBreaker; import com.tencent.cloud.polaris.circuitbreaker.instrument.feign.PolarisFeignCircuitBreaker;
import feign.Feign; import feign.Feign;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.lang.reflect.Method;
import java.net.URI; import java.net.URI;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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; import java.lang.reflect.Field;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.api.InvokeHandler;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.api.InvokeHandler;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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; import java.util.function.Function;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.Documented;
import java.lang.annotation.ElementType; 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 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. * 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. * fallback and fallbackClass cannot provide at same time.
* <p>
* Deprecated since 2.0.0.0.
* *
* @author sean yu * @author sean yu
*/ */
@Target({ElementType.METHOD}) @Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Deprecated
public @interface PolarisCircuitBreaker { public @interface PolarisCircuitBreaker {
/** /**

@ -15,13 +15,16 @@
* specific language governing permissions and limitations under the License. * 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. * PolarisCircuitBreakerFallback.
* <p>
* Deprecated since 2.0.0.0.
* *
* @author sean yu * @author sean yu
*/ */
@Deprecated
public interface PolarisCircuitBreakerFallback { public interface PolarisCircuitBreakerFallback {
PolarisCircuitBreakerHttpResponse fallback(); PolarisCircuitBreakerHttpResponse fallback();

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.ByteArrayInputStream;
import java.io.IOException; 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.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreaker; 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.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;

@ -17,7 +17,7 @@
package org.springframework.cloud.openfeign; 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.Feign;
import feign.Target; 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 {
}

@ -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.polaris.circuitbreaker.common;
import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for ${@link PolarisResultToErrorCode}.
*
* @author Shedfree Wu
*/
@ExtendWith(MockitoExtension.class)
class PolarisResultToErrorCodeTest {
private final PolarisResultToErrorCode converter = new PolarisResultToErrorCode();
@Test
void testOnSuccess() {
assertThat(converter.onSuccess("any value")).isEqualTo(200);
}
@Test
void testOnErrorWithWebClientResponseException() {
// Given
WebClientResponseException exception = WebClientResponseException.create(
404, "Not Found", null, null, null);
// When
int errorCode = converter.onError(exception);
// Then
assertThat(errorCode).isEqualTo(404);
}
@Test
void testOnErrorWithCircuitBreakerStatusCodeException() {
// When
int errorCode = converter.onError(new RuntimeException("test"));
// Then
assertThat(errorCode).isEqualTo(-1);
}
@Test
void testOnErrorWithUnknownException() {
// Given
RuntimeException exception = new RuntimeException("Unknown error");
// When
int errorCode = converter.onError(exception);
// Then
assertThat(errorCode).isEqualTo(-1);
}
@Test
void testCheckClassExist() throws Exception {
// Given
Method checkClassExist = PolarisResultToErrorCode.class.getDeclaredMethod("checkClassExist", String.class);
checkClassExist.setAccessible(true);
PolarisResultToErrorCode converter = new PolarisResultToErrorCode();
// test exist class
boolean result1 = (boolean) checkClassExist.invoke(converter, "java.lang.String");
assertThat(result1).isTrue();
// test not exist class
boolean result2 = (boolean) checkClassExist.invoke(converter, "com.nonexistent.Class");
assertThat(result2).isFalse();
}
}

@ -18,7 +18,7 @@
package com.tencent.cloud.polaris.circuitbreaker.config; package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.common.CircuitBreakerConfigModifier; 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.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.lang.reflect.Method;

@ -0,0 +1,216 @@
/*
* 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.circuitbreaker.instrument.feign;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.polaris.circuitbreaker.exception.FallbackWrapperException;
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import feign.InvocationHandlerFactory;
import feign.Target;
import feign.codec.Decoder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.openfeign.FallbackFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for ${@link PolarisFeignCircuitBreakerInvocationHandler}.
*
* @author Shedfree Wu
*/
@ExtendWith(MockitoExtension.class)
class PolarisFeignCircuitBreakerInvocationHandlerTest {
@Mock
private Target<?> target;
@Mock
private InvocationHandlerFactory.MethodHandler methodHandler;
@Mock
private FallbackFactory<TestInterface> fallbackFactory;
@Mock
private Decoder decoder;
private Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
private PolarisFeignCircuitBreakerInvocationHandler handler;
private Method testMethod;
@BeforeEach
void setUp() throws Exception {
dispatch = new HashMap<>();
testMethod = TestInterface.class.getDeclaredMethod("testMethod");
dispatch.put(testMethod, methodHandler);
handler = new PolarisFeignCircuitBreakerInvocationHandler(
target,
dispatch,
fallbackFactory,
decoder
);
}
@Test
void testConstructorWithNullTarget() {
assertThatThrownBy(() ->
new PolarisFeignCircuitBreakerInvocationHandler(
null, dispatch, fallbackFactory, decoder
)
).isInstanceOf(NullPointerException.class);
}
@Test
void testConstructorWithNullDispatch() {
assertThatThrownBy(() ->
new PolarisFeignCircuitBreakerInvocationHandler(
target, null, fallbackFactory, decoder
)).isInstanceOf(NullPointerException.class);
}
@Test
void testToFallbackMethod() throws Exception {
Method method = TestInterface.class.getMethod("testMethod");
Map<Method, InvocationHandlerFactory.MethodHandler> testDispatch = new HashMap<>();
testDispatch.put(method, methodHandler);
Map<Method, Method> result = PolarisFeignCircuitBreakerInvocationHandler.toFallbackMethod(testDispatch);
assertThat(result).isNotNull();
assertThat(result.containsKey(method)).isTrue();
assertThat(result.get(method)).isEqualTo(method);
}
@Test
void testEqualsMethod() throws Throwable {
Method equalsMethod = Object.class.getMethod("equals", Object.class);
Object mockProxy = mock(Object.class);
// Test equals with null
assertThat((Boolean) handler.invoke(mockProxy, equalsMethod, new Object[] {null})).isFalse();
// Test equals with non-proxy object
assertThat((Boolean) handler.invoke(mockProxy, equalsMethod, new Object[] {new Object()})).isFalse();
}
@Test
void testToStringMethod() throws Throwable {
Method toStringMethod = Object.class.getMethod("toString");
Object mockProxy = mock(Object.class);
when(target.toString()).thenReturn("TestTarget");
assertThat(handler.invoke(mockProxy, toStringMethod, null)).isEqualTo("TestTarget");
}
@Test
void testCustomFallbackFactoryWithFallbackError() throws Throwable {
// Arrange
handler = new PolarisFeignCircuitBreakerInvocationHandler(target, dispatch, fallbackFactory, decoder);
Exception originalException = new RuntimeException("Original error");
when(methodHandler.invoke(any())).thenThrow(originalException);
TestImpl testImpl = new TestImpl();
when(fallbackFactory.create(any())).thenReturn(testImpl);
// Act
assertThatThrownBy(() -> handler.invoke(null, testMethod, new Object[] {})).isInstanceOf(FallbackWrapperException.class);
}
@Test
void testCustomFallbackFactoryWithFallbackError2() throws Throwable {
// Arrange
handler = new PolarisFeignCircuitBreakerInvocationHandler(target, dispatch, fallbackFactory, decoder);
Exception originalException = new RuntimeException("Original error");
when(methodHandler.invoke(any())).thenThrow(originalException);
TestImpl2 testImpl = new TestImpl2();
when(fallbackFactory.create(any())).thenReturn(testImpl);
// Act
assertThatThrownBy(() -> handler.invoke(null, testMethod, new Object[] {})).
isInstanceOf(RuntimeException.class).hasMessage("test");
}
@Test
void testDefaultFallbackCreation() throws Throwable {
// Arrange
handler = new PolarisFeignCircuitBreakerInvocationHandler(target, dispatch, null, decoder);
CircuitBreakerStatus.FallbackInfo fallbackInfo = new CircuitBreakerStatus.FallbackInfo(200, new HashMap<>(), "mock body");
CallAbortedException originalException = new CallAbortedException("test rule", fallbackInfo);
Object expected = new Object();
when(methodHandler.invoke(any())).thenThrow(originalException);
when(decoder.decode(any(), any())).thenReturn(expected);
// Act
Object result = handler.invoke(null, testMethod, new Object[] {});
// Verify
assertThat(result).isEqualTo(expected);
}
@Test
void testEquals() {
PolarisFeignCircuitBreakerInvocationHandler testHandler = new PolarisFeignCircuitBreakerInvocationHandler(
target,
dispatch,
fallbackFactory,
decoder
);
assertThat(testHandler).isEqualTo(handler);
assertThat(testHandler.hashCode()).isEqualTo(handler.hashCode());
}
interface TestInterface {
String testMethod() throws InvocationTargetException;
}
static class TestImpl implements TestInterface {
@Override
public String testMethod() throws InvocationTargetException {
throw new InvocationTargetException(new RuntimeException("test"));
}
}
static class TestImpl2 implements TestInterface {
@Override
public String testMethod() throws InvocationTargetException {
throw new RuntimeException("test");
}
}
}

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.Feign;
import feign.RequestLine; import feign.RequestLine;

@ -0,0 +1,133 @@
/*
* 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.circuitbreaker.instrument.feign;
import feign.Feign;
import feign.RequestLine;
import feign.Target;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.openfeign.FallbackFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Tests for {@link PolarisFeignCircuitBreaker}.
*/
public class PolarisFeignCircuitBreakerTest {
private PolarisFeignCircuitBreaker.Builder builder;
@BeforeEach
public void setUp() {
builder = PolarisFeignCircuitBreaker.builder();
}
@Test
public void testBuilderNotNull() {
assertThat(builder).isNotNull();
}
@Test
public void testTargetWithFallback() {
// Mock the target
Class<MyService> targetType = MyService.class;
String name = "myService";
Target<MyService> target = mock(Target.class);
// mock return value
when(target.type()).thenReturn(targetType);
when(target.name()).thenReturn(name);
// Mock the fallback
MyService fallback = mock(MyService.class);
when(fallback.sayHello()).thenReturn("Fallback Hello");
// Call the target method
MyService result = builder.target(target, fallback);
// Verify that the result is not null and the fallback factory is used
assertThat(result).isNotNull();
assertThat(result.sayHello()).isEqualTo("Fallback Hello");
}
@Test
public void testTargetWithFallbackFactory() {
// Mock the target and fallback factory
Class<MyService> targetType = MyService.class;
String name = "myService";
Target<MyService> target = mock(Target.class);
// mock return value
when(target.type()).thenReturn(targetType);
when(target.name()).thenReturn(name);
FallbackFactory<MyService> fallbackFactory = mock(FallbackFactory.class);
// Mock the fallback from the factory
MyService fallback = mock(MyService.class);
when(fallback.sayHello()).thenReturn("Fallback Hello");
when(fallbackFactory.create(any())).thenReturn(fallback);
// Call the target method
MyService result = builder.target(target, fallbackFactory);
// Verify that the result is not null and the fallback factory is used
assertThat(result).isNotNull();
assertThat(result.sayHello()).isEqualTo("Fallback Hello");
}
@Test
public void testTargetWithoutFallback() {
// Mock the target
Class<MyService> targetType = MyService.class;
String name = "myService";
Target<MyService> target = mock(Target.class);
// mock return value
when(target.type()).thenReturn(targetType);
when(target.name()).thenReturn(name);
// Call the target method
MyService result = builder.target(target);
// Verify that the result is not null
assertThat(result).isNotNull();
// Additional verifications can be added here based on the implementation
}
@Test
public void testBuildWithNullableFallbackFactory() {
// Call the build method with a null fallback factory
Feign feign = builder.build(null);
// Verify that the Feign instance is not null
assertThat(feign).isNotNull();
// Additional verifications can be added here based on the implementation
}
public interface MyService {
@RequestLine("GET /hello")
String sayHello();
}
}

@ -0,0 +1,209 @@
/*
* 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.config.adapter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry;
import com.tencent.polaris.configuration.api.core.ConfigFileService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.ConfigurableApplicationContext;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
/**
* Tests for {@link PolarisRefreshEntireContextRefresher}.
*
* @author Shedfree Wu
*/
public class PolarisRefreshEntireContextRefresherTest {
@Mock
private PolarisConfigProperties polarisConfigProperties;
@Mock
private SpringValueRegistry springValueRegistry;
@Mock
private ConfigFileService configFileService;
@Mock
private ContextRefresher contextRefresher;
@Mock
private ConfigurableApplicationContext applicationContext;
@Mock
private PolarisConfigCustomExtensionLayer mockExtensionLayer;
private PolarisRefreshEntireContextRefresher refresher;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
refresher = new PolarisRefreshEntireContextRefresher(
polarisConfigProperties,
springValueRegistry,
configFileService,
contextRefresher
);
refresher.setApplicationContext(applicationContext);
}
@Test
void testRefreshSpringValue() {
// test refreshSpringValue method, it should do nothing
refresher.refreshSpringValue("test.key");
// Verify
verifyNoInteractions(contextRefresher);
verifyNoInteractions(springValueRegistry);
}
@Test
void testRefreshConfigurationPropertiesWithRefreshScope() {
// Arrange
Set<String> changeKeys = new HashSet<>();
changeKeys.add("test.key1");
changeKeys.add("test.key2");
// mock test.key1 in refresh scope
when(springValueRegistry.isRefreshScopeKey("test.key1")).thenReturn(true);
// Act
refresher.refreshConfigurationProperties(changeKeys);
// Verify
verify(contextRefresher, times(1)).refresh();
verifyNoInteractions(applicationContext);
}
@Test
void testRefreshConfigurationPropertiesWithoutRefreshScope() {
// Arrange
Set<String> changeKeys = new HashSet<>();
changeKeys.add("test.key1");
changeKeys.add("test.key2");
// mock a key not in refresh scope
when(springValueRegistry.isRefreshScopeKey(anyString())).thenReturn(false);
// Act
refresher.refreshConfigurationProperties(changeKeys);
// Verify
verify(contextRefresher, never()).refresh();
verify(applicationContext, times(1))
.publishEvent(any(EnvironmentChangeEvent.class));
}
@Test
void testSetApplicationContext() {
// Arrange
ConfigurableApplicationContext newContext = mock(ConfigurableApplicationContext.class);
// Act
refresher.setApplicationContext(newContext);
// Verify
Set<String> changeKeys = new HashSet<>();
changeKeys.add("test.key");
when(springValueRegistry.isRefreshScopeKey(anyString())).thenReturn(false);
refresher.refreshConfigurationProperties(changeKeys);
verify(newContext, times(1)).publishEvent(any(EnvironmentChangeEvent.class));
}
@Test
void testRefreshConfigurationPropertiesWithEmptyChangeKeys() {
// Arrange
Set<String> changeKeys = new HashSet<>();
// Act
refresher.refreshConfigurationProperties(changeKeys);
// Verify
verify(contextRefresher, never()).refresh();
verify(applicationContext, times(1))
.publishEvent(any(EnvironmentChangeEvent.class));
}
@Test
void testRefreshConfigurationPropertiesWithMultipleRefreshScopeKeys() {
// Arrange
Set<String> changeKeys = new HashSet<>();
changeKeys.add("test.key1");
changeKeys.add("test.key2");
changeKeys.add("test.key3");
// mock multiple keys in refresh scope
when(springValueRegistry.isRefreshScopeKey(anyString())).thenReturn(true);
// Act
refresher.refreshConfigurationProperties(changeKeys);
// Verify
verify(contextRefresher, times(1)).refresh();
verifyNoInteractions(applicationContext);
}
@Test
void testPolarisConfigCustomExtensionLayer() throws Exception {
refresher.setRegistered(true);
Field field = PolarisConfigPropertyAutoRefresher.class
.getDeclaredField("polarisConfigCustomExtensionLayer");
field.setAccessible(true);
field.set(refresher, mockExtensionLayer);
Method method = PolarisConfigPropertyAutoRefresher.class
.getDeclaredMethod("customInitRegisterPolarisConfig", PolarisConfigPropertyAutoRefresher.class);
method.setAccessible(true);
method.invoke(refresher, refresher);
method = PolarisConfigPropertyAutoRefresher.class.getDeclaredMethod(
"customRegisterPolarisConfigPublishChangeListener",
PolarisPropertySource.class, PolarisPropertySource.class);
method.setAccessible(true);
method.invoke(refresher, null, null);
// Verify
verify(mockExtensionLayer, times(1)).initRegisterConfig(refresher);
}
}

@ -25,6 +25,7 @@ import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.GzipUtil; import com.tencent.cloud.common.util.GzipUtil;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties; import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.contract.config.PolarisContractProperties; import com.tencent.cloud.polaris.contract.config.PolarisContractProperties;
@ -57,7 +58,7 @@ import org.springframework.util.CollectionUtils;
*/ */
public class PolarisContractReporter implements ApplicationListener<ApplicationReadyEvent> { 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.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource;
private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource;
@ -100,7 +101,7 @@ public class PolarisContractReporter implements ApplicationListener<ApplicationR
ReportServiceContractRequest request = new ReportServiceContractRequest(); ReportServiceContractRequest request = new ReportServiceContractRequest();
String name = polarisContractProperties.getName(); String name = polarisContractProperties.getName();
if (StringUtils.isBlank(name)) { if (StringUtils.isBlank(name)) {
name = polarisDiscoveryProperties.getService(); name = MetadataContext.LOCAL_SERVICE;
} }
request.setName(name); request.setName(name);
request.setNamespace(polarisDiscoveryProperties.getNamespace()); request.setNamespace(polarisDiscoveryProperties.getNamespace());

@ -47,7 +47,7 @@ public final class FilterConstant {
/** /**
* Swagger resource url prefix. * Swagger resource url prefix.
*/ */
public static final String SWAGGER_RESOURCE_PREFIX = "/swagger-resource/"; public static final String SWAGGER_RESOURCE_PREFIX = "/swagger-resource";
/** /**
* Swagger webjars V2 url prefix. * Swagger webjars V2 url prefix.

@ -38,13 +38,13 @@ import org.springframework.util.StringUtils;
public class TsfApiMetadataGrapher implements SmartLifecycle { public class TsfApiMetadataGrapher implements SmartLifecycle {
private static final Logger logger = LoggerFactory.getLogger(TsfApiMetadataGrapher.class);
private final AtomicBoolean isRunning = new AtomicBoolean(false); private final AtomicBoolean isRunning = new AtomicBoolean(false);
private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource; private final org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource;
private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource; private final org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource;
private final ObjectMapperProvider springdocObjectMapperProvider; private final ObjectMapperProvider springdocObjectMapperProvider;
private Logger logger = LoggerFactory.getLogger(TsfApiMetadataGrapher.class); private final ApplicationContext applicationContext;
private ApplicationContext applicationContext; private final String groupName;
private String groupName;
public TsfApiMetadataGrapher(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource, public TsfApiMetadataGrapher(org.springdoc.webmvc.api.MultipleOpenApiResource multipleOpenApiWebMvcResource,
org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource, org.springdoc.webflux.api.MultipleOpenApiResource multipleOpenApiWebFluxResource,

@ -22,6 +22,12 @@
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-rpc-enhancement</artifactId> <artifactId>spring-cloud-tencent-rpc-enhancement</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-security-crypto</artifactId>
<groupId>org.springframework.security</groupId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>

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

@ -17,14 +17,18 @@
package com.tencent.cloud.polaris.discovery.refresh; package com.tencent.cloud.polaris.discovery.refresh;
import java.util.ArrayList;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.tencent.polaris.api.plugin.registry.AbstractResourceEventListener; 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.RegistryCacheValue;
import com.tencent.polaris.api.pojo.ServiceEventKey; 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.ServiceInstancesByProto;
import com.tencent.polaris.client.pojo.ServicesByProto; import com.tencent.polaris.client.pojo.ServicesByProto;
import org.slf4j.Logger; 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.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.lang.NonNull; 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 * 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 * @author Haotian Zhang
*/ */
public class PolarisServiceStatusChangeListener extends AbstractResourceEventListener implements ApplicationEventPublisherAware { public class PolarisServiceStatusChangeListener extends AbstractResourceEventListener
implements ApplicationEventPublisherAware {
/** /**
* Index of service info status. * Index of service info status.
@ -50,9 +54,13 @@ public class PolarisServiceStatusChangeListener extends AbstractResourceEventLis
public static final AtomicLong INDEX = new AtomicLong(0); public static final AtomicLong INDEX = new AtomicLong(0);
private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceStatusChangeListener.class); private static final Logger LOG = LoggerFactory.getLogger(PolarisServiceStatusChangeListener.class);
private final ServiceInstanceChangeCallbackManager serviceInstanceChangeCallbackManager;
private ApplicationEventPublisher publisher; private ApplicationEventPublisher publisher;
public PolarisServiceStatusChangeListener(ServiceInstanceChangeCallbackManager serviceInstanceChangeCallbackManager) {
this.serviceInstanceChangeCallbackManager = serviceInstanceChangeCallbackManager;
}
@Override @Override
public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue, public void onResourceUpdated(ServiceEventKey svcEventKey, RegistryCacheValue oldValue,
RegistryCacheValue newValue) { RegistryCacheValue newValue) {
@ -88,6 +96,22 @@ public class PolarisServiceStatusChangeListener extends AbstractResourceEventLis
// Trigger reload of gateway route cache. // Trigger reload of gateway route cache.
this.publisher.publishEvent(new HeartbeatEvent(this, INDEX.getAndIncrement())); 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. * 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 java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerFallback; import java.lang.annotation.Retention;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerHttpResponse; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* CustomFallback. * @author Haotian Zhang
*
* @author sean yu
*/ */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component @Component
public class CustomFallback implements PolarisCircuitBreakerFallback { public @interface ServiceInstanceChangeListener {
@Override
public PolarisCircuitBreakerHttpResponse fallback() { /**
return new PolarisCircuitBreakerHttpResponse( * listen service name.
200, * @return service name
new HashMap<String, String>() {{ */
put("Content-Type", "application/json"); String serviceName();
}},
"{\"msg\": \"this is a fallback class\"}");
}
} }

@ -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;
}
}

@ -237,7 +237,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<PolarisRegistrati
InstancesResponse instancesResponse = polarisDiscoveryHandler.getInstances(serviceName); InstancesResponse instancesResponse = polarisDiscoveryHandler.getInstances(serviceName);
Instance[] instances = instancesResponse.getInstances(); Instance[] instances = instancesResponse.getInstances();
if (null == instances) { if (null == instances) {
return null; return "DOWN";
} }
for (Instance instance : instances) { for (Instance instance : instances) {
if (instance.getHost().equalsIgnoreCase(registration.getHost()) if (instance.getHost().equalsIgnoreCase(registration.getHost())
@ -245,7 +245,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<PolarisRegistrati
return instance.isHealthy() ? "UP" : "DOWN"; return instance.isHealthy() ? "UP" : "DOWN";
} }
} }
return null; return "DOWN";
} }
/** /**

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.HashMap;
import java.util.Map; import java.util.Map;

@ -14,8 +14,8 @@
* CONDITIONS OF ANY KIND, either express or implied. See the License for the * CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License. * 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 javax.servlet.ServletContext;
import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled; import com.tencent.cloud.common.tsf.ConditionalOnTsfConsulEnabled;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.context.config.extend.tsf.TsfCoreProperties;
import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties; import com.tencent.cloud.polaris.extend.consul.ConsulDiscoveryProperties;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.ArrayList;
import java.util.Arrays; 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, "defaultValue": false,
"description": "Zero protection test connectivity switch. Default: 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", "name": "spring.cloud.nacos.discovery.enabled",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",

@ -3,6 +3,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\ com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\
com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration,\ com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration,\
com.tencent.cloud.polaris.endpoint.PolarisDiscoveryEndpointAutoConfiguration,\ 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=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.DiscoveryPropertiesBootstrapAutoConfiguration com.tencent.cloud.polaris.DiscoveryPropertiesBootstrapAutoConfiguration

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

@ -104,6 +104,7 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, path); quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, path);
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
LOG.info("block by ratelimit rule, uri:{}", exchange.getRequest().getURI());
ServerHttpResponse response = exchange.getResponse(); ServerHttpResponse response = exchange.getResponse();
DataBuffer dataBuffer; DataBuffer dataBuffer;
if (Objects.nonNull(quotaResponse.getActiveRule()) if (Objects.nonNull(quotaResponse.getActiveRule())

@ -98,6 +98,7 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
try { try {
quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, request.getRequestURI()); quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, request.getRequestURI());
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
LOG.info("block by ratelimit rule, uri:{}", request.getRequestURI());
if (Objects.nonNull(quotaResponse.getActiveRule()) if (Objects.nonNull(quotaResponse.getActiveRule())
&& StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) { && StringUtils.isNotBlank(quotaResponse.getActiveRule().getCustomResponse().getBody())) {
response.setStatus(polarisRateLimitProperties.getRejectHttpCode()); response.setStatus(polarisRateLimitProperties.getRejectHttpCode());

@ -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.common.util.BeanFactoryUtils;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties; import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; 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 com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;

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

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

@ -17,8 +17,8 @@
package com.tencent.cloud.polaris.router.config; package com.tencent.cloud.polaris.router.config;
import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; import com.tencent.cloud.polaris.router.instrument.feign.PolarisCachingSpringLoadBalanceFactory;
import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; import com.tencent.cloud.polaris.router.instrument.feign.RouterLabelFeignInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.netflix.ribbon.RibbonClients; 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.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer; 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.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;

@ -32,19 +32,19 @@ 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.PolarisNamespaceRouterProperties;
import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties;
import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; 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.MetadataRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.NamespaceRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NamespaceRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor; 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.ServletRouterLabelResolver;
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver; import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
import com.tencent.cloud.polaris.router.zuul.PolarisRibbonRoutingFilter; import com.tencent.cloud.polaris.router.zuul.PolarisRibbonRoutingFilter;
import com.tencent.cloud.polaris.router.zuul.RouterLabelZuulFilter; import com.tencent.cloud.polaris.router.zuul.RouterLabelZuulFilter;
import com.tencent.cloud.rpc.enhancement.instrument.zuul.EnhancedZuulPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.zuul.EnhancedZuulPluginRunner;
import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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; import java.util.Map;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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; import com.tencent.cloud.polaris.router.PolarisRouterContext;

@ -15,14 +15,14 @@
* specific language governing permissions and limitations under the License. * 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.IOException;
import java.net.URI; import java.net.URI;
import com.tencent.cloud.polaris.router.PolarisRouterContext; 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.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateWrapInterceptor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;

@ -15,14 +15,14 @@
* specific language governing permissions and limitations under the License. * 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.IOException;
import java.net.URI; import java.net.URI;
import com.tencent.cloud.polaris.router.PolarisRouterContext; 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.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateWrapInterceptor;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.Collections;
import java.util.Comparator; import java.util.Comparator;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.IOException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.net.URI;
import java.util.Collections; import java.util.Collections;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.common.metadata.MetadataContextHolder;
import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider; import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider;

@ -38,7 +38,7 @@ import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils;
import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver; import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver;
import com.tencent.cloud.rpc.enhancement.zuul.EnhancedZuulPluginRunner; import com.tencent.cloud.rpc.enhancement.instrument.zuul.EnhancedZuulPluginRunner;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException; import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

@ -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. * 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.client.config.DefaultClientConfigImpl;
import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.ILoadBalancer;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.ArrayList;
import java.util.Collection; import java.util.Collection;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.Collections;
import java.util.HashMap; import java.util.HashMap;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.Collections;
import java.util.List; import java.util.List;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.net.URI;
import java.util.Collections; import java.util.Collections;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.net.URI;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.net.URI;
import java.util.HashMap; import java.util.HashMap;

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * 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.common.metadata.MetadataContextHolder;
import com.tencent.polaris.metadata.core.MessageMetadataContainer; import com.tencent.polaris.metadata.core.MessageMetadataContainer;

@ -37,7 +37,7 @@ import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer;
import com.tencent.cloud.polaris.router.PolarisRouterContext; import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver; import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver;
import com.tencent.cloud.rpc.enhancement.zuul.EnhancedZuulPluginRunner; import com.tencent.cloud.rpc.enhancement.instrument.zuul.EnhancedZuulPluginRunner;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;

@ -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; return values;
} }
public void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean downstream, Map<String, String> values) { public void putMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller, Map<String, String> values) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, downstream); MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
for (Map.Entry<String, String> entry : values.entrySet()) { for (Map.Entry<String, String> entry : values.entrySet()) {
metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), transitiveType); metadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), transitiveType);
} }

@ -158,24 +158,25 @@ public final class MetadataContextHolder {
Map<String, String> dynamicApplicationMetadata, MetadataProvider callerMetadataProvider) { Map<String, String> dynamicApplicationMetadata, MetadataProvider callerMetadataProvider) {
com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> { com.tencent.polaris.metadata.core.manager.MetadataContextHolder.refresh(metadataManager -> {
// caller transitive metadata to local custom transitive metadata // caller transitive metadata to local custom transitive metadata
MetadataContainer metadataContainerUpstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); MetadataContainer calleeCustomMetadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false);
if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) {
for (Map.Entry<String, String> entry : dynamicTransitiveMetadata.entrySet()) { for (Map.Entry<String, String> entry : dynamicTransitiveMetadata.entrySet()) {
metadataContainerUpstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH); calleeCustomMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.PASS_THROUGH);
} }
} }
// caller disposable metadata to caller custom disposable metadata // caller disposable metadata to caller custom disposable metadata
MetadataContainer metadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.CUSTOM, false); MetadataContainer callerCustomMetadataContainer = metadataManager.getMetadataContainer(MetadataType.CUSTOM, true);
if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) { if (!CollectionUtils.isEmpty(dynamicDisposableMetadata)) {
for (Map.Entry<String, String> entry : dynamicDisposableMetadata.entrySet()) { for (Map.Entry<String, String> entry : dynamicDisposableMetadata.entrySet()) {
metadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.NONE); calleeCustomMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.NONE);
callerCustomMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE);
} }
} }
// caller application metadata to caller application disposable metadata // caller application metadata to caller application disposable metadata
MetadataContainer applicationMetadataContainerDownstream = metadataManager.getMetadataContainer(MetadataType.APPLICATION, true); MetadataContainer callerApplicationMetadataContainer = metadataManager.getMetadataContainer(MetadataType.APPLICATION, true);
if (!CollectionUtils.isEmpty(dynamicApplicationMetadata)) { if (!CollectionUtils.isEmpty(dynamicApplicationMetadata)) {
for (Map.Entry<String, String> entry : dynamicApplicationMetadata.entrySet()) { for (Map.Entry<String, String> entry : dynamicApplicationMetadata.entrySet()) {
applicationMetadataContainerDownstream.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE); callerApplicationMetadataContainer.putMetadataStringValue(entry.getKey(), entry.getValue(), TransitiveType.DISPOSABLE);
} }
} }

@ -84,4 +84,18 @@ public class ApplicationContextAwareUtils implements ApplicationContextAware {
} }
return property; 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. * 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.nio.charset.StandardCharsets;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.tencent.cloud.common.metadata.MetadataContext; 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_KEY_LENGTH = 32;
static final int MAX_VALUE_LENGTH = 128; static final int MAX_VALUE_LENGTH = 128;
private static final String CUSTOM_METADATA = "tsf-custom-metadata";
private TsfContext() { private TsfContext() {
@ -74,4 +76,19 @@ public final class TsfContext {
MAX_VALUE_LENGTH)); 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,69 @@
/*
* 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.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", "name": "spring.cloud.tencent.metadata.headers",
"type": "java.util.List", "type": "java.util.List",
"description": "Custom transitive http header key 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."
} }
] ]
} }

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

Loading…
Cancel
Save