mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
sentinel starter support springboot 1.x
This commit is contained in:
parent
bfc04daf9b
commit
4600f42647
@ -32,6 +32,21 @@
|
|||||||
<artifactId>sentinel-datasource-extension</artifactId>
|
<artifactId>sentinel-datasource-extension</artifactId>
|
||||||
<version>${sentinel.version}</version>
|
<version>${sentinel.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-apollo</artifactId>
|
||||||
|
<version>${sentinel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-zookeeper</artifactId>
|
||||||
|
<version>${sentinel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||||
|
<version>${sentinel.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-web-servlet</artifactId>
|
<artifactId>sentinel-web-servlet</artifactId>
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>sentinel-example</module>
|
<module>sentinel-example</module>
|
||||||
|
<module>sentinel-dubbo-provider-example</module>
|
||||||
|
<module>sentinel-dubbo-consumer-example</module>
|
||||||
|
<module>sentinel-dubbo-api</module>
|
||||||
<module>storage-example</module>
|
<module>storage-example</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
@ -30,12 +30,6 @@
|
|||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba.boot</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
<version>0.1.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -157,42 +157,81 @@ Sentinel 控制台支持实时监控查看,您可以通过 Sentinel 控制台
|
|||||||
|
|
||||||
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180' ></p>
|
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180' ></p>
|
||||||
|
|
||||||
## Dubbo支持
|
## DataSource支持
|
||||||
|
|
||||||
[Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架。
|
Sentinel内部提供了[动态规则的扩展实现DataSource](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提供了[sentinel-dubbo-adapter](https://github.com/alibaba/Sentinel/tree/master/sentinel-adapter/sentinel-dubbo-adapter)模块用来支持Dubbo服务调用的限流降级。sentinel-starter默认也集成了该功能。
|
Sentinel starter整合了目前存在的4类DataSource。只需要在配置文件中进行相关配置,即可在Spring容器中自动注册DataSource。
|
||||||
|
|
||||||
比如有个FooService服务,定义如下:
|
比如要定义一个FileRefreshableDataSource,配置如下:
|
||||||
|
|
||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService;
|
spring.cloud.sentinel.datasource.type=file
|
||||||
public interface FooService {
|
spring.cloud.sentinel.datasource.recommendRefreshMs=2000
|
||||||
String hello(String name);
|
spring.cloud.sentinel.datasource.bufSize=2048
|
||||||
|
spring.cloud.sentinel.datasource.charset=utf-8
|
||||||
|
spring.cloud.sentinel.datasource.configParser=myParser
|
||||||
|
spring.cloud.sentinel.datasource.file=/Users/you/rule.json
|
||||||
|
|
||||||
|
然后使用`@SentinelDataSource`注解修饰DataSource即可注入:
|
||||||
|
|
||||||
|
@SentinelDataSource("spring.cloud.sentinel.datasource")
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
`@SentinelDataSource`注解的value属性可以不填。默认值就是spring.cloud.sentinel.datasource。
|
||||||
|
|
||||||
|
value属性代表配置前缀。示例中会去找spring.cloud.sentinel.datasource.xxx相关的配置。
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.type就是对应的DataSource类型。
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.recommendRefreshMs里的recommendRefreshMs对应相关DataSource的属性。
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.configParser代表ConfigParser在Spring容器里的name。如果没找到,会抛出异常。
|
||||||
|
|
||||||
|
type目前支持file, nacos, zk, apollo。
|
||||||
|
|
||||||
|
### 自定义DataSource
|
||||||
|
|
||||||
|
自定义DataSource只需要两部。
|
||||||
|
|
||||||
|
1. 定义DataSource
|
||||||
|
|
||||||
|
public class CustomDataSource implements DataSource {
|
||||||
|
private String fieldA;
|
||||||
|
private String fieldB;
|
||||||
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
该服务在Sentinel下对应的资源名是 `org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)` 。
|
2. 装配DataSource。有两种方式处理。
|
||||||
|
|
||||||
在Consumer端进行限流的话,需要处理SentinelRpcException。
|
* 直接构造DataSource
|
||||||
|
|
||||||
FooService service = applicationContext.getBean(FooService.class);
|
@Bean
|
||||||
|
public CustomDataSource customDataSource() {
|
||||||
for (int i = 0; i < 15; i++) {
|
CustomDataSource customDataSource =
|
||||||
try {
|
new CustomDataSource();
|
||||||
String message = service.hello("Jim");
|
customDataSource.setFieldA("valueA");
|
||||||
} catch (SentinelRpcException ex) {
|
customDataSource.setFieldB("valueB");
|
||||||
System.out.println("Blocked");
|
...
|
||||||
} catch (Exception ex) {
|
return customDataSource;
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
在Provider端进行限流的话,Consumer端调用的话会抛出RpcException。因为Provider端被限流抛出了SentinelRpcException。
|
* 在classpath:/META-INF/sentinel-datasource.properties中管理DataSource信息
|
||||||
|
|
||||||
### Dubbo 应用启动
|
custom = yourpackage.CustomDataSource
|
||||||
|
|
||||||
在启动ServiceApplication的前提下,再启动ConsumerApplication。
|
在application.properties中定义DataSource
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.type = custom
|
||||||
|
spring.cloud.sentinel.datasource.fieldA = valueA
|
||||||
|
spring.cloud.sentinel.datasource.fieldB = valueB
|
||||||
|
|
||||||
|
注意:由于目前Sentinel的AbstractDataSource需要有个ConfigParser作为构造函数中的参数,并且它的子类的构造都是通过多个参数的构造函数构造的。
|
||||||
|
所以目前所有的Sentinel starter中的DataSource都是基于FactoryBean并且通过设置属性构造的。如果有这方面的需求,需要再多加一个registerFactoryBean过程。
|
||||||
|
|
||||||
|
SentinelDataSourceRegistry.registerFactoryBean("custeom", CustomDataSourceFactoryBean.class);
|
||||||
|
|
||||||
|
如果自定义DataSource可以注入属性,那么没有必要使用SentinelDataSourceRegistry注册FactoryBean。
|
||||||
|
|
||||||
ConsumerApplication在Consumer端设置了限流规则,所以启动完成后查看控制台的打印信息,会发现部分调用被Block。
|
|
||||||
|
|
||||||
## More
|
## More
|
||||||
Sentinel 是一款功能强大的中间件,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。此 Demo 仅演示了 使用 Sentinel 作为限流工具的使用,更多 Sentinel 相关的信息,请参考 [Sentinel 项目](https://github.com/alibaba/Sentinel)。
|
Sentinel 是一款功能强大的中间件,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。此 Demo 仅演示了 使用 Sentinel 作为限流工具的使用,更多 Sentinel 相关的信息,请参考 [Sentinel 项目](https://github.com/alibaba/Sentinel)。
|
||||||
|
@ -165,42 +165,77 @@ To see the metrics, click **实时监控(Real-time Monitoring)** in the left-sid
|
|||||||
|
|
||||||
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180'></p>
|
<p align="center"><img src="https://cdn.nlark.com/lark/0/2018/png/54319/1532313595369-8428cd7d-9eb7-4786-a149-acf0da4a2daf.png" width="480" heigh='180'></p>
|
||||||
|
|
||||||
## Dubbo
|
## DataSource
|
||||||
|
|
||||||
[Dubbo](http://dubbo.apache.org/) is a high-performance, java based open source RPC framework.
|
Sentinel provide [DataSource](https://github.com/alibaba/Sentinel/blob/master/sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/DataSource.java) to manage dynamic rules.
|
||||||
|
|
||||||
Sentinel provide a module named [sentinel-dubbo-adapter](https://github.com/alibaba/Sentinel/tree/master/sentinel-adapter/sentinel-dubbo-adapter) to support dubbo.sentinel-starter integrates this feature by default.
|
Sentinel starter integrated 4 DataSources provided by Sentinel. It will be register into Spring Context if you write some configs in `application.properties`.
|
||||||
|
|
||||||
For example, a service named FooService, see the code below:
|
If you want to define FileRefreshableDataSource:
|
||||||
|
|
||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService;
|
spring.cloud.sentinel.datasource.type=file
|
||||||
public interface FooService {
|
spring.cloud.sentinel.datasource.recommendRefreshMs=2000
|
||||||
String hello(String name);
|
spring.cloud.sentinel.datasource.bufSize=2048
|
||||||
|
spring.cloud.sentinel.datasource.charset=utf-8
|
||||||
|
spring.cloud.sentinel.datasource.configParser=myParser
|
||||||
|
spring.cloud.sentinel.datasource.file=/Users/you/rule.json
|
||||||
|
|
||||||
|
then use `@SentinelDataSource` to annotate DataSource:
|
||||||
|
|
||||||
|
@SentinelDataSource("spring.cloud.sentinel.datasource")
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
The value() of `@SentinelDataSource` is not required, it means the prefix of configuration. Default value is `spring.cloud.sentinel.datasource`.
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.type means the type of DataSource.
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.recommendRefreshMs means the recommendRefreshMs property of specified DataSource.
|
||||||
|
|
||||||
|
spring.cloud.sentinel.datasource.configParser means the name of spring bean that type is ConfigParser. If the bean is not exists, will throw exception.
|
||||||
|
|
||||||
|
Now datasource type support 4 categories: file, nacos, zk, apollo.
|
||||||
|
|
||||||
|
### User-defined DataSource
|
||||||
|
|
||||||
|
User-defined DataSource need 2 steps.
|
||||||
|
|
||||||
|
1. Define DataSource
|
||||||
|
|
||||||
|
public class CustomDataSource implements DataSource {
|
||||||
|
private String fieldA;
|
||||||
|
private String fieldB;
|
||||||
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
The resource name of this service is `org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)` .
|
2. Assemble DataSource. There are 2 ways to do this.
|
||||||
|
|
||||||
You should handle SentinelRpcException if rpc invocation was be limited on Consumer side:
|
* Construct DataSource directly
|
||||||
|
|
||||||
FooService service = applicationContext.getBean(FooService.class);
|
@Bean
|
||||||
|
public CustomDataSource customDataSource() {
|
||||||
for (int i = 0; i < 15; i++) {
|
CustomDataSource customDataSource = new CustomDataSource();
|
||||||
try {
|
customDataSource.setFieldA("valueA");
|
||||||
String message = service.hello("Jim");
|
customDataSource.setFieldB("valueB");
|
||||||
} catch (SentinelRpcException ex) {
|
...
|
||||||
System.out.println("Blocked");
|
return customDataSource;
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
It will throw RpcException on Consumer side if it was be limited on Provider side, because Provider side throw SentinelRpcException in this scene.
|
* define DataSource metadata in `classpath:/META-INF/sentinel-datasource.properties`
|
||||||
|
|
||||||
### Dubbo Start Application
|
custom = yourpackage.CustomDataSource
|
||||||
|
|
||||||
You can startup ConsumerApplication after ServiceApplication startup.
|
define configuration in `application.properties`
|
||||||
|
|
||||||
ConsumerApplication init flow control rules after startup, so you will find some invocations have been blocked in console.
|
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 ConfigParser 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.
|
||||||
|
|
||||||
## More
|
## More
|
||||||
For more information about Sentinel, see [Sentinel Project](https://github.com/alibaba/Sentinel).
|
For more information about Sentinel, see [Sentinel Project](https://github.com/alibaba/Sentinel).
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.springframework.cloud.alibaba.cloud.examples;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fangjian
|
||||||
|
*/
|
||||||
|
public class JsonFlowRuleListParser implements ConfigParser<String, List<FlowRule>> {
|
||||||
|
@Override
|
||||||
|
public List<FlowRule> parse(String source) {
|
||||||
|
return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,8 @@ import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author xiaojing
|
* @author xiaojing
|
||||||
*/
|
*/
|
||||||
@ -23,6 +25,11 @@ public class ServiceApplication {
|
|||||||
return new RestTemplate();
|
return new RestTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConfigParser myParser() {
|
||||||
|
return new JsonFlowRuleListParser();
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(ServiceApplication.class, args);
|
SpringApplication.run(ServiceApplication.class, args);
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo;
|
|
||||||
|
|
||||||
import org.springframework.boot.Banner;
|
|
||||||
import org.springframework.boot.CommandLineRunner;
|
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
||||||
import org.springframework.cloud.alibaba.cloud.examples.dubbo.provider.ProviderApplication;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fangjian
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class DubboProviderRunner implements CommandLineRunner {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(String... args) throws Exception {
|
|
||||||
SpringApplicationBuilder providerBuilder = new SpringApplicationBuilder()
|
|
||||||
.bannerMode(Banner.Mode.OFF).registerShutdownHook(false)
|
|
||||||
.logStartupInfo(false).web(false);
|
|
||||||
providerBuilder.sources(ProviderApplication.class).run(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fangjian
|
|
||||||
*/
|
|
||||||
public interface FooService {
|
|
||||||
|
|
||||||
String hello(String name);
|
|
||||||
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.consumer;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.springframework.boot.Banner;
|
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
|
||||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
|
||||||
import com.alibaba.dubbo.config.ConsumerConfig;
|
|
||||||
import com.alibaba.dubbo.config.RegistryConfig;
|
|
||||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fangjian
|
|
||||||
*/
|
|
||||||
@DubboComponentScan("org.springframework.cloud.alibaba.cloud.examples.dubbo.provider")
|
|
||||||
public class ConsumerApplication {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationConfig applicationConfig() {
|
|
||||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
|
||||||
applicationConfig.setName("demo-consumer");
|
|
||||||
return applicationConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public RegistryConfig registryConfig() {
|
|
||||||
RegistryConfig registryConfig = new RegistryConfig();
|
|
||||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
|
||||||
return registryConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ConsumerConfig consumerConfig() {
|
|
||||||
ConsumerConfig consumerConfig = new ConsumerConfig();
|
|
||||||
return consumerConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public FooServiceConsumer annotationDemoServiceConsumer() {
|
|
||||||
return new FooServiceConsumer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
SpringApplicationBuilder consumerBuilder = new SpringApplicationBuilder()
|
|
||||||
.bannerMode(Banner.Mode.OFF).registerShutdownHook(false)
|
|
||||||
.logStartupInfo(false).web(false);
|
|
||||||
ApplicationContext applicationContext = consumerBuilder
|
|
||||||
.sources(ConsumerApplication.class).run(args);
|
|
||||||
|
|
||||||
FlowRule flowRule = new FlowRule();
|
|
||||||
flowRule.setResource(
|
|
||||||
"org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)");
|
|
||||||
flowRule.setCount(10);
|
|
||||||
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
|
||||||
flowRule.setLimitApp("default");
|
|
||||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
|
||||||
|
|
||||||
FooServiceConsumer service = applicationContext.getBean(FooServiceConsumer.class);
|
|
||||||
|
|
||||||
for (int i = 0; i < 15; i++) {
|
|
||||||
try {
|
|
||||||
String message = service.hello("Jim");
|
|
||||||
System.out.println((i + 1) + " -> Success: " + message);
|
|
||||||
}
|
|
||||||
catch (SentinelRpcException ex) {
|
|
||||||
System.out.println("Blocked");
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.consumer;
|
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService;
|
|
||||||
|
|
||||||
import com.alibaba.dubbo.config.annotation.Reference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fangjian
|
|
||||||
*/
|
|
||||||
public class FooServiceConsumer {
|
|
||||||
|
|
||||||
@Reference(url = "dubbo://127.0.0.1:25758", timeout = 3000)
|
|
||||||
private FooService fooService;
|
|
||||||
|
|
||||||
public String hello(String name) {
|
|
||||||
return fooService.hello(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.provider;
|
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService;
|
|
||||||
|
|
||||||
import com.alibaba.dubbo.config.annotation.Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fangjian
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class FooServiceImpl implements FooService {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String hello(String name) {
|
|
||||||
return "hello, " + name;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.provider;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
|
|
||||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
|
||||||
import com.alibaba.dubbo.config.ProtocolConfig;
|
|
||||||
import com.alibaba.dubbo.config.RegistryConfig;
|
|
||||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fangjian
|
|
||||||
*/
|
|
||||||
@DubboComponentScan("org.springframework.cloud.alibaba.cloud.examples.dubbo.provider")
|
|
||||||
public class ProviderApplication {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ApplicationConfig applicationConfig() {
|
|
||||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
|
||||||
applicationConfig.setName("demo-provider");
|
|
||||||
return applicationConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public RegistryConfig registryConfig() {
|
|
||||||
RegistryConfig registryConfig = new RegistryConfig();
|
|
||||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
|
||||||
return registryConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ProtocolConfig protocolConfig() {
|
|
||||||
ProtocolConfig protocolConfig = new ProtocolConfig();
|
|
||||||
protocolConfig.setName("dubbo");
|
|
||||||
protocolConfig.setPort(25758);
|
|
||||||
return protocolConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -3,3 +3,12 @@ server.port=18083
|
|||||||
management.security.enabled=false
|
management.security.enabled=false
|
||||||
spring.cloud.sentinel.port=8721
|
spring.cloud.sentinel.port=8721
|
||||||
spring.cloud.sentinel.dashboard=localhost:8080
|
spring.cloud.sentinel.dashboard=localhost:8080
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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.configParser=myParser
|
||||||
|
spring.cloud.sentinel.datasource.file=/Users/you/rule.json
|
@ -25,6 +25,29 @@
|
|||||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-extension</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-zookeeper</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-apollo</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-annotation-aspectj</artifactId>
|
<artifactId>sentinel-annotation-aspectj</artifactId>
|
||||||
|
@ -14,41 +14,20 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.cloud.alibaba.sentinel.custom;
|
package org.springframework.cloud.alibaba.sentinel;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.Entry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author xiaojing
|
* @author fangjian
|
||||||
*/
|
*/
|
||||||
public class SentinelEntry {
|
public interface SentinelConstants {
|
||||||
|
|
||||||
private String key;
|
String PROPERTY_PREFIX = "spring.cloud.sentinel";
|
||||||
private String handler;
|
|
||||||
|
|
||||||
private Entry entry;
|
String PROPERTY_ITEM_SEPARATOR = ".";
|
||||||
|
|
||||||
|
String PROPERTY_DATASOURCE_NAME = "datasource";
|
||||||
|
|
||||||
|
String PROPERTY_DATASOURCE_PREFIX = PROPERTY_PREFIX + PROPERTY_ITEM_SEPARATOR
|
||||||
|
+ PROPERTY_DATASOURCE_NAME;
|
||||||
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKey(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getHandler() {
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHandler(String handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Entry getEntry() {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntry(Entry entry) {
|
|
||||||
this.entry = entry;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ import org.springframework.core.Ordered;
|
|||||||
* @author xiaojing
|
* @author xiaojing
|
||||||
* @author hengyunabc
|
* @author hengyunabc
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = "spring.cloud.sentinel")
|
@ConfigurationProperties(prefix = SentinelConstants.PROPERTY_PREFIX)
|
||||||
public class SentinelProperties {
|
public class SentinelProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,25 +16,22 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.alibaba.sentinel;
|
package org.springframework.cloud.alibaba.sentinel;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
import javax.servlet.Filter;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
|
||||||
import javax.servlet.Filter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author xiaojing
|
* @author xiaojing
|
||||||
@ -47,30 +44,10 @@ public class SentinelWebAutoConfiguration {
|
|||||||
private static final Logger logger = LoggerFactory
|
private static final Logger logger = LoggerFactory
|
||||||
.getLogger(SentinelWebAutoConfiguration.class);
|
.getLogger(SentinelWebAutoConfiguration.class);
|
||||||
|
|
||||||
@Value("${project.name:${spring.application.name:}}")
|
|
||||||
private String projectName;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SentinelProperties properties;
|
private SentinelProperties properties;
|
||||||
|
|
||||||
public static final String APP_NAME = "project.name";
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
private void init() {
|
|
||||||
if (StringUtils.isEmpty(System.getProperty(APP_NAME))) {
|
|
||||||
System.setProperty(APP_NAME, projectName);
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))) {
|
|
||||||
System.setProperty(TransportConfig.SERVER_PORT, properties.getPort());
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))) {
|
|
||||||
System.setProperty(TransportConfig.CONSOLE_SERVER, properties.getDashboard());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnWebApplication
|
|
||||||
public FilterRegistrationBean servletRequestListener() {
|
public FilterRegistrationBean servletRequestListener() {
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||||
|
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An annotation to inject {@link com.alibaba.csp.sentinel.datasource.DataSource} instance
|
||||||
|
* into a Spring Bean. The Properties of DataSource bean get from config files with
|
||||||
|
* specific prefix.
|
||||||
|
*
|
||||||
|
* @author fangjian
|
||||||
|
* @see com.alibaba.csp.sentinel.datasource.DataSource
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.FIELD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface SentinelDataSource {
|
||||||
|
|
||||||
|
@AliasFor("prefix")
|
||||||
|
String value() default "";
|
||||||
|
|
||||||
|
@AliasFor("value")
|
||||||
|
String prefix() default "";
|
||||||
|
|
||||||
|
String name() default ""; // spring bean name
|
||||||
|
|
||||||
|
}
|
@ -16,20 +16,52 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.alibaba.sentinel.custom;
|
package org.springframework.cloud.alibaba.sentinel.custom;
|
||||||
|
|
||||||
|
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.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author xiaojing
|
* @author xiaojing
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
|
||||||
|
@EnableConfigurationProperties(SentinelProperties.class)
|
||||||
public class SentinelAutoConfiguration {
|
public class SentinelAutoConfiguration {
|
||||||
|
|
||||||
|
@Value("${project.name:${spring.application.name:}}")
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SentinelProperties properties;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME))) {
|
||||||
|
System.setProperty(AppNameUtil.APP_NAME, projectName);
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))) {
|
||||||
|
System.setProperty(TransportConfig.SERVER_PORT, properties.getPort());
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))) {
|
||||||
|
System.setProperty(TransportConfig.CONSOLE_SERVER, properties.getDashboard());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public SentinelResourceAspect sentinelResourceAspect() {
|
public SentinelResourceAspect sentinelResourceAspect() {
|
||||||
@ -38,9 +70,15 @@ public class SentinelAutoConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
@ConditionalOnClass(value = RestTemplate.class)
|
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
|
||||||
public SentinelBeanPostProcessor sentinelBeanPostProcessor() {
|
public SentinelBeanPostProcessor sentinelBeanPostProcessor() {
|
||||||
return new SentinelBeanPostProcessor();
|
return new SentinelBeanPostProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SentinelDataSourcePostProcessor sentinelDataSourcePostProcessor() {
|
||||||
|
return new SentinelDataSourcePostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ import com.alibaba.csp.sentinel.util.StringUtil;
|
|||||||
*/
|
*/
|
||||||
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
|
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory
|
private static final Logger logger = LoggerFactory
|
||||||
.getLogger(SentinelProtectInterceptor.class);
|
.getLogger(SentinelProtectInterceptor.class);
|
||||||
|
|
||||||
private SentinelProtect sentinelProtect;
|
private SentinelProtect sentinelProtect;
|
||||||
@ -68,12 +68,12 @@ public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor
|
|||||||
response = execution.execute(request, body);
|
response = execution.execute(request, body);
|
||||||
}
|
}
|
||||||
catch (BlockException e) {
|
catch (BlockException e) {
|
||||||
LOGGER.error("RestTemplate block", e);
|
logger.error("RestTemplate block", e);
|
||||||
try {
|
try {
|
||||||
handleBlockException(e);
|
handleBlockException(e);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
LOGGER.error("sentinel handle BlockException error.", e);
|
logger.error("sentinel handle BlockException error.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* 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 static org.springframework.core.io.support.ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
|
||||||
|
|
||||||
|
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 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 com.alibaba.csp.sentinel.datasource.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link DataSource} Loader
|
||||||
|
*
|
||||||
|
* @author fangjian
|
||||||
|
*/
|
||||||
|
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<String, Class<? extends DataSource>> dataSourceClassesCache = new ConcurrentHashMap<String, Class<? extends DataSource>>(
|
||||||
|
4);
|
||||||
|
|
||||||
|
static void loadAllDataSourceClassesCache() {
|
||||||
|
Map<String, Class<? extends DataSource>> dataSourceClassesMap = loadAllDataSourceClassesCache(
|
||||||
|
ALL_PROPERTIES_RESOURCES_LOCATION);
|
||||||
|
|
||||||
|
dataSourceClassesCache.putAll(dataSourceClassesMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, Class<? extends DataSource>> loadAllDataSourceClassesCache(
|
||||||
|
String resourcesLocation) {
|
||||||
|
|
||||||
|
Map<String, Class<? extends DataSource>> dataSourcesMap = new HashMap<String, Class<? extends DataSource>>(
|
||||||
|
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<Object, Object> entry : properties.entrySet()) {
|
||||||
|
|
||||||
|
String type = (String) entry.getKey();
|
||||||
|
String className = (String) entry.getValue();
|
||||||
|
|
||||||
|
if (!ClassUtils.isPresent(className, classLoader)) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(
|
||||||
|
"Sentinel DataSource implementation [ type : "
|
||||||
|
+ type + ": , class : " + className
|
||||||
|
+ " , url : " + resource.getURL()
|
||||||
|
+ "] was not present in current classpath , "
|
||||||
|
+ "thus loading will be ignored , please add dependency if required !");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.isTrue(!dataSourcesMap.containsKey(type),
|
||||||
|
"The duplicated type[" + type
|
||||||
|
+ "] of SentinelDataSource were found in "
|
||||||
|
+ "resource [" + resource.getURL() + "]");
|
||||||
|
|
||||||
|
Class<?> dataSourceClass = ClassUtils.resolveClassName(className,
|
||||||
|
classLoader);
|
||||||
|
Assert.isAssignable(DataSource.class, dataSourceClass);
|
||||||
|
|
||||||
|
dataSourcesMap.put(type,
|
||||||
|
(Class<? extends DataSource>) dataSourceClass);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Sentinel DataSource implementation [ type : "
|
||||||
|
+ type + ": , class : " + className
|
||||||
|
+ "] was loaded.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
if (logger.isErrorEnabled()) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataSourcesMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<? extends DataSource> loadClass(String type)
|
||||||
|
throws IllegalArgumentException {
|
||||||
|
|
||||||
|
Class<? extends DataSource> dataSourceClass = dataSourceClassesCache.get(type);
|
||||||
|
|
||||||
|
if (dataSourceClass == null) {
|
||||||
|
if (dataSourceClassesCache.isEmpty()) {
|
||||||
|
loadAllDataSourceClassesCache();
|
||||||
|
dataSourceClass = dataSourceClassesCache.get(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSourceClass == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Sentinel DataSource implementation [ type : " + type
|
||||||
|
+ " ] can't be found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataSourceClass;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* 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 static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
|
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.PropertyValues;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.SentinelConstants;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelDataSource;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.util.PropertySourcesUtils;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.env.ConfigurableEnvironment;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SentinelDataSource @SentinelDataSource} Post Processor
|
||||||
|
*
|
||||||
|
* @author fangjian
|
||||||
|
* @see com.alibaba.csp.sentinel.datasource.DataSource
|
||||||
|
* @see SentinelDataSource
|
||||||
|
*/
|
||||||
|
public class SentinelDataSourcePostProcessor
|
||||||
|
extends InstantiationAwareBeanPostProcessorAdapter
|
||||||
|
implements MergedBeanDefinitionPostProcessor {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory
|
||||||
|
.getLogger(SentinelDataSourcePostProcessor.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfigurableEnvironment environment;
|
||||||
|
|
||||||
|
private final Map<String, List<SentinelDataSourceField>> dataSourceFieldCache = new ConcurrentHashMap<>(
|
||||||
|
64);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
|
||||||
|
Class<?> beanType, final String beanName) {
|
||||||
|
// find all fields using by @SentinelDataSource annotation
|
||||||
|
ReflectionUtils.doWithFields(beanType, new ReflectionUtils.FieldCallback() {
|
||||||
|
@Override
|
||||||
|
public void doWith(Field field)
|
||||||
|
throws IllegalArgumentException, IllegalAccessException {
|
||||||
|
SentinelDataSource annotation = getAnnotation(field,
|
||||||
|
SentinelDataSource.class);
|
||||||
|
if (annotation != null) {
|
||||||
|
if (Modifier.isStatic(field.getModifiers())) {
|
||||||
|
if (logger.isWarnEnabled()) {
|
||||||
|
logger.warn(
|
||||||
|
"@SentinelDataSource annotation is not supported on static fields: "
|
||||||
|
+ field);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dataSourceFieldCache.containsKey(beanName)) {
|
||||||
|
dataSourceFieldCache.get(beanName)
|
||||||
|
.add(new SentinelDataSourceField(annotation, field));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
List<SentinelDataSourceField> list = new ArrayList<>();
|
||||||
|
list.add(new SentinelDataSourceField(annotation, field));
|
||||||
|
dataSourceFieldCache.put(beanName, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
|
||||||
|
PropertyDescriptor[] pds, Object bean, String beanName)
|
||||||
|
throws BeanCreationException {
|
||||||
|
if (dataSourceFieldCache.containsKey(beanName)) {
|
||||||
|
List<SentinelDataSourceField> sentinelDataSourceFields = dataSourceFieldCache
|
||||||
|
.get(beanName);
|
||||||
|
for(SentinelDataSourceField sentinelDataSourceField : sentinelDataSourceFields) {
|
||||||
|
try {
|
||||||
|
// construct DataSource field annotated by @SentinelDataSource
|
||||||
|
Field field = sentinelDataSourceField.getField();
|
||||||
|
ReflectionUtils.makeAccessible(field);
|
||||||
|
String dataSourceBeanName = constructDataSource(
|
||||||
|
sentinelDataSourceField.getSentinelDataSource());
|
||||||
|
field.set(bean, applicationContext.getBean(dataSourceBeanName));
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String constructDataSource(SentinelDataSource annotation) {
|
||||||
|
String prefix = annotation.value();
|
||||||
|
if (StringUtils.isEmpty(prefix)) {
|
||||||
|
prefix = SentinelConstants.PROPERTY_DATASOURCE_PREFIX;
|
||||||
|
}
|
||||||
|
Map<String, Object> propertyMap = PropertySourcesUtils
|
||||||
|
.getSubProperties(environment.getPropertySources(), prefix);
|
||||||
|
String alias = propertyMap.get("type").toString();
|
||||||
|
Class dataSourceClass = DataSourceLoader.loadClass(alias);
|
||||||
|
|
||||||
|
String beanName = StringUtils.isEmpty(annotation.name())
|
||||||
|
? StringUtils.uncapitalize(dataSourceClass.getSimpleName()) + "_" + prefix
|
||||||
|
: annotation.name();
|
||||||
|
if (applicationContext.containsBean(beanName)) {
|
||||||
|
return beanName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class targetClass = null;
|
||||||
|
// if alias exists in SentinelDataSourceRegistry, wired properties into
|
||||||
|
// FactoryBean
|
||||||
|
if (SentinelDataSourceRegistry.checkFactoryBean(alias)) {
|
||||||
|
targetClass = SentinelDataSourceRegistry.getFactoryBean(alias);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// if alias not exists in SentinelDataSourceRegistry, wired properties into
|
||||||
|
// raw class
|
||||||
|
targetClass = dataSourceClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerDataSource(beanName, targetClass, propertyMap);
|
||||||
|
|
||||||
|
return beanName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerDataSource(String beanName, Class targetClass,
|
||||||
|
Map<String, Object> propertyMap) {
|
||||||
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||||
|
.genericBeanDefinition(targetClass);
|
||||||
|
for (String propertyName : propertyMap.keySet()) {
|
||||||
|
Field field = ReflectionUtils.findField(targetClass, propertyName);
|
||||||
|
if (field != null) {
|
||||||
|
if (field.getType().isAssignableFrom(ConfigParser.class)) {
|
||||||
|
// ConfigParser get from ApplicationContext
|
||||||
|
builder.addPropertyReference(propertyName,
|
||||||
|
propertyMap.get(propertyName).toString());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// wired properties
|
||||||
|
builder.addPropertyValue(propertyName, propertyMap.get(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
|
||||||
|
.getAutowireCapableBeanFactory();
|
||||||
|
beanFactory.registerBeanDefinition(beanName, builder.getBeanDefinition());
|
||||||
|
}
|
||||||
|
|
||||||
|
class SentinelDataSourceField {
|
||||||
|
private SentinelDataSource sentinelDataSource;
|
||||||
|
private Field field;
|
||||||
|
|
||||||
|
public SentinelDataSourceField(SentinelDataSource sentinelDataSource,
|
||||||
|
Field field) {
|
||||||
|
this.sentinelDataSource = sentinelDataSource;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SentinelDataSource getSentinelDataSource() {
|
||||||
|
return sentinelDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSentinelDataSource(SentinelDataSource sentinelDataSource) {
|
||||||
|
this.sentinelDataSource = sentinelDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Field getField() {
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField(Field field) {
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ApolloDataSourceFactoryBean;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.FileRefreshableDataSourceFactoryBean;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry to save DataSource FactoryBean
|
||||||
|
*
|
||||||
|
* @author fangjian
|
||||||
|
* @see com.alibaba.csp.sentinel.datasource.DataSource
|
||||||
|
* @see FileRefreshableDataSourceFactoryBean
|
||||||
|
* @see ZookeeperDataSourceFactoryBean
|
||||||
|
* @see NacosDataSourceFactoryBean
|
||||||
|
* @see ApolloDataSourceFactoryBean
|
||||||
|
*/
|
||||||
|
public class SentinelDataSourceRegistry {
|
||||||
|
|
||||||
|
private static ConcurrentHashMap<String, Class<? extends FactoryBean>> cache = new ConcurrentHashMap<>(
|
||||||
|
32);
|
||||||
|
|
||||||
|
static {
|
||||||
|
SentinelDataSourceRegistry.registerFactoryBean("file",
|
||||||
|
FileRefreshableDataSourceFactoryBean.class);
|
||||||
|
SentinelDataSourceRegistry.registerFactoryBean("zk",
|
||||||
|
ZookeeperDataSourceFactoryBean.class);
|
||||||
|
SentinelDataSourceRegistry.registerFactoryBean("nacos",
|
||||||
|
NacosDataSourceFactoryBean.class);
|
||||||
|
SentinelDataSourceRegistry.registerFactoryBean("apollo",
|
||||||
|
ApolloDataSourceFactoryBean.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void registerFactoryBean(String alias,
|
||||||
|
Class<? extends FactoryBean> clazz) {
|
||||||
|
cache.putIfAbsent(alias, clazz);
|
||||||
|
cache.put(alias, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<? extends FactoryBean> getFactoryBean(String alias) {
|
||||||
|
return cache.get(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkFactoryBean(String alias) {
|
||||||
|
return cache.containsKey(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fangjian
|
||||||
|
* @see ApolloDataSource
|
||||||
|
*/
|
||||||
|
public class ApolloDataSourceFactoryBean implements FactoryBean<ApolloDataSource> {
|
||||||
|
|
||||||
|
private String namespaceName;
|
||||||
|
private String flowRulesKey;
|
||||||
|
private String defaultFlowRuleValue;
|
||||||
|
private ConfigParser configParser;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApolloDataSource getObject() throws Exception {
|
||||||
|
return new ApolloDataSource(namespaceName, flowRulesKey, defaultFlowRuleValue,
|
||||||
|
configParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return ApolloDataSource.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNamespaceName() {
|
||||||
|
return namespaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNamespaceName(String namespaceName) {
|
||||||
|
this.namespaceName = namespaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlowRulesKey() {
|
||||||
|
return flowRulesKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlowRulesKey(String flowRulesKey) {
|
||||||
|
this.flowRulesKey = flowRulesKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDefaultFlowRuleValue() {
|
||||||
|
return defaultFlowRuleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultFlowRuleValue(String defaultFlowRuleValue) {
|
||||||
|
this.defaultFlowRuleValue = defaultFlowRuleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigParser getConfigParser() {
|
||||||
|
return configParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigParser(ConfigParser configParser) {
|
||||||
|
this.configParser = configParser;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fangjian
|
||||||
|
* @see FileRefreshableDataSource
|
||||||
|
*/
|
||||||
|
public class FileRefreshableDataSourceFactoryBean implements FactoryBean<FileRefreshableDataSource> {
|
||||||
|
|
||||||
|
private String file;
|
||||||
|
private String charset;
|
||||||
|
private long recommendRefreshMs;
|
||||||
|
private int bufSize;
|
||||||
|
private ConfigParser configParser;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileRefreshableDataSource getObject() throws Exception {
|
||||||
|
return new FileRefreshableDataSource(new File(file), configParser,
|
||||||
|
recommendRefreshMs, bufSize, Charset.forName(charset));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return FileRefreshableDataSource.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFile(String file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCharset() {
|
||||||
|
return charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharset(String charset) {
|
||||||
|
this.charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getRecommendRefreshMs() {
|
||||||
|
return recommendRefreshMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecommendRefreshMs(long recommendRefreshMs) {
|
||||||
|
this.recommendRefreshMs = recommendRefreshMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBufSize() {
|
||||||
|
return bufSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBufSize(int bufSize) {
|
||||||
|
this.bufSize = bufSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigParser getConfigParser() {
|
||||||
|
return configParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigParser(ConfigParser configParser) {
|
||||||
|
this.configParser = configParser;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fangjian
|
||||||
|
* @see NacosDataSource
|
||||||
|
*/
|
||||||
|
public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {
|
||||||
|
|
||||||
|
private String serverAddr;
|
||||||
|
private String groupId;
|
||||||
|
private String dataId;
|
||||||
|
private ConfigParser configParser;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NacosDataSource getObject() throws Exception {
|
||||||
|
return new NacosDataSource(serverAddr, groupId, dataId, configParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return NacosDataSource.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerAddr() {
|
||||||
|
return serverAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerAddr(String serverAddr) {
|
||||||
|
this.serverAddr = serverAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupId(String groupId) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataId() {
|
||||||
|
return dataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataId(String dataId) {
|
||||||
|
this.dataId = dataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigParser getConfigParser() {
|
||||||
|
return configParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigParser(ConfigParser configParser) {
|
||||||
|
this.configParser = configParser;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ConfigParser;
|
||||||
|
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fangjian
|
||||||
|
* @see ZookeeperDataSource
|
||||||
|
*/
|
||||||
|
public class ZookeeperDataSourceFactoryBean implements FactoryBean<ZookeeperDataSource> {
|
||||||
|
|
||||||
|
private String serverAddr;
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
private String groupId;
|
||||||
|
private String dataId;
|
||||||
|
|
||||||
|
private ConfigParser configParser;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZookeeperDataSource getObject() throws Exception {
|
||||||
|
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
|
||||||
|
// the path will be /{groupId}/{dataId}
|
||||||
|
return new ZookeeperDataSource(serverAddr, groupId, dataId, configParser);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// using path directly
|
||||||
|
return new ZookeeperDataSource(serverAddr, path, configParser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return ZookeeperDataSource.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerAddr() {
|
||||||
|
return serverAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServerAddr(String serverAddr) {
|
||||||
|
this.serverAddr = serverAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupId() {
|
||||||
|
return groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupId(String groupId) {
|
||||||
|
this.groupId = groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataId() {
|
||||||
|
return dataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataId(String dataId) {
|
||||||
|
this.dataId = dataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigParser getConfigParser() {
|
||||||
|
return configParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigParser(ConfigParser configParser) {
|
||||||
|
this.configParser = configParser;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import org.springframework.core.env.EnumerablePropertySource;
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.core.env.PropertySources;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link PropertySources} Utilities
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||||
|
*/
|
||||||
|
public abstract class PropertySourcesUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Sub {@link Properties}
|
||||||
|
*
|
||||||
|
* @param propertySources {@link PropertySource} Iterable
|
||||||
|
* @param prefix the prefix of property name
|
||||||
|
* @return Map
|
||||||
|
* @see Properties
|
||||||
|
*/
|
||||||
|
public static Map<String, Object> getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix) {
|
||||||
|
|
||||||
|
Map<String, Object> subProperties = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
|
String normalizedPrefix = normalizePrefix(prefix);
|
||||||
|
|
||||||
|
for (PropertySource<?> source : propertySources) {
|
||||||
|
if (source instanceof EnumerablePropertySource) {
|
||||||
|
for (String name : ((EnumerablePropertySource<?>) source).getPropertyNames()) {
|
||||||
|
if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
|
||||||
|
String subName = name.substring(normalizedPrefix.length());
|
||||||
|
if (!subProperties.containsKey(subName)) { // take first one
|
||||||
|
Object value = source.getProperty(name);
|
||||||
|
subProperties.put(subName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return subProperties;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize the prefix
|
||||||
|
*
|
||||||
|
* @param prefix the prefix
|
||||||
|
* @return the prefix
|
||||||
|
*/
|
||||||
|
public static String normalizePrefix(String prefix) {
|
||||||
|
return prefix.endsWith(".") ? prefix : prefix + ".";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
nacos = com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource
|
||||||
|
file =com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource
|
||||||
|
apollo = com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource
|
||||||
|
zk = com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource
|
@ -15,6 +15,18 @@
|
|||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-sentinel</artifactId>
|
<artifactId>spring-cloud-alibaba-sentinel</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-zookeeper</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-datasource-apollo</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user