diff --git a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc
index 59eaa589..e4c9817f 100644
--- a/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc
+++ b/spring-cloud-alibaba-docs/src/main/asciidoc-zh/sentinel.adoc
@@ -1 +1,257 @@
== Spring Cloud Alibaba Sentinel
+
+### Sentinel介绍
+
+随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
+
+Sentinel 具有以下特征:
+
+
+* *丰富的应用场景*:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
+* *完备的实时监控*:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
+* *广泛的开源生态*:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
+* *完善的 SPI 扩展点*:Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
+
+### 如何使用Sentinel
+
+如果要在您的项目中引入Sentinel,使用group ID为 `org.springframework.cloud` 和artifact ID为 `spring-cloud-starter-alibaba-sentinel` 的starter。
+
+```xml
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+```
+
+下面这个例子就是一个最简单的使用Sentinel的例子:
+
+```java
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceApplication.class, args);
+ }
+
+}
+
+@RestController
+public class TestController {
+
+ @GetMapping(value = "/hello")
+ @SentinelResource("hello")
+ public String hello() {
+ return "Hello Sentinel";
+ }
+
+}
+```
+
+@SentinelResource注解用来标识资源是否被限流、降级。上述例子上该注解的属性'hello'表示资源名。
+
+@SentinelResource还提供了其它额外的属性如 `blockHandler`,`blockHandlerClass`,`fallback` 用于表示限流或降级的操作,更多内容可以参考 https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81[Sentinel注解支持]。
+
+##### Sentinel 控制台
+
+Sentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。您只需要对应用进行简单的配置,就可以使用这些功能。
+
+*注意*: 集群资源汇总仅支持 500 台以下的应用集群,有大概 1 - 2 秒的延时。
+
+.Sentinel Dashboard
+image::https://github.com/alibaba/Sentinel/wiki/image/dashboard.png[]
+
+开启该功能需要3个步骤:
+
+###### 获取控制台
+
+您可以从 https://github.com/alibaba/Sentinel/releases[release 页面] 下载最新版本的控制台 jar 包。
+
+您也可以从最新版本的源码自行构建 Sentinel 控制台:
+
+* 下载 https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard[控制台] 工程
+* 使用以下命令将代码打包成一个 fat jar: `mvn clean package`
+
+
+###### 启动控制台
+
+Sentinel 控制台是一个标准的SpringBoot应用,以SpringBoot的方式运行jar包即可。
+
+```shell
+java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
+```
+
+如若8080端口冲突,可使用 `-Dserver.port=新端口` 进行设置。
+
+#### 配置控制台信息
+
+.application.yml
+----
+spring:
+ cloud:
+ sentinel:
+ transport:
+ port: 8719
+ dashboard: localhost:8080
+----
+
+这里的 `spring.cloud.sentinel.transport.port` 端口配置会在应用对应的机器上启动一个Http Server,该Serve会与Sentinel控制台做交互。比如Sentinel控制台添加了1个限流规则,会把规则数据push给这个Http Server接受,Http Server再将规则注册到Sentinel中。
+
+更多Sentinel控制台的使用及问题参考: https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0[Sentinel控制台]
+
+### Feign支持
+
+DOING
+
+### RestTemplate支持
+
+Spring Cloud Alibaba Sentinel支持对 `RestTemplate` 的服务调用使用Sentinel进行保护,在构造 `RestTemplate` bean的时候需要加上 `@SentinelProtect` 注解。
+
+```java
+@Bean
+@SentinelProtect(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
+public RestTemplate restTemplate() {
+ return new RestTemplate();
+}
+```
+
+`@SentinelProtect` 注解的参数跟 `@SentinelResource` 一致,使用方式也一致。
+
+限流的资源规则提供两种粒度:
+
+* `schema://host:port/path`:协议、主机、端口和路径
+
+* `schema://host:port`:协议、主机和端口
+
+NOTE: 以 `https://www.taobao.com/test` 这个url为例。对应的资源名有两种粒度,分别是 `https://www.taobao.com:80` 以及 `https://www.taobao.com:80/test`
+
+
+### 动态数据源支持
+
+*在版本 0.2.0.RELEASE 或 0.1.0.RELEASE 之前*,要在Spring Cloud Alibaba Sentinel下使用动态数据源,需要3个步骤:
+
+* 配置文件中定义数据源信息。比如使用文件:
+
+.application.properties
+----
+spring.cloud.sentinel.datasource.type=file
+spring.cloud.sentinel.datasource.recommendRefreshMs=3000
+spring.cloud.sentinel.datasource.bufSize=4056196
+spring.cloud.sentinel.datasource.charset=utf-8
+spring.cloud.sentinel.datasource.converter=flowConverter
+spring.cloud.sentinel.datasource.file=/Users/you/yourrule.json
+----
+
+* 创建一个Converter类实现 `com.alibaba.csp.sentinel.datasource.Converter` 接口,并且需要在 `ApplicationContext` 中有该类的一个Bean
+
+```java
+@Component("flowConverter")
+public class JsonFlowRuleListParser implements Converter> {
+ @Override
+ public List convert(String source) {
+ return JSON.parseObject(source, new TypeReference>() {
+ });
+ }
+}
+```
+
+这个Converter的bean name需要跟 `application.properties` 配置文件中的converter配置一致
+
+* 在任意一个 Spring Bean 中定义一个被 `@SentinelDataSource` 注解修饰的 `ReadableDataSource` 属性
+
+```java
+@SentinelDataSource("spring.cloud.sentinel.datasource")
+private ReadableDataSource dataSource;
+```
+
+`@SentinelDataSource` 注解的value属性表示数据源在 `application.properties` 配置文件中前缀。 该在例子中,前缀为 `spring.cloud.sentinel.datasource` 。
+
+如果 `ApplicationContext` 中存在超过1个 `ReadableDataSource` bean,那么不会加载这些 `ReadableDataSource` 中的任意一个。 只有在 `ApplicationContext` 存在一个 `ReadableDataSource` 的情况下才会生效。
+
+如果数据源生效并且规则成功加载,控制台会打印类似如下信息:
+
+```
+[Sentinel Starter] load 3 flow rules
+```
+
+*在版本 0.2.0.RELEASE 或 0.1.0.RELEASE 之后*,要在Spring Cloud Alibaba Sentinel下使用动态数据源,只需要1个步骤:
+
+* 直接在 `application.properties` 配置文件中配置数据源信息即可
+
+比如配置了4个数据源:
+
+```
+spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
+
+spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
+spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
+spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
+spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
+
+spring.cloud.sentinel.datasource.ds3.zk.path = /Sentinel-Demo/SYSTEM-CODE-DEMO-FLOW
+spring.cloud.sentinel.datasource.ds3.zk.server-addr = localhost:2181
+
+spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application
+spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel
+spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test
+
+```
+
+这样配置方式参考了Spring Cloud Stream Binder的配置,内部使用了 `TreeMap` 进行存储,comparator为 `String.CASE_INSENSITIVE_ORDER` 。
+
+NOTE: d1, ds2, ds3, ds4 是 `ReadableDataSource` 的名字,可随意编写。后面的 `file` ,`zk` ,`nacos` , `apollo` 就是对应具体的数据源。 它们后面的配置就是这些数据源各自的配置。
+
+每种数据源都有两个共同的配置项: `data-type` 和 `converter-class` 。
+
+`data-type` 配置项表示 `Converter`,Spring Cloud Alibaba Sentinel默认提供两种内置的值,分别是 `json` 和 `xml` (不填默认是json)。 如果不想使用内置的 `json` 或 `xml` 这两种 `Converter`,可以填写 `custom` 表示自定义 `Converter`,然后再配置 `converter-class` 配置项,该配置项需要写类的全路径名。
+
+这两种内置的 `Converter` 只支持解析 json数组 或 xml数组。内部解析的时候会自动判断每个json对象或xml对象属于哪4种Sentinel规则(`FlowRule`,`DegradeRule`,`SystemRule`,`AuthorityRule`)。
+
+比如10个规则数组里解析出5个限流规则和5个降级规则。 这种情况下该数据源不会注册,日志里页会进行警告。
+
+如果10个规则里有9个限流规则,1个解析报错了。这种情况下日志会警告有个规则格式错误,另外9个限流规则会注册上去。
+
+这里json或xml解析用的是 `jackson`。`ObjectMapper` 或 `XmlMapper` 使用默认的配置,遇到不认识的字段会解析报错。 因为不这样做的话限流 json 也会解析成 系统规则(系统规则所有的配置都有默认值),所以需要这样严格解析。
+
+当然还有一种情况是json对象或xml对象可能会匹配上所有4种规则(比如json对象里只配了 `resource` 字段,那么会匹配上4种规则),这种情况下日志里会警告,并且过滤掉这个对象。
+
+用户使用这种配置的时候只需要填写正确的json或xml就行,有任何不合理的信息都会在日志里打印出来。
+
+如果数据源生效并且规则成功加载,控制台会打印类似如下信息:
+
+```
+[Sentinel Starter] DataSource ds1-sentinel-file-datasource load 3 DegradeRule
+[Sentinel Starter] DataSource ds2-sentinel-nacos-datasource load 2 FlowRule
+```
+
+NOTE: 默认情况下,xml格式是不支持的。需要添加 `jackson-dataformat-xml` 依赖后才会自动生效。
+
+关于Sentinel动态数据源的实现原理,参考: https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95[动态规则扩展]
+
+### Endpoint支持
+
+在使用Endpoint特性之前需要在 Maven 中添加 `spring-boot-starter-actuator` 依赖,并在配置中允许 Endpoints 的访问。
+
+* Spring Boot 1.x 中添加配置 `management.security.enabled=false`。暴露的endpoint路径为 `/sentinel`
+* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`。暴露的endpoint路径为 `/actuator/sentinel`
+
+### More
+
+下表显示 Spring Cloud Alibaba Sentinel 的所有配置信息:
+
+:frame: topbot
+[width="60%",options="header"]
+|====
+^|配置项 ^|含义 ^|默认值
+|`spring.cloud.sentinel.enabled`|Sentinel自动化配置是否生效|true
+|`spring.cloud.sentinel.eager`|取消Sentinel控制台懒加载|false
+|`spring.cloud.sentinel.charset`|metric文件字符集|UTF-8
+|`spring.cloud.sentinel.transport.port`|应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer|8721
+|`spring.cloud.sentinel.transport.dashboard`|Sentinel 控制台地址|
+|`spring.cloud.sentinel.transport.heartbeatIntervalMs`|应用与Sentinel控制台的心跳间隔时间|
+|`spring.cloud.sentinel.filter.order`|Servlet Filter的加载顺序。Starter内部会构造这个filter|Integer.MIN_VALUE
+|`spring.cloud.sentinel.filter.spring.url-patterns`|数据类型是数组。表示Servlet Filter的url pattern集合|/*
+|`spring.cloud.sentinel.metric.fileSingleSize`|Sentinel metric 单个文件的大小|
+|`spring.cloud.sentinel.metric.fileTotalCount`|Sentinel metric 总文件数量|
+|`spring.cloud.sentinel.servlet.blockPage`| 自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL |
+|`spring.cloud.sentinel.flow.coldFactor`| https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8[冷启动因子] |3
+|====
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml
index e8ffc685..3fe3b98b 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml
@@ -31,6 +31,24 @@
spring-boot-starter-actuator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
index c07c20e3..af535e6d 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md
@@ -196,77 +196,33 @@ Sentinel 控制台支持实时监控查看,您可以通过 Sentinel 控制台
Sentinel 内部提供了[动态规则的扩展实现 ReadableDataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。
-Sentinel starter 整合了目前存在的几类 DataSource。只需要在配置文件中进行相关配置,即可在 Spring 容器中自动注册 DataSource。
+Sentinel starter 整合了目前存在的几类 ReadableDataSource。只需要在配置文件中进行相关配置,即可在 Spring 容器中自动注册 DataSource。
-比如要定义一个 `FileRefreshableDataSource`,配置如下:
+比如要定义两个ReadableDataSource,分别是 `FileRefreshableDataSource` 和 `NacosDataSource`,配置如下:
- spring.cloud.sentinel.datasource.type=file
- spring.cloud.sentinel.datasource.recommendRefreshMs=2000
- spring.cloud.sentinel.datasource.bufSize=2048
- spring.cloud.sentinel.datasource.charset=utf-8
- spring.cloud.sentinel.datasource.converter=myParser
- spring.cloud.sentinel.datasource.file=/Users/you/rule.json
+```properties
+spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
+spring.cloud.sentinel.datasource.ds1.file.data-type=json
-然后使用`@SentinelDataSource` 注解修饰 DataSource 即可注入:
+spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
+spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
+spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
+spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
+```
- @SentinelDataSource("spring.cloud.sentinel.datasource")
- private ReadableDataSource dataSource;
+`ds1` 和 `ds2` 表示ReadableDataSource的名称,可随意编写。`ds1` 和 `ds2` 后面的 `file` 和 `nacos` 表示ReadableDataSource的类型。
-`@SentinelDataSource` 注解的 value 属性可以不填。默认值就是 `spring.cloud.sentinel.datasource`。
+目前支持`file`, `nacos`, `zk`, `apollo` 这4种类型。
-`value` 属性代表配置前缀。示例中会去找 `spring.cloud.sentinel.datasource.xxx` 相关的配置。
+其中`nacos`,`zk`,`apollo`这3种类型的使用需要加上对应的依赖`sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`, `sentinel-datasource-apollo`。
-`spring.cloud.sentinel.datasource.type` 就是对应的 DataSource 类型。
+当ReadableDataSource加载规则数据成功的时候,控制台会打印出相应的日志信息:
-`spring.cloud.sentinel.datasource.recommendRefreshMs` 里的 `recommendRefreshMs` 对应相关 DataSource 的属性。
+```
+[Sentinel Starter] DataSource ds1-sentinel-file-datasource load 3 DegradeRule
+[Sentinel Starter] DataSource ds2-sentinel-nacos-datasource load 2 FlowRule
+```
-`spring.cloud.sentinel.datasource.converter`代表 `Converter` 在 Spring 容器里的 name。如果没找到,会抛出异常。
-
-type目前支持file, nacos, zk, apollo。其中nacos,zk,apollo的使用需要加上对应的依赖`sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`, `sentinel-datasource-apollo`
-
-### 自定义DataSource
-
-自定义DataSource只需要两步。
-
-1. 定义DataSource
-
- public class CustomDataSource implements ReadableDataSource {
- private String fieldA;
- private String fieldB;
- ...
- }
-
-2. 装配DataSource。有两种方式处理。
-
- * 直接构造DataSource
-
- @Bean
- public CustomDataSource customDataSource() {
- CustomDataSource customDataSource =
- new CustomDataSource();
- customDataSource.setFieldA("valueA");
- customDataSource.setFieldB("valueB");
- ...
- return customDataSource;
- }
-
- * 在classpath:/META-INF/sentinel-datasource.properties中管理DataSource信息
-
- custom = yourpackage.CustomDataSource
-
- 在application.properties中定义DataSource
-
- spring.cloud.sentinel.datasource.type = custom
- spring.cloud.sentinel.datasource.fieldA = valueA
- spring.cloud.sentinel.datasource.fieldB = valueB
-
- 注意:由于目前Sentinel的AbstractDataSource需要有个Converter作为构造函数中的参数,并且它的子类的构造都是通过多个参数的构造函数构造的。
- 所以目前所有的Sentinel starter中的DataSource都是基于FactoryBean并且通过设置属性构造的。如果有这方面的需求,需要再多加一个registerFactoryBean过程。
-
- SentinelDataSourceRegistry.registerFactoryBean("custeom", CustomDataSourceFactoryBean.class);
-
- 如果自定义DataSource可以注入属性,那么没有必要使用SentinelDataSourceRegistry注册FactoryBean。
-
## More
Sentinel 是一款功能强大的中间件,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。此 Demo 仅演示了 使用 Sentinel 作为限流工具的使用,更多 Sentinel 相关的信息,请参考 [Sentinel 项目](https://github.com/alibaba/Sentinel)。
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md
index 157ad0e8..e3135729 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md
@@ -71,7 +71,7 @@ Before we start the demo, let's learn how to connect Sentinel to a Spring Cloud
2. Start the application in IDE or by building a fatjar.
1. Start in IDE: Find main class `ServiceApplication`, and execute the main method.
- 2. Build a fatjar:Execute command `mvn clean package` to build a fatjar,and run command `java -jar sentinel-core-example.jar` to start the application.
+ 2. Build a fatjar:Execute command `mvn clean package` to build a fatjar, and run command `java -jar sentinel-core-example.jar` to start the application.
### Invoke Service
@@ -86,7 +86,7 @@ The screenshot belows shows invoke success:
1. Open http://localhost:8080 in browser, and you can find a Sentinel-Example Application has been registered to the dashboard.
- **Note: If you can't find your application in the dashboard, invoke a method that has been defined as a Sentinel Resource,for Sentinel uses lazy load strategy.**
+ **Note: If you can't find your application in the dashboard, invoke a method that has been defined as a Sentinel Resource, for Sentinel uses lazy load strategy.**

@@ -125,8 +125,8 @@ The screenshot belows shows invoke success:
2. When a custom resource is blocked by Sentinel, the default logic is throw BlockException.
- If you want to customize your flow control logic, implement interface `SentinelExceptionHandler`, set @SentinelResource's blockHandler() and blockHandlerClass(). See the code below:
-
+ If you want to customize your flow control logic, implement interface `SentinelExceptionHandler`, set @SentinelResource's blockHandler() and blockHandlerClass(). See the code below:
+
@SentinelResource(value = "resource", blockHandler = "", blockHandlerClass = ExceptionUtil.class)
public String hello() {
return "Hello";
@@ -171,71 +171,30 @@ Sentinel provide [ReadableDataSource](https://github.com/alibaba/Sentinel/blob/m
Sentinel starter integrated 4 DataSources provided by Sentinel. It will be register into Spring Context if you write some configs in `application.properties`.
-If you want to define FileRefreshableDataSource:
+If you want to define `FileRefreshableDataSource` and `NacosDataSource`, see the code below:
- spring.cloud.sentinel.datasource.type=file
- spring.cloud.sentinel.datasource.recommendRefreshMs=2000
- spring.cloud.sentinel.datasource.bufSize=2048
- spring.cloud.sentinel.datasource.charset=utf-8
- spring.cloud.sentinel.datasource.converter=myParser
- spring.cloud.sentinel.datasource.file=/Users/you/rule.json
-
-then use `@SentinelDataSource` to annotate DataSource:
-
- @SentinelDataSource("spring.cloud.sentinel.datasource")
- private ReadableDataSource dataSource;
-
-The value() of `@SentinelDataSource` is not required, it means the prefix of configuration. Default value is `spring.cloud.sentinel.datasource`.
+```properties
+spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
+spring.cloud.sentinel.datasource.ds1.file.data-type=json
-spring.cloud.sentinel.datasource.type means the type of DataSource.
+spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
+spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
+spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
+spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
+```
-spring.cloud.sentinel.datasource.recommendRefreshMs means the recommendRefreshMs property of specified DataSource.
+`ds1` and `ds2` means the name of ReadableDataSource, you can write whatever you want. The `file` and `nacos` after name `ds1` and `ds2` means the type of ReadableDataSource.
-spring.cloud.sentinel.datasource.converter means the name of spring bean that type is Converter. If the bean is not exists, will throw exception.
-
-Now datasource type support 4 categories: file, nacos, zk, apollo. If you want to using nacos, zk or apollo, you should add `sentinel-datasource-nacos`, `sentinel-datasource-zookeeper` or `sentinel-datasource-apollo` dependency.
+Now ReadableDataSource type support 4 categories: `file`, `nacos`, `zk` and `apollo`.
-### User-defined DataSource
+If you want to use `nacos`, `zk` or `apollo` ReadableDataSource, you could add `sentinel-datasource-nacos`, `sentinel-datasource-zookeeper` or `sentinel-datasource-apollo` dependency.
-User-defined DataSource need 2 steps.
+When ReadableDataSource load rule data successfully, console will print some logs:
-1. Define DataSource
-
- public class CustomDataSource implements ReadableDataSource {
- private String fieldA;
- private String fieldB;
- ...
- }
-
-2. Assemble DataSource. There are 2 ways to do this.
-
- * Construct DataSource directly
-
- @Bean
- public CustomDataSource customDataSource() {
- CustomDataSource customDataSource = new CustomDataSource();
- customDataSource.setFieldA("valueA");
- customDataSource.setFieldB("valueB");
- ...
- return customDataSource;
- }
-
- * define DataSource metadata in `classpath:/META-INF/sentinel-datasource.properties`
-
- custom = yourpackage.CustomDataSource
-
- define configuration in `application.properties`
-
- spring.cloud.sentinel.datasource.type = custom
- spring.cloud.sentinel.datasource.fieldA = valueA
- spring.cloud.sentinel.datasource.fieldB = valueB
-
-Note: The AbstractDataSource of Sentinel need a Converter as a constructor param and the subclass of AbstractDataSource was construct by multi-param constructor.
-Now All DataSources in starter was construct by FactoryBean. If you want to do it in this way, you should register FactoryBean by SentinelDataSourceRegistry.
-
- SentinelDataSourceRegistry.registerFactoryBean("custeom", CustomDataSourceFactoryBean.class);
-
-It is no need to using SentinelDataSourceRegistry to register FactoryBean if your User-defined DataSource can inject fields.
+```
+[Sentinel Starter] DataSource ds1-sentinel-file-datasource load 3 DegradeRule
+[Sentinel Starter] DataSource ds2-sentinel-nacos-datasource load 2 FlowRule
+```
## More
For more information about Sentinel, see [Sentinel Project](https://github.com/alibaba/Sentinel).
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListConverter.java
similarity index 83%
rename from spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java
rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListConverter.java
index b205c96c..c5cea94d 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListConverter.java
@@ -10,7 +10,7 @@ import com.alibaba.fastjson.TypeReference;
/**
* @author fangjian
*/
-public class JsonFlowRuleListParser implements Converter> {
+public class JsonFlowRuleListConverter implements Converter> {
@Override
public List convert(String source) {
return JSON.parseObject(source, new TypeReference>() {
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java
index 8ced5aff..93183382 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java
@@ -27,7 +27,7 @@ public class ServiceApplication {
@Bean
public Converter myParser() {
- return new JsonFlowRuleListParser();
+ return new JsonFlowRuleListConverter();
}
public static void main(String[] args) {
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
index b6117190..19c2868e 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
@@ -1,14 +1,16 @@
spring.application.name=sentinel-example
server.port=18083
management.security.enabled=false
-spring.cloud.sentinel.transport.port=8721
spring.cloud.sentinel.transport.dashboard=localhost:8080
+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.type=file
-spring.cloud.sentinel.datasource.recommendRefreshMs=3000
-spring.cloud.sentinel.datasource.bufSize=4056196
-spring.cloud.sentinel.datasource.charset=utf-8
-spring.cloud.sentinel.datasource.converter=myParser
-spring.cloud.sentinel.datasource.file=/Users/you/rule.json
\ No newline at end of file
+#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
+#spring.cloud.sentinel.datasource.ds1.file.data-type=custom
+#spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter
+
+spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json
+spring.cloud.sentinel.datasource.ds2.file.data-type=json
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/degraderule.json b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/degraderule.json
new file mode 100644
index 00000000..5977c5fc
--- /dev/null
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/degraderule.json
@@ -0,0 +1,16 @@
+[
+ {
+ "resource": "abc0",
+ "count": 20.0,
+ "grade": 0,
+ "passCount": 0,
+ "timeWindow": 10
+ },
+ {
+ "resource": "abc1",
+ "count": 15.0,
+ "grade": 0,
+ "passCount": 0,
+ "timeWindow": 10
+ }
+]
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json
new file mode 100644
index 00000000..679dff4a
--- /dev/null
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.json
@@ -0,0 +1,26 @@
+[
+ {
+ "resource": "resource",
+ "controlBehavior": 0,
+ "count": 1,
+ "grade": 1,
+ "limitApp": "default",
+ "strategy": 0
+ },
+ {
+ "resource": "p",
+ "controlBehavior": 0,
+ "count": 1,
+ "grade": 1,
+ "limitApp": "default",
+ "strategy": 0
+ },
+ {
+ "resource": "abc",
+ "controlBehavior": 0,
+ "count": 1,
+ "grade": 1,
+ "limitApp": "default",
+ "strategy": 0
+ }
+]
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.xml
new file mode 100644
index 00000000..7f1926d3
--- /dev/null
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/flowrule.xml
@@ -0,0 +1,21 @@
+
+
+
+ resource
+ 0
+ 1
+ 1
+ default
+ 0
+
+
+ test
+ 0
+ 1
+ 1
+ default
+ 0
+
+
+
+
diff --git a/spring-cloud-alibaba-sentinel-datasource/pom.xml b/spring-cloud-alibaba-sentinel-datasource/pom.xml
index af959677..db4ed997 100644
--- a/spring-cloud-alibaba-sentinel-datasource/pom.xml
+++ b/spring-cloud-alibaba-sentinel-datasource/pom.xml
@@ -41,8 +41,27 @@
true
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ provided
+
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ provided
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ provided
+ true
+
+
org.springframework.boot
spring-boot
diff --git a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java b/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java
deleted file mode 100644
index da894ae5..00000000
--- a/spring-cloud-alibaba-sentinel-datasource/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2018 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * 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.alibaba.sentinel.datasource;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
-import org.springframework.core.io.support.PropertiesLoaderUtils;
-import org.springframework.core.io.support.ResourcePatternResolver;
-import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-
-import static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
-
-/**
- * {@link ReadableDataSource} Loader
- *
- * @author Jim
- */
-public class DataSourceLoader {
-
- private static final Logger logger = LoggerFactory.getLogger(DataSourceLoader.class);
-
- private final static String PROPERTIES_RESOURCE_LOCATION = "META-INF/sentinel-datasource.properties";
-
- private final static String ALL_PROPERTIES_RESOURCES_LOCATION = CLASSPATH_ALL_URL_PREFIX
- + PROPERTIES_RESOURCE_LOCATION;
-
- private final static ConcurrentMap> dataSourceClassesCache
- = new ConcurrentHashMap>(
- 4);
-
- static void loadAllDataSourceClassesCache() {
- Map> dataSourceClassesMap = loadAllDataSourceClassesCache(
- ALL_PROPERTIES_RESOURCES_LOCATION);
-
- dataSourceClassesCache.putAll(dataSourceClassesMap);
- }
-
- static Map> loadAllDataSourceClassesCache(
- String resourcesLocation) {
-
- Map> dataSourcesMap
- = new HashMap>(
- 4);
-
- ClassLoader classLoader = DataSourceLoader.class.getClassLoader();
-
- ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
-
- try {
-
- Resource[] resources = resolver.getResources(resourcesLocation);
-
- for (Resource resource : resources) {
- if (resource.exists()) {
- Properties properties = PropertiesLoaderUtils
- .loadProperties(resource);
- for (Map.Entry
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ provided
+
+
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java
index 49460a98..feac8acc 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java
@@ -17,256 +17,285 @@
package org.springframework.cloud.alibaba.sentinel;
import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
+import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import org.springframework.core.Ordered;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+
/**
* @author xiaojing
* @author hengyunabc
+ * @author jiashuai.xie
+ * @author Jim
*/
@ConfigurationProperties(prefix = SentinelConstants.PROPERTY_PREFIX)
public class SentinelProperties {
- /**
- * 是否提前初始化心跳连接
- */
- private boolean eager = false;
+ /**
+ * earlier initialize heart-beat when the spring container starts when the
+ * transport dependency is on classpath ,the configuration is effective
+ */
+ private boolean eager = false;
- /**
- * Enable sentinel auto configure, the default value is true
- */
- private boolean enabled = true;
+ /**
+ * enable sentinel auto configure, the default value is true
+ */
+ private boolean enabled = true;
- /**
- * 字符编码集
- */
- private String charset = "UTF-8";
+ /**
+ * charset when sentinel write or search metric file {@link SentinelConfig#CHARSET}
+ */
+ private String charset = "UTF-8";
- /**
- * 通信相关配置
- */
- @NestedConfigurationProperty
- private Transport transport = new Transport();
+ /**
+ * configurations about datasource, like 'nacos', 'apollo', 'file', 'zookeeper'
+ */
+ private Map datasource = new TreeMap<>(
+ String.CASE_INSENSITIVE_ORDER);
- /**
- * 监控数据相关配置
- */
- @NestedConfigurationProperty
- private Metric metric = new Metric();
+ /**
+ * transport configuration about dashboard and client
+ */
+ @NestedConfigurationProperty
+ private Transport transport = new Transport();
- /**
- * web 相关配置
- */
- @NestedConfigurationProperty
- private Servlet servlet = new Servlet();
+ /**
+ * metric configuration about resource
+ */
+ @NestedConfigurationProperty
+ private Metric metric = new Metric();
- /**
- * 限流相关
- */
- @NestedConfigurationProperty
- private Filter filter = new Filter();
+ /**
+ * web servlet configuration when the application is web ,the configuration is
+ * effective
+ */
+ @NestedConfigurationProperty
+ private Servlet servlet = new Servlet();
- @NestedConfigurationProperty
- private Flow flow = new Flow();
+ /**
+ * sentinel filter when the application is web ,the configuration is effective
+ *
+ */
+ @NestedConfigurationProperty
+ private Filter filter = new Filter();
- public boolean isEager() {
- return eager;
- }
+ /**
+ * flow configuration
+ */
+ @NestedConfigurationProperty
+ private Flow flow = new Flow();
- public void setEager(boolean eager) {
- this.eager = eager;
- }
+ public boolean isEager() {
+ return eager;
+ }
- public Flow getFlow() {
- return flow;
- }
+ public void setEager(boolean eager) {
+ this.eager = eager;
+ }
- public void setFlow(Flow flow) {
- this.flow = flow;
- }
+ public Flow getFlow() {
+ return flow;
+ }
- public String getCharset() {
- return charset;
- }
+ public void setFlow(Flow flow) {
+ this.flow = flow;
+ }
- public void setCharset(String charset) {
- this.charset = charset;
- }
+ public String getCharset() {
+ return charset;
+ }
- public Transport getTransport() {
- return transport;
- }
+ public void setCharset(String charset) {
+ this.charset = charset;
+ }
- public void setTransport(Transport transport) {
- this.transport = transport;
- }
+ public Transport getTransport() {
+ return transport;
+ }
- public Metric getMetric() {
- return metric;
- }
+ public void setTransport(Transport transport) {
+ this.transport = transport;
+ }
- public void setMetric(Metric metric) {
- this.metric = metric;
- }
+ public Metric getMetric() {
+ return metric;
+ }
- public Servlet getServlet() {
- return servlet;
- }
+ public void setMetric(Metric metric) {
+ this.metric = metric;
+ }
- public void setServlet(Servlet servlet) {
- this.servlet = servlet;
- }
+ public Servlet getServlet() {
+ return servlet;
+ }
- public boolean isEnabled() {
- return enabled;
- }
+ public void setServlet(Servlet servlet) {
+ this.servlet = servlet;
+ }
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
+ public boolean isEnabled() {
+ return enabled;
+ }
- public Filter getFilter() {
- return filter;
- }
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
- public void setFilter(Filter filter) {
- this.filter = filter;
- }
+ public Filter getFilter() {
+ return filter;
+ }
- public static class Flow {
+ public void setFilter(Filter filter) {
+ this.filter = filter;
+ }
- /**
- * 限流冷启动因子
- */
- private String coldFactor = "3";
+ public Map getDatasource() {
+ return datasource;
+ }
- public String getColdFactor() {
- return coldFactor;
- }
+ public void setDatasource(Map datasource) {
+ this.datasource = datasource;
+ }
- public void setColdFactor(String coldFactor) {
- this.coldFactor = coldFactor;
- }
+ public static class Flow {
- }
+ /**
+ * the cold factor {@link SentinelConfig#COLD_FACTOR}
+ */
+ private String coldFactor = "3";
- public static class Servlet {
+ public String getColdFactor() {
+ return coldFactor;
+ }
- /**
- * url 限流后的处理页面
- */
- private String blockPage;
+ public void setColdFactor(String coldFactor) {
+ this.coldFactor = coldFactor;
+ }
- public String getBlockPage() {
- return blockPage;
- }
+ }
- public void setBlockPage(String blockPage) {
- this.blockPage = blockPage;
- }
- }
+ public static class Servlet {
- public static class Metric {
+ /**
+ * The process page when the flow control is triggered
+ */
+ private String blockPage;
- /**
- * 监控数据写磁盘时单个文件的大小
- */
- private String fileSingleSize;
+ public String getBlockPage() {
+ return blockPage;
+ }
- /**
- * 监控数据在磁盘上的总数量
- */
- private String fileTotalCount;
+ public void setBlockPage(String blockPage) {
+ this.blockPage = blockPage;
+ }
+ }
- public String getFileSingleSize() {
- return fileSingleSize;
- }
+ public static class Metric {
- public void setFileSingleSize(String fileSingleSize) {
- this.fileSingleSize = fileSingleSize;
- }
+ /**
+ * the metric file size {@link SentinelConfig#SINGLE_METRIC_FILE_SIZE}
+ */
+ private String fileSingleSize;
- public String getFileTotalCount() {
- return fileTotalCount;
- }
+ /**
+ * the total metric file count {@link SentinelConfig#TOTAL_METRIC_FILE_COUNT}
+ */
+ private String fileTotalCount;
- public void setFileTotalCount(String fileTotalCount) {
- this.fileTotalCount = fileTotalCount;
- }
- }
+ public String getFileSingleSize() {
+ return fileSingleSize;
+ }
- public static class Transport {
+ public void setFileSingleSize(String fileSingleSize) {
+ this.fileSingleSize = fileSingleSize;
+ }
- /**
- * sentinel api port,default value is 8721
- */
- private String port = "8721";
+ public String getFileTotalCount() {
+ return fileTotalCount;
+ }
- /**
- * Sentinel dashboard address, won't try to connect dashboard when address is
- * empty
- */
- private String dashboard = "";
+ public void setFileTotalCount(String fileTotalCount) {
+ this.fileTotalCount = fileTotalCount;
+ }
+ }
- /**
- * 客户端和DashBord心跳发送时间
- */
- private String heartbeatIntervalMs;
+ public static class Transport {
- public String getHeartbeatIntervalMs() {
- return heartbeatIntervalMs;
- }
+ /**
+ * sentinel api port,default value is 8721 {@link TransportConfig#SERVER_PORT}
+ */
+ private String port = "8721";
- public void setHeartbeatIntervalMs(String heartbeatIntervalMs) {
- this.heartbeatIntervalMs = heartbeatIntervalMs;
- }
+ /**
+ * sentinel dashboard address, won't try to connect dashboard when address is
+ * empty {@link TransportConfig#CONSOLE_SERVER}
+ */
+ private String dashboard = "";
- public String getPort() {
- return port;
- }
+ /**
+ * send heartbeat interval millisecond
+ * {@link TransportConfig#HEARTBEAT_INTERVAL_MS}
+ */
+ private String heartbeatIntervalMs;
- public void setPort(String port) {
- this.port = port;
- }
+ public String getHeartbeatIntervalMs() {
+ return heartbeatIntervalMs;
+ }
- public String getDashboard() {
- return dashboard;
- }
+ public void setHeartbeatIntervalMs(String heartbeatIntervalMs) {
+ this.heartbeatIntervalMs = heartbeatIntervalMs;
+ }
- public void setDashboard(String dashboard) {
- this.dashboard = dashboard;
- }
+ public String getPort() {
+ return port;
+ }
- }
+ public void setPort(String port) {
+ this.port = port;
+ }
- public static class Filter {
+ public String getDashboard() {
+ return dashboard;
+ }
- /**
- * Sentinel filter chain order.
- */
- private int order = Ordered.HIGHEST_PRECEDENCE;
+ public void setDashboard(String dashboard) {
+ this.dashboard = dashboard;
+ }
- /**
- * URL pattern for sentinel filter,default is /*
- */
- private List urlPatterns;
+ }
- public int getOrder() {
- return this.order;
- }
+ public static class Filter {
- public void setOrder(int order) {
- this.order = order;
- }
+ /**
+ * sentinel filter chain order.
+ */
+ private int order = Ordered.HIGHEST_PRECEDENCE;
- public List getUrlPatterns() {
- return urlPatterns;
- }
+ /**
+ * URL pattern for sentinel filter,default is /*
+ */
+ private List urlPatterns;
- public void setUrlPatterns(List urlPatterns) {
- this.urlPatterns = urlPatterns;
- }
- }
+ public int getOrder() {
+ return this.order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ public List getUrlPatterns() {
+ return urlPatterns;
+ }
+
+ public void setUrlPatterns(List urlPatterns) {
+ this.urlPatterns = urlPatterns;
+ }
+ }
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java
index 9112781b..ea74c449 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java
@@ -18,6 +18,20 @@ package org.springframework.cloud.alibaba.sentinel.custom;
import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
+import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
+
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
@@ -28,115 +42,131 @@ import com.alibaba.csp.sentinel.init.InitExecutor;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.AppNameUtil;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
-import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourcePostProcessor;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.util.StringUtils;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
/**
* @author xiaojing
+ * @author Jim
*/
@Configuration
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelAutoConfiguration {
- @Value("${project.name:${spring.application.name:}}")
- private String projectName;
+ @Value("${project.name:${spring.application.name:}}")
+ private String projectName;
- @Autowired
- private SentinelProperties properties;
+ @Autowired
+ private SentinelProperties properties;
- @Autowired(required = false)
- private UrlCleaner urlCleaner;
+ @Autowired(required = false)
+ private UrlCleaner urlCleaner;
- @Autowired(required = false)
- private UrlBlockHandler urlBlockHandler;
+ @Autowired(required = false)
+ private UrlBlockHandler urlBlockHandler;
- @PostConstruct
- private void init() {
- if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME))
- && StringUtils.hasText(projectName)) {
- System.setProperty(AppNameUtil.APP_NAME, projectName);
- }
- if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))
- && StringUtils.hasText(properties.getTransport().getPort())) {
- System.setProperty(TransportConfig.SERVER_PORT,
- properties.getTransport().getPort());
- }
- if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))
- && StringUtils.hasText(properties.getTransport().getDashboard())) {
- System.setProperty(TransportConfig.CONSOLE_SERVER,
- properties.getTransport().getDashboard());
- }
- if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_INTERVAL_MS))
- && StringUtils
- .hasText(properties.getTransport().getHeartbeatIntervalMs())) {
- System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS,
- properties.getTransport().getHeartbeatIntervalMs());
- }
- if (StringUtils.isEmpty(System.getProperty(SentinelConfig.CHARSET))
- && StringUtils.hasText(properties.getCharset())) {
- System.setProperty(SentinelConfig.CHARSET, properties.getCharset());
- }
- if (StringUtils
- .isEmpty(System.getProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE))
- && StringUtils.hasText(properties.getMetric().getFileSingleSize())) {
- System.setProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE,
- properties.getMetric().getFileSingleSize());
- }
- if (StringUtils
- .isEmpty(System.getProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT))
- && StringUtils.hasText(properties.getMetric().getFileTotalCount())) {
- System.setProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT,
- properties.getMetric().getFileTotalCount());
- }
- if (StringUtils.isEmpty(System.getProperty(SentinelConfig.COLD_FACTOR))
- && StringUtils.hasText(properties.getFlow().getColdFactor())) {
- System.setProperty(SentinelConfig.COLD_FACTOR,
- properties.getFlow().getColdFactor());
- }
+ @PostConstruct
+ private void init() {
+ if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME))
+ && StringUtils.hasText(projectName)) {
+ System.setProperty(AppNameUtil.APP_NAME, projectName);
+ }
+ if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))
+ && StringUtils.hasText(properties.getTransport().getPort())) {
+ System.setProperty(TransportConfig.SERVER_PORT,
+ properties.getTransport().getPort());
+ }
+ if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))
+ && StringUtils.hasText(properties.getTransport().getDashboard())) {
+ System.setProperty(TransportConfig.CONSOLE_SERVER,
+ properties.getTransport().getDashboard());
+ }
+ if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_INTERVAL_MS))
+ && StringUtils
+ .hasText(properties.getTransport().getHeartbeatIntervalMs())) {
+ System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS,
+ properties.getTransport().getHeartbeatIntervalMs());
+ }
+ if (StringUtils.isEmpty(System.getProperty(SentinelConfig.CHARSET))
+ && StringUtils.hasText(properties.getCharset())) {
+ System.setProperty(SentinelConfig.CHARSET, properties.getCharset());
+ }
+ if (StringUtils
+ .isEmpty(System.getProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE))
+ && StringUtils.hasText(properties.getMetric().getFileSingleSize())) {
+ System.setProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE,
+ properties.getMetric().getFileSingleSize());
+ }
+ if (StringUtils
+ .isEmpty(System.getProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT))
+ && StringUtils.hasText(properties.getMetric().getFileTotalCount())) {
+ System.setProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT,
+ properties.getMetric().getFileTotalCount());
+ }
+ if (StringUtils.isEmpty(System.getProperty(SentinelConfig.COLD_FACTOR))
+ && StringUtils.hasText(properties.getFlow().getColdFactor())) {
+ System.setProperty(SentinelConfig.COLD_FACTOR,
+ properties.getFlow().getColdFactor());
+ }
- if (StringUtils.hasText(properties.getServlet().getBlockPage())) {
- WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
- }
- if (urlBlockHandler != null) {
- WebCallbackManager.setUrlBlockHandler(urlBlockHandler);
- }
- if (urlCleaner != null) {
- WebCallbackManager.setUrlCleaner(urlCleaner);
- }
+ if (StringUtils.hasText(properties.getServlet().getBlockPage())) {
+ WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
+ }
+ if (urlBlockHandler != null) {
+ WebCallbackManager.setUrlBlockHandler(urlBlockHandler);
+ }
+ if (urlCleaner != null) {
+ WebCallbackManager.setUrlCleaner(urlCleaner);
+ }
- // earlier initialize
- if (properties.isEager()) {
- InitExecutor.doInit();
- }
- }
+ // earlier initialize
+ if (properties.isEager()) {
+ InitExecutor.doInit();
+ }
+ }
- @Bean
- @ConditionalOnMissingBean
- public SentinelResourceAspect sentinelResourceAspect() {
- return new SentinelResourceAspect();
- }
+ @Bean
+ @ConditionalOnMissingBean
+ public SentinelResourceAspect sentinelResourceAspect() {
+ return new SentinelResourceAspect();
+ }
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
- public SentinelBeanPostProcessor sentinelBeanPostProcessor() {
- return new SentinelBeanPostProcessor();
- }
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
+ public SentinelBeanPostProcessor sentinelBeanPostProcessor() {
+ return new SentinelBeanPostProcessor();
+ }
- @Bean
- @ConditionalOnMissingBean
- public SentinelDataSourcePostProcessor sentinelDataSourcePostProcessor() {
- return new SentinelDataSourcePostProcessor();
- }
+ @Bean
+ public SentinelDataSourceHandler sentinelDataSourceHandler() {
+ return new SentinelDataSourceHandler();
+ }
+
+ @Bean("sentinel-json-converter")
+ public JsonConverter jsonConverter(
+ @Qualifier("sentinel-object-mapper") ObjectMapper objectMapper) {
+ return new JsonConverter(objectMapper);
+ }
+
+ @Bean("sentinel-object-mapper")
+ public ObjectMapper objectMapper() {
+ return new ObjectMapper();
+ }
+
+ @ConditionalOnClass(XmlMapper.class)
+ protected static class SentinelXmlConfiguration {
+ @Bean("sentinel-xml-converter")
+ public XmlConverter xmlConverter(
+ @Qualifier("sentinel-xml-mapper") XmlMapper xmlMapper) {
+ return new XmlConverter(xmlMapper);
+ }
+
+ @Bean("sentinel-xml-mapper")
+ public XmlMapper xmlMapper() {
+ return new XmlMapper();
+ }
+ }
}
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 609cc8d2..fdad9664 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
@@ -34,7 +34,7 @@ import org.springframework.web.client.RestTemplate;
/**
* PostProcessor handle @SentinelProtect Annotation, add interceptor for RestTemplate
*
- * @author fangjian
+ * @author Jim
* @see SentinelProtect
* @see SentinelProtectInterceptor
*/
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java
new file mode 100644
index 00000000..4121d198
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelDataSourceHandler.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2018 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.alibaba.sentinel.custom;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
+import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration;
+import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
+import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
+import org.springframework.context.event.EventListener;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.ResourceUtils;
+import org.springframework.util.StringUtils;
+
+import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
+import com.alibaba.csp.sentinel.property.SentinelProperty;
+import com.alibaba.csp.sentinel.slots.block.AbstractRule;
+import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
+import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
+import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.slots.system.SystemRule;
+import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
+
+/**
+ * Sentinel {@link ReadableDataSource} Handler Handle the configurations of
+ * 'spring.cloud.sentinel.datasource'
+ *
+ * @author Jim
+ * @see SentinelProperties#datasource
+ * @see JsonConverter
+ * @see XmlConverter
+ */
+public class SentinelDataSourceHandler {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(SentinelDataSourceHandler.class);
+
+ private List dataTypeList = Arrays.asList("json", "xml");
+
+ private List> rulesList = Arrays.asList(FlowRule.class,
+ DegradeRule.class, SystemRule.class, AuthorityRule.class);
+
+ private List dataSourceBeanNameList = Collections
+ .synchronizedList(new ArrayList());
+
+ private final String DATATYPE_FIELD = "dataType";
+ private final String CUSTOM_DATATYPE = "custom";
+ private final String CONVERTERCLASS_FIELD = "converterClass";
+
+ @Autowired
+ private SentinelProperties sentinelProperties;
+
+ @EventListener(classes = ApplicationReadyEvent.class)
+ public void buildDataSource(ApplicationReadyEvent event) throws Exception {
+
+ DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) event
+ .getApplicationContext().getAutowireCapableBeanFactory();
+
+ for (Map.Entry entry : sentinelProperties
+ .getDatasource().entrySet()) {
+ String dataSourceName = entry.getKey();
+ DataSourcePropertiesConfiguration dataSourceProperties = entry.getValue();
+
+ if (dataSourceProperties.getInvalidField().size() != 1) {
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " multi datasource active and won't loaded: "
+ + dataSourceProperties.getInvalidField());
+ return;
+ }
+
+ if (dataSourceProperties.getFile() != null) {
+ try {
+ dataSourceProperties.getFile()
+ .setFile(ResourceUtils
+ .getFile(StringUtils.trimAllWhitespace(
+ dataSourceProperties.getFile().getFile()))
+ .getAbsolutePath());
+ }
+ catch (IOException e) {
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " handle file error: " + e.getMessage());
+ throw new RuntimeException("[Sentinel Starter] DataSource "
+ + dataSourceName + " handle file error: " + e.getMessage(),
+ e);
+ }
+ registerBean(beanFactory, dataSourceProperties.getFile(),
+ dataSourceName + "-sentinel-file-datasource");
+ }
+
+ if (dataSourceProperties.getNacos() != null) {
+ registerBean(beanFactory, dataSourceProperties.getNacos(),
+ dataSourceName + "-sentinel-nacos-datasource");
+ }
+
+ if (dataSourceProperties.getApollo() != null) {
+ registerBean(beanFactory, dataSourceProperties.getApollo(),
+ dataSourceName + "-sentinel-apollo-datasource");
+ }
+
+ if (dataSourceProperties.getZk() != null) {
+ registerBean(beanFactory, dataSourceProperties.getZk(),
+ dataSourceName + "-sentinel-zk-datasource");
+ }
+
+ }
+
+ for (String beanName : dataSourceBeanNameList) {
+ ReadableDataSource dataSource = beanFactory.getBean(beanName,
+ ReadableDataSource.class);
+ Object ruleConfig;
+ try {
+ logger.info("[Sentinel Starter] DataSource " + beanName
+ + " start to loadConfig");
+ ruleConfig = dataSource.loadConfig();
+ }
+ catch (Exception e) {
+ logger.error("[Sentinel Starter] DataSource " + beanName
+ + " loadConfig error: " + e.getMessage(), e);
+ return;
+ }
+ SentinelProperty sentinelProperty = dataSource.getProperty();
+ Class ruleType = getAndCheckRuleType(ruleConfig, beanName);
+ if (ruleType != null) {
+ if (ruleType == FlowRule.class) {
+ FlowRuleManager.register2Property(sentinelProperty);
+ }
+ else if (ruleType == DegradeRule.class) {
+ DegradeRuleManager.register2Property(sentinelProperty);
+ }
+ else if (ruleType == SystemRule.class) {
+ SystemRuleManager.register2Property(sentinelProperty);
+ }
+ else {
+ AuthorityRuleManager.register2Property(sentinelProperty);
+ }
+ }
+ }
+ }
+
+ private void registerBean(DefaultListableBeanFactory beanFactory,
+ final AbstractDataSourceProperties dataSourceProperties,
+ String dataSourceName) {
+
+ Map propertyMap = new HashMap<>();
+ for (Field field : dataSourceProperties.getClass().getDeclaredFields()) {
+ try {
+ field.setAccessible(true);
+ Object fieldVal = field.get(dataSourceProperties);
+ if (fieldVal != null) {
+ propertyMap.put(field.getName(), fieldVal);
+ }
+ }
+ catch (IllegalAccessException e) {
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " field: " + field.getName() + " invoke error");
+ throw new RuntimeException("[Sentinel Starter] DataSource "
+ + dataSourceName + " field: " + field.getName() + " invoke error",
+ e);
+ }
+ }
+ propertyMap.put(CONVERTERCLASS_FIELD, dataSourceProperties.getConverterClass());
+ propertyMap.put(DATATYPE_FIELD, dataSourceProperties.getDataType());
+
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder
+ .genericBeanDefinition(dataSourceProperties.getFactoryBeanName());
+
+ for (Map.Entry entry : propertyMap.entrySet()) {
+ String propertyName = entry.getKey();
+ Object propertyValue = entry.getValue();
+ Field field = ReflectionUtils.findField(dataSourceProperties.getClass(),
+ propertyName);
+ if (field != null) {
+ if (DATATYPE_FIELD.equals(propertyName)) {
+ String dataType = StringUtils
+ .trimAllWhitespace(propertyValue.toString());
+ if (CUSTOM_DATATYPE.equals(dataType)) {
+ try {
+ if (StringUtils
+ .isEmpty(dataSourceProperties.getConverterClass())) {
+ throw new RuntimeException(
+ "[Sentinel Starter] DataSource " + dataSourceName
+ + "dataType is custom, please set converter-class "
+ + "property");
+ }
+ // construct custom Converter with 'converterClass'
+ // configuration and register
+ String customConvertBeanName = "sentinel-"
+ + dataSourceProperties.getConverterClass();
+ if (!beanFactory.containsBean(customConvertBeanName)) {
+ beanFactory.registerBeanDefinition(customConvertBeanName,
+ BeanDefinitionBuilder
+ .genericBeanDefinition(
+ Class.forName(dataSourceProperties
+ .getConverterClass()))
+ .getBeanDefinition());
+ }
+ builder.addPropertyReference("converter",
+ customConvertBeanName);
+ }
+ catch (ClassNotFoundException e) {
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " handle "
+ + dataSourceProperties.getClass().getSimpleName()
+ + " error, class name: "
+ + dataSourceProperties.getConverterClass());
+ throw new RuntimeException(
+ "[Sentinel Starter] DataSource " + dataSourceName
+ + " handle "
+ + dataSourceProperties.getClass()
+ .getSimpleName()
+ + " error, class name: "
+ + dataSourceProperties.getConverterClass(),
+ e);
+ }
+ }
+ else {
+ if (!dataTypeList.contains(StringUtils
+ .trimAllWhitespace(propertyValue.toString()))) {
+ throw new RuntimeException("[Sentinel Starter] DataSource "
+ + dataSourceName + " dataType: " + propertyValue
+ + " is not support now. please using these types: "
+ + dataTypeList.toString());
+ }
+ // converter type now support xml or json.
+ // The bean name of these converters wrapped by
+ // 'sentinel-{converterType}-converter'
+ builder.addPropertyReference("converter",
+ "sentinel-" + propertyValue.toString() + "-converter");
+ }
+ }
+ else if (CONVERTERCLASS_FIELD.equals(propertyName)) {
+ continue;
+ }
+ else {
+ // wired properties
+ builder.addPropertyValue(propertyName, propertyValue);
+ }
+ }
+ }
+
+ beanFactory.registerBeanDefinition(dataSourceName, builder.getBeanDefinition());
+ // init in Spring
+ beanFactory.getBean(dataSourceName);
+ dataSourceBeanNameList.add(dataSourceName);
+ }
+
+ private Class getAndCheckRuleType(Object ruleConfig, String dataSourceName) {
+ if (rulesList.contains(ruleConfig.getClass())) {
+ logger.info("[Sentinel Starter] DataSource {} load {} {}", dataSourceName, 1,
+ ruleConfig.getClass().getSimpleName());
+ return ruleConfig.getClass();
+ }
+ else if (ruleConfig instanceof List) {
+ List convertedRuleList = (List) ruleConfig;
+ if (CollectionUtils.isEmpty(convertedRuleList)) {
+ logger.warn("[Sentinel Starter] DataSource {} rule list is empty.",
+ dataSourceName);
+ return null;
+ }
+
+ if (checkRuleTypeValid(convertedRuleList)) {
+ if (checkAllRuleTypeSame(convertedRuleList)) {
+ logger.info("[Sentinel Starter] DataSource {} load {} {}",
+ dataSourceName, convertedRuleList.size(),
+ convertedRuleList.get(0).getClass().getSimpleName());
+ return convertedRuleList.get(0).getClass();
+ }
+ else {
+ logger.warn(
+ "[Sentinel Starter] DataSource {} all rules are not same rule type and it will not be used. "
+ + "Rule List: {}",
+ dataSourceName, convertedRuleList.toString());
+ }
+ }
+ else {
+ List classList = new ArrayList<>();
+ for (Object rule : convertedRuleList) {
+ classList.add(rule.getClass());
+ }
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " rule class is invalid. Class List: " + classList);
+ throw new RuntimeException(
+ "[Sentinel Starter] DataSource " + dataSourceName
+ + " rule class is invalid. Class List: " + classList);
+ }
+ }
+ else {
+ logger.error("[Sentinel Starter] DataSource " + dataSourceName
+ + " rule class is invalid. Class: " + ruleConfig.getClass());
+ throw new RuntimeException("[Sentinel Starter] DataSource " + dataSourceName
+ + " rule class is invalid. Class: " + ruleConfig.getClass());
+ }
+ return null;
+ }
+
+ private boolean checkRuleTypeValid(List convertedRuleList) {
+ int matchCount = 0;
+ for (Object rule : convertedRuleList) {
+ if (rulesList.contains(rule.getClass())) {
+ matchCount++;
+ }
+ }
+ return matchCount == convertedRuleList.size();
+ }
+
+ private boolean checkAllRuleTypeSame(List convertedRuleList) {
+ int matchCount = 0;
+ for(Object rule : convertedRuleList) {
+ if(rulesList.contains(rule.getClass()) && rule.getClass() == convertedRuleList.get(0).getClass()) {
+ matchCount ++;
+ }
+ }
+ return matchCount == convertedRuleList.size();
+ }
+
+ public List getDataSourceBeanNameList() {
+ return dataSourceBeanNameList;
+ }
+
+}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java
index 2a71f0b5..05262314 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java
@@ -20,15 +20,19 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.cloud.alibaba.sentinel.custom.SentinelDataSourceHandler;
+import org.springframework.context.ApplicationContext;
+
+import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
-import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
/**
* Endpoint for Sentinel, contains ans properties and rules
@@ -39,6 +43,12 @@ public class SentinelEndpoint extends AbstractEndpoint