diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/error.sh b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/error.sh new file mode 100644 index 00000000..5602a98d --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/error.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +n=1 +while [ $n -le 10 ] +do + echo `curl -s http://localhost:18083/test` + let n++ +done diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/index.sh b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/index.sh new file mode 100644 index 00000000..7db176b8 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/index.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +n=1 +while [ $n -le 10 ] +do + echo `curl -s http://localhost:18083/index` + let n++ +done diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/sleep.sh b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/sleep.sh new file mode 100644 index 00000000..423c3d15 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/scripts/sleep.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +n=1 +while [ $n -le 10 ] +do + echo `curl -s http://localhost:18083/sleep` + let n++ +done diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java index 5dfd4eba..830bf32f 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java @@ -3,6 +3,7 @@ package org.springframework.cloud.alibaba.cloud.examples; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.alibaba.cloud.examples.ConsumerApplication.EchoService; +import org.springframework.cloud.alibaba.sentinel.annotation.SentinelRestTemplate; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; @@ -28,6 +29,13 @@ public class ConsumerApplication { return new RestTemplate(); } + @LoadBalanced + @Bean + @SentinelRestTemplate + public RestTemplate restTemplate1() { + return new RestTemplate(); + } + public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java index 55c751c7..d261cee4 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java @@ -18,18 +18,52 @@ public class TestController { @Autowired private RestTemplate restTemplate; + + @Autowired + private RestTemplate restTemplate1; + @Autowired private EchoService echoService; @Autowired private DiscoveryClient discoveryClient; + // @PostConstruct + // public void init() { + // restTemplate1.setErrorHandler(new ResponseErrorHandler() { + // @Override + // public boolean hasError(ClientHttpResponse response) throws IOException { + // return false; + // } + // + // @Override + // public void handleError(ClientHttpResponse response) throws IOException { + // System.err.println("handle error"); + // } + // }); + // } + @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) public String rest(@PathVariable String str) { return restTemplate.getForObject("http://service-provider/echo/" + str, String.class); } + @RequestMapping(value = "/index", method = RequestMethod.GET) + public String index() { + return restTemplate1.getForObject("http://service-provider", String.class); + } + + @RequestMapping(value = "/test", method = RequestMethod.GET) + public String test() { + return restTemplate1.getForObject("http://service-provider/test", String.class); + } + + @RequestMapping(value = "/sleep", method = RequestMethod.GET) + public String sleep() { + return restTemplate1.getForObject("http://service-provider/sleep", String.class); + } + @RequestMapping(value = "/notFound-feign", method = RequestMethod.GET) public String notFound() { return echoService.notFound(); diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties index 02b7ce32..2d260cb2 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties @@ -10,4 +10,8 @@ spring.cloud.sentinel.eager=true spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json spring.cloud.sentinel.datasource.ds1.file.data-type=json -spring.cloud.sentinel.datasource.ds1.file.rule-type=flow \ No newline at end of file +spring.cloud.sentinel.datasource.ds1.file.rule-type=flow + +spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json +spring.cloud.sentinel.datasource.ds2.file.data-type=json +spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/degraderule.json b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/degraderule.json new file mode 100644 index 00000000..a090d34e --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/degraderule.json @@ -0,0 +1,20 @@ +[ + { + "resource": "GET:http://service-provider/test", + "count": 0.5, + "grade": 1, + "timeWindow": 30 + }, + { + "resource": "GET:http://service-provider", + "count": 0.5, + "grade": 1, + "timeWindow": 10 + }, + { + "resource": "GET:http://service-provider/sleep", + "count": 20.0, + "grade": 0, + "timeWindow": 30 + } +] \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java index ae090f6e..5f71f51d 100644 --- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java @@ -3,6 +3,8 @@ package org.springframework.cloud.alibaba.cloud.examples; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -22,6 +24,27 @@ public class ProviderApplication { @RestController class EchoController { + + @RequestMapping(value = "/", method = RequestMethod.GET) + public ResponseEntity index() { + return new ResponseEntity("index error", HttpStatus.INTERNAL_SERVER_ERROR); + } + + @RequestMapping(value = "/test", method = RequestMethod.GET) + public ResponseEntity test() { + return new ResponseEntity("error", HttpStatus.INTERNAL_SERVER_ERROR); + } + + @RequestMapping(value = "/sleep", method = RequestMethod.GET) + public String sleep() { + try { + Thread.sleep(1000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "ok"; + } + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) public String echo(@PathVariable String string) { return "hello Nacos Discovery " + string; diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java index 7ec733b5..26641002 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java @@ -168,9 +168,9 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces throws BeansException { if (cache.containsKey(beanName)) { // add interceptor for each RestTemplate with @SentinelRestTemplate annotation - StringBuilder interceptorBeanName = new StringBuilder(); + StringBuilder interceptorBeanNamePrefix = new StringBuilder(); SentinelRestTemplate sentinelRestTemplate = cache.get(beanName); - interceptorBeanName + interceptorBeanNamePrefix .append(StringUtils.uncapitalize( SentinelProtectInterceptor.class.getSimpleName())) .append("_") @@ -179,26 +179,25 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces .append(sentinelRestTemplate.fallbackClass().getSimpleName()) .append(sentinelRestTemplate.fallback()); RestTemplate restTemplate = (RestTemplate) bean; - registerBean(interceptorBeanName.toString(), sentinelRestTemplate); + String interceptorBeanName = interceptorBeanNamePrefix + "@" + + bean.toString(); + registerBean(interceptorBeanName, sentinelRestTemplate, (RestTemplate) bean); SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext - .getBean(interceptorBeanName.toString(), - SentinelProtectInterceptor.class); + .getBean(interceptorBeanName, SentinelProtectInterceptor.class); restTemplate.getInterceptors().add(0, sentinelProtectInterceptor); } return bean; } private void registerBean(String interceptorBeanName, - SentinelRestTemplate sentinelRestTemplate) { + SentinelRestTemplate sentinelRestTemplate, RestTemplate restTemplate) { // register SentinelProtectInterceptor bean DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext .getAutowireCapableBeanFactory(); - if (beanFactory.containsBean(interceptorBeanName)) { - return; - } BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder .genericBeanDefinition(SentinelProtectInterceptor.class); beanDefinitionBuilder.addConstructorArgValue(sentinelRestTemplate); + beanDefinitionBuilder.addConstructorArgValue(restTemplate); BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder .getRawBeanDefinition(); beanFactory.registerBeanDefinition(interceptorBeanName, diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java index 48f63ef3..dc69efbb 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java @@ -27,11 +27,12 @@ import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.RestTemplate; import com.alibaba.csp.sentinel.Entry; +import com.alibaba.csp.sentinel.EntryType; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.Tracer; -import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; @@ -44,8 +45,12 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor private final SentinelRestTemplate sentinelRestTemplate; - public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate) { + private final RestTemplate restTemplate; + + public SentinelProtectInterceptor(SentinelRestTemplate sentinelRestTemplate, + RestTemplate restTemplate) { this.sentinelRestTemplate = sentinelRestTemplate; + this.restTemplate = restTemplate; } @Override @@ -61,32 +66,33 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor entryWithPath = false; } Entry hostEntry = null, hostWithPathEntry = null; - ClientHttpResponse response; + ClientHttpResponse response = null; try { - ContextUtil.enter(hostWithPathResource); + hostEntry = SphU.entry(hostResource, EntryType.OUT); if (entryWithPath) { - hostWithPathEntry = SphU.entry(hostWithPathResource); + hostWithPathEntry = SphU.entry(hostWithPathResource, EntryType.OUT); } - hostEntry = SphU.entry(hostResource); response = execution.execute(request, body); + if (this.restTemplate.getErrorHandler().hasError(response)) { + Tracer.trace( + new IllegalStateException("RestTemplate ErrorHandler has error")); + } } catch (Throwable e) { if (!BlockException.isBlockException(e)) { Tracer.trace(e); - throw new IllegalStateException(e); } else { return handleBlockException(request, body, execution, (BlockException) e); } } finally { - if (hostEntry != null) { - hostEntry.exit(); - } if (hostWithPathEntry != null) { hostWithPathEntry.exit(); } - ContextUtil.exit(); + if (hostEntry != null) { + hostEntry.exit(); + } } return response; }