mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Merge pull request #5 from spring-cloud-incubator/master
Sync upstream/master
This commit is contained in:
commit
e3bd0c8c06
@ -35,7 +35,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
|||||||
|
|
||||||
**[RocketMQ](https://rocketmq.apache.org/)**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
|
**[RocketMQ](https://rocketmq.apache.org/)**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
|
||||||
|
|
||||||
**[Dubbo](https://github.com/apache/incubator-dubbo)**:Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。
|
**[Dubbo](https://github.com/apache/dubbo)**:Apache Dubbo™ 是一款高性能 Java RPC 框架。
|
||||||
|
|
||||||
**[Seata](https://github.com/seata/seata)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
|
**[Seata](https://github.com/seata/seata)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||||
<version>0.2.1.RELEASE</version>
|
<version>0.9.0.RELEASE</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -35,7 +35,7 @@ For more features, please refer to [Roadmap](https://github.com/spring-cloud-inc
|
|||||||
|
|
||||||
**[RocketMQ](https://rocketmq.apache.org/)**:A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
|
**[RocketMQ](https://rocketmq.apache.org/)**:A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
|
||||||
|
|
||||||
**[Dubbo](https://github.com/apache/incubator-dubbo)**:A high-performance, Java based open source RPC framework.
|
**[Dubbo](https://github.com/apache/dubbo)**:A high-performance, Java based open source RPC framework.
|
||||||
|
|
||||||
**[Seata](https://github.com/seata/seata)**:A distributed transaction solution with high performance and ease of use for microservices architecture.
|
**[Seata](https://github.com/seata/seata)**:A distributed transaction solution with high performance and ease of use for microservices architecture.
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ These artifacts are available from Maven Central and Spring Release repository v
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||||
<version>0.2.1.RELEASE</version>
|
<version>0.9.0.RELEASE</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -23,7 +23,7 @@ Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和
|
|||||||
|
|
||||||
**Dubbo**
|
**Dubbo**
|
||||||
|
|
||||||
Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。
|
Apache Dubbo™ 是一款高性能 Java RPC 框架。
|
||||||
|
|
||||||
**Fescar**
|
**Fescar**
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ Apache RocketMQ™ is an open source distributed messaging and streaming data pl
|
|||||||
|
|
||||||
**Dubbo**
|
**Dubbo**
|
||||||
|
|
||||||
Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC framework.
|
Apache Dubbo™ is a high-performance, Java based open source RPC framework.
|
||||||
|
|
||||||
**Fescar**
|
**Fescar**
|
||||||
|
|
||||||
|
2
pom.xml
2
pom.xml
@ -93,7 +93,7 @@
|
|||||||
<module>spring-cloud-alibaba-dependencies</module>
|
<module>spring-cloud-alibaba-dependencies</module>
|
||||||
<module>spring-cloud-alibaba-sentinel</module>
|
<module>spring-cloud-alibaba-sentinel</module>
|
||||||
<module>spring-cloud-alibaba-sentinel-datasource</module>
|
<module>spring-cloud-alibaba-sentinel-datasource</module>
|
||||||
<module>spring-cloud-alibaba-sentinel-zuul</module>
|
<module>spring-cloud-alibaba-sentinel-gateway</module>
|
||||||
<module>spring-cloud-alibaba-nacos-config</module>
|
<module>spring-cloud-alibaba-nacos-config</module>
|
||||||
<module>spring-cloud-alibaba-nacos-discovery</module>
|
<module>spring-cloud-alibaba-nacos-discovery</module>
|
||||||
<module>spring-cloud-alibaba-seata</module>
|
<module>spring-cloud-alibaba-seata</module>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<name>Spring Cloud Alibaba Coverage</name>
|
<name>Spring Cloud Alibaba Coverage</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring.cloud.alibaba.version>0.9.0.BUILD-SNAPSHOT</spring.cloud.alibaba.version>
|
<spring.cloud.alibaba.version>0.9.1.BUILD-SNAPSHOT</spring.cloud.alibaba.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -17,23 +17,23 @@
|
|||||||
<description>Spring Cloud Alibaba Dependencies</description>
|
<description>Spring Cloud Alibaba Dependencies</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<sentinel.version>1.5.2</sentinel.version>
|
<sentinel.version>1.6.1</sentinel.version>
|
||||||
<oss.version>3.1.0</oss.version>
|
<oss.version>3.1.0</oss.version>
|
||||||
<seata.version>0.5.0</seata.version>
|
<seata.version>0.5.2</seata.version>
|
||||||
<nacos.client.version>1.0.0</nacos.client.version>
|
<nacos.client.version>1.0.1</nacos.client.version>
|
||||||
<nacos.config.version>0.8.0</nacos.config.version>
|
<nacos.config.version>0.8.0</nacos.config.version>
|
||||||
<acm.version>1.0.8</acm.version>
|
<acm.version>1.0.9</acm.version>
|
||||||
<ans.version>1.0.1</ans.version>
|
<ans.version>1.0.1</ans.version>
|
||||||
<aliyun.sdk.version>4.0.1</aliyun.sdk.version>
|
<aliyun.sdk.version>4.4.1</aliyun.sdk.version>
|
||||||
<alicloud.context.version>1.0.5</alicloud.context.version>
|
<alicloud.context.version>1.0.5</alicloud.context.version>
|
||||||
<aliyun.sdk.edas.version>2.16.0</aliyun.sdk.edas.version>
|
<aliyun.sdk.edas.version>2.44.0</aliyun.sdk.edas.version>
|
||||||
<rocketmq.starter.version>2.0.2</rocketmq.starter.version>
|
<rocketmq.starter.version>2.0.2</rocketmq.starter.version>
|
||||||
<schedulerX.client.version>2.1.6</schedulerX.client.version>
|
<schedulerX.client.version>2.1.6</schedulerX.client.version>
|
||||||
<dubbo.version>2.7.1</dubbo.version>
|
<dubbo.version>2.7.1</dubbo.version>
|
||||||
<dubbo-spring-boot.version>2.7.1</dubbo-spring-boot.version>
|
<dubbo-spring-boot.version>2.7.1</dubbo-spring-boot.version>
|
||||||
<dubbo-registry-nacos.version>0.0.2</dubbo-registry-nacos.version>
|
<dubbo-registry-nacos.version>2.7.1</dubbo-registry-nacos.version>
|
||||||
<aliyun.java.sdk.dysmsapi>1.1.0</aliyun.java.sdk.dysmsapi>
|
<aliyun.java.sdk.dysmsapi>1.1.0</aliyun.java.sdk.dysmsapi>
|
||||||
<aliyun.sdk.mns>1.1.8</aliyun.sdk.mns>
|
<aliyun.sdk.mns>1.1.8.6</aliyun.sdk.mns>
|
||||||
<aliyun.java.sdk.dyvmsapi>1.1.1</aliyun.java.sdk.dyvmsapi>
|
<aliyun.java.sdk.dyvmsapi>1.1.1</aliyun.java.sdk.dyvmsapi>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@ -152,6 +152,11 @@
|
|||||||
<artifactId>sentinel-zuul-adapter</artifactId>
|
<artifactId>sentinel-zuul-adapter</artifactId>
|
||||||
<version>${sentinel.version}</version>
|
<version>${sentinel.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
|
||||||
|
<version>${sentinel.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||||
@ -187,6 +192,17 @@
|
|||||||
<artifactId>sentinel-cluster-client-default</artifactId>
|
<artifactId>sentinel-cluster-client-default</artifactId>
|
||||||
<version>${sentinel.version}</version>
|
<version>${sentinel.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-spring-webflux-adapter</artifactId>
|
||||||
|
<version>${sentinel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
|
||||||
|
<version>${sentinel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Alibaba Seata-->
|
<!--Alibaba Seata-->
|
||||||
@ -227,7 +243,7 @@
|
|||||||
|
|
||||||
<!-- Dubbo Nacos registry dependency -->
|
<!-- Dubbo Nacos registry dependency -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<artifactId>dubbo-registry-nacos</artifactId>
|
<artifactId>dubbo-registry-nacos</artifactId>
|
||||||
<version>${dubbo-registry-nacos.version}</version>
|
<version>${dubbo-registry-nacos.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
@ -252,7 +268,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
|
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -60,6 +60,7 @@ public class DefaultHttpRequest implements HttpRequest {
|
|||||||
return HttpMethod.resolve(getMethodValue());
|
return HttpMethod.resolve(getMethodValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getMethodValue() {
|
public String getMethodValue() {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ public class MutableHttpServerRequest implements HttpServerRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Override method since Spring Framework 5.0
|
// Override method since Spring Framework 5.0
|
||||||
|
@Override
|
||||||
public String getMethodValue() {
|
public String getMethodValue() {
|
||||||
return httpMethod.name();
|
return httpMethod.name();
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,12 @@ public class DubboRestServiceMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (!(o instanceof DubboRestServiceMetadata)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof DubboRestServiceMetadata)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
DubboRestServiceMetadata that = (DubboRestServiceMetadata) o;
|
DubboRestServiceMetadata that = (DubboRestServiceMetadata) o;
|
||||||
return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) &&
|
return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) &&
|
||||||
Objects.equals(restMethodMetadata, that.restMethodMetadata);
|
Objects.equals(restMethodMetadata, that.restMethodMetadata);
|
||||||
|
@ -77,8 +77,12 @@ public class DubboTransportedMethodMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (!(o instanceof DubboTransportedMethodMetadata)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof DubboTransportedMethodMetadata)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o;
|
DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o;
|
||||||
return Objects.equals(methodMetadata, that.methodMetadata) &&
|
return Objects.equals(methodMetadata, that.methodMetadata) &&
|
||||||
Objects.equals(attributes, that.attributes);
|
Objects.equals(attributes, that.attributes);
|
||||||
|
@ -110,8 +110,12 @@ public class MethodMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
MethodMetadata that = (MethodMetadata) o;
|
MethodMetadata that = (MethodMetadata) o;
|
||||||
return Objects.equals(name, that.name) &&
|
return Objects.equals(name, that.name) &&
|
||||||
Objects.equals(returnType, that.returnType) &&
|
Objects.equals(returnType, that.returnType) &&
|
||||||
|
@ -61,8 +61,12 @@ public class MethodParameterMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
MethodParameterMetadata that = (MethodParameterMetadata) o;
|
MethodParameterMetadata that = (MethodParameterMetadata) o;
|
||||||
return index == that.index &&
|
return index == that.index &&
|
||||||
Objects.equals(name, that.name) &&
|
Objects.equals(name, that.name) &&
|
||||||
|
@ -235,8 +235,12 @@ public class RequestMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (!(o instanceof RequestMetadata)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof RequestMetadata)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
RequestMetadata that = (RequestMetadata) o;
|
RequestMetadata that = (RequestMetadata) o;
|
||||||
return Objects.equals(method, that.method) &&
|
return Objects.equals(method, that.method) &&
|
||||||
Objects.equals(path, that.path) &&
|
Objects.equals(path, that.path) &&
|
||||||
|
@ -183,8 +183,12 @@ public class RestMethodMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (!(o instanceof RestMethodMetadata)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof RestMethodMetadata)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
RestMethodMetadata that = (RestMethodMetadata) o;
|
RestMethodMetadata that = (RestMethodMetadata) o;
|
||||||
return queryMapEncoded == that.queryMapEncoded &&
|
return queryMapEncoded == that.queryMapEncoded &&
|
||||||
Objects.equals(method, that.method) &&
|
Objects.equals(method, that.method) &&
|
||||||
|
@ -52,8 +52,12 @@ public class ServiceRestMetadata {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) {
|
||||||
if (!(o instanceof ServiceRestMetadata)) return false;
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof ServiceRestMetadata)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ServiceRestMetadata that = (ServiceRestMetadata) o;
|
ServiceRestMetadata that = (ServiceRestMetadata) o;
|
||||||
return Objects.equals(url, that.url) &&
|
return Objects.equals(url, that.url) &&
|
||||||
Objects.equals(meta, that.meta);
|
Objects.equals(meta, that.meta);
|
||||||
|
@ -64,7 +64,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName();
|
protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName();
|
||||||
|
|
||||||
private static final Set<String> schedulerTasks = new HashSet<>();
|
private static final Set<String> SCHEDULER_TASKS = new HashSet<>();
|
||||||
|
|
||||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
|||||||
|
|
||||||
private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) {
|
private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) {
|
||||||
String taskId = url.toIdentityString();
|
String taskId = url.toIdentityString();
|
||||||
if (schedulerTasks.add(taskId)) {
|
if (SCHEDULER_TASKS.add(taskId)) {
|
||||||
schedule(() -> doSubscribeDubboServiceURLs(url, listener));
|
schedule(() -> doSubscribeDubboServiceURLs(url, listener));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +110,7 @@ public class DubboGenericServiceFactory {
|
|||||||
dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
|
dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
|
||||||
dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
|
dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setAsText(String text) throws java.lang.IllegalArgumentException {
|
public void setAsText(String text) throws java.lang.IllegalArgumentException {
|
||||||
// Trim all whitespace
|
// Trim all whitespace
|
||||||
String content = StringUtils.trimAllWhitespace(text);
|
String content = StringUtils.trimAllWhitespace(text);
|
||||||
|
@ -128,7 +128,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,OSS Starter 也
|
|||||||
|
|
||||||
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/oss 来查看 OSS Endpoint 的信息。
|
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/oss 来查看 OSS Endpoint 的信息。
|
||||||
|
|
||||||
Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/acutator/oss 来访问。
|
Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/actuator/oss 来访问。
|
||||||
|
|
||||||
Endpoint 内部会显示所有的 OSSClient 配置信息,以及该 OSSClient 对应的 Bucket 列表。
|
Endpoint 内部会显示所有的 OSSClient 配置信息,以及该 OSSClient 对应的 Bucket 列表。
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ You can verify results on the OSS console when you finish uploading or downloadi
|
|||||||
|
|
||||||
## Endpoint
|
## Endpoint
|
||||||
|
|
||||||
OSS starter also supports the implmentation of Spring Boot acutator endpoints.
|
OSS starter also supports the implementation of Spring Boot actuator endpoints.
|
||||||
|
|
||||||
**Prerequisite:**
|
**Prerequisite:**
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ To view the endpoint information, visit the following URLs:
|
|||||||
|
|
||||||
Spring Boot1.x: OSS Endpoint URL is http://127.0.0.1:18084/oss.
|
Spring Boot1.x: OSS Endpoint URL is http://127.0.0.1:18084/oss.
|
||||||
|
|
||||||
Spring Boot2.x: OSS Endpoint URL is http://127.0.0.1:18084/acutator/oss.
|
Spring Boot2.x: OSS Endpoint URL is http://127.0.0.1:18084/actuator/oss.
|
||||||
|
|
||||||
Endpoint will show the configurations and the list of buckets of all OSSClients.
|
Endpoint will show the configurations and the list of buckets of all OSSClients.
|
||||||
|
|
||||||
|
@ -21,6 +21,9 @@
|
|||||||
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example</module>
|
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example</module>
|
||||||
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example</module>
|
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example</module>
|
||||||
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api</module>
|
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api</module>
|
||||||
|
<module>sentinel-example/sentinel-webflux-example</module>
|
||||||
|
<module>sentinel-example/sentinel-spring-cloud-gateway-example</module>
|
||||||
|
<module>sentinel-example/sentinel-zuul-example</module>
|
||||||
<module>nacos-example/nacos-discovery-example</module>
|
<module>nacos-example/nacos-discovery-example</module>
|
||||||
<module>nacos-example/nacos-config-example</module>
|
<module>nacos-example/nacos-config-example</module>
|
||||||
<module>nacos-example/nacos-gateway-example</module>
|
<module>nacos-example/nacos-gateway-example</module>
|
||||||
|
@ -60,7 +60,7 @@ public class RocketMQApplication {
|
|||||||
配置 Binding 信息:
|
配置 Binding 信息:
|
||||||
```properties
|
```properties
|
||||||
# 配置rocketmq的nameserver地址
|
# 配置rocketmq的nameserver地址
|
||||||
spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876
|
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
|
||||||
# 定义name为output的binding
|
# 定义name为output的binding
|
||||||
spring.cloud.stream.bindings.output.destination=test-topic
|
spring.cloud.stream.bindings.output.destination=test-topic
|
||||||
spring.cloud.stream.bindings.output.content-type=application/json
|
spring.cloud.stream.bindings.output.content-type=application/json
|
||||||
@ -125,7 +125,7 @@ server.port=28081
|
|||||||
配置信息如下:
|
配置信息如下:
|
||||||
|
|
||||||
```properties
|
```properties
|
||||||
spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876
|
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
|
||||||
|
|
||||||
spring.cloud.stream.bindings.output.destination=test-topic
|
spring.cloud.stream.bindings.output.destination=test-topic
|
||||||
spring.cloud.stream.bindings.output.content-type=application/json
|
spring.cloud.stream.bindings.output.content-type=application/json
|
||||||
|
@ -56,7 +56,7 @@ public class RocketMQApplication {
|
|||||||
Configure Binding:
|
Configure Binding:
|
||||||
```properties
|
```properties
|
||||||
# configure the nameserver of rocketmq
|
# configure the nameserver of rocketmq
|
||||||
spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876
|
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
|
||||||
# configure the output binding named output
|
# configure the output binding named output
|
||||||
spring.cloud.stream.bindings.output.destination=test-topic
|
spring.cloud.stream.bindings.output.destination=test-topic
|
||||||
spring.cloud.stream.bindings.output.content-type=application/json
|
spring.cloud.stream.bindings.output.content-type=application/json
|
||||||
@ -121,7 +121,7 @@ And using two input bindings to subscribe messages.
|
|||||||
see the configuration below:
|
see the configuration below:
|
||||||
|
|
||||||
```properties
|
```properties
|
||||||
spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876
|
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
|
||||||
|
|
||||||
spring.cloud.stream.bindings.output.destination=test-topic
|
spring.cloud.stream.bindings.output.destination=test-topic
|
||||||
spring.cloud.stream.bindings.output.content-type=application/json
|
spring.cloud.stream.bindings.output.content-type=application/json
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
package org.springframework.cloud.alibaba.cloud.examples;
|
package org.springframework.cloud.alibaba.cloud.examples;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.alibaba.cloud.examples.RocketMQConsumerApplication.MySink;
|
import org.springframework.cloud.alibaba.cloud.examples.RocketMQConsumerApplication.MySink;
|
||||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||||
import org.springframework.cloud.stream.annotation.Input;
|
import org.springframework.cloud.stream.annotation.Input;
|
||||||
|
import org.springframework.cloud.stream.binder.PollableMessageSource;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
import org.springframework.messaging.SubscribableChannel;
|
import org.springframework.messaging.SubscribableChannel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,10 +32,36 @@ public class RocketMQConsumerApplication {
|
|||||||
|
|
||||||
@Input("input4")
|
@Input("input4")
|
||||||
SubscribableChannel input4();
|
SubscribableChannel input4();
|
||||||
|
|
||||||
|
@Input("input5")
|
||||||
|
PollableMessageSource input5();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(RocketMQConsumerApplication.class, args);
|
SpringApplication.run(RocketMQConsumerApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ConsumerCustomRunner customRunner() {
|
||||||
|
return new ConsumerCustomRunner();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConsumerCustomRunner implements CommandLineRunner {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MySink mySink;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(String... args) throws InterruptedException {
|
||||||
|
while (true) {
|
||||||
|
mySink.input5().poll(m -> {
|
||||||
|
String payload = (String) m.getPayload();
|
||||||
|
System.out.println("pull msg: " + payload);
|
||||||
|
}, new ParameterizedTypeReference<String>() {
|
||||||
|
});
|
||||||
|
Thread.sleep(2_000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@ spring.cloud.stream.bindings.input4.content-type=text/plain
|
|||||||
spring.cloud.stream.bindings.input4.group=transaction-group
|
spring.cloud.stream.bindings.input4.group=transaction-group
|
||||||
spring.cloud.stream.bindings.input4.consumer.concurrency=5
|
spring.cloud.stream.bindings.input4.consumer.concurrency=5
|
||||||
|
|
||||||
|
spring.cloud.stream.bindings.input5.destination=pull-topic
|
||||||
|
spring.cloud.stream.bindings.input5.content-type=text/plain
|
||||||
|
spring.cloud.stream.bindings.input5.group=pull-topic-group
|
||||||
|
|
||||||
spring.application.name=rocketmq-consume-example
|
spring.application.name=rocketmq-consume-example
|
||||||
|
|
||||||
server.port=28082
|
server.port=28082
|
||||||
|
@ -9,6 +9,7 @@ import org.springframework.cloud.stream.annotation.EnableBinding;
|
|||||||
import org.springframework.cloud.stream.annotation.Output;
|
import org.springframework.cloud.stream.annotation.Output;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.messaging.MessageChannel;
|
import org.springframework.messaging.MessageChannel;
|
||||||
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
@ -23,6 +24,9 @@ public class RocketMQProduceApplication {
|
|||||||
|
|
||||||
@Output("output2")
|
@Output("output2")
|
||||||
MessageChannel output2();
|
MessageChannel output2();
|
||||||
|
|
||||||
|
@Output("output3")
|
||||||
|
MessageChannel output3();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -31,7 +35,12 @@ public class RocketMQProduceApplication {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CustomRunner customRunner() {
|
public CustomRunner customRunner() {
|
||||||
return new CustomRunner();
|
return new CustomRunner("output1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CustomRunner customRunner2() {
|
||||||
|
return new CustomRunner("output3");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -40,11 +49,22 @@ public class RocketMQProduceApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class CustomRunner implements CommandLineRunner {
|
public static class CustomRunner implements CommandLineRunner {
|
||||||
|
|
||||||
|
private final String bindingName;
|
||||||
|
|
||||||
|
public CustomRunner(String bindingName) {
|
||||||
|
this.bindingName = bindingName;
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SenderService senderService;
|
private SenderService senderService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MySource mySource;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(String... args) throws Exception {
|
public void run(String... args) throws Exception {
|
||||||
|
if (this.bindingName.equals("output1")) {
|
||||||
int count = 5;
|
int count = 5;
|
||||||
for (int index = 1; index <= count; index++) {
|
for (int index = 1; index <= count; index++) {
|
||||||
String msgContent = "msg-" + index;
|
String msgContent = "msg-" + index;
|
||||||
@ -59,6 +79,16 @@ public class RocketMQProduceApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (this.bindingName.equals("output3")) {
|
||||||
|
int count = 50;
|
||||||
|
for (int index = 1; index <= count; index++) {
|
||||||
|
String msgContent = "pullMsg-" + index;
|
||||||
|
mySource.output3()
|
||||||
|
.send(MessageBuilder.withPayload(msgContent).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CustomRunnerWithTransactional implements CommandLineRunner {
|
public static class CustomRunnerWithTransactional implements CommandLineRunner {
|
||||||
|
@ -12,6 +12,10 @@ spring.cloud.stream.bindings.output2.content-type=application/json
|
|||||||
spring.cloud.stream.rocketmq.bindings.output2.producer.transactional=true
|
spring.cloud.stream.rocketmq.bindings.output2.producer.transactional=true
|
||||||
spring.cloud.stream.rocketmq.bindings.output2.producer.group=myTxProducerGroup
|
spring.cloud.stream.rocketmq.bindings.output2.producer.group=myTxProducerGroup
|
||||||
|
|
||||||
|
spring.cloud.stream.bindings.output3.destination=pull-topic
|
||||||
|
spring.cloud.stream.bindings.output3.content-type=text/plain
|
||||||
|
spring.cloud.stream.rocketmq.bindings.output3.producer.group=pull-binder-group
|
||||||
|
|
||||||
spring.application.name=rocketmq-produce-example
|
spring.application.name=rocketmq-produce-example
|
||||||
|
|
||||||
server.port=28081
|
server.port=28081
|
||||||
|
@ -20,7 +20,15 @@ transport {
|
|||||||
worker-thread-size = 8
|
worker-thread-size = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
## transaction log store
|
||||||
store {
|
store {
|
||||||
|
## store mode: file、db
|
||||||
|
mode = "file"
|
||||||
|
|
||||||
|
## file store
|
||||||
|
file {
|
||||||
|
dir = "sessionStore"
|
||||||
|
|
||||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||||
max-branch-session-size = 16384
|
max-branch-session-size = 16384
|
||||||
# globe session size , if exceeded throws exceptions
|
# globe session size , if exceeded throws exceptions
|
||||||
@ -29,6 +37,18 @@ store {
|
|||||||
file-write-buffer-cache-size = 16384
|
file-write-buffer-cache-size = 16384
|
||||||
# when recover batch read size
|
# when recover batch read size
|
||||||
session.reload.read_size = 100
|
session.reload.read_size = 100
|
||||||
|
# async, sync
|
||||||
|
flush-disk-mode = async
|
||||||
|
}
|
||||||
|
|
||||||
|
## database store
|
||||||
|
db {
|
||||||
|
driver_class = ""
|
||||||
|
url = ""
|
||||||
|
user = ""
|
||||||
|
password = ""
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
service {
|
service {
|
||||||
#vgroup->rgroup
|
#vgroup->rgroup
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
registry {
|
registry {
|
||||||
# file 、nacos 、eureka、redis、zk、consul
|
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||||
type = "file"
|
type = "file"
|
||||||
|
|
||||||
nacos {
|
nacos {
|
||||||
@ -26,6 +26,19 @@ registry {
|
|||||||
cluster = "default"
|
cluster = "default"
|
||||||
serverAddr = "127.0.0.1:8500"
|
serverAddr = "127.0.0.1:8500"
|
||||||
}
|
}
|
||||||
|
etcd3 {
|
||||||
|
cluster = "default"
|
||||||
|
serverAddr = "http://localhost:2379"
|
||||||
|
}
|
||||||
|
sofa {
|
||||||
|
serverAddr = "127.0.0.1:9603"
|
||||||
|
application = "default"
|
||||||
|
region = "DEFAULT_ZONE"
|
||||||
|
datacenter = "DefaultDataCenter"
|
||||||
|
cluster = "default"
|
||||||
|
group = "SEATA_GROUP"
|
||||||
|
addressWaitTime = "3000"
|
||||||
|
}
|
||||||
file {
|
file {
|
||||||
name = "file.conf"
|
name = "file.conf"
|
||||||
}
|
}
|
||||||
@ -41,7 +54,7 @@ config {
|
|||||||
cluster = "default"
|
cluster = "default"
|
||||||
}
|
}
|
||||||
apollo {
|
apollo {
|
||||||
app.id = "fescar-server"
|
app.id = "seata-server"
|
||||||
apollo.meta = "http://192.168.1.204:8801"
|
apollo.meta = "http://192.168.1.204:8801"
|
||||||
}
|
}
|
||||||
zk {
|
zk {
|
||||||
|
@ -20,7 +20,15 @@ transport {
|
|||||||
worker-thread-size = 8
|
worker-thread-size = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
## transaction log store
|
||||||
store {
|
store {
|
||||||
|
## store mode: file、db
|
||||||
|
mode = "file"
|
||||||
|
|
||||||
|
## file store
|
||||||
|
file {
|
||||||
|
dir = "sessionStore"
|
||||||
|
|
||||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||||
max-branch-session-size = 16384
|
max-branch-session-size = 16384
|
||||||
# globe session size , if exceeded throws exceptions
|
# globe session size , if exceeded throws exceptions
|
||||||
@ -29,6 +37,18 @@ store {
|
|||||||
file-write-buffer-cache-size = 16384
|
file-write-buffer-cache-size = 16384
|
||||||
# when recover batch read size
|
# when recover batch read size
|
||||||
session.reload.read_size = 100
|
session.reload.read_size = 100
|
||||||
|
# async, sync
|
||||||
|
flush-disk-mode = async
|
||||||
|
}
|
||||||
|
|
||||||
|
## database store
|
||||||
|
db {
|
||||||
|
driver_class = ""
|
||||||
|
url = ""
|
||||||
|
user = ""
|
||||||
|
password = ""
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
service {
|
service {
|
||||||
#vgroup->rgroup
|
#vgroup->rgroup
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
registry {
|
registry {
|
||||||
# file 、nacos 、eureka、redis、zk、consul
|
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||||
type = "file"
|
type = "file"
|
||||||
|
|
||||||
nacos {
|
nacos {
|
||||||
@ -26,6 +26,19 @@ registry {
|
|||||||
cluster = "default"
|
cluster = "default"
|
||||||
serverAddr = "127.0.0.1:8500"
|
serverAddr = "127.0.0.1:8500"
|
||||||
}
|
}
|
||||||
|
etcd3 {
|
||||||
|
cluster = "default"
|
||||||
|
serverAddr = "http://localhost:2379"
|
||||||
|
}
|
||||||
|
sofa {
|
||||||
|
serverAddr = "127.0.0.1:9603"
|
||||||
|
application = "default"
|
||||||
|
region = "DEFAULT_ZONE"
|
||||||
|
datacenter = "DefaultDataCenter"
|
||||||
|
cluster = "default"
|
||||||
|
group = "SEATA_GROUP"
|
||||||
|
addressWaitTime = "3000"
|
||||||
|
}
|
||||||
file {
|
file {
|
||||||
name = "file.conf"
|
name = "file.conf"
|
||||||
}
|
}
|
||||||
@ -41,7 +54,7 @@ config {
|
|||||||
cluster = "default"
|
cluster = "default"
|
||||||
}
|
}
|
||||||
apollo {
|
apollo {
|
||||||
app.id = "fescar-server"
|
app.id = "seata-server"
|
||||||
apollo.meta = "http://192.168.1.204:8801"
|
apollo.meta = "http://192.168.1.204:8801"
|
||||||
}
|
}
|
||||||
zk {
|
zk {
|
||||||
|
@ -101,7 +101,7 @@ CREATE TABLE `account_tbl` (
|
|||||||
进入解压之后的 bin 目录,执行如下命令来启动
|
进入解压之后的 bin 目录,执行如下命令来启动
|
||||||
|
|
||||||
```$shell
|
```$shell
|
||||||
sh seata-server.sh $LISTEN_PORT $MODE
|
sh seata-server.sh $LISTEN_PORT $MODE(file or db)
|
||||||
```
|
```
|
||||||
|
|
||||||
在这个示例中,采用如下命令来启动 Seata Server
|
在这个示例中,采用如下命令来启动 Seata Server
|
||||||
@ -110,7 +110,7 @@ sh seata-server.sh $LISTEN_PORT $MODE
|
|||||||
sh seata-server.sh 8091 file
|
sh seata-server.sh 8091 file
|
||||||
```
|
```
|
||||||
|
|
||||||
**注意** 如果你修改了endpoint且注册中心使用默认file类型,那么记得需要在各个示例工程中的 `file.conf` 文件中,修改 grouplist 的值。
|
**注意** 如果你修改了endpoint且注册中心使用默认file类型,那么记得需要在各个示例工程中的 `file.conf` 文件中,修改 grouplist 的值(当registry.conf 中registry.type 或 config.type 为file 时会读取内部的file节点中的文件名,若type不为file将直接从配置类型的对应元数据的注册配置中心读取数据),推荐大家使用 nacos 作为配置注册中心。
|
||||||
|
|
||||||
|
|
||||||
## 运行示例
|
## 运行示例
|
||||||
|
@ -20,7 +20,15 @@ transport {
|
|||||||
worker-thread-size = 8
|
worker-thread-size = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
## transaction log store
|
||||||
store {
|
store {
|
||||||
|
## store mode: file、db
|
||||||
|
mode = "file"
|
||||||
|
|
||||||
|
## file store
|
||||||
|
file {
|
||||||
|
dir = "sessionStore"
|
||||||
|
|
||||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||||
max-branch-session-size = 16384
|
max-branch-session-size = 16384
|
||||||
# globe session size , if exceeded throws exceptions
|
# globe session size , if exceeded throws exceptions
|
||||||
@ -29,6 +37,18 @@ store {
|
|||||||
file-write-buffer-cache-size = 16384
|
file-write-buffer-cache-size = 16384
|
||||||
# when recover batch read size
|
# when recover batch read size
|
||||||
session.reload.read_size = 100
|
session.reload.read_size = 100
|
||||||
|
# async, sync
|
||||||
|
flush-disk-mode = async
|
||||||
|
}
|
||||||
|
|
||||||
|
## database store
|
||||||
|
db {
|
||||||
|
driver_class = ""
|
||||||
|
url = ""
|
||||||
|
user = ""
|
||||||
|
password = ""
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
service {
|
service {
|
||||||
#vgroup->rgroup
|
#vgroup->rgroup
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
registry {
|
registry {
|
||||||
# file 、nacos 、eureka、redis、zk、consul
|
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||||
type = "file"
|
type = "file"
|
||||||
|
|
||||||
nacos {
|
nacos {
|
||||||
@ -26,6 +26,19 @@ registry {
|
|||||||
cluster = "default"
|
cluster = "default"
|
||||||
serverAddr = "127.0.0.1:8500"
|
serverAddr = "127.0.0.1:8500"
|
||||||
}
|
}
|
||||||
|
etcd3 {
|
||||||
|
cluster = "default"
|
||||||
|
serverAddr = "http://localhost:2379"
|
||||||
|
}
|
||||||
|
sofa {
|
||||||
|
serverAddr = "127.0.0.1:9603"
|
||||||
|
application = "default"
|
||||||
|
region = "DEFAULT_ZONE"
|
||||||
|
datacenter = "DefaultDataCenter"
|
||||||
|
cluster = "default"
|
||||||
|
group = "SEATA_GROUP"
|
||||||
|
addressWaitTime = "3000"
|
||||||
|
}
|
||||||
file {
|
file {
|
||||||
name = "file.conf"
|
name = "file.conf"
|
||||||
}
|
}
|
||||||
@ -41,7 +54,7 @@ config {
|
|||||||
cluster = "default"
|
cluster = "default"
|
||||||
}
|
}
|
||||||
apollo {
|
apollo {
|
||||||
app.id = "fescar-server"
|
app.id = "seata-server"
|
||||||
apollo.meta = "http://192.168.1.204:8801"
|
apollo.meta = "http://192.168.1.204:8801"
|
||||||
}
|
}
|
||||||
zk {
|
zk {
|
||||||
|
@ -184,7 +184,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Sentinel Starter
|
|||||||
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
|
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
|
||||||
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
|
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
|
||||||
|
|
||||||
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/acutator/sentinel 来访问。
|
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/actuator/sentinel 来访问。
|
||||||
|
|
||||||
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532084199224-1a41591d-7a06-4680-be8a-5de319ac635d.png" width="480" heigh='360' ></p>
|
<p align="center"><img src="https://cdn.yuque.com/lark/0/2018/png/54319/1532084199224-1a41591d-7a06-4680-be8a-5de319ac635d.png" width="480" heigh='360' ></p>
|
||||||
|
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
spring.application.name=sentinel-example
|
spring.application.name=sentinel-example
|
||||||
server.port=18083
|
server.port=18083
|
||||||
management.endpoints.web.exposure.include=*
|
management.endpoints.web.exposure.include=*
|
||||||
|
management.endpoint.health.show-details=always
|
||||||
|
|
||||||
|
# we can disable health check, default is enable
|
||||||
|
management.health.diskspace.enabled=false
|
||||||
|
# management.health.sentinel.enabled=false
|
||||||
|
|
||||||
spring.cloud.sentinel.transport.dashboard=localhost:8080
|
spring.cloud.sentinel.transport.dashboard=localhost:8080
|
||||||
spring.cloud.sentinel.eager=true
|
spring.cloud.sentinel.eager=true
|
||||||
|
|
||||||
@ -19,4 +25,4 @@ spring.cloud.sentinel.datasource.ds4.file.file=classpath: system.json
|
|||||||
spring.cloud.sentinel.datasource.ds4.file.rule-type=system
|
spring.cloud.sentinel.datasource.ds4.file.rule-type=system
|
||||||
|
|
||||||
spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json
|
spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json
|
||||||
spring.cloud.sentinel.datasource.ds5.file.rule-type=param-flow
|
spring.cloud.sentinel.datasource.ds5.file.rule-type=param_flow
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"resource": "resource",
|
"resource": "/hello",
|
||||||
"controlBehavior": 0,
|
"controlBehavior": 0,
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"grade": 1,
|
"grade": 1,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件,Sentinel 把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。
|
[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件,Sentinel 把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。
|
||||||
|
|
||||||
[Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架,有对应的[SpringBoot工程](https://github.com/apache/incubator-dubbo-spring-boot-project)。
|
[Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架,有对应的[SpringBoot工程](https://github.com/apache/dubbo-spring-boot-project)。
|
||||||
|
|
||||||
本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-core-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example)。
|
本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-core-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example)。
|
||||||
|
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||||
|
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
||||||
|
<artifactId>sentinel-spring-cloud-gateway-example</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>Example demonstrating how to use sentinel with spring cloud gateway</description>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||||
|
</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>-->
|
||||||
|
<!-- define in spring-boot-autoconfigure module -->
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>com.fasterxml.jackson.dataformat</groupId>-->
|
||||||
|
<!--<artifactId>jackson-dataformat-xml</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>${maven-deploy-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class MySCGConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BlockRequestHandler blockRequestHandler() {
|
||||||
|
return new BlockRequestHandler() {
|
||||||
|
@Override
|
||||||
|
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
|
||||||
|
return ServerResponse.status(444)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||||
|
.body(fromObject("SCS Sentinel block"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class RulesWebFluxController {
|
||||||
|
|
||||||
|
@GetMapping("/api")
|
||||||
|
public Mono<Set<ApiDefinition>> apiRules() {
|
||||||
|
return Mono.just(GatewayApiDefinitionManager.getApiDefinitions());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/gateway")
|
||||||
|
public Mono<Set<GatewayFlowRule>> apiGateway() {
|
||||||
|
return Mono.just(GatewayRuleManager.getRules());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/flow")
|
||||||
|
public Mono<List<FlowRule>> apiFlow() {
|
||||||
|
return Mono.just(FlowRuleManager.getRules());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SentinelSpringCloudGatewayApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
//GatewayCallbackManager.setRequestOriginParser(s -> "123");
|
||||||
|
SpringApplication.run(SentinelSpringCloudGatewayApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"apiName": "some_customized_api",
|
||||||
|
"predicateItems": [
|
||||||
|
{
|
||||||
|
"pattern": "/product/baz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": "/product/foo/**",
|
||||||
|
"matchStrategy": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"pattern": "/spring-cloud/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": "/spring-cloud-alibaba/**"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiName": "another_customized_api",
|
||||||
|
"predicateItems": [
|
||||||
|
{
|
||||||
|
"pattern": "/ahas"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,41 @@
|
|||||||
|
server:
|
||||||
|
port: 18085
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: sentinel-spring-cloud-gateway
|
||||||
|
cloud:
|
||||||
|
gateway:
|
||||||
|
enabled: true
|
||||||
|
discovery:
|
||||||
|
locator:
|
||||||
|
lower-case-service-id: true
|
||||||
|
routes:
|
||||||
|
# Add your routes here.
|
||||||
|
- id: aliyun_route
|
||||||
|
uri: https://www.aliyun.com/
|
||||||
|
predicates:
|
||||||
|
- Path=/product/**
|
||||||
|
- id: httpbin_route
|
||||||
|
uri: https://httpbin.org
|
||||||
|
predicates:
|
||||||
|
- Path=/httpbin/**
|
||||||
|
filters:
|
||||||
|
- RewritePath=/httpbin/(?<segment>.*), /$\{segment}
|
||||||
|
|
||||||
|
sentinel:
|
||||||
|
datasource.ds2.file:
|
||||||
|
file: "classpath: gateway.json"
|
||||||
|
ruleType: gw-flow
|
||||||
|
datasource.ds1.file:
|
||||||
|
file: "classpath: api.json"
|
||||||
|
ruleType: gw-api-group
|
||||||
|
transport:
|
||||||
|
dashboard: localhost:8080
|
||||||
|
filter:
|
||||||
|
enabled: true
|
||||||
|
scg.fallback:
|
||||||
|
mode: response
|
||||||
|
response-status: 444
|
||||||
|
response-body: 1234
|
||||||
|
|
||||||
|
management.endpoints.web.exposure.include: "*"
|
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"resource": "some_customized_api",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "httpbin_route",
|
||||||
|
"count": 0,
|
||||||
|
"paramItem": {
|
||||||
|
"parseStrategy": 2,
|
||||||
|
"fieldName": "Spring-Cloud-Alibaba"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "httpbin_route",
|
||||||
|
"count": 0,
|
||||||
|
"paramItem": {
|
||||||
|
"parseStrategy": 3,
|
||||||
|
"fieldName": "name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||||
|
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
||||||
|
<artifactId>sentinel-webflux-example</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>Example demonstrating how to use sentinel with webflux</description>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</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>-->
|
||||||
|
<!-- define in spring-boot-autoconfigure module -->
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>com.fasterxml.jackson.dataformat</groupId>-->
|
||||||
|
<!--<artifactId>jackson-dataformat-xml</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>${maven-deploy-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class MyConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BlockRequestHandler blockRequestHandler() {
|
||||||
|
return new BlockRequestHandler() {
|
||||||
|
@Override
|
||||||
|
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange,
|
||||||
|
Throwable t) {
|
||||||
|
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||||
|
.body(fromObject("block"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SentinelWebFluxApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SentinelWebFluxApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class SentinelWebFluxController {
|
||||||
|
|
||||||
|
@GetMapping("/mono")
|
||||||
|
public Mono<String> mono() {
|
||||||
|
return Mono.just("simple string")
|
||||||
|
// transform the publisher here.
|
||||||
|
.transform(new SentinelReactorTransformer<>("mono"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/flux")
|
||||||
|
public Flux<String> flux() {
|
||||||
|
return Flux.fromArray(new String[] { "a", "b", "c" })
|
||||||
|
// transform the publisher here.
|
||||||
|
.transform(new SentinelReactorTransformer<>("flux"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
spring.application.name=sentinel-example
|
||||||
|
server.port=18084
|
||||||
|
management.endpoints.web.exposure.include=*
|
||||||
|
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.ds1.file.rule-type=flow
|
@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"resource": "/mono",
|
||||||
|
"controlBehavior": 0,
|
||||||
|
"count": 0,
|
||||||
|
"grade": 1,
|
||||||
|
"limitApp": "default",
|
||||||
|
"strategy": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "/flux",
|
||||||
|
"controlBehavior": 0,
|
||||||
|
"count": 0,
|
||||||
|
"grade": 1,
|
||||||
|
"limitApp": "default",
|
||||||
|
"strategy": 0
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||||
|
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
||||||
|
<artifactId>sentinel-zuul-example</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>Example demonstrating how to use sentinel with zuul</description>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||||
|
</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>-->
|
||||||
|
<!-- define in spring-boot-autoconfigure module -->
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>com.fasterxml.jackson.dataformat</groupId>-->
|
||||||
|
<!--<artifactId>jackson-dataformat-xml</artifactId>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>${maven-deploy-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||||
|
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class RulesController {
|
||||||
|
|
||||||
|
@GetMapping("/api")
|
||||||
|
public Set<ApiDefinition> apiRules() {
|
||||||
|
return GatewayApiDefinitionManager.getApiDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/gateway")
|
||||||
|
public Set<GatewayFlowRule> apiGateway() {
|
||||||
|
return GatewayRuleManager.getRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/flow")
|
||||||
|
public List<FlowRule> apiFlow() {
|
||||||
|
return FlowRuleManager.getRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableZuulProxy
|
||||||
|
public class SentinelZuulApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SentinelZuulApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.cloud.examples;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.RequestOriginParser;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ZuulConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ZuulBlockFallbackProvider zuulBlockFallbackProvider1() {
|
||||||
|
return new ZuulBlockFallbackProvider() {
|
||||||
|
@Override
|
||||||
|
public String getRoute() {
|
||||||
|
return "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockResponse fallbackResponse(String route, Throwable cause) {
|
||||||
|
if (route.equals("my-service3")) {
|
||||||
|
return new BlockResponse(433, "Sentinel Block3", route);
|
||||||
|
} else if (route.equals("my-service4")) {
|
||||||
|
return new BlockResponse(444, "my-service4", route);
|
||||||
|
} else {
|
||||||
|
return new BlockResponse(499, "Sentinel Block 499", route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RequestOriginParser requestOriginParser() {
|
||||||
|
return new RequestOriginParser() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String parseOrigin(HttpServletRequest request) {
|
||||||
|
return "123";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"apiName": "some_customized_api",
|
||||||
|
"predicateItems": [
|
||||||
|
{
|
||||||
|
"pattern": "/product/baz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": "/product/foo/**",
|
||||||
|
"matchStrategy": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"pattern": "/spring-cloud/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pattern": "/spring-cloud-alibaba/**"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"apiName": "another_customized_api",
|
||||||
|
"predicateItems": [
|
||||||
|
{
|
||||||
|
"pattern": "/ahas"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,40 @@
|
|||||||
|
server:
|
||||||
|
port: 18086
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: sentinel-zuul
|
||||||
|
cloud:
|
||||||
|
sentinel:
|
||||||
|
datasource.ds2.file:
|
||||||
|
file: "classpath: gateway.json"
|
||||||
|
ruleType: gw-flow
|
||||||
|
datasource.ds1.file:
|
||||||
|
file: "classpath: api.json"
|
||||||
|
ruleType: gw-api-group
|
||||||
|
transport:
|
||||||
|
dashboard: localhost:8080
|
||||||
|
filter:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
management.endpoints.web.exposure.include: "*"
|
||||||
|
|
||||||
|
|
||||||
|
zuul.routes.my-service.path: "/product/foo/**"
|
||||||
|
zuul.routes.my-service.service-id: "my-service"
|
||||||
|
|
||||||
|
zuul.routes.my-service2.path: "/my-service2/**"
|
||||||
|
zuul.routes.my-service2.service-id: "my-service2"
|
||||||
|
|
||||||
|
zuul.routes.my-service3.path: "/my-service3/**"
|
||||||
|
zuul.routes.my-service3.service-id: "my-service3"
|
||||||
|
|
||||||
|
zuul.routes.my-service4.path: "/my-service4/**"
|
||||||
|
zuul.routes.my-service4.service-id: "my-service4"
|
||||||
|
|
||||||
|
|
||||||
|
spring.cloud.sentinel.zuul.order.pre: 2000
|
||||||
|
spring.cloud.sentinel.zuul.order.post: 500
|
||||||
|
spring.cloud.sentinel.zuul.order.error: -100
|
||||||
|
|
||||||
|
|
||||||
|
spring.cloud.sentinel.zuul.enabled: true
|
@ -0,0 +1,26 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"resource": "some_customized_api",
|
||||||
|
"count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "my-service2",
|
||||||
|
"count": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "my-service3",
|
||||||
|
"count": 0,
|
||||||
|
"paramItem": {
|
||||||
|
"parseStrategy": 2,
|
||||||
|
"fieldName": "Spring-Cloud-Alibaba"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "my-service4",
|
||||||
|
"count": 0,
|
||||||
|
"paramItem": {
|
||||||
|
"parseStrategy": 3,
|
||||||
|
"fieldName": "name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
@ -306,7 +306,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,SMS Starter 也
|
|||||||
|
|
||||||
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/sms-info 来查看 SMS Endpoint 的信息。
|
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/sms-info 来查看 SMS Endpoint 的信息。
|
||||||
|
|
||||||
Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/acutator/sms-info 来访问。
|
Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/actuator/sms-info 来访问。
|
||||||
|
|
||||||
Endpoint 内部会显示最近 20 条单个短信发送的记录和批量短信发送的记录,以及当前短信消息的配置信息(包括是**SmsReport** 还是 **SmsUp**,**队列名称**,以及对应的 **MessageListener** )。
|
Endpoint 内部会显示最近 20 条单个短信发送的记录和批量短信发送的记录,以及当前短信消息的配置信息(包括是**SmsReport** 还是 **SmsUp**,**队列名称**,以及对应的 **MessageListener** )。
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ spring:
|
|||||||
- `spring.application.name` : Spring 应用名称,用于 Spring Cloud 服务注册和发现。
|
- `spring.application.name` : Spring 应用名称,用于 Spring Cloud 服务注册和发现。
|
||||||
> 该值在 Dubbo Spring Cloud 加持下被视作 `dubbo.application.name`,因此,无需再显示地配置 `dubbo.application.name`
|
> 该值在 Dubbo Spring Cloud 加持下被视作 `dubbo.application.name`,因此,无需再显示地配置 `dubbo.application.name`
|
||||||
- `spring.main.allow-bean-definition-overriding` : 在 Spring Boot 2.1 以及更高的版本增加该设定,
|
- `spring.main.allow-bean-definition-overriding` : 在 Spring Boot 2.1 以及更高的版本增加该设定,
|
||||||
因为 Spring Boot 默认调整了 Bean 定义覆盖行为。(推荐一个好的 Dubbo 讨论 [issue #3193](https://github.com/apache/incubator-dubbo/issues/3193#issuecomment-474340165))
|
因为 Spring Boot 默认调整了 Bean 定义覆盖行为。(推荐一个好的 Dubbo 讨论 [issue #3193](https://github.com/apache/dubbo/issues/3193#issuecomment-474340165))
|
||||||
- `spring.cloud.nacos.discovery` : Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
|
- `spring.cloud.nacos.discovery` : Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
|
||||||
|
|
||||||
> 以上完整的 YAML 配置文件,请参考 `spring-cloud-dubbo-server-sample` [`bootstrap.yaml`](spring-cloud-dubbo-server-sample/src/main/resources/bootstrap.yaml) 文件
|
> 以上完整的 YAML 配置文件,请参考 `spring-cloud-dubbo-server-sample` [`bootstrap.yaml`](spring-cloud-dubbo-server-sample/src/main/resources/bootstrap.yaml) 文件
|
||||||
|
@ -76,6 +76,7 @@ public class DubboGatewayServlet extends HttpServletBean {
|
|||||||
return serviceName;
|
return serviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||||
|
|
||||||
String serviceName = resolveServiceName(request);
|
String serviceName = resolveServiceName(request);
|
||||||
|
@ -28,25 +28,25 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
*/
|
*/
|
||||||
public class NacosPropertySourceRepository {
|
public class NacosPropertySourceRepository {
|
||||||
|
|
||||||
private final static ConcurrentHashMap<String, NacosPropertySource> nacosPropertySourceRepository = new ConcurrentHashMap<>();
|
private final static ConcurrentHashMap<String, NacosPropertySource> NACOS_PROPERTY_SOURCE_REPOSITORY = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return all nacos properties from application context
|
* @return all nacos properties from application context
|
||||||
*/
|
*/
|
||||||
public static List<NacosPropertySource> getAll() {
|
public static List<NacosPropertySource> getAll() {
|
||||||
List<NacosPropertySource> result = new ArrayList<>();
|
List<NacosPropertySource> result = new ArrayList<>();
|
||||||
result.addAll(nacosPropertySourceRepository.values());
|
result.addAll(NACOS_PROPERTY_SOURCE_REPOSITORY.values());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void collectNacosPropertySources(
|
public static void collectNacosPropertySources(
|
||||||
NacosPropertySource nacosPropertySource) {
|
NacosPropertySource nacosPropertySource) {
|
||||||
nacosPropertySourceRepository.putIfAbsent(nacosPropertySource.getDataId(),
|
NACOS_PROPERTY_SOURCE_REPOSITORY.putIfAbsent(nacosPropertySource.getDataId(),
|
||||||
nacosPropertySource);
|
nacosPropertySource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NacosPropertySource getNacosPropertySource(String dataId) {
|
public static NacosPropertySource getNacosPropertySource(String dataId) {
|
||||||
|
|
||||||
return nacosPropertySourceRepository.get(dataId);
|
return NACOS_PROPERTY_SOURCE_REPOSITORY.get(dataId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,12 @@ public class NacosConfigEndpoint {
|
|||||||
|
|
||||||
private final NacosRefreshHistory refreshHistory;
|
private final NacosRefreshHistory refreshHistory;
|
||||||
|
|
||||||
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
private ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {
|
||||||
|
@Override
|
||||||
|
protected DateFormat initialValue() {
|
||||||
|
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public NacosConfigEndpoint(NacosConfigProperties properties,
|
public NacosConfigEndpoint(NacosConfigProperties properties,
|
||||||
NacosRefreshHistory refreshHistory) {
|
NacosRefreshHistory refreshHistory) {
|
||||||
@ -60,7 +65,7 @@ public class NacosConfigEndpoint {
|
|||||||
for (NacosPropertySource ps : all) {
|
for (NacosPropertySource ps : all) {
|
||||||
Map<String, Object> source = new HashMap<>(16);
|
Map<String, Object> source = new HashMap<>(16);
|
||||||
source.put("dataId", ps.getDataId());
|
source.put("dataId", ps.getDataId());
|
||||||
source.put("lastSynced", dateFormat.format(ps.getTimestamp()));
|
source.put("lastSynced", dateFormat.get().format(ps.getTimestamp()));
|
||||||
sources.add(source);
|
sources.add(source);
|
||||||
}
|
}
|
||||||
result.put("Sources", sources);
|
result.put("Sources", sources);
|
||||||
|
@ -27,10 +27,15 @@ public class NacosRefreshHistory {
|
|||||||
|
|
||||||
private LinkedList<Record> records = new LinkedList<>();
|
private LinkedList<Record> records = new LinkedList<>();
|
||||||
|
|
||||||
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
private ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {
|
||||||
|
@Override
|
||||||
|
protected DateFormat initialValue() {
|
||||||
|
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public void add(String dataId, String md5) {
|
public void add(String dataId, String md5) {
|
||||||
records.addFirst(new Record(dateFormat.format(new Date()), dataId, md5));
|
records.addFirst(new Record(dateFormat.get().format(new Date()), dataId, md5));
|
||||||
if (records.size() > MAX_SIZE) {
|
if (records.size() > MAX_SIZE) {
|
||||||
records.removeLast();
|
records.removeLast();
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,9 @@
|
|||||||
package org.springframework.cloud.alibaba.nacos;
|
package org.springframework.cloud.alibaba.nacos;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.cloud.alibaba.nacos.discovery.NacosDiscoveryClientAutoConfiguration;
|
|
||||||
import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration;
|
import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration;
|
||||||
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
|
import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration;
|
||||||
import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry;
|
import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry;
|
||||||
|
@ -118,57 +118,10 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void nacosServicesWatch() {
|
public void nacosServicesWatch() {
|
||||||
try {
|
|
||||||
|
|
||||||
boolean changed = false;
|
// nacos doesn't support watch now , publish an event every 30 seconds.
|
||||||
NamingService namingService = properties.namingServiceInstance();
|
|
||||||
|
|
||||||
ListView<String> listView = properties.namingServiceInstance()
|
|
||||||
.getServicesOfServer(1, Integer.MAX_VALUE);
|
|
||||||
|
|
||||||
List<String> serviceList = listView.getData();
|
|
||||||
|
|
||||||
// if there are new services found, publish event
|
|
||||||
Set<String> currentServices = new HashSet<>(serviceList);
|
|
||||||
currentServices.removeAll(cacheServices);
|
|
||||||
if (currentServices.size() > 0) {
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if some services disappear, publish event
|
|
||||||
if (cacheServices.removeAll(new HashSet<>(serviceList))
|
|
||||||
&& cacheServices.size() > 0) {
|
|
||||||
changed = true;
|
|
||||||
|
|
||||||
for (String serviceName : cacheServices) {
|
|
||||||
namingService.unsubscribe(serviceName,
|
|
||||||
subscribeListeners.get(serviceName));
|
|
||||||
subscribeListeners.remove(serviceName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheServices = new HashSet<>(serviceList);
|
|
||||||
|
|
||||||
// subscribe services's node change, publish event if nodes changed
|
|
||||||
for (String serviceName : cacheServices) {
|
|
||||||
if (!subscribeListeners.containsKey(serviceName)) {
|
|
||||||
EventListener eventListener = event -> NacosWatch.this.publisher
|
|
||||||
.publishEvent(new HeartbeatEvent(NacosWatch.this,
|
|
||||||
nacosWatchIndex.getAndIncrement()));
|
|
||||||
subscribeListeners.put(serviceName, eventListener);
|
|
||||||
namingService.subscribe(serviceName, eventListener);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
this.publisher.publishEvent(
|
this.publisher.publishEvent(
|
||||||
new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement()));
|
new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement()));
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
log.error("Error watching Nacos Service change", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,16 @@ public class NacosRibbonClientConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public ServerList<?> ribbonServerList(IClientConfig config, NacosDiscoveryProperties nacosDiscoveryProperties) {
|
public ServerList<?> ribbonServerList(IClientConfig config,
|
||||||
|
NacosDiscoveryProperties nacosDiscoveryProperties) {
|
||||||
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
|
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
|
||||||
serverList.initWithNiwsConfig(config);
|
serverList.initWithNiwsConfig(config);
|
||||||
return serverList;
|
return serverList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public NacosServerIntrospector nacosServerIntrospector() {
|
||||||
|
return new NacosServerIntrospector();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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.nacos.ribbon;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
|
||||||
|
|
||||||
|
import com.netflix.loadbalancer.Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xiaojing
|
||||||
|
*/
|
||||||
|
public class NacosServerIntrospector extends DefaultServerIntrospector {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getMetadata(Server server) {
|
||||||
|
if (server instanceof NacosServer) {
|
||||||
|
return ((NacosServer) server).getMetadata();
|
||||||
|
}
|
||||||
|
return super.getMetadata(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSecure(Server server) {
|
||||||
|
if (server instanceof NacosServer) {
|
||||||
|
return Boolean.valueOf(((NacosServer) server).getMetadata().get("secure"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.isSecure(server);
|
||||||
|
}
|
||||||
|
}
|
@ -53,12 +53,7 @@ public class SeataFeignClient implements Client {
|
|||||||
public Response execute(Request request, Request.Options options) throws IOException {
|
public Response execute(Request request, Request.Options options) throws IOException {
|
||||||
|
|
||||||
Request modifiedRequest = getModifyRequest(request);
|
Request modifiedRequest = getModifyRequest(request);
|
||||||
|
|
||||||
try {
|
|
||||||
return this.delegate.execute(modifiedRequest, options);
|
return this.delegate.execute(modifiedRequest, options);
|
||||||
} finally {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Request getModifyRequest(Request request) {
|
private Request getModifyRequest(Request request) {
|
||||||
|
@ -17,7 +17,13 @@
|
|||||||
package org.springframework.cloud.alibaba.seata.feign;
|
package org.springframework.cloud.alibaba.seata.feign;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.seata.core.context.RootContext;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||||
|
|
||||||
@ -26,12 +32,15 @@ import feign.Request;
|
|||||||
import feign.Response;
|
import feign.Response;
|
||||||
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
|
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
|
||||||
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
|
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author xiaojing
|
* @author xiaojing
|
||||||
*/
|
*/
|
||||||
public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
|
public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
|
||||||
|
|
||||||
|
private static final int MAP_SIZE = 16;
|
||||||
|
|
||||||
private final BeanFactory beanFactory;
|
private final BeanFactory beanFactory;
|
||||||
|
|
||||||
SeataLoadBalancerFeignClient(Client delegate,
|
SeataLoadBalancerFeignClient(Client delegate,
|
||||||
@ -43,6 +52,7 @@ public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response execute(Request request, Request.Options options) throws IOException {
|
public Response execute(Request request, Request.Options options) throws IOException {
|
||||||
|
Request modifiedRequest = getModifyRequest(request);
|
||||||
return super.execute(request, options);
|
return super.execute(request, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,4 +60,22 @@ public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
|
|||||||
return (Client) new SeataFeignObjectWrapper(beanFactory).wrap(delegate);
|
return (Client) new SeataFeignObjectWrapper(beanFactory).wrap(delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Request getModifyRequest(Request request) {
|
||||||
|
|
||||||
|
String xid = RootContext.getXID();
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(xid)) {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Collection<String>> headers = new HashMap<>(MAP_SIZE);
|
||||||
|
headers.putAll(request.headers());
|
||||||
|
|
||||||
|
List<String> fescarXid = new ArrayList<>();
|
||||||
|
fescarXid.add(xid);
|
||||||
|
headers.put(RootContext.KEY_XID, fescarXid);
|
||||||
|
|
||||||
|
return Request.create(request.method(), request.url(), headers, request.body(),
|
||||||
|
request.charset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,12 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||||
|
@ -6,6 +6,8 @@ import java.util.Optional;
|
|||||||
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
|
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
|
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.AuthorityRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
||||||
@ -40,7 +42,15 @@ public enum RuleType {
|
|||||||
/**
|
/**
|
||||||
* authority
|
* authority
|
||||||
*/
|
*/
|
||||||
AUTHORITY("authority", AuthorityRule.class);
|
AUTHORITY("authority", AuthorityRule.class),
|
||||||
|
/**
|
||||||
|
* gateway flow
|
||||||
|
*/
|
||||||
|
GW_FLOW("gw-flow", GatewayFlowRule.class),
|
||||||
|
/**
|
||||||
|
* api
|
||||||
|
*/
|
||||||
|
GW_API_GROUP("gw-api-group", ApiDefinition.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* alias for {@link AbstractRule}
|
* alias for {@link AbstractRule}
|
||||||
|
@ -4,7 +4,10 @@ import javax.validation.constraints.NotEmpty;
|
|||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
|
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
|
||||||
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
||||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
|
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
|
||||||
@ -28,6 +31,8 @@ public class AbstractDataSourceProperties {
|
|||||||
private String converterClass;
|
private String converterClass;
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private final String factoryBeanName;
|
private final String factoryBeanName;
|
||||||
|
@JsonIgnore
|
||||||
|
private Environment env;
|
||||||
|
|
||||||
public AbstractDataSourceProperties(String factoryBeanName) {
|
public AbstractDataSourceProperties(String factoryBeanName) {
|
||||||
this.factoryBeanName = factoryBeanName;
|
this.factoryBeanName = factoryBeanName;
|
||||||
@ -61,6 +66,14 @@ public class AbstractDataSourceProperties {
|
|||||||
return factoryBeanName;
|
return factoryBeanName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Environment getEnv() {
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnv(Environment env) {
|
||||||
|
this.env = env;
|
||||||
|
}
|
||||||
|
|
||||||
public void preCheck(String dataSourceName) {
|
public void preCheck(String dataSourceName) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -82,6 +95,12 @@ public class AbstractDataSourceProperties {
|
|||||||
case AUTHORITY:
|
case AUTHORITY:
|
||||||
AuthorityRuleManager.register2Property(dataSource.getProperty());
|
AuthorityRuleManager.register2Property(dataSource.getProperty());
|
||||||
break;
|
break;
|
||||||
|
case GW_FLOW:
|
||||||
|
GatewayRuleManager.register2Property(dataSource.getProperty());
|
||||||
|
break;
|
||||||
|
case GW_API_GROUP:
|
||||||
|
GatewayApiDefinitionManager.register2Property(dataSource.getProperty());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@ package org.springframework.cloud.alibaba.sentinel.datasource.config;
|
|||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
|
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@ -34,9 +32,13 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preCheck(String dataSourceName) {
|
public void preCheck(String dataSourceName) {
|
||||||
if (StringUtils.isEmpty(serverAddr) && acmPropertiesInvalid()) {
|
if (StringUtils.isEmpty(serverAddr)) {
|
||||||
|
serverAddr = this.getEnv().getProperty(
|
||||||
|
"spring.cloud.sentinel.datasource.nacos.server-addr", "");
|
||||||
|
if (StringUtils.isEmpty(serverAddr)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"NacosDataSource properties value not correct. serverAddr is empty but there is empty value in accessKey, secretKey, endpoint, namespace property");
|
"NacosDataSource server-addr is empty");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,9 +98,4 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
|
|||||||
this.secretKey = secretKey;
|
this.secretKey = secretKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean acmPropertiesInvalid() {
|
|
||||||
return StringUtils.isEmpty(endpoint) || StringUtils.isEmpty(accessKey)
|
|
||||||
|| StringUtils.isEmpty(secretKey) || StringUtils.isEmpty(namespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.datasource.config;
|
package org.springframework.cloud.alibaba.sentinel.datasource.config;
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
|
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zookeeper Properties class Using by {@link DataSourcePropertiesConfiguration} and
|
* Zookeeper Properties class Using by {@link DataSourcePropertiesConfiguration} and
|
||||||
@ -16,7 +15,6 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties
|
|||||||
super(ZookeeperDataSourceFactoryBean.class.getName());
|
super(ZookeeperDataSourceFactoryBean.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotEmpty
|
|
||||||
private String serverAddr;
|
private String serverAddr;
|
||||||
|
|
||||||
private String path;
|
private String path;
|
||||||
@ -25,6 +23,18 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties
|
|||||||
|
|
||||||
private String dataId;
|
private String dataId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preCheck(String dataSourceName) {
|
||||||
|
if (StringUtils.isEmpty(serverAddr)) {
|
||||||
|
serverAddr = this.getEnv()
|
||||||
|
.getProperty("spring.cloud.sentinel.datasource.zk.server-addr", "");
|
||||||
|
if (StringUtils.isEmpty(serverAddr)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"ZookeeperDataSource server-addr is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String getServerAddr() {
|
public String getServerAddr() {
|
||||||
return serverAddr;
|
return serverAddr;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.datasource.converter;
|
package org.springframework.cloud.alibaba.sentinel.datasource.converter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||||
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.AuthorityRule;
|
||||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
|
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.degrade.DegradeRuleManager;
|
||||||
@ -13,15 +26,6 @@ import com.alibaba.csp.sentinel.slots.system.SystemRule;
|
|||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert sentinel rules for json or xml array Using strict mode to parse json or xml
|
* Convert sentinel rules for json or xml array Using strict mode to parse json or xml
|
||||||
@ -34,8 +38,8 @@ import java.util.Optional;
|
|||||||
* @see ParamFlowRule
|
* @see ParamFlowRule
|
||||||
* @see ObjectMapper
|
* @see ObjectMapper
|
||||||
*/
|
*/
|
||||||
public abstract class SentinelConverter<T extends AbstractRule>
|
public abstract class SentinelConverter<T extends Object>
|
||||||
implements Converter<String, List<AbstractRule>> {
|
implements Converter<String, Collection<Object>> {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SentinelConverter.class);
|
private static final Logger log = LoggerFactory.getLogger(SentinelConverter.class);
|
||||||
|
|
||||||
@ -49,11 +53,20 @@ public abstract class SentinelConverter<T extends AbstractRule>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AbstractRule> convert(String source) {
|
public Collection<Object> convert(String source) {
|
||||||
List<AbstractRule> ruleList = new ArrayList<>();
|
Collection<Object> ruleCollection;
|
||||||
|
|
||||||
|
// hard code
|
||||||
|
if (ruleClass == GatewayFlowRule.class || ruleClass == ApiDefinition.class) {
|
||||||
|
ruleCollection = new HashSet<>();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ruleCollection = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
if (StringUtils.isEmpty(source)) {
|
if (StringUtils.isEmpty(source)) {
|
||||||
log.warn("converter can not convert rules because source is empty");
|
log.warn("converter can not convert rules because source is empty");
|
||||||
return ruleList;
|
return ruleCollection;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
List sourceArray = objectMapper.readValue(source,
|
List sourceArray = objectMapper.readValue(source,
|
||||||
@ -70,11 +83,11 @@ public abstract class SentinelConverter<T extends AbstractRule>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Optional.ofNullable(convertRule(item))
|
Optional.ofNullable(convertRule(item))
|
||||||
.ifPresent(convertRule -> ruleList.add(convertRule));
|
.ifPresent(convertRule -> ruleCollection.add(convertRule));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ruleList.size() != sourceArray.size()) {
|
if (ruleCollection.size() != sourceArray.size()) {
|
||||||
throw new IllegalArgumentException("convert " + ruleList.size()
|
throw new IllegalArgumentException("convert " + ruleCollection.size()
|
||||||
+ " rules but there are " + sourceArray.size()
|
+ " rules but there are " + sourceArray.size()
|
||||||
+ " rules from datasource. RuleClass: "
|
+ " rules from datasource. RuleClass: "
|
||||||
+ ruleClass.getSimpleName());
|
+ ruleClass.getSimpleName());
|
||||||
@ -83,12 +96,12 @@ public abstract class SentinelConverter<T extends AbstractRule>
|
|||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new RuntimeException("convert error: " + e.getMessage(), e);
|
throw new RuntimeException("convert error: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
return ruleList;
|
return ruleCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractRule convertRule(String ruleStr) {
|
private Object convertRule(String ruleStr) {
|
||||||
try {
|
try {
|
||||||
final AbstractRule rule = objectMapper.readValue(ruleStr, ruleClass);
|
final Object rule = objectMapper.readValue(ruleStr, ruleClass);
|
||||||
RuleType ruleType = RuleType.getByClass(ruleClass).get();
|
RuleType ruleType = RuleType.getByClass(ruleClass).get();
|
||||||
switch (ruleType) {
|
switch (ruleType) {
|
||||||
case FLOW:
|
case FLOW:
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||||
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
|
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link FactoryBean} for creating {@link ApolloDataSource} instance.
|
* A {@link FactoryBean} for creating {@link ApolloDataSource} instance.
|
||||||
*
|
*
|
||||||
|
@ -3,11 +3,11 @@ package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||||
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
|
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link FactoryBean} for creating {@link FileRefreshableDataSource} instance.
|
* A {@link FactoryBean} for creating {@link FileRefreshableDataSource} instance.
|
||||||
*
|
*
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||||
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
|
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
|
||||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
|
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
|
||||||
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||||
|
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link FactoryBean} for creating {@link ZookeeperDataSource} instance.
|
* A {@link FactoryBean} for creating {@link ZookeeperDataSource} instance.
|
||||||
*
|
*
|
||||||
@ -28,7 +28,8 @@ public class ZookeeperDataSourceFactoryBean implements FactoryBean<ZookeeperData
|
|||||||
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
|
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
|
||||||
// the path will be /{groupId}/{dataId}
|
// the path will be /{groupId}/{dataId}
|
||||||
return new ZookeeperDataSource(serverAddr, groupId, dataId, converter);
|
return new ZookeeperDataSource(serverAddr, groupId, dataId, converter);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// using path directly
|
// using path directly
|
||||||
return new ZookeeperDataSource(serverAddr, path, converter);
|
return new ZookeeperDataSource(serverAddr, path, converter);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public class SentinelConverterTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testJsonConverter() {
|
public void testJsonConverter() {
|
||||||
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
|
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
|
||||||
List<FlowRule> flowRules = jsonConverter
|
List<FlowRule> flowRules = (List<FlowRule>) jsonConverter
|
||||||
.convert(readFileContent("classpath: flowrule.json"));
|
.convert(readFileContent("classpath: flowrule.json"));
|
||||||
assertEquals("json converter flow rule size was wrong", 1, flowRules.size());
|
assertEquals("json converter flow rule size was wrong", 1, flowRules.size());
|
||||||
assertEquals("json converter flow rule resource name was wrong", "resource",
|
assertEquals("json converter flow rule resource name was wrong", "resource",
|
||||||
@ -67,7 +67,7 @@ public class SentinelConverterTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testConverterEmptyContent() {
|
public void testConverterEmptyContent() {
|
||||||
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
|
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
|
||||||
List<FlowRule> flowRules = jsonConverter.convert("");
|
List<FlowRule> flowRules = (List<FlowRule>) jsonConverter.convert("");
|
||||||
assertEquals("json converter flow rule size was not empty", 0, flowRules.size());
|
assertEquals("json converter flow rule size was not empty", 0, flowRules.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ public class SentinelConverterTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testXmlConverter() {
|
public void testXmlConverter() {
|
||||||
XmlConverter jsonConverter = new XmlConverter(xmlMapper, FlowRule.class);
|
XmlConverter jsonConverter = new XmlConverter(xmlMapper, FlowRule.class);
|
||||||
List<FlowRule> flowRules = jsonConverter
|
List<FlowRule> flowRules = (List<FlowRule>) jsonConverter
|
||||||
.convert(readFileContent("classpath: flowrule.xml"));
|
.convert(readFileContent("classpath: flowrule.xml"));
|
||||||
assertEquals("xml converter flow rule size was wrong", 2, flowRules.size());
|
assertEquals("xml converter flow rule size was wrong", 2, flowRules.size());
|
||||||
assertEquals("xml converter flow rule1 resource name was wrong", "resource",
|
assertEquals("xml converter flow rule1 resource name was wrong", "resource",
|
||||||
|
@ -14,7 +14,7 @@ Sentinel can provide `ServiceId` level and `API Path` level flow control for spr
|
|||||||
```xml
|
```xml
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
|
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||||
<version>x.y.z</version>
|
<version>x.y.z</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
@ -10,19 +10,28 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
|
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||||
<name>Spring Cloud Alibaba Sentinel Zuul</name>
|
<name>Spring Cloud Alibaba Sentinel Gateway</name>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
||||||
<scope>provided</scope>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-zuul-adapter</artifactId>
|
<artifactId>sentinel-zuul-adapter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.gateway;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
public interface ConfigConstants {
|
||||||
|
|
||||||
|
String APP_TYPE_ZUUL_GATEWAY = "12";
|
||||||
|
|
||||||
|
String ZUUl_PREFIX = "spring.cloud.sentinel.zuul";
|
||||||
|
|
||||||
|
String GATEWAY_PREFIX = "spring.cloud.sentinel.scg";
|
||||||
|
|
||||||
|
String FALLBACK_MSG_RESPONSE = "response";
|
||||||
|
String FALLBACK_REDIRECT = "redirect";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.gateway;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
public class FallbackProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The fallback mode for sentinel spring-cloud-gateway. choose `redirect` or
|
||||||
|
* `response`.
|
||||||
|
*/
|
||||||
|
private String mode;
|
||||||
|
/**
|
||||||
|
* Redirect Url for `redirect` mode.
|
||||||
|
*/
|
||||||
|
private String redirect;
|
||||||
|
/**
|
||||||
|
* Response Body for `response` mode.
|
||||||
|
*/
|
||||||
|
private String responseBody;
|
||||||
|
/**
|
||||||
|
* Response Status for `response` mode.
|
||||||
|
*/
|
||||||
|
private Integer responseStatus = HttpStatus.TOO_MANY_REQUESTS.value();
|
||||||
|
/**
|
||||||
|
* Content-Type for `response` mode.
|
||||||
|
*/
|
||||||
|
private String contentType = MediaType.APPLICATION_JSON_UTF8.toString();
|
||||||
|
|
||||||
|
public String getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallbackProperties setMode(String mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRedirect() {
|
||||||
|
return redirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallbackProperties setRedirect(String redirect) {
|
||||||
|
this.redirect = redirect;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResponseBody() {
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallbackProperties setResponseBody(String responseBody) {
|
||||||
|
this.responseBody = responseBody;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getResponseStatus() {
|
||||||
|
return responseStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallbackProperties setResponseStatus(Integer responseStatus) {
|
||||||
|
this.responseStatus = responseStatus;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FallbackProperties setContentType(String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.gateway.scg;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.gateway.ConfigConstants;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.gateway.FallbackProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = ConfigConstants.GATEWAY_PREFIX)
|
||||||
|
public class SentinelGatewayProperties {
|
||||||
|
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private FallbackProperties fallback;
|
||||||
|
|
||||||
|
public FallbackProperties getFallback() {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SentinelGatewayProperties setFallback(FallbackProperties fallback) {
|
||||||
|
this.fallback = fallback;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.gateway.scg;
|
||||||
|
|
||||||
|
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
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.gateway.ConfigConstants;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.gateway.FallbackProperties;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||||
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.RedirectBlockRequestHandler;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
|
||||||
|
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||||
|
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(GlobalFilter.class)
|
||||||
|
@ConditionalOnProperty(prefix = ConfigConstants.GATEWAY_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
|
@EnableConfigurationProperties(SentinelGatewayProperties.class)
|
||||||
|
public class SentinelSCGAutoConfiguration {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory
|
||||||
|
.getLogger(SentinelSCGAutoConfiguration.class);
|
||||||
|
|
||||||
|
private final List<ViewResolver> viewResolvers;
|
||||||
|
private final ServerCodecConfigurer serverCodecConfigurer;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Optional<BlockRequestHandler> blockRequestHandlerOptional;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SentinelGatewayProperties gatewayProperties;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
// blockRequestHandlerOptional has low priority
|
||||||
|
blockRequestHandlerOptional.ifPresent(GatewayCallbackManager::setBlockHandler);
|
||||||
|
initAppType();
|
||||||
|
initFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SentinelSCGAutoConfiguration(
|
||||||
|
ObjectProvider<List<ViewResolver>> viewResolversProvider,
|
||||||
|
ServerCodecConfigurer serverCodecConfigurer) {
|
||||||
|
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
|
||||||
|
this.serverCodecConfigurer = serverCodecConfigurer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initAppType() {
|
||||||
|
System.setProperty(SentinelConfig.APP_TYPE,
|
||||||
|
String.valueOf(SentinelGatewayConstants.APP_TYPE_GATEWAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFallback() {
|
||||||
|
FallbackProperties fallbackProperties = gatewayProperties.getFallback();
|
||||||
|
if (fallbackProperties == null
|
||||||
|
|| StringUtil.isBlank(fallbackProperties.getMode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ConfigConstants.FALLBACK_MSG_RESPONSE.equals(fallbackProperties.getMode())) {
|
||||||
|
if (StringUtil.isNotBlank(fallbackProperties.getResponseBody())) {
|
||||||
|
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
|
||||||
|
@Override
|
||||||
|
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange,
|
||||||
|
Throwable t) {
|
||||||
|
return ServerResponse
|
||||||
|
.status(fallbackProperties.getResponseStatus())
|
||||||
|
.contentType(MediaType
|
||||||
|
.valueOf(fallbackProperties.getContentType()))
|
||||||
|
.body(fromObject(fallbackProperties.getResponseBody()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
logger.info(
|
||||||
|
"[Sentinel SpringCloudGateway] using AnonymousBlockRequestHandler, responseStatus: "
|
||||||
|
+ fallbackProperties.getResponseStatus()
|
||||||
|
+ ", responseBody: "
|
||||||
|
+ fallbackProperties.getResponseStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String redirectUrl = fallbackProperties.getRedirect();
|
||||||
|
if (ConfigConstants.FALLBACK_REDIRECT.equals(fallbackProperties.getMode())
|
||||||
|
&& StringUtil.isNotBlank(redirectUrl)) {
|
||||||
|
GatewayCallbackManager
|
||||||
|
.setBlockHandler(new RedirectBlockRequestHandler(redirectUrl));
|
||||||
|
logger.info(
|
||||||
|
"[Sentinel SpringCloudGateway] using RedirectBlockRequestHandler, redirectUrl: "
|
||||||
|
+ redirectUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
|
||||||
|
// Register the block exception handler for Spring Cloud Gateway.
|
||||||
|
logger.info(
|
||||||
|
"[Sentinel SpringCloudGateway] register SentinelGatewayBlockExceptionHandler");
|
||||||
|
return new SentinelGatewayBlockExceptionHandler(viewResolvers,
|
||||||
|
serverCodecConfigurer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(-1)
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SentinelGatewayFilter sentinelGatewayFilter() {
|
||||||
|
logger.info("[Sentinel SpringCloudGateway] register SentinelGatewayFilter");
|
||||||
|
return new SentinelGatewayFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,16 +1,16 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.zuul.handler;
|
package org.springframework.cloud.alibaba.sentinel.gateway.zuul;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.collections.MapUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultBlockFallbackProvider;
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.DefaultBlockFallbackProvider;
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackManager;
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager;
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider;
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author tiger
|
* @author tiger
|
||||||
@ -30,7 +30,7 @@ public class FallBackProviderHandler implements SmartInitializingSingleton {
|
|||||||
public void afterSingletonsInstantiated() {
|
public void afterSingletonsInstantiated() {
|
||||||
Map<String, ZuulBlockFallbackProvider> providerMap = beanFactory
|
Map<String, ZuulBlockFallbackProvider> providerMap = beanFactory
|
||||||
.getBeansOfType(ZuulBlockFallbackProvider.class);
|
.getBeansOfType(ZuulBlockFallbackProvider.class);
|
||||||
if (MapUtils.isNotEmpty(providerMap)) {
|
if (!CollectionUtils.isEmpty(providerMap)) {
|
||||||
providerMap.forEach((k, v) -> {
|
providerMap.forEach((k, v) -> {
|
||||||
logger.info("[Sentinel Zuul] Register provider name:{}, instance: {}", k,
|
logger.info("[Sentinel Zuul] Register provider name:{}, instance: {}", k,
|
||||||
v);
|
v);
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||||
|
*
|
||||||
|
* 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.gateway.zuul;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
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.gateway.ConfigConstants;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.RequestOriginParser;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.ZuulGatewayCallbackManager;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter;
|
||||||
|
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||||
|
|
||||||
|
import com.netflix.zuul.http.ZuulServlet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sentinel Spring Cloud Zuul AutoConfiguration
|
||||||
|
*
|
||||||
|
* @author tiger
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(ZuulServlet.class)
|
||||||
|
@ConditionalOnProperty(prefix = ConfigConstants.ZUUl_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
|
@EnableConfigurationProperties(SentinelZuulProperties.class)
|
||||||
|
public class SentinelZuulAutoConfiguration {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory
|
||||||
|
.getLogger(SentinelZuulAutoConfiguration.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Optional<RequestOriginParser> requestOriginParserOptional;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SentinelZuulProperties zuulProperties;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
requestOriginParserOptional
|
||||||
|
.ifPresent(ZuulGatewayCallbackManager::setOriginParser);
|
||||||
|
System.setProperty(SentinelConfig.APP_TYPE,
|
||||||
|
String.valueOf(ConfigConstants.APP_TYPE_ZUUL_GATEWAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SentinelZuulPreFilter sentinelZuulPreFilter() {
|
||||||
|
logger.info("[Sentinel Zuul] register SentinelZuulPreFilter {}",
|
||||||
|
zuulProperties.getOrder().getPre());
|
||||||
|
return new SentinelZuulPreFilter(zuulProperties.getOrder().getPre());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SentinelZuulPostFilter sentinelZuulPostFilter() {
|
||||||
|
logger.info("[Sentinel Zuul] register SentinelZuulPostFilter {}",
|
||||||
|
zuulProperties.getOrder().getPost());
|
||||||
|
return new SentinelZuulPostFilter(zuulProperties.getOrder().getPost());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public SentinelZuulErrorFilter sentinelZuulErrorFilter() {
|
||||||
|
logger.info("[Sentinel Zuul] register SentinelZuulErrorFilter {}",
|
||||||
|
zuulProperties.getOrder().getError());
|
||||||
|
return new SentinelZuulErrorFilter(zuulProperties.getOrder().getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FallBackProviderHandler fallBackProviderHandler(
|
||||||
|
DefaultListableBeanFactory beanFactory) {
|
||||||
|
return new FallBackProviderHandler(beanFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.gateway.zuul;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.gateway.ConfigConstants;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.constants.ZuulConstant;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulErrorFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPostFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.zuul.filters.SentinelZuulPreFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties(prefix = ConfigConstants.ZUUl_PREFIX)
|
||||||
|
public class SentinelZuulProperties {
|
||||||
|
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private SentinelZuulProperties.Order order;
|
||||||
|
|
||||||
|
public Order getOrder() {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SentinelZuulProperties setOrder(Order order) {
|
||||||
|
this.order = order;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Order {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of {@link SentinelZuulPreFilter}.
|
||||||
|
*/
|
||||||
|
private int pre = 10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of {@link SentinelZuulPostFilter}.
|
||||||
|
*/
|
||||||
|
private int post = ZuulConstant.SEND_RESPONSE_FILTER_ORDER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of {@link SentinelZuulErrorFilter}.
|
||||||
|
*/
|
||||||
|
private int error = -1;
|
||||||
|
|
||||||
|
public int getPre() {
|
||||||
|
return pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPre(int pre) {
|
||||||
|
this.pre = pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPost() {
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPost(int post) {
|
||||||
|
this.post = post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setError(int error) {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
org.springframework.cloud.alibaba.sentinel.gateway.zuul.SentinelZuulAutoConfiguration,\
|
||||||
|
org.springframework.cloud.alibaba.sentinel.gateway.scg.SentinelSCGAutoConfiguration
|
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
|
||||||
*
|
|
||||||
* 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.zuul;
|
|
||||||
|
|
||||||
import static org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration.PREFIX;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.zuul.handler.FallBackProviderHandler;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultRequestOriginParser;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultUrlCleaner;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.RequestOriginParser;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.fallback.UrlCleaner;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelErrorFilter;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPostFilter;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPreFilter;
|
|
||||||
import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
|
|
||||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
|
||||||
|
|
||||||
import com.netflix.zuul.ZuulFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sentinel Spring Cloud Zuul AutoConfiguration
|
|
||||||
*
|
|
||||||
* @author tiger
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnProperty(prefix = PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
|
||||||
public class SentinelZuulAutoConfiguration {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Environment environment;
|
|
||||||
|
|
||||||
public static final String PREFIX = "spring.cloud.sentinel.zuul";
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SentinelZuulProperties sentinelZuulProperties() {
|
|
||||||
SentinelZuulProperties properties = new SentinelZuulProperties();
|
|
||||||
String enabledStr = environment.getProperty(PREFIX + "." + "enabled");
|
|
||||||
String preOrderStr = environment.getProperty(PREFIX + "." + "order.pre");
|
|
||||||
String postOrderStr = environment.getProperty(PREFIX + "." + "order.post");
|
|
||||||
String errorOrderStr = environment.getProperty(PREFIX + "." + "order.error");
|
|
||||||
if (StringUtil.isNotEmpty(enabledStr)) {
|
|
||||||
Boolean enabled = Boolean.valueOf(enabledStr);
|
|
||||||
properties.setEnabled(enabled);
|
|
||||||
}
|
|
||||||
if (StringUtil.isNotEmpty(preOrderStr)) {
|
|
||||||
properties.getOrder().setPre(Integer.parseInt(preOrderStr));
|
|
||||||
}
|
|
||||||
if (StringUtil.isNotEmpty(postOrderStr)) {
|
|
||||||
properties.getOrder().setPost(Integer.parseInt(postOrderStr));
|
|
||||||
}
|
|
||||||
if (StringUtil.isNotEmpty(errorOrderStr)) {
|
|
||||||
properties.getOrder().setError(Integer.parseInt(errorOrderStr));
|
|
||||||
}
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(UrlCleaner.class)
|
|
||||||
public UrlCleaner urlCleaner() {
|
|
||||||
return new DefaultUrlCleaner();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(RequestOriginParser.class)
|
|
||||||
public RequestOriginParser requestOriginParser() {
|
|
||||||
return new DefaultRequestOriginParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ZuulFilter preFilter(SentinelZuulProperties sentinelZuulProperties,
|
|
||||||
UrlCleaner urlCleaner, RequestOriginParser requestOriginParser) {
|
|
||||||
return new SentinelPreFilter(sentinelZuulProperties, urlCleaner,
|
|
||||||
requestOriginParser);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ZuulFilter postFilter(SentinelZuulProperties sentinelZuulProperties) {
|
|
||||||
return new SentinelPostFilter(sentinelZuulProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ZuulFilter errorFilter(SentinelZuulProperties sentinelZuulProperties) {
|
|
||||||
return new SentinelErrorFilter(sentinelZuulProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public FallBackProviderHandler fallBackProviderListener(
|
|
||||||
DefaultListableBeanFactory beanFactory) {
|
|
||||||
return new FallBackProviderHandler(beanFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration
|
|
@ -15,11 +15,6 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba.csp</groupId>
|
|
||||||
<artifactId>sentinel-web-servlet</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.csp</groupId>
|
<groupId>com.alibaba.csp</groupId>
|
||||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||||
@ -42,6 +37,28 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-web-servlet</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-spring-webflux-adapter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
@ -88,6 +105,11 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.csp</groupId>
|
||||||
|
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--spring boot-->
|
<!--spring boot-->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -129,12 +151,6 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
@ -18,26 +18,35 @@ package org.springframework.cloud.alibaba.sentinel;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
import javax.servlet.Filter;
|
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.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
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.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
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 com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
|
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
|
||||||
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author xiaojing
|
* @author xiaojing
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnWebApplication
|
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||||
|
@ConditionalOnClass(CommonFilter.class)
|
||||||
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
|
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
|
||||||
@EnableConfigurationProperties(SentinelProperties.class)
|
@EnableConfigurationProperties(SentinelProperties.class)
|
||||||
public class SentinelWebAutoConfiguration {
|
public class SentinelWebAutoConfiguration {
|
||||||
@ -48,6 +57,22 @@ public class SentinelWebAutoConfiguration {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SentinelProperties properties;
|
private SentinelProperties properties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Optional<UrlCleaner> urlCleanerOptional;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Optional<UrlBlockHandler> urlBlockHandlerOptional;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Optional<RequestOriginParser> requestOriginParserOptional;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
|
||||||
|
urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner);
|
||||||
|
requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
|
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
|
||||||
public FilterRegistrationBean sentinelFilter() {
|
public FilterRegistrationBean sentinelFilter() {
|
||||||
@ -66,7 +91,8 @@ public class SentinelWebAutoConfiguration {
|
|||||||
Filter filter = new CommonFilter();
|
Filter filter = new CommonFilter();
|
||||||
registration.setFilter(filter);
|
registration.setFilter(filter);
|
||||||
registration.setOrder(filterConfig.getOrder());
|
registration.setOrder(filterConfig.getOrder());
|
||||||
log.info("[Sentinel Starter] register Sentinel with urlPatterns: {}.",
|
log.info(
|
||||||
|
"[Sentinel Starter] register Sentinel CommonFilter with urlPatterns: {}.",
|
||||||
filterConfig.getUrlPatterns());
|
filterConfig.getUrlPatterns());
|
||||||
return registration;
|
return registration;
|
||||||
|
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||||
|
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.spring.webflux.SentinelWebFluxFilter;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.WebFluxCallbackManager;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.spring.webflux.exception.SentinelBlockExceptionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||||
|
@ConditionalOnClass(SentinelReactorTransformer.class)
|
||||||
|
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
|
||||||
|
@EnableConfigurationProperties(SentinelProperties.class)
|
||||||
|
public class SentinelWebFluxAutoConfiguration {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory
|
||||||
|
.getLogger(SentinelWebFluxAutoConfiguration.class);
|
||||||
|
|
||||||
|
private final List<ViewResolver> viewResolvers;
|
||||||
|
private final ServerCodecConfigurer serverCodecConfigurer;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Optional<BlockRequestHandler> blockRequestHandler;
|
||||||
|
|
||||||
|
public SentinelWebFluxAutoConfiguration(
|
||||||
|
ObjectProvider<List<ViewResolver>> viewResolvers,
|
||||||
|
ServerCodecConfigurer serverCodecConfigurer) {
|
||||||
|
this.viewResolvers = viewResolvers.getIfAvailable(Collections::emptyList);
|
||||||
|
this.serverCodecConfigurer = serverCodecConfigurer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
blockRequestHandler.ifPresent(WebFluxCallbackManager::setBlockHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(-2)
|
||||||
|
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
|
||||||
|
public SentinelBlockExceptionHandler sentinelBlockExceptionHandler() {
|
||||||
|
return new SentinelBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(-1)
|
||||||
|
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
|
||||||
|
public SentinelWebFluxFilter sentinelWebFluxFilter() {
|
||||||
|
log.info("[Sentinel Starter] register Sentinel SentinelWebFluxFilter");
|
||||||
|
return new SentinelWebFluxFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.alibaba.sentinel.custom;
|
package org.springframework.cloud.alibaba.sentinel.custom;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
@ -33,12 +37,14 @@ import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConver
|
|||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
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.core.env.Environment;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateGroupItem;
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
|
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
|
||||||
|
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||||
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
|
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
|
||||||
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
||||||
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
import com.alibaba.csp.sentinel.config.SentinelConfig;
|
||||||
@ -52,7 +58,15 @@ import com.alibaba.csp.sentinel.slots.system.SystemRule;
|
|||||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
||||||
import com.alibaba.csp.sentinel.util.AppNameUtil;
|
import com.alibaba.csp.sentinel.util.AppNameUtil;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.Version;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,15 +85,6 @@ public class SentinelAutoConfiguration {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SentinelProperties properties;
|
private SentinelProperties properties;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Optional<UrlCleaner> urlCleanerOptional;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Optional<UrlBlockHandler> urlBlockHandlerOptional;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private Optional<RequestOriginParser> requestOriginParserOptional;
|
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
private void init() {
|
private void init() {
|
||||||
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
|
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
|
||||||
@ -142,10 +147,6 @@ public class SentinelAutoConfiguration {
|
|||||||
WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
|
WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
|
|
||||||
urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner);
|
|
||||||
requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser);
|
|
||||||
|
|
||||||
// earlier initialize
|
// earlier initialize
|
||||||
if (properties.isEager()) {
|
if (properties.isEager()) {
|
||||||
InitExecutor.doInit();
|
InitExecutor.doInit();
|
||||||
@ -170,15 +171,71 @@ public class SentinelAutoConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SentinelDataSourceHandler sentinelDataSourceHandler(
|
public SentinelDataSourceHandler sentinelDataSourceHandler(
|
||||||
DefaultListableBeanFactory beanFactory) {
|
DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties,
|
||||||
return new SentinelDataSourceHandler(beanFactory);
|
Environment env) {
|
||||||
|
return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnClass(ObjectMapper.class)
|
@ConditionalOnClass(ObjectMapper.class)
|
||||||
|
@Configuration
|
||||||
protected static class SentinelConverterConfiguration {
|
protected static class SentinelConverterConfiguration {
|
||||||
|
|
||||||
|
static class ApiPredicateItemDeserializer
|
||||||
|
extends StdDeserializer<ApiPredicateItem> {
|
||||||
|
private Map<String, Class<? extends ApiPredicateItem>> registry = new HashMap<String, Class<? extends ApiPredicateItem>>();
|
||||||
|
|
||||||
|
ApiPredicateItemDeserializer() {
|
||||||
|
super(ApiPredicateItem.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerApiPredicateItem(String uniqueAttribute,
|
||||||
|
Class<? extends ApiPredicateItem> apiPredicateItemClass) {
|
||||||
|
registry.put(uniqueAttribute, apiPredicateItemClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiPredicateItem deserialize(JsonParser jp,
|
||||||
|
DeserializationContext ctxt) throws IOException {
|
||||||
|
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
|
||||||
|
ObjectNode root = mapper.readTree(jp);
|
||||||
|
Class<? extends ApiPredicateItem> apiPredicateItemClass = null;
|
||||||
|
Iterator<Entry<String, JsonNode>> elementsIterator = root.fields();
|
||||||
|
while (elementsIterator.hasNext()) {
|
||||||
|
Entry<String, JsonNode> element = elementsIterator.next();
|
||||||
|
String name = element.getKey();
|
||||||
|
if (registry.containsKey(name)) {
|
||||||
|
apiPredicateItemClass = registry.get(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (apiPredicateItemClass == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return mapper.readValue(root.toString(), apiPredicateItemClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
protected static class SentinelJsonConfiguration {
|
||||||
|
|
||||||
private ObjectMapper objectMapper = new ObjectMapper();
|
private ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
public SentinelJsonConfiguration() {
|
||||||
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
|
||||||
|
false);
|
||||||
|
|
||||||
|
ApiPredicateItemDeserializer deserializer = new ApiPredicateItemDeserializer();
|
||||||
|
deserializer.registerApiPredicateItem("pattern",
|
||||||
|
ApiPathPredicateItem.class);
|
||||||
|
deserializer.registerApiPredicateItem("items",
|
||||||
|
ApiPredicateGroupItem.class);
|
||||||
|
SimpleModule module = new SimpleModule(
|
||||||
|
"PolymorphicApiPredicateItemDeserializerModule",
|
||||||
|
new Version(1, 0, 0, null));
|
||||||
|
module.addDeserializer(ApiPredicateItem.class, deserializer);
|
||||||
|
objectMapper.registerModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean("sentinel-json-flow-converter")
|
@Bean("sentinel-json-flow-converter")
|
||||||
public JsonConverter jsonFlowConverter() {
|
public JsonConverter jsonFlowConverter() {
|
||||||
return new JsonConverter(objectMapper, FlowRule.class);
|
return new JsonConverter(objectMapper, FlowRule.class);
|
||||||
@ -204,13 +261,38 @@ public class SentinelAutoConfiguration {
|
|||||||
return new JsonConverter(objectMapper, ParamFlowRule.class);
|
return new JsonConverter(objectMapper, ParamFlowRule.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean("sentinel-json-gw-flow-converter")
|
||||||
|
public JsonConverter jsonGatewayFlowConverter() {
|
||||||
|
return new JsonConverter(objectMapper, GatewayFlowRule.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("sentinel-json-gw-api-group-converter")
|
||||||
|
public JsonConverter jsonApiConverter() {
|
||||||
|
return new JsonConverter(objectMapper, ApiDefinition.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConditionalOnClass(XmlMapper.class)
|
@ConditionalOnClass(XmlMapper.class)
|
||||||
|
@Configuration
|
||||||
protected static class SentinelXmlConfiguration {
|
protected static class SentinelXmlConfiguration {
|
||||||
|
|
||||||
private XmlMapper xmlMapper = new XmlMapper();
|
private XmlMapper xmlMapper = new XmlMapper();
|
||||||
|
|
||||||
|
public SentinelXmlConfiguration() {
|
||||||
|
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
|
||||||
|
false);
|
||||||
|
ApiPredicateItemDeserializer deserializer = new ApiPredicateItemDeserializer();
|
||||||
|
deserializer.registerApiPredicateItem("pattern",
|
||||||
|
ApiPathPredicateItem.class);
|
||||||
|
deserializer.registerApiPredicateItem("items",
|
||||||
|
ApiPredicateGroupItem.class);
|
||||||
|
SimpleModule module = new SimpleModule(
|
||||||
|
"PolymorphicGatewayDeserializerModule",
|
||||||
|
new Version(1, 0, 0, null));
|
||||||
|
module.addDeserializer(ApiPredicateItem.class, deserializer);
|
||||||
|
xmlMapper.registerModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean("sentinel-xml-flow-converter")
|
@Bean("sentinel-xml-flow-converter")
|
||||||
public XmlConverter xmlFlowConverter() {
|
public XmlConverter xmlFlowConverter() {
|
||||||
return new XmlConverter(xmlMapper, FlowRule.class);
|
return new XmlConverter(xmlMapper, FlowRule.class);
|
||||||
@ -236,6 +318,17 @@ public class SentinelAutoConfiguration {
|
|||||||
return new XmlConverter(xmlMapper, ParamFlowRule.class);
|
return new XmlConverter(xmlMapper, ParamFlowRule.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean("sentinel-xml-gw-flow-converter")
|
||||||
|
public XmlConverter xmlGatewayFlowConverter() {
|
||||||
|
return new XmlConverter(xmlMapper, GatewayFlowRule.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("sentinel-xml-gw-api-group-converter")
|
||||||
|
public XmlConverter xmlApiConverter() {
|
||||||
|
return new XmlConverter(xmlMapper, ApiDefinition.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,5 @@
|
|||||||
package org.springframework.cloud.alibaba.sentinel.custom;
|
package org.springframework.cloud.alibaba.sentinel.custom;
|
||||||
|
|
||||||
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
|
||||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
|
||||||
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
|
|
||||||
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -25,6 +7,22 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
||||||
|
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sentinel {@link ReadableDataSource} Handler Handle the configurations of
|
* Sentinel {@link ReadableDataSource} Handler Handle the configurations of
|
||||||
* 'spring.cloud.sentinel.datasource'
|
* 'spring.cloud.sentinel.datasource'
|
||||||
@ -47,12 +45,16 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
|
|||||||
|
|
||||||
private final DefaultListableBeanFactory beanFactory;
|
private final DefaultListableBeanFactory beanFactory;
|
||||||
|
|
||||||
public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory) {
|
private final SentinelProperties sentinelProperties;
|
||||||
this.beanFactory = beanFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
private final Environment env;
|
||||||
private SentinelProperties sentinelProperties;
|
|
||||||
|
public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory,
|
||||||
|
SentinelProperties sentinelProperties, Environment env) {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
this.sentinelProperties = sentinelProperties;
|
||||||
|
this.env = env;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSingletonsInstantiated() {
|
public void afterSingletonsInstantiated() {
|
||||||
@ -68,6 +70,7 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
|
|||||||
}
|
}
|
||||||
AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
|
AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
|
||||||
.getValidDataSourceProperties();
|
.getValidDataSourceProperties();
|
||||||
|
abstractDataSourceProperties.setEnv(env);
|
||||||
abstractDataSourceProperties.preCheck(dataSourceName);
|
abstractDataSourceProperties.preCheck(dataSourceName);
|
||||||
registerBean(abstractDataSourceProperties, dataSourceName
|
registerBean(abstractDataSourceProperties, dataSourceName
|
||||||
+ "-sentinel-" + validFields.get(0) + "-datasource");
|
+ "-sentinel-" + validFields.get(0) + "-datasource");
|
||||||
@ -181,56 +184,8 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
|
|||||||
AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory
|
AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory
|
||||||
.getBean(dataSourceName);
|
.getBean(dataSourceName);
|
||||||
|
|
||||||
logAndCheckRuleType(newDataSource, dataSourceName,
|
|
||||||
dataSourceProperties.getRuleType().getClazz());
|
|
||||||
|
|
||||||
// register property in RuleManager
|
// register property in RuleManager
|
||||||
dataSourceProperties.postRegister(newDataSource);
|
dataSourceProperties.postRegister(newDataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logAndCheckRuleType(AbstractDataSource dataSource, String dataSourceName,
|
|
||||||
Class<? extends AbstractRule> ruleClass) {
|
|
||||||
Object ruleConfig;
|
|
||||||
try {
|
|
||||||
ruleConfig = dataSource.loadConfig();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
log.error("[Sentinel Starter] DataSource " + dataSourceName
|
|
||||||
+ " loadConfig error: " + e.getMessage(), e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ruleConfig instanceof List) {
|
|
||||||
List convertedRuleList = (List) ruleConfig;
|
|
||||||
if (CollectionUtils.isEmpty(convertedRuleList)) {
|
|
||||||
log.warn("[Sentinel Starter] DataSource {} rule list is empty.",
|
|
||||||
dataSourceName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (convertedRuleList.stream()
|
|
||||||
.noneMatch(rule -> rule.getClass() == ruleClass)) {
|
|
||||||
log.error("[Sentinel Starter] DataSource {} none rules are {} type.",
|
|
||||||
dataSourceName, ruleClass.getSimpleName());
|
|
||||||
throw new IllegalArgumentException("[Sentinel Starter] DataSource "
|
|
||||||
+ dataSourceName + " none rules are " + ruleClass.getSimpleName()
|
|
||||||
+ " type.");
|
|
||||||
}
|
|
||||||
else if (!convertedRuleList.stream()
|
|
||||||
.allMatch(rule -> rule.getClass() == ruleClass)) {
|
|
||||||
log.warn("[Sentinel Starter] DataSource {} all rules are not {} type.",
|
|
||||||
dataSourceName, ruleClass.getSimpleName());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.info("[Sentinel Starter] DataSource {} load {} {}", dataSourceName,
|
|
||||||
convertedRuleList.size(), ruleClass.getSimpleName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.error("[Sentinel Starter] DataSource " + dataSourceName
|
|
||||||
+ " rule class is not List<" + ruleClass.getSimpleName()
|
|
||||||
+ ">. Class: " + ruleConfig.getClass());
|
|
||||||
throw new IllegalArgumentException("[Sentinel Starter] DataSource "
|
|
||||||
+ dataSourceName + " rule class is not List<"
|
|
||||||
+ ruleClass.getSimpleName() + ">. Class: " + ruleConfig.getClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.alibaba.sentinel.endpoint;
|
package org.springframework.cloud.alibaba.sentinel.endpoint;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
|
||||||
|
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
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;
|
||||||
@ -38,4 +40,10 @@ public class SentinelEndpointAutoConfiguration {
|
|||||||
return new SentinelEndpoint(sentinelProperties);
|
return new SentinelEndpoint(sentinelProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@ConditionalOnEnabledHealthIndicator("sentinel")
|
||||||
|
public SentinelHealthIndicator sentinelHealthIndicator(DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties) {
|
||||||
|
return new SentinelHealthIndicator(beanFactory, sentinelProperties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 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.endpoint;
|
||||||
|
|
||||||
|
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
||||||
|
import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
|
||||||
|
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
|
||||||
|
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.health.Health;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.boot.actuate.health.Status;
|
||||||
|
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link HealthIndicator} for Sentinel, which checks the status of
|
||||||
|
* Sentinel Dashboard and DataSource.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Check the status of Sentinel Dashboard by sending a heartbeat message to it.
|
||||||
|
* If return true, it's OK.
|
||||||
|
*
|
||||||
|
* Check the status of Sentinel DataSource by calling loadConfig method of {@link AbstractDataSource}.
|
||||||
|
* If no Exception thrown, it's OK.
|
||||||
|
*
|
||||||
|
* If Dashboard and DataSource are both OK, the health status is UP.
|
||||||
|
*</p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note:
|
||||||
|
* If Sentinel isn't enabled, the health status is up.
|
||||||
|
* If Sentinel Dashboard isn't configured, it's OK and mark the status of Dashboard with UNKNOWN.
|
||||||
|
* More informations are provided in details.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author cdfive
|
||||||
|
*/
|
||||||
|
public class SentinelHealthIndicator extends AbstractHealthIndicator {
|
||||||
|
|
||||||
|
private DefaultListableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
private SentinelProperties sentinelProperties;
|
||||||
|
|
||||||
|
public SentinelHealthIndicator(DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties) {
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
this.sentinelProperties = sentinelProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||||
|
Map<String, Object> detailMap = new HashMap<>();
|
||||||
|
|
||||||
|
// If sentinel isn't enabled, set the status up and set the enabled to false in detail
|
||||||
|
if (!sentinelProperties.isEnabled()) {
|
||||||
|
detailMap.put("enabled", false);
|
||||||
|
builder.up().withDetails(detailMap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detailMap.put("enabled", true);
|
||||||
|
|
||||||
|
// Check health of Dashboard
|
||||||
|
boolean dashboardUp = true;
|
||||||
|
String consoleServer = TransportConfig.getConsoleServer();
|
||||||
|
if (StringUtils.isEmpty(consoleServer)) {
|
||||||
|
// If Dashboard isn't configured, it's OK and mark the status of Dashboard with UNKNOWN.
|
||||||
|
detailMap.put("dashboard", new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
|
||||||
|
} else {
|
||||||
|
// If Dashboard is configured, send a heartbeat message to it and check the result
|
||||||
|
HeartbeatSender heartbeatSender = HeartbeatSenderProvider.getHeartbeatSender();
|
||||||
|
boolean result = heartbeatSender.sendHeartbeat();
|
||||||
|
if (result) {
|
||||||
|
detailMap.put("dashboard", Status.UP);
|
||||||
|
} else {
|
||||||
|
// If failed to send heartbeat message, means that the Dashboard is DOWN
|
||||||
|
dashboardUp = false;
|
||||||
|
detailMap.put("dashboard", new Status(Status.DOWN.getCode(), consoleServer + " can't be connected"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check health of DataSource
|
||||||
|
boolean dataSourceUp = true;
|
||||||
|
Map<String, Object> dataSourceDetailMap = new HashMap<>();
|
||||||
|
detailMap.put("dataSource", dataSourceDetailMap);
|
||||||
|
|
||||||
|
// Get all DataSources and each call loadConfig to check if it's OK
|
||||||
|
// If no Exception thrown, it's OK
|
||||||
|
// Note:
|
||||||
|
// Even if the dynamic config center is down, the loadConfig() might return successfully
|
||||||
|
// e.g. for Nacos client, it might retrieve from the local cache)
|
||||||
|
// But in most circumstances it's okay
|
||||||
|
Map<String, AbstractDataSource> dataSourceMap = beanFactory.getBeansOfType(AbstractDataSource.class);
|
||||||
|
for (Map.Entry<String, AbstractDataSource> dataSourceMapEntry : dataSourceMap.entrySet()) {
|
||||||
|
String dataSourceBeanName = dataSourceMapEntry.getKey();
|
||||||
|
AbstractDataSource dataSource = dataSourceMapEntry.getValue();
|
||||||
|
try {
|
||||||
|
dataSource.loadConfig();
|
||||||
|
dataSourceDetailMap.put(dataSourceBeanName, Status.UP);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// If one DataSource failed to loadConfig, means that the DataSource is DOWN
|
||||||
|
dataSourceUp = false;
|
||||||
|
dataSourceDetailMap.put(dataSourceBeanName, new Status(Status.DOWN.getCode(), e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Dashboard and DataSource are both OK, the health status is UP
|
||||||
|
if (dashboardUp && dataSourceUp) {
|
||||||
|
builder.up().withDetails(detailMap);
|
||||||
|
} else {
|
||||||
|
builder.down().withDetails(detailMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user