diff --git a/pom.xml b/pom.xml index b305f1c1..dbf0860d 100644 --- a/pom.xml +++ b/pom.xml @@ -45,8 +45,10 @@ flystar32@163.com - fangjian + Jim Fang fangjian0423@gmail.com + Alibaba + https://github.com/fangjian0423 xiaolongzuo diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/rocketmq.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/rocketmq.adoc index 738c8f99..340da4d8 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/rocketmq.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/rocketmq.adoc @@ -166,7 +166,7 @@ NOTE: 在使用 RocketMQ Binder 的同时也可以配置 rocketmq.** 用于触 MessageBuilder builder = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, "binder") .setHeader(RocketMQHeaders.KEYS, "my-key") - .setHeader("DELAY", "1"); + .setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "1"); Message message = builder.build(); output().send(message); ``` diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/circuitbreaker-sentinel.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/circuitbreaker-sentinel.adoc new file mode 100644 index 00000000..b2695e72 --- /dev/null +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/circuitbreaker-sentinel.adoc @@ -0,0 +1,73 @@ +=== Circuit Breaker: Spring Cloud Circuit Breaker With Sentinel & Configuring Sentinel Circuit Breakers + +==== Default Configuration + +To provide a default configuration for all of your circuit breakers create a `Customizer` bean that is passed a +`SentinelCircuitBreakerFactory` or `ReactiveSentinelCircuitBreakerFactory`. +The `configureDefault` method can be used to provide a default configuration. + +==== +[source,java] +---- +@Bean +public Customizer defaultCustomizer() { + return factory -> factory.configureDefault(id -> new SentinelConfigBuilder(id) + .build()); +} +---- +==== + +You can choose to provide default circuit breaking rules via `SentinelConfigBuilder#rules(rules)`. +You can also choose to load circuit breaking rules later elsewhere using +`DegradeRuleManager.loadRules(rules)` API of Sentinel, or via Sentinel dashboard. + +===== Reactive Example + +==== +[source,java] +---- +@Bean +public Customizer defaultCustomizer() { + return factory -> factory.configureDefault(id -> new SentinelConfigBuilder(id) + .build()); +} +---- +==== + +==== Specific Circuit Breaker Configuration + +Similarly to providing a default configuration, you can create a `Customizer` bean this is passed a +`SentinelCircuitBreakerFactory`. + +==== +[source,java] +---- +@Bean +public Customizer slowCustomizer() { + String slowId = "slow"; + List rules = Collections.singletonList( + new DegradeRule(slowId).setGrade(RuleConstant.DEGRADE_GRADE_RT) + .setCount(100) + .setTimeWindow(10) + ); + return factory -> factory.configure(builder -> builder.rules(rules), slowId); +} +---- +==== + +===== Reactive Example + +==== +[source,java] +---- +@Bean +public Customizer customizer() { + List rules = Collections.singletonList( + new DegradeRule().setGrade(RuleConstant.DEGRADE_GRADE_RT) + .setCount(100) + .setTimeWindow(10) + ); + return factory -> factory.configure(builder -> builder.rules(rules), "foo", "bar"); +} +---- +==== \ No newline at end of file diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/rocketmq.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/rocketmq.adoc index 14de88e7..540d42c4 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/rocketmq.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/rocketmq.adoc @@ -114,7 +114,7 @@ All the message types in this code are provided by the `spring-messaging`module. **The lower layer of Spring Cloud Stream also implements various code abstractions based on the previous code.** -=== How to use Spring Cloud Alibaba RocketMQ Binder ### +=== How to use Spring Cloud Alibaba RocketMQ Binder For using the Spring Cloud Alibaba RocketMQ Binder, you just need to add it to your Spring Cloud Stream application, using the following Maven coordinates: @@ -165,7 +165,7 @@ For example, `TAGS`, `DELAY`, `TRANSACTIONAL_ARG`, `KEYS`, `WAIT_STORE_MSG_OK`, MessageBuilder builder = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, "binder") .setHeader(RocketMQHeaders.KEYS, "my-key") - .setHeader("DELAY", "1"); + .setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "1"); Message message = builder.build(); output().send(message); ``` diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc index 017ee591..f7fc3e6d 100644 --- a/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc +++ b/spring-cloud-alibaba-docs/src/main/asciidoc/sentinel.adoc @@ -255,7 +255,7 @@ To learn more about how dynamic data sources work in Sentinel, refer to https:// === Support Zuul -https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[参考 Sentinel 网关限流] +Refer https://github.com/alibaba/Sentinel/wiki/API-Gateway-Flow-Control[API Gateway Flow Control] If you want to use Sentinel Starter with Zuul, you need to add the `spring-cloud-alibaba-sentinel-gateway` dependency, and you need to add the `spring-cloud-starter-netflix-zuul` dependency to let Zuul AutoConfiguration class in the gateway module takes effect: @@ -278,7 +278,7 @@ If you want to use Sentinel Starter with Zuul, you need to add the `spring-cloud === Support Spring Cloud Gateway -https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[参考 Sentinel 网关限流] +Refer https://github.com/alibaba/Sentinel/wiki/API-Gateway-Flow-Control[API Gateway Flow Control] If you want to use Sentinel Starter with Spring Cloud Gateway, you need to add the `spring-cloud-alibaba-sentinel-gateway` dependency and add the `spring-cloud-starter-gateway` dependency to let Spring Cloud Gateway AutoConfiguration class in the module takes effect: @@ -299,6 +299,8 @@ If you want to use Sentinel Starter with Spring Cloud Gateway, you need to add t ``` +include::circuitbreaker-sentinel.adoc[] + === Sentinel Endpoint Sentinel provides an Endpoint internally with a corresponding endpoint id of `sentinel`. diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java index 74bb1e38..b1a75923 100644 --- a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java +++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java @@ -25,16 +25,19 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer; import org.springframework.cloud.client.loadbalancer.RetryLoadBalancerInterceptor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; import org.springframework.core.env.Environment; import org.springframework.core.type.MethodMetadata; import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; @@ -56,8 +59,8 @@ import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory; @ConditionalOnClass(name = { "org.springframework.web.client.RestTemplate" }) @AutoConfigureAfter(name = { "org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration" }) -public class DubboLoadBalancedRestTemplateAutoConfiguration - implements BeanClassLoaderAware, SmartInitializingSingleton { +public class DubboLoadBalancedRestTemplateAutoConfiguration implements + BeanClassLoaderAware, ApplicationContextAware, SmartInitializingSingleton { private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class; @@ -89,6 +92,9 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration @Autowired(required = false) private Map restTemplates = Collections.emptyMap(); + @Nullable + private ApplicationContext applicationContext; + private ClassLoader classLoader; /** @@ -111,18 +117,21 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration * {@link SmartInitializingSingleton} beans or * {@link RestTemplateCustomizer#customize(RestTemplate) customization}) */ - @EventListener(ApplicationStartedEvent.class) - public void adaptRestTemplates() { + @EventListener(ContextRefreshedEvent.class) + public void adaptRestTemplates(ContextRefreshedEvent event) { - DubboTransportedAttributesResolver attributesResolver = new DubboTransportedAttributesResolver( - environment); + if (event.getApplicationContext() == this.applicationContext) { - for (Map.Entry entry : restTemplates.entrySet()) { - String beanName = entry.getKey(); - Map dubboTranslatedAttributes = getDubboTranslatedAttributes( - beanName, attributesResolver); - if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) { - adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes); + DubboTransportedAttributesResolver attributesResolver = new DubboTransportedAttributesResolver( + environment); + + for (Map.Entry entry : restTemplates.entrySet()) { + String beanName = entry.getKey(); + Map dubboTranslatedAttributes = getDubboTranslatedAttributes( + beanName, attributesResolver); + if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) { + adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes); + } } } } @@ -132,7 +141,7 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration * {@link DubboTransported @DubboTransported} * * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} - * {@link RestTemplate} + * {@link RestTemplate} * @param attributesResolver {@link DubboTransportedAttributesResolver} * @return non-null {@link Map} */ @@ -144,10 +153,10 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition; MethodMetadata factoryMethodMetadata = annotatedBeanDefinition .getFactoryMethodMetadata(); - attributes = factoryMethodMetadata != null - ? Optional.ofNullable(factoryMethodMetadata - .getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME)).orElse(attributes) - : Collections.emptyMap(); + attributes = factoryMethodMetadata != null ? Optional + .ofNullable(factoryMethodMetadata + .getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME)) + .orElse(attributes) : Collections.emptyMap(); } return attributesResolver.resolve(attributes); } @@ -158,8 +167,8 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration * * @param restTemplate {@link LoadBalanced @LoadBalanced} {@link RestTemplate} Bean * @param dubboTranslatedAttributes the annotation dubboTranslatedAttributes - * {@link RestTemplate} bean being annotated - * {@link DubboTransported @DubboTransported} + * {@link RestTemplate} bean being annotated + * {@link DubboTransported @DubboTransported} */ private void adaptRestTemplate(RestTemplate restTemplate, Map dubboTranslatedAttributes) { @@ -188,4 +197,9 @@ public class DubboLoadBalancedRestTemplateAutoConfiguration this.classLoader = classLoader; } + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + } diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/com/alibaba/cloud/examples/FooServiceConsumer.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/com/alibaba/cloud/examples/FooServiceConsumer.java index e4a6022c..48c03b86 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/com/alibaba/cloud/examples/FooServiceConsumer.java +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/com/alibaba/cloud/examples/FooServiceConsumer.java @@ -7,7 +7,7 @@ import org.apache.dubbo.config.annotation.Reference; */ public class FooServiceConsumer { - @Reference(version = "${foo.service.version}", application = "${dubbo.application.id}", url = "dubbo://localhost:12345", timeout = 30000) + @Reference(version = "${foo.service.version}", application = "${dubbo.application.id}", url = "dubbo://localhost:12345?version=1.0.0", timeout = 30000) private FooService fooService; public String hello(String name) { diff --git a/spring-cloud-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelBeanPostProcessor.java b/spring-cloud-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelBeanPostProcessor.java index 565ceb6a..474c8bcd 100644 --- a/spring-cloud-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelBeanPostProcessor.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelBeanPostProcessor.java @@ -31,7 +31,6 @@ import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.StandardMethodMetadata; -import org.springframework.core.type.classreading.MethodMetadataReadingVisitor; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpResponse; @@ -171,12 +170,6 @@ public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProces && checkMethodMetadataReadingVisitor(beanDefinition); } - // private boolean checkStandardMethodMetadata(RootBeanDefinition beanDefinition) { - // return beanDefinition.getSource() instanceof StandardMethodMetadata - // && ((StandardMethodMetadata) beanDefinition.getSource()) - // .isAnnotated(SentinelRestTemplate.class.getName()); - // } - private boolean checkMethodMetadataReadingVisitor(RootBeanDefinition beanDefinition) { return beanDefinition.getSource() instanceof MethodMetadata && ((MethodMetadata) beanDefinition.getSource())