1
0
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:
Mercy Ma 2019-06-20 22:05:13 +08:00 committed by GitHub
commit e3bd0c8c06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
123 changed files with 3294 additions and 655 deletions

View File

@ -35,7 +35,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
**[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)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
@ -72,7 +72,7 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.1.RELEASE</version>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -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.
**[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.
@ -61,7 +61,7 @@ Spring Cloud uses Maven for most build-related activities, and you should be abl
## How to Use
### Add maven dependency
### Add maven dependency
Version 0.2.1.RELEASE is compatible with the Spring Cloud Finchley. Version 0.1.1.RELEASE is compatible with the Spring Cloud Edgware.
These artifacts are available from Maven Central and Spring Release repository via BOM:
@ -71,7 +71,7 @@ These artifacts are available from Maven Central and Spring Release repository v
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.1.RELEASE</version>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -23,7 +23,7 @@ Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和
**Dubbo**
Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。
Apache Dubbo™ 是一款高性能 Java RPC 框架。
**Fescar**

View File

@ -26,7 +26,7 @@ Apache RocketMQ™ is an open source distributed messaging and streaming data pl
**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**

View File

@ -93,7 +93,7 @@
<module>spring-cloud-alibaba-dependencies</module>
<module>spring-cloud-alibaba-sentinel</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-discovery</module>
<module>spring-cloud-alibaba-seata</module>

View File

@ -13,7 +13,7 @@
<name>Spring Cloud Alibaba Coverage</name>
<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>
<dependencies>
<dependency>
@ -98,4 +98,4 @@
</plugins>
</build>
</project>
</project>

View File

@ -17,23 +17,23 @@
<description>Spring Cloud Alibaba Dependencies</description>
<properties>
<sentinel.version>1.5.2</sentinel.version>
<sentinel.version>1.6.1</sentinel.version>
<oss.version>3.1.0</oss.version>
<seata.version>0.5.0</seata.version>
<nacos.client.version>1.0.0</nacos.client.version>
<seata.version>0.5.2</seata.version>
<nacos.client.version>1.0.1</nacos.client.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>
<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>
<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>
<schedulerX.client.version>2.1.6</schedulerX.client.version>
<dubbo.version>2.7.1</dubbo.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.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>
</properties>
@ -152,6 +152,11 @@
<artifactId>sentinel-zuul-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
@ -187,6 +192,17 @@
<artifactId>sentinel-cluster-client-default</artifactId>
<version>${sentinel.version}</version>
</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-->
@ -227,7 +243,7 @@
<!-- Dubbo Nacos registry dependency -->
<dependency>
<groupId>com.alibaba</groupId>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo-registry-nacos.version}</version>
</dependency>
@ -252,7 +268,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View File

@ -60,6 +60,7 @@ public class DefaultHttpRequest implements HttpRequest {
return HttpMethod.resolve(getMethodValue());
}
@Override
public String getMethodValue() {
return method;
}

View File

@ -73,6 +73,7 @@ public class MutableHttpServerRequest implements HttpServerRequest {
}
// Override method since Spring Framework 5.0
@Override
public String getMethodValue() {
return httpMethod.name();
}

View File

@ -44,8 +44,12 @@ public class DubboRestServiceMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DubboRestServiceMetadata)) return false;
if (this == o) {
return true;
}
if (!(o instanceof DubboRestServiceMetadata)) {
return false;
}
DubboRestServiceMetadata that = (DubboRestServiceMetadata) o;
return Objects.equals(serviceRestMetadata, that.serviceRestMetadata) &&
Objects.equals(restMethodMetadata, that.restMethodMetadata);

View File

@ -77,8 +77,12 @@ public class DubboTransportedMethodMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DubboTransportedMethodMetadata)) return false;
if (this == o) {
return true;
}
if (!(o instanceof DubboTransportedMethodMetadata)) {
return false;
}
DubboTransportedMethodMetadata that = (DubboTransportedMethodMetadata) o;
return Objects.equals(methodMetadata, that.methodMetadata) &&
Objects.equals(attributes, that.attributes);

View File

@ -110,8 +110,12 @@ public class MethodMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MethodMetadata that = (MethodMetadata) o;
return Objects.equals(name, that.name) &&
Objects.equals(returnType, that.returnType) &&

View File

@ -61,8 +61,12 @@ public class MethodParameterMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MethodParameterMetadata that = (MethodParameterMetadata) o;
return index == that.index &&
Objects.equals(name, that.name) &&

View File

@ -235,8 +235,12 @@ public class RequestMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RequestMetadata)) return false;
if (this == o) {
return true;
}
if (!(o instanceof RequestMetadata)) {
return false;
}
RequestMetadata that = (RequestMetadata) o;
return Objects.equals(method, that.method) &&
Objects.equals(path, that.path) &&

View File

@ -183,8 +183,12 @@ public class RestMethodMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RestMethodMetadata)) return false;
if (this == o) {
return true;
}
if (!(o instanceof RestMethodMetadata)) {
return false;
}
RestMethodMetadata that = (RestMethodMetadata) o;
return queryMapEncoded == that.queryMapEncoded &&
Objects.equals(method, that.method) &&

View File

@ -52,8 +52,12 @@ public class ServiceRestMetadata {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ServiceRestMetadata)) return false;
if (this == o) {
return true;
}
if (!(o instanceof ServiceRestMetadata)) {
return false;
}
ServiceRestMetadata that = (ServiceRestMetadata) o;
return Objects.equals(url, that.url) &&
Objects.equals(meta, that.meta);

View File

@ -64,7 +64,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
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());
@ -164,7 +164,7 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) {
String taskId = url.toIdentityString();
if (schedulerTasks.add(taskId)) {
if (SCHEDULER_TASKS.add(taskId)) {
schedule(() -> doSubscribeDubboServiceURLs(url, listener));
}
}

View File

@ -110,6 +110,7 @@ public class DubboGenericServiceFactory {
dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws java.lang.IllegalArgumentException {
// Trim all whitespace
String content = StringUtils.trimAllWhitespace(text);

View File

@ -128,7 +128,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息OSS Starter 也
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 列表。

View File

@ -114,7 +114,7 @@ You can verify results on the OSS console when you finish uploading or downloadi
## Endpoint
OSS starter also supports the implmentation of Spring Boot acutator endpoints.
OSS starter also supports the implementation of Spring Boot actuator endpoints.
**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 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.

View File

@ -21,6 +21,9 @@
<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-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-config-example</module>
<module>nacos-example/nacos-gateway-example</module>

View File

@ -60,7 +60,7 @@ public class RocketMQApplication {
配置 Binding 信息:
```properties
# 配置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
spring.cloud.stream.bindings.output.destination=test-topic
spring.cloud.stream.bindings.output.content-type=application/json
@ -125,7 +125,7 @@ server.port=28081
配置信息如下:
```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.content-type=application/json

View File

@ -56,7 +56,7 @@ public class RocketMQApplication {
Configure Binding:
```properties
# 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
spring.cloud.stream.bindings.output.destination=test-topic
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:
```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.content-type=application/json

View File

@ -1,10 +1,15 @@
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.autoconfigure.SpringBootApplication;
import org.springframework.cloud.alibaba.cloud.examples.RocketMQConsumerApplication.MySink;
import org.springframework.cloud.stream.annotation.EnableBinding;
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;
/**
@ -27,10 +32,36 @@ public class RocketMQConsumerApplication {
@Input("input4")
SubscribableChannel input4();
@Input("input5")
PollableMessageSource input5();
}
public static void main(String[] 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);
}
}
}
}

View File

@ -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.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
server.port=28082

View File

@ -9,6 +9,7 @@ import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
@ -23,6 +24,9 @@ public class RocketMQProduceApplication {
@Output("output2")
MessageChannel output2();
@Output("output3")
MessageChannel output3();
}
public static void main(String[] args) {
@ -31,7 +35,12 @@ public class RocketMQProduceApplication {
@Bean
public CustomRunner customRunner() {
return new CustomRunner();
return new CustomRunner("output1");
}
@Bean
public CustomRunner customRunner2() {
return new CustomRunner("output3");
}
@Bean
@ -40,24 +49,45 @@ public class RocketMQProduceApplication {
}
public static class CustomRunner implements CommandLineRunner {
private final String bindingName;
public CustomRunner(String bindingName) {
this.bindingName = bindingName;
}
@Autowired
private SenderService senderService;
@Autowired
private MySource mySource;
@Override
public void run(String... args) throws Exception {
int count = 5;
for (int index = 1; index <= count; index++) {
String msgContent = "msg-" + index;
if (index % 3 == 0) {
senderService.send(msgContent);
}
else if (index % 3 == 1) {
senderService.sendWithTags(msgContent, "tagStr");
}
else {
senderService.sendObject(new Foo(index, "foo"), "tagObj");
if (this.bindingName.equals("output1")) {
int count = 5;
for (int index = 1; index <= count; index++) {
String msgContent = "msg-" + index;
if (index % 3 == 0) {
senderService.send(msgContent);
}
else if (index % 3 == 1) {
senderService.sendWithTags(msgContent, "tagStr");
}
else {
senderService.sendObject(new Foo(index, "foo"), "tagObj");
}
}
}
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());
}
}
}
}

View File

@ -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.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
server.port=28081

View File

@ -20,15 +20,35 @@ transport {
worker-thread-size = 8
}
}
## transaction log store
store {
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
max-branch-session-size = 16384
# globe session size , if exceeded throws exceptions
max-global-session-size = 512
# file buffer size , if exceeded allocate new buffer
file-write-buffer-cache-size = 16384
# when recover batch read size
session.reload.read_size = 100
## store mode: file、db
mode = "file"
## file store
file {
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
max-branch-session-size = 16384
# globe session size , if exceeded throws exceptions
max-global-session-size = 512
# file buffer size , if exceeded allocate new buffer
file-write-buffer-cache-size = 16384
# when recover batch read size
session.reload.read_size = 100
# async, sync
flush-disk-mode = async
}
## database store
db {
driver_class = ""
url = ""
user = ""
password = ""
}
}
service {
#vgroup->rgroup

View File

@ -1,5 +1,5 @@
registry {
# file 、nacos 、eureka、redis、zk、consul
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "file"
nacos {
@ -26,6 +26,19 @@ registry {
cluster = "default"
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 {
name = "file.conf"
}
@ -41,7 +54,7 @@ config {
cluster = "default"
}
apollo {
app.id = "fescar-server"
app.id = "seata-server"
apollo.meta = "http://192.168.1.204:8801"
}
zk {
@ -52,4 +65,4 @@ config {
file {
name = "file.conf"
}
}
}

View File

@ -20,15 +20,35 @@ transport {
worker-thread-size = 8
}
}
## transaction log store
store {
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
max-branch-session-size = 16384
# globe session size , if exceeded throws exceptions
max-global-session-size = 512
# file buffer size , if exceeded allocate new buffer
file-write-buffer-cache-size = 16384
# when recover batch read size
session.reload.read_size = 100
## store mode: file、db
mode = "file"
## file store
file {
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
max-branch-session-size = 16384
# globe session size , if exceeded throws exceptions
max-global-session-size = 512
# file buffer size , if exceeded allocate new buffer
file-write-buffer-cache-size = 16384
# when recover batch read size
session.reload.read_size = 100
# async, sync
flush-disk-mode = async
}
## database store
db {
driver_class = ""
url = ""
user = ""
password = ""
}
}
service {
#vgroup->rgroup

View File

@ -1,5 +1,5 @@
registry {
# file 、nacos 、eureka、redis、zk、consul
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "file"
nacos {
@ -26,6 +26,19 @@ registry {
cluster = "default"
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 {
name = "file.conf"
}
@ -41,7 +54,7 @@ config {
cluster = "default"
}
apollo {
app.id = "fescar-server"
app.id = "seata-server"
apollo.meta = "http://192.168.1.204:8801"
}
zk {
@ -52,4 +65,4 @@ config {
file {
name = "file.conf"
}
}
}

View File

@ -101,7 +101,7 @@ CREATE TABLE `account_tbl` (
进入解压之后的 bin 目录,执行如下命令来启动
```$shell
sh seata-server.sh $LISTEN_PORT $MODE
sh seata-server.sh $LISTEN_PORT $MODE(file or db)
```
在这个示例中,采用如下命令来启动 Seata Server
@ -110,7 +110,7 @@ sh seata-server.sh $LISTEN_PORT $MODE
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 作为配置注册中心
## 运行示例

View File

@ -20,15 +20,35 @@ transport {
worker-thread-size = 8
}
}
## transaction log store
store {
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
max-branch-session-size = 16384
# globe session size , if exceeded throws exceptions
max-global-session-size = 512
# file buffer size , if exceeded allocate new buffer
file-write-buffer-cache-size = 16384
# when recover batch read size
session.reload.read_size = 100
## store mode: file、db
mode = "file"
## file store
file {
dir = "sessionStore"
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
max-branch-session-size = 16384
# globe session size , if exceeded throws exceptions
max-global-session-size = 512
# file buffer size , if exceeded allocate new buffer
file-write-buffer-cache-size = 16384
# when recover batch read size
session.reload.read_size = 100
# async, sync
flush-disk-mode = async
}
## database store
db {
driver_class = ""
url = ""
user = ""
password = ""
}
}
service {
#vgroup->rgroup

View File

@ -1,5 +1,5 @@
registry {
# file 、nacos 、eureka、redis、zk、consul
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "file"
nacos {
@ -26,6 +26,19 @@ registry {
cluster = "default"
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 {
name = "file.conf"
}
@ -41,7 +54,7 @@ config {
cluster = "default"
}
apollo {
app.id = "fescar-server"
app.id = "seata-server"
apollo.meta = "http://192.168.1.204:8801"
}
zk {
@ -52,4 +65,4 @@ config {
file {
name = "file.conf"
}
}
}

View File

@ -184,7 +184,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息Sentinel Starter
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
* 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>

View File

@ -1,6 +1,12 @@
spring.application.name=sentinel-example
server.port=18083
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.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.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

View File

@ -1,6 +1,6 @@
[
{
"resource": "resource",
"resource": "/hello",
"controlBehavior": 0,
"count": 1,
"grade": 1,

View File

@ -6,7 +6,7 @@
[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)。

View File

@ -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>

View File

@ -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"));
}
};
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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"
}
]
}
]

View File

@ -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: "*"

View File

@ -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"
}
}
]

View File

@ -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>

View File

@ -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"));
}
};
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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

View File

@ -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
}
]

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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";
}
};
}
}

View File

@ -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"
}
]
}
]

View File

@ -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

View File

@ -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"
}
}
]

View File

@ -306,7 +306,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息SMS Starter 也
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** )。

View File

@ -157,7 +157,7 @@ spring:
- `spring.application.name` : Spring 应用名称,用于 Spring Cloud 服务注册和发现。
> 该值在 Dubbo Spring Cloud 加持下被视作 `dubbo.application.name`,因此,无需再显示地配置 `dubbo.application.name`
- `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 服务器主机和端口
> 以上完整的 YAML 配置文件,请参考 `spring-cloud-dubbo-server-sample` [`bootstrap.yaml`](spring-cloud-dubbo-server-sample/src/main/resources/bootstrap.yaml) 文件
@ -345,4 +345,4 @@ HTTP 响应为:
- [spring-cloud-dubbo-provider-web-sample](spring-cloud-dubbo-provider-web-sample)Dubbo Spring Cloud 服务提供方示例Web 应用)
- [spring-cloud-dubbo-provider-sample](spring-cloud-dubbo-provider-sample)Dubbo Spring Cloud 服务提供方示例(非 Web 应用)
- [spring-cloud-dubbo-consumer-sample](spring-cloud-dubbo-consumer-sample)Dubbo Spring Cloud 服务消费方示例
- [spring-cloud-dubbo-servlet-gateway](spring-cloud-dubbo-servlet-gateway)-sampleDubbo Spring Cloud Servlet 网关简易实现示例
- [spring-cloud-dubbo-servlet-gateway](spring-cloud-dubbo-servlet-gateway)-sampleDubbo Spring Cloud Servlet 网关简易实现示例

View File

@ -76,6 +76,7 @@ public class DubboGatewayServlet extends HttpServletBean {
return serviceName;
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String serviceName = resolveServiceName(request);

View File

@ -28,25 +28,25 @@ import java.util.concurrent.ConcurrentHashMap;
*/
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
*/
public static List<NacosPropertySource> getAll() {
List<NacosPropertySource> result = new ArrayList<>();
result.addAll(nacosPropertySourceRepository.values());
result.addAll(NACOS_PROPERTY_SOURCE_REPOSITORY.values());
return result;
}
public static void collectNacosPropertySources(
NacosPropertySource nacosPropertySource) {
nacosPropertySourceRepository.putIfAbsent(nacosPropertySource.getDataId(),
NACOS_PROPERTY_SOURCE_REPOSITORY.putIfAbsent(nacosPropertySource.getDataId(),
nacosPropertySource);
}
public static NacosPropertySource getNacosPropertySource(String dataId) {
return nacosPropertySourceRepository.get(dataId);
return NACOS_PROPERTY_SOURCE_REPOSITORY.get(dataId);
}
}

View File

@ -41,7 +41,12 @@ public class NacosConfigEndpoint {
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,
NacosRefreshHistory refreshHistory) {
@ -60,7 +65,7 @@ public class NacosConfigEndpoint {
for (NacosPropertySource ps : all) {
Map<String, Object> source = new HashMap<>(16);
source.put("dataId", ps.getDataId());
source.put("lastSynced", dateFormat.format(ps.getTimestamp()));
source.put("lastSynced", dateFormat.get().format(ps.getTimestamp()));
sources.add(source);
}
result.put("Sources", sources);

View File

@ -27,10 +27,15 @@ public class NacosRefreshHistory {
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) {
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) {
records.removeLast();
}

View File

@ -17,12 +17,9 @@
package org.springframework.cloud.alibaba.nacos;
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.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
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.NacosRegistration;
import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry;

View File

@ -118,57 +118,10 @@ public class NacosWatch implements ApplicationEventPublisherAware, SmartLifecycl
}
public void nacosServicesWatch() {
try {
boolean changed = false;
NamingService namingService = properties.namingServiceInstance();
// nacos doesn't support watch now , publish an event every 30 seconds.
this.publisher.publishEvent(
new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement()));
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(
new HeartbeatEvent(this, nacosWatchIndex.getAndIncrement()));
}
}
catch (Exception e) {
log.error("Error watching Nacos Service change", e);
}
}
}

View File

@ -33,9 +33,16 @@ public class NacosRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config, NacosDiscoveryProperties nacosDiscoveryProperties) {
public ServerList<?> ribbonServerList(IClientConfig config,
NacosDiscoveryProperties nacosDiscoveryProperties) {
NacosServerList serverList = new NacosServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(config);
return serverList;
}
@Bean
@ConditionalOnMissingBean
public NacosServerIntrospector nacosServerIntrospector() {
return new NacosServerIntrospector();
}
}

View File

@ -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);
}
}

View File

@ -35,49 +35,44 @@ import org.springframework.util.StringUtils;
*/
public class SeataFeignClient implements Client {
private final Client delegate;
private final BeanFactory beanFactory;
private static final int MAP_SIZE = 16;
private final Client delegate;
private final BeanFactory beanFactory;
private static final int MAP_SIZE = 16;
SeataFeignClient(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.delegate = new Client.Default(null, null);
}
SeataFeignClient(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.delegate = new Client.Default(null, null);
}
SeataFeignClient(BeanFactory beanFactory, Client delegate) {
this.delegate = delegate;
this.beanFactory = beanFactory;
}
SeataFeignClient(BeanFactory beanFactory, Client delegate) {
this.delegate = delegate;
this.beanFactory = beanFactory;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
@Override
public Response execute(Request request, Request.Options options) throws IOException {
Request modifiedRequest = getModifyRequest(request);
Request modifiedRequest = getModifyRequest(request);
return this.delegate.execute(modifiedRequest, options);
}
try {
return this.delegate.execute(modifiedRequest, options);
} finally {
private Request getModifyRequest(Request request) {
}
}
String xid = RootContext.getXID();
private Request getModifyRequest(Request request) {
if (StringUtils.isEmpty(xid)) {
return request;
}
String xid = RootContext.getXID();
Map<String, Collection<String>> headers = new HashMap<>(MAP_SIZE);
headers.putAll(request.headers());
if (StringUtils.isEmpty(xid)) {
return request;
}
List<String> fescarXid = new ArrayList<>();
fescarXid.add(xid);
headers.put(RootContext.KEY_XID, fescarXid);
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());
}
return Request.create(request.method(), request.url(), headers, request.body(),
request.charset());
}
}

View File

@ -65,7 +65,7 @@ public class SeataFeignClientAutoConfiguration {
protected static class FeignBeanPostProcessorConfiguration {
@Bean
SeataBeanPostProcessor seataBeanPostProcessor(
SeataBeanPostProcessor seataBeanPostProcessor(
SeataFeignObjectWrapper seataFeignObjectWrapper) {
return new SeataBeanPostProcessor(seataFeignObjectWrapper);
}

View File

@ -32,7 +32,7 @@ public class SeataFeignContext extends FeignContext {
private final FeignContext delegate;
SeataFeignContext(SeataFeignObjectWrapper seataFeignObjectWrapper,
FeignContext delegate) {
FeignContext delegate) {
this.seataFeignObjectWrapper = seataFeignObjectWrapper;
this.delegate = delegate;
}

View File

@ -17,7 +17,13 @@
package org.springframework.cloud.alibaba.seata.feign;
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.cloud.netflix.ribbon.SpringClientFactory;
@ -26,23 +32,27 @@ import feign.Request;
import feign.Response;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
import org.springframework.util.StringUtils;
/**
* @author xiaojing
*/
public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
private static final int MAP_SIZE = 16;
private final BeanFactory beanFactory;
SeataLoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory, BeanFactory beanFactory) {
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory, BeanFactory beanFactory) {
super(wrap(delegate, beanFactory), lbClientFactory, clientFactory);
this.beanFactory = beanFactory;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
Request modifiedRequest = getModifyRequest(request);
return super.execute(request, options);
}
@ -50,4 +60,22 @@ public class SeataLoadBalancerFeignClient extends LoadBalancerFeignClient {
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());
}
}

View File

@ -27,6 +27,12 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>

View File

@ -6,6 +6,8 @@ import java.util.Optional;
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
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.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
@ -40,7 +42,15 @@ public enum RuleType {
/**
* 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}

View File

@ -4,7 +4,10 @@ import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
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.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
@ -28,6 +31,8 @@ public class AbstractDataSourceProperties {
private String converterClass;
@JsonIgnore
private final String factoryBeanName;
@JsonIgnore
private Environment env;
public AbstractDataSourceProperties(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
@ -61,6 +66,14 @@ public class AbstractDataSourceProperties {
return factoryBeanName;
}
protected Environment getEnv() {
return env;
}
public void setEnv(Environment env) {
this.env = env;
}
public void preCheck(String dataSourceName) {
}
@ -82,6 +95,12 @@ public class AbstractDataSourceProperties {
case AUTHORITY:
AuthorityRuleManager.register2Property(dataSource.getProperty());
break;
case GW_FLOW:
GatewayRuleManager.register2Property(dataSource.getProperty());
break;
case GW_API_GROUP:
GatewayApiDefinitionManager.register2Property(dataSource.getProperty());
break;
default:
break;
}

View File

@ -2,8 +2,6 @@ package org.springframework.cloud.alibaba.sentinel.datasource.config;
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.util.StringUtils;
@ -34,9 +32,13 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
@Override
public void preCheck(String dataSourceName) {
if (StringUtils.isEmpty(serverAddr) && acmPropertiesInvalid()) {
throw new IllegalArgumentException(
"NacosDataSource properties value not correct. serverAddr is empty but there is empty value in accessKey, secretKey, endpoint, namespace property");
if (StringUtils.isEmpty(serverAddr)) {
serverAddr = this.getEnv().getProperty(
"spring.cloud.sentinel.datasource.nacos.server-addr", "");
if (StringUtils.isEmpty(serverAddr)) {
throw new IllegalArgumentException(
"NacosDataSource server-addr is empty");
}
}
}
@ -96,9 +98,4 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
this.secretKey = secretKey;
}
public boolean acmPropertiesInvalid() {
return StringUtils.isEmpty(endpoint) || StringUtils.isEmpty(accessKey)
|| StringUtils.isEmpty(secretKey) || StringUtils.isEmpty(namespace);
}
}

View File

@ -1,8 +1,7 @@
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.util.StringUtils;
/**
* Zookeeper Properties class Using by {@link DataSourcePropertiesConfiguration} and
@ -16,7 +15,6 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties
super(ZookeeperDataSourceFactoryBean.class.getName());
}
@NotEmpty
private String serverAddr;
private String path;
@ -25,6 +23,18 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties
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() {
return serverAddr;
}

View File

@ -1,7 +1,20 @@
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.slots.block.AbstractRule;
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.DegradeRuleManager;
@ -13,15 +26,6 @@ import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
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
@ -34,8 +38,8 @@ import java.util.Optional;
* @see ParamFlowRule
* @see ObjectMapper
*/
public abstract class SentinelConverter<T extends AbstractRule>
implements Converter<String, List<AbstractRule>> {
public abstract class SentinelConverter<T extends Object>
implements Converter<String, Collection<Object>> {
private static final Logger log = LoggerFactory.getLogger(SentinelConverter.class);
@ -49,11 +53,20 @@ public abstract class SentinelConverter<T extends AbstractRule>
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
public Collection<Object> convert(String source) {
Collection<Object> ruleCollection;
// hard code
if (ruleClass == GatewayFlowRule.class || ruleClass == ApiDefinition.class) {
ruleCollection = new HashSet<>();
}
else {
ruleCollection = new ArrayList<>();
}
if (StringUtils.isEmpty(source)) {
log.warn("converter can not convert rules because source is empty");
return ruleList;
return ruleCollection;
}
try {
List sourceArray = objectMapper.readValue(source,
@ -70,11 +83,11 @@ public abstract class SentinelConverter<T extends AbstractRule>
}
Optional.ofNullable(convertRule(item))
.ifPresent(convertRule -> ruleList.add(convertRule));
.ifPresent(convertRule -> ruleCollection.add(convertRule));
});
if (ruleList.size() != sourceArray.size()) {
throw new IllegalArgumentException("convert " + ruleList.size()
if (ruleCollection.size() != sourceArray.size()) {
throw new IllegalArgumentException("convert " + ruleCollection.size()
+ " rules but there are " + sourceArray.size()
+ " rules from datasource. RuleClass: "
+ ruleClass.getSimpleName());
@ -83,12 +96,12 @@ public abstract class SentinelConverter<T extends AbstractRule>
catch (Exception e) {
throw new RuntimeException("convert error: " + e.getMessage(), e);
}
return ruleList;
return ruleCollection;
}
private AbstractRule convertRule(String ruleStr) {
private Object convertRule(String ruleStr) {
try {
final AbstractRule rule = objectMapper.readValue(ruleStr, ruleClass);
final Object rule = objectMapper.readValue(ruleStr, ruleClass);
RuleType ruleType = RuleType.getByClass(ruleClass).get();
switch (ruleType) {
case FLOW:

View File

@ -1,10 +1,10 @@
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.apollo.ApolloDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* A {@link FactoryBean} for creating {@link ApolloDataSource} instance.
*
@ -13,51 +13,51 @@ import org.springframework.beans.factory.FactoryBean;
*/
public class ApolloDataSourceFactoryBean implements FactoryBean<ApolloDataSource> {
private String namespaceName;
private String flowRulesKey;
private String defaultFlowRuleValue;
private Converter converter;
private String namespaceName;
private String flowRulesKey;
private String defaultFlowRuleValue;
private Converter converter;
@Override
public ApolloDataSource getObject() throws Exception {
return new ApolloDataSource(namespaceName, flowRulesKey, defaultFlowRuleValue,
converter);
}
@Override
public ApolloDataSource getObject() throws Exception {
return new ApolloDataSource(namespaceName, flowRulesKey, defaultFlowRuleValue,
converter);
}
@Override
public Class<?> getObjectType() {
return ApolloDataSource.class;
}
@Override
public Class<?> getObjectType() {
return ApolloDataSource.class;
}
public String getNamespaceName() {
return namespaceName;
}
public String getNamespaceName() {
return namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public void setNamespaceName(String namespaceName) {
this.namespaceName = namespaceName;
}
public String getFlowRulesKey() {
return flowRulesKey;
}
public String getFlowRulesKey() {
return flowRulesKey;
}
public void setFlowRulesKey(String flowRulesKey) {
this.flowRulesKey = flowRulesKey;
}
public void setFlowRulesKey(String flowRulesKey) {
this.flowRulesKey = flowRulesKey;
}
public String getDefaultFlowRuleValue() {
return defaultFlowRuleValue;
}
public String getDefaultFlowRuleValue() {
return defaultFlowRuleValue;
}
public void setDefaultFlowRuleValue(String defaultFlowRuleValue) {
this.defaultFlowRuleValue = defaultFlowRuleValue;
}
public void setDefaultFlowRuleValue(String defaultFlowRuleValue) {
this.defaultFlowRuleValue = defaultFlowRuleValue;
}
public Converter getConverter() {
return converter;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
}

View File

@ -3,11 +3,11 @@ package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.io.File;
import java.nio.charset.Charset;
import org.springframework.beans.factory.FactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import org.springframework.beans.factory.FactoryBean;
/**
* A {@link FactoryBean} for creating {@link FileRefreshableDataSource} instance.
*
@ -23,7 +23,7 @@ public class FileRefreshableDataSourceFactoryBean
private int bufSize;
private Converter converter;
@Override
@Override
public FileRefreshableDataSource getObject() throws Exception {
return new FileRefreshableDataSource(new File(file), converter,
recommendRefreshMs, bufSize, Charset.forName(charset));

View File

@ -1,12 +1,13 @@
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.nacos.NacosDataSource;
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.

View File

@ -1,11 +1,11 @@
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.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.
*
@ -14,68 +14,69 @@ import org.springframework.beans.factory.FactoryBean;
*/
public class ZookeeperDataSourceFactoryBean implements FactoryBean<ZookeeperDataSource> {
private String serverAddr;
private String serverAddr;
private String path;
private String path;
private String groupId;
private String dataId;
private String groupId;
private String dataId;
private Converter converter;
private Converter converter;
@Override
public ZookeeperDataSource getObject() throws Exception {
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
// the path will be /{groupId}/{dataId}
return new ZookeeperDataSource(serverAddr, groupId, dataId, converter);
} else {
// using path directly
return new ZookeeperDataSource(serverAddr, path, converter);
}
}
@Override
public ZookeeperDataSource getObject() throws Exception {
if (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {
// the path will be /{groupId}/{dataId}
return new ZookeeperDataSource(serverAddr, groupId, dataId, converter);
}
else {
// using path directly
return new ZookeeperDataSource(serverAddr, path, converter);
}
}
@Override
public Class<?> getObjectType() {
return ZookeeperDataSource.class;
}
@Override
public Class<?> getObjectType() {
return ZookeeperDataSource.class;
}
public String getServerAddr() {
return serverAddr;
}
public String getServerAddr() {
return serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getPath() {
return path;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public void setPath(String path) {
this.path = path;
}
public String getGroupId() {
return groupId;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getDataId() {
return dataId;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public Converter getConverter() {
return converter;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
}

View File

@ -46,7 +46,7 @@ public class SentinelConverterTests {
@Test
public void testJsonConverter() {
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
List<FlowRule> flowRules = jsonConverter
List<FlowRule> flowRules = (List<FlowRule>) jsonConverter
.convert(readFileContent("classpath: flowrule.json"));
assertEquals("json converter flow rule size was wrong", 1, flowRules.size());
assertEquals("json converter flow rule resource name was wrong", "resource",
@ -67,7 +67,7 @@ public class SentinelConverterTests {
@Test
public void testConverterEmptyContent() {
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());
}
@ -86,7 +86,7 @@ public class SentinelConverterTests {
@Test
public void testXmlConverter() {
XmlConverter jsonConverter = new XmlConverter(xmlMapper, FlowRule.class);
List<FlowRule> flowRules = jsonConverter
List<FlowRule> flowRules = (List<FlowRule>) jsonConverter
.convert(readFileContent("classpath: flowrule.xml"));
assertEquals("xml converter flow rule size was wrong", 2, flowRules.size());
assertEquals("xml converter flow rule1 resource name was wrong", "resource",

View File

@ -14,7 +14,7 @@ Sentinel can provide `ServiceId` level and `API Path` level flow control for spr
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>x.y.z</version>
</dependency>

View File

@ -10,19 +10,28 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
<name>Spring Cloud Alibaba Sentinel Zuul</name>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<name>Spring Cloud Alibaba Sentinel Gateway</name>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
</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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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 org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
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.zuul.fallback.ZuulBlockFallbackManager;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.DefaultBlockFallbackProvider;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
/**
* @author tiger
@ -30,7 +30,7 @@ public class FallBackProviderHandler implements SmartInitializingSingleton {
public void afterSingletonsInstantiated() {
Map<String, ZuulBlockFallbackProvider> providerMap = beanFactory
.getBeansOfType(ZuulBlockFallbackProvider.class);
if (MapUtils.isNotEmpty(providerMap)) {
if (!CollectionUtils.isEmpty(providerMap)) {
providerMap.forEach((k, v) -> {
logger.info("[Sentinel Zuul] Register provider name:{}, instance: {}", k,
v);

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -1,2 +0,0 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration

View File

@ -15,11 +15,6 @@
<dependencies>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
@ -42,6 +37,28 @@
<optional>true</optional>
</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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
@ -88,6 +105,11 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
</dependency>
<!--spring boot-->
<dependency>
@ -129,12 +151,6 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -18,26 +18,35 @@ package org.springframework.cloud.alibaba.sentinel;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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
*/
@Configuration
@ConditionalOnWebApplication
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(CommonFilter.class)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelWebAutoConfiguration {
@ -48,6 +57,22 @@ public class SentinelWebAutoConfiguration {
@Autowired
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
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
public FilterRegistrationBean sentinelFilter() {
@ -66,7 +91,8 @@ public class SentinelWebAutoConfiguration {
Filter filter = new CommonFilter();
registration.setFilter(filter);
registration.setOrder(filterConfig.getOrder());
log.info("[Sentinel Starter] register Sentinel with urlPatterns: {}.",
log.info(
"[Sentinel Starter] register Sentinel CommonFilter with urlPatterns: {}.",
filterConfig.getUrlPatterns());
return registration;

View File

@ -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();
}
}

View File

@ -16,7 +16,11 @@
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;
@ -33,12 +37,14 @@ import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConver
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
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;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateGroupItem;
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.annotation.aspectj.SentinelResourceAspect;
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.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.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
/**
@ -71,15 +85,6 @@ public class SentinelAutoConfiguration {
@Autowired
private SentinelProperties properties;
@Autowired
private Optional<UrlCleaner> urlCleanerOptional;
@Autowired
private Optional<UrlBlockHandler> urlBlockHandlerOptional;
@Autowired
private Optional<RequestOriginParser> requestOriginParserOptional;
@PostConstruct
private void init() {
if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR))
@ -142,10 +147,6 @@ public class SentinelAutoConfiguration {
WebServletConfig.setBlockPage(properties.getServlet().getBlockPage());
}
urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner);
requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser);
// earlier initialize
if (properties.isEager()) {
InitExecutor.doInit();
@ -170,72 +171,164 @@ public class SentinelAutoConfiguration {
@Bean
public SentinelDataSourceHandler sentinelDataSourceHandler(
DefaultListableBeanFactory beanFactory) {
return new SentinelDataSourceHandler(beanFactory);
DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties,
Environment env) {
return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);
}
@ConditionalOnClass(ObjectMapper.class)
@Configuration
protected static class SentinelConverterConfiguration {
private ObjectMapper objectMapper = new ObjectMapper();
static class ApiPredicateItemDeserializer
extends StdDeserializer<ApiPredicateItem> {
private Map<String, Class<? extends ApiPredicateItem>> registry = new HashMap<String, Class<? extends ApiPredicateItem>>();
@Bean("sentinel-json-flow-converter")
public JsonConverter jsonFlowConverter() {
return new JsonConverter(objectMapper, FlowRule.class);
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);
}
}
@Bean("sentinel-json-degrade-converter")
public JsonConverter jsonDegradeConverter() {
return new JsonConverter(objectMapper, DegradeRule.class);
@Configuration
protected static class SentinelJsonConfiguration {
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")
public JsonConverter jsonFlowConverter() {
return new JsonConverter(objectMapper, FlowRule.class);
}
@Bean("sentinel-json-degrade-converter")
public JsonConverter jsonDegradeConverter() {
return new JsonConverter(objectMapper, DegradeRule.class);
}
@Bean("sentinel-json-system-converter")
public JsonConverter jsonSystemConverter() {
return new JsonConverter(objectMapper, SystemRule.class);
}
@Bean("sentinel-json-authority-converter")
public JsonConverter jsonAuthorityConverter() {
return new JsonConverter(objectMapper, AuthorityRule.class);
}
@Bean("sentinel-json-param-flow-converter")
public JsonConverter jsonParamFlowConverter() {
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);
}
}
@Bean("sentinel-json-system-converter")
public JsonConverter jsonSystemConverter() {
return new JsonConverter(objectMapper, SystemRule.class);
@ConditionalOnClass(XmlMapper.class)
@Configuration
protected static class SentinelXmlConfiguration {
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")
public XmlConverter xmlFlowConverter() {
return new XmlConverter(xmlMapper, FlowRule.class);
}
@Bean("sentinel-xml-degrade-converter")
public XmlConverter xmlDegradeConverter() {
return new XmlConverter(xmlMapper, DegradeRule.class);
}
@Bean("sentinel-xml-system-converter")
public XmlConverter xmlSystemConverter() {
return new XmlConverter(xmlMapper, SystemRule.class);
}
@Bean("sentinel-xml-authority-converter")
public XmlConverter xmlAuthorityConverter() {
return new XmlConverter(xmlMapper, AuthorityRule.class);
}
@Bean("sentinel-xml-param-flow-converter")
public XmlConverter xmlParamFlowConverter() {
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);
}
}
@Bean("sentinel-json-authority-converter")
public JsonConverter jsonAuthorityConverter() {
return new JsonConverter(objectMapper, AuthorityRule.class);
}
@Bean("sentinel-json-param-flow-converter")
public JsonConverter jsonParamFlowConverter() {
return new JsonConverter(objectMapper, ParamFlowRule.class);
}
}
@ConditionalOnClass(XmlMapper.class)
protected static class SentinelXmlConfiguration {
private XmlMapper xmlMapper = new XmlMapper();
@Bean("sentinel-xml-flow-converter")
public XmlConverter xmlFlowConverter() {
return new XmlConverter(xmlMapper, FlowRule.class);
}
@Bean("sentinel-xml-degrade-converter")
public XmlConverter xmlDegradeConverter() {
return new XmlConverter(xmlMapper, DegradeRule.class);
}
@Bean("sentinel-xml-system-converter")
public XmlConverter xmlSystemConverter() {
return new XmlConverter(xmlMapper, SystemRule.class);
}
@Bean("sentinel-xml-authority-converter")
public XmlConverter xmlAuthorityConverter() {
return new XmlConverter(xmlMapper, AuthorityRule.class);
}
@Bean("sentinel-xml-param-flow-converter")
public XmlConverter xmlParamFlowConverter() {
return new XmlConverter(xmlMapper, ParamFlowRule.class);
}
}
}

View File

@ -1,23 +1,5 @@
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.util.Arrays;
import java.util.HashMap;
@ -25,6 +7,22 @@ import java.util.List;
import java.util.Map;
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
* 'spring.cloud.sentinel.datasource'
@ -47,12 +45,16 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
private final DefaultListableBeanFactory beanFactory;
public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
private final SentinelProperties sentinelProperties;
@Autowired
private SentinelProperties sentinelProperties;
private final Environment env;
public SentinelDataSourceHandler(DefaultListableBeanFactory beanFactory,
SentinelProperties sentinelProperties, Environment env) {
this.beanFactory = beanFactory;
this.sentinelProperties = sentinelProperties;
this.env = env;
}
@Override
public void afterSingletonsInstantiated() {
@ -68,6 +70,7 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
}
AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
.getValidDataSourceProperties();
abstractDataSourceProperties.setEnv(env);
abstractDataSourceProperties.preCheck(dataSourceName);
registerBean(abstractDataSourceProperties, dataSourceName
+ "-sentinel-" + validFields.get(0) + "-datasource");
@ -181,56 +184,8 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory
.getBean(dataSourceName);
logAndCheckRuleType(newDataSource, dataSourceName,
dataSourceProperties.getRuleType().getClazz());
// register property in RuleManager
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());
}
}
}

Some files were not shown because too many files have changed in this diff Show More