support resttemplate default fallback

pull/913/head
seanyu 3 years ago
parent 8850be6fd4
commit 526f9d4f27

@ -76,12 +76,4 @@ public class PolarisCircuitBreakerAutoConfiguration {
return new CircuitBreakerConfigModifier(properties);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
public static PolarisCircuitBreakerRestTemplateBeanPostProcessor sentinelBeanPostProcessor(
ApplicationContext applicationContext, CircuitBreakerFactory circuitBreakerFactory) {
return new PolarisCircuitBreakerRestTemplateBeanPostProcessor(applicationContext, circuitBreakerFactory);
}
}

@ -28,7 +28,13 @@ import org.springframework.context.annotation.Import;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.polaris.enabled")
@Import({PolarisCircuitBreakerAutoConfiguration.class, ReactivePolarisCircuitBreakerAutoConfiguration.class, PolarisCircuitBreakerFeignClientAutoConfiguration.class})
@Import({
PolarisCircuitBreakerAutoConfiguration.class,
ReactivePolarisCircuitBreakerAutoConfiguration.class,
PolarisCircuitBreakerFeignClientAutoConfiguration.class,
GatewayPolarisCircuitBreakerAutoConfiguration.class,
PolarisCircuitBreakerRestTemplateAutoConfiguration.class
})
public class PolarisCircuitBreakerBootstrapConfiguration {
}

@ -0,0 +1,24 @@
package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerRestTemplateBeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisCircuitBreakerEnabled
@AutoConfigureAfter(PolarisCircuitBreakerAutoConfiguration.class)
public class PolarisCircuitBreakerRestTemplateAutoConfiguration {
@Bean
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
public static PolarisCircuitBreakerRestTemplateBeanPostProcessor polarisCircuitBreakerRestTemplateBeanPostProcessor(
ApplicationContext applicationContext) {
return new PolarisCircuitBreakerRestTemplateBeanPostProcessor(applicationContext);
}
}

@ -60,7 +60,7 @@ public class ReactivePolarisCircuitBreakerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
public ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI) {
public ReactiveCircuitBreakerFactory polarisReactiveCircuitBreakerFactory(CircuitBreakAPI circuitBreakAPI) {
ReactivePolarisCircuitBreakerFactory factory = new ReactivePolarisCircuitBreakerFactory(circuitBreakAPI);
customizers.forEach(customizer -> customizer.customize(factory));
return factory;

@ -11,6 +11,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.AbstractClientHttpResponse;
import static com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateReporter.POLARIS_CIRCUIT_BREAKER_FALLBACK_HEADER;
public class PolarisCircuitBreakerHttpResponse extends AbstractClientHttpResponse {
private final CircuitBreakerStatus.FallbackInfo fallbackInfo;
@ -57,12 +59,12 @@ public class PolarisCircuitBreakerHttpResponse extends AbstractClientHttpRespons
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
if (fallbackInfo.getHeaders() != null) {
HttpHeaders headers = new HttpHeaders();
fallbackInfo.getHeaders().forEach(headers::add);
return headers;
}
return null;
headers.add(POLARIS_CIRCUIT_BREAKER_FALLBACK_HEADER, "true");
return headers;
}
}

@ -13,6 +13,6 @@ public @interface PolarisCircuitBreakerRestTemplate {
String fallback() default "";
Class<PolarisCircuitBreakerFallback> fallbackClass() default PolarisCircuitBreakerFallback.class;
Class<? extends PolarisCircuitBreakerFallback> fallbackClass() default PolarisCircuitBreakerFallback.class;
}

@ -2,6 +2,9 @@ package com.tencent.cloud.polaris.circuitbreaker.resttemplate;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@ -17,20 +20,22 @@ import org.springframework.web.client.RestTemplate;
public class PolarisCircuitBreakerRestTemplateBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
private static final Logger log = LoggerFactory.getLogger(PolarisCircuitBreakerRestTemplateBeanPostProcessor.class);
private final ApplicationContext applicationContext;
private final CircuitBreakerFactory circuitBreakerFactory;
public PolarisCircuitBreakerRestTemplateBeanPostProcessor(ApplicationContext applicationContext, CircuitBreakerFactory circuitBreakerFactory) {
public PolarisCircuitBreakerRestTemplateBeanPostProcessor(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.circuitBreakerFactory = circuitBreakerFactory;
}
private ConcurrentHashMap<String, PolarisCircuitBreakerRestTemplate> cache = new ConcurrentHashMap<>();
private void checkPolarisCircuitBreakerRestTemplate(PolarisCircuitBreakerRestTemplate polarisCircuitBreakerRestTemplate,
String beanName) {
private final ConcurrentHashMap<String, PolarisCircuitBreakerRestTemplate> cache = new ConcurrentHashMap<>();
private void checkPolarisCircuitBreakerRestTemplate(PolarisCircuitBreakerRestTemplate polarisCircuitBreakerRestTemplate) {
if (
StringUtils.hasText(polarisCircuitBreakerRestTemplate.fallback()) &&
!PolarisCircuitBreakerFallback.class.toGenericString().equals(polarisCircuitBreakerRestTemplate.fallbackClass().toGenericString())
) {
throw new IllegalArgumentException("PolarisCircuitBreakerRestTemplate's fallback and fallbackClass could not set at sametime !");
}
}
@Override
@ -45,7 +50,7 @@ public class PolarisCircuitBreakerRestTemplateBeanPostProcessor implements Merge
polarisCircuitBreakerRestTemplate = beanDefinition.getResolvedFactoryMethod()
.getAnnotation(PolarisCircuitBreakerRestTemplate.class);
}
checkPolarisCircuitBreakerRestTemplate(polarisCircuitBreakerRestTemplate, beanName);
checkPolarisCircuitBreakerRestTemplate(polarisCircuitBreakerRestTemplate);
cache.put(beanName, polarisCircuitBreakerRestTemplate);
}
}
@ -63,6 +68,7 @@ public class PolarisCircuitBreakerRestTemplateBeanPostProcessor implements Merge
.append(polarisCircuitBreakerRestTemplate.fallbackClass().getSimpleName());
RestTemplate restTemplate = (RestTemplate) bean;
String interceptorBeanName = interceptorBeanNamePrefix + "@" + bean;
CircuitBreakerFactory circuitBreakerFactory = this.applicationContext.getBean(CircuitBreakerFactory.class);
registerBean(interceptorBeanName, polarisCircuitBreakerRestTemplate, applicationContext, circuitBreakerFactory);
PolarisCircuitBreakerRestTemplateInterceptor polarisCircuitBreakerRestTemplateInterceptor = applicationContext
.getBean(interceptorBeanName, PolarisCircuitBreakerRestTemplateInterceptor.class);

@ -5,7 +5,6 @@ import java.lang.reflect.Method;
import com.tencent.polaris.api.pojo.CircuitBreakerStatus;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.context.ApplicationContext;
@ -14,6 +13,7 @@ import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
public class PolarisCircuitBreakerRestTemplateInterceptor implements ClientHttpRequestInterceptor {
@ -45,11 +45,11 @@ public class PolarisCircuitBreakerRestTemplateInterceptor implements ClientHttpR
}
},
t -> {
if (!StringUtils.isEmpty(polarisCircuitBreakerRestTemplate.fallback())) {
if (StringUtils.hasText(polarisCircuitBreakerRestTemplate.fallback())) {
CircuitBreakerStatus.FallbackInfo fallbackInfo = new CircuitBreakerStatus.FallbackInfo(200, null, polarisCircuitBreakerRestTemplate.fallback());
return new PolarisCircuitBreakerHttpResponse(fallbackInfo);
}
if (polarisCircuitBreakerRestTemplate.fallbackClass() != null && polarisCircuitBreakerRestTemplate.fallbackClass().getSuperclass() != null) {
if (!PolarisCircuitBreakerFallback.class.toGenericString().equals(polarisCircuitBreakerRestTemplate.fallbackClass().toGenericString())) {
Method method = ReflectionUtils.findMethod(PolarisCircuitBreakerFallback.class, "fallback");
PolarisCircuitBreakerFallback polarisCircuitBreakerFallback = applicationContext.getBean(polarisCircuitBreakerRestTemplate.fallbackClass());
return (PolarisCircuitBreakerHttpResponse) ReflectionUtils.invokeMethod(method, polarisCircuitBreakerFallback);

@ -2,6 +2,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.GatewayPolarisCircuitBreakerAutoConfiguration
com.tencent.cloud.polaris.circuitbreaker.config.GatewayPolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerRestTemplateAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration

@ -40,4 +40,16 @@ public class ServiceBController {
public String info() {
return "hello world ! I'm a service B1";
}
@GetMapping("/health")
public String health() {
System.out.println("health check: 200 instance");
return "hello world ! I'm a service B1";
}
@GetMapping("/health-svc")
public String healthsvc() {
System.out.println("health-svc check: 200 instance");
return "hello world ! I'm a service B1";
}
}

@ -18,6 +18,8 @@
package com.tencent.cloud.polaris.ciruitbreaker.example;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -43,4 +45,18 @@ public class ServiceBController {
public String info() {
return "failed for call service B2";
}
@GetMapping("/health")
@ResponseStatus(value = HttpStatus.BAD_GATEWAY, reason = "failed for call my service")
public String health() {
System.out.println("health check: 502 instance");
return "hello world ! I'm a service B1";
}
@GetMapping("/health-svc")
@ResponseStatus(value = HttpStatus.BAD_GATEWAY, reason = "failed for call my service")
public String healthsvc() {
System.out.println("health-svc check: 502 instance");
return "hello world ! I'm a service B1";
}
}

@ -0,0 +1,17 @@
package com.tencent.cloud.polaris.circuitbreaker.resttemplate.example;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerFallback;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerHttpResponse;
import org.springframework.stereotype.Component;
@Component
public class CustomPolarisCircuitBreakerFallback implements PolarisCircuitBreakerFallback {
@Override
public PolarisCircuitBreakerHttpResponse fallback() {
return new PolarisCircuitBreakerHttpResponse(
200,
"{\"msg\": \"this is a fallback class\"}");
}
}

@ -19,7 +19,9 @@ package com.tencent.cloud.polaris.circuitbreaker.resttemplate.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -35,24 +37,38 @@ import org.springframework.web.client.RestTemplate;
public class ServiceAController {
@Autowired
private RestTemplate restTemplate;
@Qualifier("defaultRestTemplate")
private RestTemplate defaultRestTemplate;
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
@Qualifier("fallbackRestTemplate")
private RestTemplate fallbackRestTemplate;
@Autowired
@Qualifier("fallbackClassRestTemplate")
private RestTemplate fallbackClassRestTemplate;
// @GetMapping("/getBServiceInfo")
// public String getBServiceInfo() {
// return circuitBreakerFactory
// .create("polaris-circuitbreaker-callee-service#/example/service/b/info")
// .run(() ->
// restTemplate.getForObject("/example/service/b/info", String.class),
// throwable -> "trigger the refuse for service b"
// );
// }
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
@GetMapping("/getBServiceInfo")
public String getBServiceInfo() {
return restTemplate.getForObject("/example/service/b/info", String.class);
return circuitBreakerFactory
.create("polaris-circuitbreaker-callee-service#/example/service/b/info")
.run(() ->
defaultRestTemplate.getForObject("/example/service/b/info", String.class),
throwable -> "trigger the refuse for service b"
);
}
@GetMapping("/getBServiceInfo/fallback")
public String getBServiceInfoFallback() {
return fallbackRestTemplate.getForObject("/example/service/b/info", String.class);
}
@GetMapping("/getBServiceInfo/fallbackClass")
public String getBServiceInfoFallbackClass() {
return fallbackClassRestTemplate.getForObject("/example/service/b/info", String.class);
}
}

@ -20,10 +20,14 @@ package com.tencent.cloud.polaris.circuitbreaker.resttemplate.example;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerFallback;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerRestTemplate;
import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisCircuitBreakerRestTemplateBeanPostProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriBuilderFactory;
@ -40,10 +44,29 @@ public class ServiceAResTemplate {
SpringApplication.run(ServiceAResTemplate.class, args);
}
@Bean
@LoadBalanced
public RestTemplate defaultRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://polaris-circuitbreaker-callee-service");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
@Bean
@LoadBalanced
@PolarisCircuitBreakerRestTemplate
public RestTemplate restTemplate() {
public RestTemplate fallbackRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://polaris-circuitbreaker-callee-service");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
@Bean
@LoadBalanced
@PolarisCircuitBreakerRestTemplate(fallbackClass = CustomPolarisCircuitBreakerFallback.class)
public RestTemplate fallbackClassRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://polaris-circuitbreaker-callee-service");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);

@ -56,6 +56,7 @@ import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
*/
public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter implements ResponseErrorHandler, ApplicationContextAware {
public static final String POLARIS_CIRCUIT_BREAKER_FALLBACK_HEADER = "PolarisCircuitBreakerFallback";
static final String HEADER_HAS_ERROR = "X-SCT-Has-Error";
private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedRestTemplateReporter.class);
private final ConsumerAPI consumerAPI;
@ -117,6 +118,9 @@ public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter
}
private void reportResult(URI url, ClientHttpResponse response) {
if (Boolean.parseBoolean(response.getHeaders().getFirst(POLARIS_CIRCUIT_BREAKER_FALLBACK_HEADER))){
return;
}
ServiceCallResult resultRequest = createServiceCallResult(url);
try {
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();

Loading…
Cancel
Save