Merge remote-tracking branch 'upstream/2021.x' into refresh_specific_configuration_properties

# Conflicts:
#	spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/NacosConfigAutoConfiguration.java
pull/2437/head
Freeman Lau 3 years ago
commit a2d7366dc4

@ -0,0 +1,31 @@
name: Integration Testing
on:
push:
branches:
- 2021.x
pull_request:
branches:
- 2021.x
jobs:
integration-testing:
name: Integration Testing
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Dependies Cache
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Compile & Checkstyle
run: mvn clean compile
- name: Testing
run: mvn clean -Dit.enabled=true test

@ -9,13 +9,15 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
依托 Spring Cloud Alibaba您只需要添加一些注解和少量配置就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
此外,阿里云同时还提供了 Spring Cloud Alibaba 企业版 [微服务解决方案](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar),包括无侵入服务治理(全链路灰度,无损上下线,离群实例摘除等),企业级 Nacos 注册配置中心和企业级云原生网关等众多产品。
参考文档 请查看 [WIKI](https://github.com/alibaba/spring-cloud-alibaba/wiki) 。
为 Spring Cloud Alibaba 贡献代码请参考 [如何贡献](https://github.com/alibaba/spring-cloud-alibaba/wiki/%E5%A6%82%E4%BD%95%E8%B4%A1%E7%8C%AE%E4%BB%A3%E7%A0%81) 。
## 主要功能
* **服务限流降级**:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
* **服务限流降级**:默认支持 WebServlet、WebFlux、OpenFeign、RestTemplate、Spring Cloud Gateway、Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
* **服务注册与发现**:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。
* **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
@ -25,7 +27,9 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
* **阿里云短信服务**:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
更多功能请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
更多功能请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/Roadmap-zh.md)
除了上述所具有的功能外针对企业级用户的场景Spring Cloud Alibaba 配套的企业版微服务治理方案 [微服务引擎MSE](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar) 还提供了企业级微服务治理中心,包括全链路灰度、服务预热、无损上下线和离群实例摘除等更多更强大的治理能力,同时还提供了企业级 Nacos 注册配置中心,企业级云原生网关等多种产品及解决方案。
## 组件
@ -41,22 +45,24 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
**[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务Object Storage Service简称 OSS是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
**[Alibaba Cloud SchedulerX](https://help.aliyun.com/document_detail/43136.html)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
**[Alibaba Cloud SchedulerX](https://cn.aliyun.com/aliware/schedulerx)**: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2022.0/Roadmap-zh.md)。
## 如何构建
* master 分支对应的是 Spring Cloud Greenwich最低支持 JDK 1.8。
* finchley 分支对应的是 Spring Cloud Finchley最低支持 JDK 1.8。
* 1.x 分支对应的是 Spring Cloud Edgware最低支持 JDK 1.7。
* 2022.x 分支对应的是 Spring Cloud 2022 与 Spring Boot 2.6.x最低支持 JDK 1.8。
* 2020.0 分支对应的是 Spring Cloud 2020 与 Spring Boot 2.4.x最低支持 JDK 1.8。
* 2.2.x 分支对应的是 Spring Cloud Hoxton 与 Spring Boot 2.2.x最低支持 JDK 1.8。
* greenwich 分支对应的是 Spring Cloud Greenwich 与 Spring Boot 2.1.x最低支持 JDK 1.8。
* finchley 分支对应的是 Spring Cloud Finchley 与 Spring Boot 2.0.x最低支持 JDK 1.8。
* 1.x 分支对应的是 Spring Cloud Edgware 与 Spring Boot 1.x最低支持 JDK 1.7。
Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone 到本地,然后执行以下命令:
```bash
./mvnw install
```
执行完毕后,项目将被安装到本地 Maven 仓库。
## 如何使用
@ -64,19 +70,19 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone
### 如何引入依赖
如果需要使用已发布的版本,在 `dependencyManagement` 中添加如下配置。
```xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<version>2.2.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
```
然后在 `dependencies` 中添加自己所需使用的依赖即可使用。
## 演示 Demo
@ -111,7 +117,8 @@ Example 列表:
* 2.0.x 版本适用于 Spring Boot 2.0.x
* 2.1.x 版本适用于 Spring Boot 2.1.x
* 2.2.x 版本适用于 Spring Boot 2.2.x
* 2020.x 版本适用于 Spring Boot 2.4.x
* 2022.x 版本适用于 Spring Boot 2.6.x
## 社区交流
@ -121,9 +128,11 @@ spring-cloud-alibaba@googlegroups.com欢迎通过此邮件列表讨论与 spr
### 钉钉群
![DingQR](https://img.alicdn.com/tfs/TB1jXikzAL0gK0jSZFtXXXQCXXa-1002-323.png)
如图片有问题,访问 https://img.alicdn.com/tfs/TB1jXikzAL0gK0jSZFtXXXQCXXa-1002-323.png
* Spring Cloud Alibaba 开源交流群1群21914947
* Spring Cloud Alibaba 开源交流群2群已满21992595
* Spring Cloud Alibaba 开源交流群3群35153903
* Spring Cloud Alibaba 开源交流群4群已满30301472
* Spring Cloud Alibaba 开源交流群5群34930571
## 社区相关开源

@ -16,17 +16,19 @@ With Spring Cloud Alibaba, you only need to add some annotations and a small amo
## Features
* **Flow control and service degradation**Flow control for HTTP services is supported by default. You can also customize flow control and service degradation rules using annotations. The rules can be changed dynamically.
* **Service registration and discovery**Service can be registered and clients can discover the instances using Spring-managed beans, auto integration Ribbon.
* **Distributed configuration**support for externalized configuration in a distributed system, auto refresh when configuration changes.
* **Event-driven**support for building highly scalable event-driven microservices connected with shared messaging systems.
* **Distributed Transaction**support for distributed transaction solution with high performance and ease of use.
* **Alibaba Cloud Object Storage**massive, secure, low-cost, and highly reliable cloud storage services. Support for storing and accessing any type of data in any application, anytime, anywhere.
* **Alibaba Cloud SchedulerX**accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds.
* **Alibaba Cloud SMS** A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
* **Flow control and service degradation**: Flow control for HTTP services is supported by default. You can also customize flow control and service degradation rules using annotations. The rules can be changed dynamically.
* **Service registration and discovery**: Service can be registered and clients can discover the instances using Spring-managed beans, auto integration Ribbon.
* **Distributed configuration**: Support for externalized configuration in a distributed system, auto refresh when configuration changes.
* **Event-driven**: Support for building highly scalable event-driven microservices connected with shared messaging systems.
* **Distributed Transaction**: Support for distributed transaction solution with high performance and ease of use.
* **Alibaba Cloud Object Storage**: Massive, secure, low-cost, and highly reliable cloud storage services. Support for storing and accessing any type of data in any application, anytime, anywhere.
* **Alibaba Cloud SchedulerX**: Accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds.
* **Alibaba Cloud SMS**: A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
For more features, please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md).
In addition to the above-mentioned features, for the needs of enterprise users' scenarios, [Microservices Engine (MSE)](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar) of Spring Cloud Alibaba's enterprise version provides an enterprise-level microservices governance center, which includes more powerful governance capabilities such as Grayscale Release, Service Warm-up, Lossless Online and Offline and Outlier Ejection. At the same time, it also provides a variety of products and solutions such as enterprise-level Nacos registration / configuration center, enterprise-level cloud native gateway.
## Components
@ -34,51 +36,53 @@ For more features, please refer to [Roadmap](https://github.com/alibaba/spring-c
**[Nacos](https://github.com/alibaba/Nacos)**: An easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
**[RocketMQ](https://rocketmq.apache.org/)**A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
**[RocketMQ](https://rocketmq.apache.org/)**: A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
**[Dubbo](https://github.com/apache/dubbo)**A high-performance, Java based open source RPC framework.
**[Dubbo](https://github.com/apache/dubbo)**: A high-performance, Java based open source RPC framework.
**[Seata](https://github.com/seata/seata)**A distributed transaction solution with high performance and ease of use for microservices architecture.
**[Seata](https://github.com/seata/seata)**: A distributed transaction solution with high performance and ease of use for microservices architecture.
**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**An application configuration center that enables you to centralize the management of application configurations, and accomplish real-time configuration push in a distributed environment.
**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**: An application configuration center that enables you to centralize the management of application configurations, and accomplish real-time configuration push in a distributed environment.
**[Alibaba Cloud OSS](https://www.aliyun.com/product/oss)**: An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world.
**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: A messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
**[Alibaba Cloud SchedulerX](https://www.aliyun.com/aliware/schedulerx?spm=5176.10695662.784137.1.4b07363dej23L3)**:accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds..
**[Alibaba Cloud SchedulerX](https://www.aliyun.com/aliware/schedulerx?spm=5176.10695662.784137.1.4b07363dej23L3)**: Accurate, highly reliable, and highly available scheduled job scheduling services with response time within seconds..
For more features please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md).
## How to build
* **master branch**: Corresponds to Spring Cloud Greenwich & Spring Boot 2.x. JDK 1.8 or later versions are supported.
* **finchley branch**: Corresponds to Spring Cloud Finchley & Spring Boot 2.x. JDK 1.8 or later versions are supported.
* **2022.x branch**: Corresponds to Spring Cloud 2021 & Spring Boot 2.6.x. JDK 1.8 or later versions are supported.
* **2020.0 branch**: Corresponds to Spring Cloud 2020 & Spring Boot 2.4.x. JDK 1.8 or later versions are supported.
* **2.2.x branch**: Corresponds to Spring Cloud Hoxton & Spring Boot 2.2.x. JDK 1.8 or later versions are supported.
* **greenwich branch**: Corresponds to Spring Cloud Greenwich & Spring Boot 2.1.x. JDK 1.8 or later versions are supported.
* **finchley branch**: Corresponds to Spring Cloud Finchley & Spring Boot 2.0.x. JDK 1.8 or later versions are supported.
* **1.x branch**: Corresponds to Spring Cloud Edgware & Spring Boot 1.x, JDK 1.7 or later versions are supported.
Spring Cloud uses Maven for most build-related activities, and you should be able to get off the ground quite quickly by cloning the project you are interested in and typing:
```bash
./mvnw install
```
## How to Use
### Add maven dependency
These artifacts are available from Maven Central and Spring Release repository via BOM:
```xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
```
add the module in `dependencies`.
@ -118,6 +122,8 @@ As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been c
* 2.0.x for Spring Boot 2.0.x
* 2.1.x for Spring Boot 2.1.x
* 2.2.x for Spring Boot 2.2.x
* 2020.x for Spring Boot 2.4.x
* 2022.x for Spring Boot 2.6.x
## Code of Conduct
This project is a sub-project of Spring Cloud, it adheres to the Contributor Covenant [code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
@ -135,7 +141,7 @@ Add yourself as an @author to the .java files that you modify substantially (mor
Add some Javadocs and, if you change the namespace, some XSD doc elements.
A few unit tests would help a lot as wellsomeone has to do it.
A few unit tests would help a lot as wellsomeone has to do it.
If no-one else is using your branch, please rebase it against the current master (or other target branch in the main project).

@ -4,5 +4,6 @@
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress files="[\\/]spring-cloud-alibaba-examples[\\/]" checks="HideUtilityClassConstructorCheck" />
<suppress files="[\\/]spring-cloud-alibaba-tests[\\/]" checks="HideUtilityClassConstructorCheck" />
<suppress files=".*" checks="LineLength" />
</suppressions>

@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>3.0.1</version>
<version>3.1.1</version>
<relativePath/>
</parent>
@ -80,28 +80,29 @@
<properties>
<!-- Project revision -->
<revision>2022.0-SNAPSHOT</revision>
<revision>2021.0.1.0</revision>
<!-- Spring Cloud -->
<spring.cloud.version>2020.0.1</spring.cloud.version>
<spring.cloud.version>2021.0.1</spring.cloud.version>
<!-- Apache Dubbo -->
<dubbo.version>2.7.15</dubbo.version>
<curator.version>4.0.1</curator.version>
<!-- Apache RocketMQ -->
<rocketmq.starter.version>2.0.2</rocketmq.starter.version>
<rocketmq.version>4.9.2</rocketmq.version>
<!-- Maven Plugin Versions -->
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version>
<maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>
<maven-source-plugin.version>2.2.1</maven-source-plugin.version>
<!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<flatten-maven-plugin.version>1.1.0</flatten-maven-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<flatten-maven-plugin.version>1.2.7</flatten-maven-plugin.version>
<gmavenplus-plugin.version>1.6</gmavenplus-plugin.version>
<jacoco.version>0.8.3</jacoco.version>
<jacoco.version>0.8.5</jacoco.version>
</properties>
<modules>
@ -110,6 +111,7 @@
<module>spring-cloud-alibaba-docs</module>
<module>spring-cloud-alibaba-starters</module>
<module>spring-cloud-alibaba-coverage</module>
<module>spring-cloud-alibaba-tests</module>
</modules>
<dependencyManagement>
@ -181,8 +183,13 @@
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq.starter.version}</version>
<artifactId>rocketmq-client</artifactId>
<version>${rocketmq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<version>${rocketmq.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<version>3.0.1</version>
<version>3.1.1</version>
<relativePath/>
</parent>
@ -18,18 +18,18 @@
<description>Spring Cloud Alibaba Dependencies</description>
<properties>
<revision>2022.0-SNAPSHOT</revision>
<sentinel.version>1.8.0</sentinel.version>
<seata.version>1.3.0</seata.version>
<nacos.client.version>1.4.1</nacos.client.version>
<revision>2021.0.1.0</revision>
<sentinel.version>1.8.3</sentinel.version>
<seata.version>1.4.2</seata.version>
<nacos.client.version>1.4.2</nacos.client.version>
<nacos.config.version>0.8.0</nacos.config.version>
<spring.context.support.version>1.0.10</spring.context.support.version>
<spring.context.support.version>1.0.11</spring.context.support.version>
<!-- Maven Plugin Versions -->
<maven-source-plugin.version>2.2.1</maven-source-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<flatten-maven-plugin.version>1.1.0</flatten-maven-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<flatten-maven-plugin.version>1.2.7</flatten-maven-plugin.version>
</properties>
<dependencyManagement>

@ -260,7 +260,7 @@ Nacos 内部有 https://nacos.io/zh-cn/docs/concepts.html[Namespace 的概念]:
[quote]
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
在没有明确指定 `${spring.cloud.nacos.config.namespace}` 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。如果需要使用自定义的命名空间可以通过以下配置来实现
在没有明确指定 `${spring.cloud.nacos.config.namespace}` 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespace。如果需要使用自定义的命名空间可以通过以下配置来实现
[source,properties]
----
spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7
@ -281,7 +281,7 @@ NOTE: 该配置必须放在 bootstrap.properties 文件中。并且在添加配
=== 支持自定义扩展的 Data Id 配置
Nacos Config 从 0.2.1 版本后,可支持自定义 Data Id 的配置。关于这部分详细的设计可参考 https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/141[这里]。
Nacos Config 从 0.2.1 版本后,可支持自定义 Data Id 的配置。关于这部分详细的设计可参考 https://github.com/alibaba/spring-cloud-alibaba/issues/141[这里]。
一个完整的配置案例如下所示:
[source,properties]

@ -216,7 +216,7 @@ NOTE: 在启动 Consumer 应用之前请先将 Nacos 服务启动好。具体启
=== Nacos Discovery 对外暴露的 Endpoint
Nacos Discovery 内部提供了一个 Endpoint, 对应的 endpoint id 为 `nacos-discovery`。
Nacos Discovery 内部提供了一个 Endpoint, 对应的 endpoint id 为 `nacosdiscovery`。
Endpoint 暴露的 json 中包含了两种属性:

@ -0,0 +1,378 @@
== Spring Cloud Alibaba RocketMQ Binder (NEW)
=== RocketMQ 介绍
https://rocketmq.apache.org[RocketMQ] 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
具有以下特点:
* 能够保证严格的消息顺序
* 提供丰富的消息拉取模式
* 高效的订阅者水平扩展能力
* 实时的消息订阅机制
* 亿级消息堆积能力
=== RocketMQ 基本使用
* 下载 RocketMQ
下载 https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip[RocketMQ最新的二进制文件],并解压
解压后的目录结构如下:
```
apache-rocketmq
├── LICENSE
├── NOTICE
├── README.md
├── benchmark
├── bin
├── conf
└── lib
```
* 启动 NameServer
```bash
nohup sh bin/mqnamesrv &
tail -f ~/logs/rocketmqlogs/namesrv.log
```
* 启动 Broker
```bash
nohup sh bin/mqbroker -n localhost:9876 &
tail -f ~/logs/rocketmqlogs/broker.log
```
* 发送、接收消息
发送消息:
```bash
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
```
发送成功后显示:`SendResult [sendStatus=SEND_OK, msgId= ...`
接收消息:
```bash
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
```
接收成功后显示:`ConsumeMessageThread_%d Receive New Messages: [MessageExt...`
* 关闭 Server
```bash
sh bin/mqshutdown broker
sh bin/mqshutdown namesrv
```
=== Spring Cloud Stream 介绍
Spring Cloud Stream 是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot 来创建具有生产级别的单机 Spring 应用,并且使用 `Spring Integration` 与 Broker 进行连接。
Spring Cloud Stream 提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。
Spring Cloud Stream 内部有两个概念Binder 和 Binding。
* Binder: 跟外部消息中间件集成的组件,用来创建 Binding各消息中间件都有自己的 Binder 实现。
比如 `Kafka` 的实现 `KafkaMessageChannelBinder``RabbitMQ` 的实现 `RabbitMessageChannelBinder` 以及 `RocketMQ` 的实现 `RocketMQMessageChannelBinder`。
* Binding: 包括 Input Binding 和 Output Binding。
Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁,实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。
.Spring Cloud Stream
image::https://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/images/SCSt-overview.png[]
使用 Spring Cloud Stream 完成一段简单的消息发送和消息接收代码:
```java
MessageChannel messageChannel = new DirectChannel();
// 消息订阅
((SubscribableChannel) messageChannel).subscribe(new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
System.out.println("receive msg: " + message.getPayload());
}
});
// 消息发送
messageChannel.send(MessageBuilder.withPayload("simple msg").build());
```
这段代码所有的消息类都是 `spring-messaging` 模块里提供的。屏蔽具体消息中间件的底层实现,如果想用更换消息中间件,在配置文件里配置相关消息中间件信息以及修改 binder 依赖即可。
**Spring Cloud Stream 底层基于这段代码去做了各种抽象。**
=== 如何使用 Spring Cloud Alibaba RocketMQ Binder
如果要在您的项目中引入 RocketMQ Binder需要引入如下 maven 依赖:
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
</dependency>
```
或者可以使用 Spring Cloud Stream RocketMQ Starter
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
```
=== Spring Cloud Alibaba RocketMQ Binder 实现
这是 Spring Cloud Stream RocketMQ Binder 的实现架构:
.SCS RocketMQ Binder
image::https://img.alicdn.com/tfs/TB1v8rcbUY1gK0jSZFCXXcwqXXa-1236-773.png[]
RocketMQ Binder 的重构优化去除了对 https://github.com/apache/rocketmq-spring[RocketMQ-Spring]框架的依赖 。
RocketMQ Binder 核心类 `RocketMQMessageChannelBinder` 实现了 Spring Cloud Stream 规范,内部会构建 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQInboundChannelAdapter.java[RocketMQInboundChannelAdapter] 和 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProducerMessageHandler.java[RocketMQProducerMessageHandler]。
`RocketMQProducerMessageHandler` 会基于 Binding 配置通过 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/outbound/RocketMQProduceFactory.java[RocketMQProduceFactory]构造 RocketMQ Producer其内部会把 `spring-messaging` 模块内 `org.springframework.messaging.Message` 消息类转换成 RocketMQ 的消息类 `org.apache.rocketmq.common.message.Message`,然后发送出去。
`RocketMQInboundChannelAdapter` 也会基于 Binding 配置通过 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/integration/inbound/RocketMQConsumerFactory.java[RocketMQConsumerFactory]构造 DefaultMQPushConsumer其内部会启动 RocketMQ Consumer 接收消息。
NOTE: 与 https://github.com/apache/rocketmq-spring[RocketMQ-Spring] 框架的兼容需要手动处理
目前 Binder 支持在 `Header` 中设置相关的 key 来进行 RocketMQ Message 消息的特性设置。
比如 `TAGS`、`KEYS`、`TRANSACTIONAL_ARGS` 等 RocketMQ 消息对应的标签,详情见 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/contants/RocketMQConst.java[com.alibaba.cloud.stream.binder.rocketmq.constant.RocketMQConst]
```java
MessageBuilder builder = MessageBuilder.withPayload(msg)
.setHeader(RocketMQHeaders.TAGS, "binder")
.setHeader(RocketMQHeaders.KEYS, "my-key");
Message message = builder.build();
output().send(message);
```
NOTE: 更多使用请参考样例: https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-examples/rocketmq-example/rocketmq-produce-example/src/main/java/com/alibaba/cloud/examples/SenderService.java[com.alibaba.cloud.examples.SenderService]
=== MessageSource 支持
SCS RocketMQ Binder 支持 `MessageSource`,可以进行消息的拉取,例子如下:
```java
@SpringBootApplication
@EnableBinding(MQApplication.PolledProcessor.class)
public class MQApplication {
private final Logger logger =
LoggerFactory.getLogger(MQApplication.class);
public static void main(String[] args) {
SpringApplication.run(MQApplication.class, args);
}
@Bean
public ApplicationRunner runner(PollableMessageSource source,
MessageChannel dest) {
return args -> {
while (true) {
boolean result = source.poll(m -> {
String payload = (String) m.getPayload();
logger.info("Received: " + payload);
dest.send(MessageBuilder.withPayload(payload.toUpperCase())
.copyHeaders(m.getHeaders())
.build());
}, new ParameterizedTypeReference<String>() { });
if (result) {
logger.info("Processed a message");
}
else {
logger.info("Nothing to do");
}
Thread.sleep(5_000);
}
};
}
public static interface PolledProcessor {
@Input
PollableMessageSource source();
@Output
MessageChannel dest();
}
}
```
=== 配置选项
==== RocketMQ Binder Properties
spring.cloud.stream.rocketmq.binder.name-server::
RocketMQ NameServer 地址(老版本使用 namesrv-addr 配置项)。
+
Default: `127.0.0.1:9876`.
spring.cloud.stream.rocketmq.binder.access-key::
阿里云账号 AccessKey。
+
Default: null.
spring.cloud.stream.rocketmq.binder.secret-key::
阿里云账号 SecretKey。
+
Default: null.
spring.cloud.stream.rocketmq.binder.enable-msg-trace::
是否为 Producer 和 Consumer 开启消息轨迹功能
+
Default: `true`.
spring.cloud.stream.rocketmq.binder.customized-trace-topic::
消息轨迹开启后存储的 topic 名称。
+
Default: `RMQ_SYS_TRACE_TOPIC`.
==== RocketMQ Consumer Properties
下面的这些配置是以 `spring.cloud.stream.rocketmq.bindings.<channelName>.consumer.` 为前缀的 RocketMQ Consumer 相关的配置。
更多见 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java[com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties]。
enable::
是否启用 Consumer。
+
默认值: `true`.
subscription::
Consumer 基于 TAGS 订阅,多个 tag 以 `||` 分割。更多见 `com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties.subscription`
+
默认值: empty.
messageModel::
Consumer 消费模式。如果想让每一个的订阅者都能接收到消息,可以使用广播模式。更多见 `org.apache.rocketmq.common.protocol.heartbeat.MessageModel`
+
默认值: `CLUSTERING`.
consumeFromWhere::
Consumer 从哪里开始消费。更多见 `org.apache.rocketmq.common.consumer.ConsumeFromWhere`
+
默认值: `CONSUME_FROM_LAST_OFFSET`.
#下面的这些配置是 Consumer Push 模式相关的配置。#
`spring.cloud.stream.rocketmq.bindings.<channelName>.consumer.push.`
orderly::
是否同步消费消息模式
+
默认值: `false`.
delayLevelWhenNextConsume::
异步消费消息模式下消费失败重试策略:
* -1,不重复,直接放入死信队列
* 0,broker 控制重试策略
* >0,client 控制重试策略
+
默认值: `0`.
suspendCurrentQueueTimeMillis::
同步消费消息模式下消费失败后再次消费的时间间隔。
+
默认值: `1000`.
其他更多参数见 `com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties.Push`
#下面的这些配置是 Consumer Pull 模式相关的配置。#
`spring.cloud.stream.rocketmq.bindings.<channelName>.consumer.pull.`
pullThreadNums::
消费时拉取的线程数
+
默认值: `20`.
pollTimeoutMillis::
拉取时的超时毫秒数
+
默认值: `1000 * 5`.
其他更多参数见 `com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties.Pull`.
NOTE: 更多参数见 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQConsumerProperties.java[com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties]
==== RocketMQ Provider Properties
下面的这些配置是以 `spring.cloud.stream.rocketmq.bindings.<channelName>.producer.` 为前缀的 RocketMQ Producer 相关的配置。更多见 https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java[com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties]
enable::
是否启用 Producer。
+
默认值: `true`.
group::
Producer group name。
+
默认值: empty.
maxMessageSize::
消息发送的最大字节数。
+
默认值: `8249344`.
producerType::
消息生产者类型,普通或者事务。更多见 `com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties.ProducerType`.
+
默认值: `Normal`.
transactionListener::
事务消息监听器的beanName在 `producerType=Trans` 时才有效;必须是实现 `org.apache.rocketmq.client.producer.TransactionListener` 接口的Spring Bean。
sendType::
消息发送类型(同步、异步、单向)。更多见`com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties.SendType`.
+
默认值: `Sync`.
sendCallBack::
消息发送后回调函数的beanName在 `sendType=Async` 时才有效;必须是实现 `org.apache.rocketmq.client.producer.SendCallback` 接口的Spring Bean。
vipChannelEnabled::
是否在 Vip Channel 上发送消息。
+
默认值: `true`.
sendMessageTimeout::
发送消息的超时时间(毫秒)。
+
默认值: `3000`.
compressMessageBodyThreshold::
消息体压缩阀值(当消息体超过 4k 的时候会被压缩)。
+
默认值: `4096`.
retryTimesWhenSendFailed::
在同步发送消息的模式下,消息发送失败的重试次数。
+
默认值: `2`.
retryTimesWhenSendAsyncFailed::
在异步发送消息的模式下,消息发送失败的重试次数。
+
默认值: `2`.
retryAnotherBroker::
消息发送失败的情况下是否重试其它的 broker。
+
默认值: `false`.
NOTE: 生产者其他更多参数请见:
https://github.com/alibaba/spring-cloud-alibaba/blob/rocketmq/spring-cloud-alibaba-starters/spring-cloud-starter-stream-rocketmq/src/main/java/com/alibaba/cloud/stream/binder/rocketmq/properties/RocketMQProducerProperties.java[com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties]
=== 阿里云 MQ 服务
使用阿里云 MQ 服务需要配置 AccessKey、SecretKey 以及云上的 NameServer 地址。
NOTE: 0.1.2 & 0.2.2 & 0.9.0 才支持该功能
```properties
spring.cloud.stream.rocketmq.binder.access-key=YourAccessKey
spring.cloud.stream.rocketmq.binder.secret-key=YourSecretKey
spring.cloud.stream.rocketmq.binder.name-server=NameServerInMQ
```
NOTE: topic 和 group 请以 实例id% 为前缀进行配置。比如 topic 为 "test",需要配置成 "实例id%test"
.NameServer 的获取(配置中请去掉 http:// 前缀)
image::https://spring-cloud-alibaba.oss-cn-beijing.aliyuncs.com/MQ.png[]

@ -249,6 +249,11 @@ spring.cloud.stream.rocketmq.binder.customized-trace-topic::
消息轨迹开启后存储的 topic 名称。
+
Default: `RMQ_SYS_TRACE_TOPIC`.
+
spring.cloud.stream.rocketmq.binder.access-channel::
商业版rocketmq消息轨迹topic自适应值为CLOUD
+
Default: null.
==== RocketMQ Consumer Properties
@ -346,6 +351,7 @@ NOTE: 0.1.2 & 0.2.2 & 0.9.0 才支持该功能
spring.cloud.stream.rocketmq.binder.access-key=YourAccessKey
spring.cloud.stream.rocketmq.binder.secret-key=YourSecretKey
spring.cloud.stream.rocketmq.binder.name-server=NameServerInMQ
spring.cloud.stream.rocketmq.binder.access-channel=CLOUD
```
NOTE: topic 和 group 请以 实例id% 为前缀进行配置。比如 topic 为 "test",需要配置成 "实例id%test"

@ -0,0 +1,186 @@
== Spring Cloud Alibaba 2021.0.1.0 升级指南
=== 版本号
从 2021.0.1.0 开始SCA 版本将会对应 Spring Cloud 版本,
前三位为 Spring Cloud 版本,最后一位为扩展版本
=== 升级步骤
升级版本 (注意版本对应关系)
```xml
<dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
```
*注意事项:* `spring-cloud-starter-alibaba-nacos-config` 模块移除了 `spring-cloud-starter-bootstrap` 依赖,如果你想以旧版的方式使用,你需要手动加上该依赖,现在推荐使用 `spring.config.import` 方式引入配置
完成以上步骤就能无缝切换到 `spring cloud alibaba 2021.0.1.0` 版本
=== 新特性及其使用
==== 支持 spring.config.import
这里假设有一个配置文件(`bootstrap.yml`),升级到新版本应该怎么配置呢
```yaml
# bootstrap.yml
spring:
cloud:
nacos:
config:
name: test.yml
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
extension-configs:
- dataId: test01.yml
group: group_01
- dataId: test02.yml
group: group_02
refresh: false
```
这两个配置是等价的
```yaml
# application.yml
spring:
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
config:
import:
- optional:nacos:test.yml # 监听 DEFAULT_GROUP:test.yml
- optional:nacos:test01.yml?group=group_01 # 覆盖默认 group监听 group_01:test01.yml
- optional:nacos:test02.yml?group=group_02&refreshEnabled=false # 不开启动态刷新
- nacos:test03.yml # 在拉取nacos配置异常时会快速失败会导致 spring 容器启动失败
```
注意事项:
- 如果使用 `spring.config.import` 就不能使用 bootstrap.yml/properties 引入配置的方式了 !!!
- 如果引入了 `spring-cloud-starter-alibaba-nacos-config`,并且使用 import 方式导入配置,
项目启动时会自动检测是否引入了 `nacos:` 条目,如果没有 import nacos 条目,会出现如下错误:
----
The spring.config.import property is missing a nacos: entry
Action:
Add a spring.config.import=nacos: property to your configuration.
If configuration is not required add spring.config.import=optional:nacos: instead.
To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.
----
你可以手动通设置 `spring.cloud.nacos.config.import-check.enabled=false` 关闭它,但是不建议这么做,这个功能可以帮助你检查是否引入多余依赖
- 假如想保留以前的使用方式 (bootstrap引入配置),你只需要添加依赖 `spring-cloud-starter-bootstrap` 依赖,不需要修改一行代码
你可以前往 https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-2.4.x-example[这里] 查看具体example
==== Nacos 容错能力
新增配置项 `spring.cloud.nacos.discovery.failure-tolerance-enabled`
设置为 true (默认 false) 开启 nacos 服务发现失败容错能力,该功能会在 nacos 获取实例失败时返回上一次获取的实例,可以在 nacos server 网络不稳定时提供容错能力,不会导致请求全部挂掉
==== 支持 feign 灵活的熔断配置
当 Sentinel 作为 Spring Cloud 断路器实现时,支持为每个 FeignClient 添加断路器配置
添加依赖
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-circuitbreaker-sentinel</artifactId>
</dependency>
```
这里有两个 FeignClint
```java
@FeignClient(value = "user", fallback = UserFallback.class)
public interface UserClient {
@GetMapping("/{success}")
String success(@PathVariable Boolean success);
}
@FeignClient(value = "order", fallback = OrderFallback.class)
public interface OrderClient {
@GetMapping("/{success}")
String success(@PathVariable Boolean success);
@GetMapping("/{success}")
String error(@PathVariable Boolean success);
}
```
现在有这些需求:
1. 我想要对全局的 FeignClient 配置一个默认熔断规则
2. 我想要对 user FeignClient 配置熔断规则
3. 我想要对 order FeignClient 的指定方法(error)配置熔断规则
添加以下配置
```yaml
feign:
circuitbreaker:
enabled: true
sentinel:
default-rule: default # 全局规则名称
rules:
# 全局配置,这些参数的意思请查看 com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule
# 可配置多条规则
default:
- grade: 2
count: 1
timeWindow: 1
statIntervalMs: 1000
minRequestAmount: 5
- grade: 2
count: 1
# 针对 user FeignClient
user:
- grade: 2
count: 1
timeWindow: 1
statIntervalMs: 1000
minRequestAmount: 5
# 针对 order FeignClient error 方法,注意中括号,不然会解析出来的值会不一致
"[order#error(Boolean)]":
- grade: 2
count: 1
timeWindow: 1
statIntervalMs: 1000
minRequestAmount: 5
```
该功能还支持从配置中心动态刷新,可以将上述配置放入配置中心(nacosconsul),修改规则会立刻生效,如果不需要该功能可以通过 `feign.sentinel.enable-refresh-rules=false` 来禁用它
*注意事项:* 如果你使用的是 `spring-cloud-starter-alibaba-sentinel`,请**不要**配置 `feign.sentinel.enable=true`,会使配置失效
你可以前往 https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example[这里] 查看具体 example
=== 对升级的一点建议
1. 在 spring boot 2.6 之后默认开启了禁止循环引入,建议大家不要关闭,这是一种不好的编码习惯,如果你的项目里出现了循环引用,请选择重构它
2. 抛弃 bootstrap 引入配置的方式,使用 `spring.config.import` 方式引入配置spring boot 2.4 对这一块做了很大的优化工作,不再需要全量启动一个容器来刷新配置

@ -222,7 +222,7 @@ spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
#spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.data-id=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json

@ -3,7 +3,7 @@
`Spring Cloud Alibaba Sidecar` 是一个用来快速**完美整合** Spring Cloud
与 *异构微服务* 的框架,灵感来自
https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-sidecar[Spring
Cloud Netflix Sidecar]目前支持的服务发现组件:
Cloud Netflix Sidecar]目前支持的服务发现组件:
* Nacos
* Consul
@ -14,7 +14,7 @@ Cloud Netflix Sidecar] 。目前支持的服务发现组件:
非Spring Cloud应用统称异构微服务。比如你的遗留项目或者非JVM应用。
==== ``完美整合''的三层含义
==== "完美整合"的三层含义
* 享受服务发现的优势
* 有负载均衡
@ -89,7 +89,7 @@ spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:

@ -19,6 +19,8 @@ include::sentinel.adoc[]
include::dubbo.adoc[]
include::rocketmq-new.adoc[]
include::rocketmq.adoc[]
include::ans.adoc[]

@ -280,7 +280,7 @@ NOTE: This configuration must be in the bootstrap.properties file, and the value
=== Support Custom Data Id
As of Spring Cloud Alibaba Nacos Config, data id can be self-defined. For detailed design of this part, refer to https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/141[Github issue].
As of Spring Cloud Alibaba Nacos Config, data id can be self-defined. For detailed design of this part, refer to https://github.com/alibaba/spring-cloud-alibaba/issues/141[Github issue].
The following is a complete sample:
[source,properties]

@ -219,7 +219,7 @@ Next, access the `http://ip:port/echo/app-name` interface provided by the consum
=== Nacos Discovery Endpoint
Nacos Discovery provides an Endpoint internally with a corresponding endpoint id of `nacos-discovery`.
Nacos Discovery provides an Endpoint internally with a corresponding endpoint id of `nacosdiscovery`.
Endpoint exposed json contains two properties:

@ -2,7 +2,7 @@
=== Introduction of RocketMQ
https://rocketmq.apache.org[RocketMQ] is an open-source distributed message system. It is based on highly available distributed cluster technologies and provides message publishing and subscription service with low latency and high stability. RocketMQ is widely used in a variety of industries, such as decoupling of asynchronous communication, enterprise sulotions, financial settlements, telecommunication, e-commerce, logistics, marketing, social media, instant messaging, mobile applications, mobile games, vedios, IoT, and Internet of Vehicles.
https://rocketmq.apache.org[RocketMQ] is an open-source distributed message system. It is based on highly available distributed cluster technologies and provides message publishing and subscription service with low latency and high stability. RocketMQ is widely used in a variety of industries, such as decoupling of asynchronous communication, enterprise solutions, financial settlements, telecommunication, e-commerce, logistics, marketing, social media, instant messaging, mobile applications, mobile games, videos, IoT, and Internet of Vehicles.
It has the following features:
@ -57,7 +57,7 @@ Send messages:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
```
Output when the message is successfuly sent: `SendResult [sendStatus=SEND_OK, msgId= ...`
Output when the message is successfully sent: `SendResult [sendStatus=SEND_OK, msgId= ...`
Receive messages:
@ -246,7 +246,11 @@ spring.cloud.stream.rocketmq.binder.customized-trace-topic::
The trace topic for message trace.
+
Default: `RMQ_SYS_TRACE_TOPIC`.
+
spring.cloud.stream.rocketmq.binder.access-channel::
The commercial version of rocketmq message trajectory topic is adaptive,the value is CLOUD
+
Default: null.
==== RocketMQ Consumer Properties

@ -0,0 +1,185 @@
== Spring Cloud Alibaba 2021.0.1.0 Upgrade Guide
=== Version Number
Starting from 2021.0.1.0, the SCA version will correspond to the Spring Cloud version, the first three are the Spring Cloud version, and the last one is the extended version.
=== Upgrade Steps
Upgrade version (note the version correspondence)
```xml
<dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
```
*Note:* The `spring-cloud-starter-alibaba-nacos-config` module removes the `spring-cloud-starter-bootstrap` dependency. If you want to use with the bootstrap way, you need to manually add this dependency, now recommended to import configuration using `spring.config.import`.
After completing the above steps, you can smoothly switch to the `Spring Cloud Alibaba 2021.0.1.0` version.
=== New Features and Usage
==== Support `spring.config.import`
Suppose there is a configuration file (`bootstrap.yml`) here, how should it be configured to upgrade to a new version?
```yaml
# bootstrap.yml
spring:
cloud:
nacos:
config:
name: test.yml
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
extension-configs:
- dataId: test01.yml
group: group_01
- dataId: test02.yml
group: group_02
refresh: false
```
The two configurations are equivalent.
```yaml
# application.yml
spring:
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
config:
import:
- optional:nacos:test.yml # Listening DEFAULT_GROUP:test.yml
- optional:nacos:test01.yml?group=group_01 # Override default grouplistening group_01:test01.yml
- optional:nacos:test02.yml?group=group_02&refreshEnabled=false # Do not enable dynamic refresh
- nacos:test03.yml # When the nacos configuration is pulled abnormally, it will fail quickly, which will cause the Spring container to fail to start.
```
Note:
- If you use `spring.config.import`, you can't use bootstrap.yml/properties.
- If `spring-cloud-starter-alibaba-nacos-config` is using and the configuration is imported using the `spring.config.import` way, the project will automatically detect whether the `nacos:` entry has been imported. If there is no import nacos entry, the following error will occur:
----
The spring.config.import property is missing a nacos: entry
Action:
Add a spring.config.import=nacos: property to your configuration.
If configuration is not required add spring.config.import=optional:nacos: instead.
To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.
----
You can manually turn it off by setting `spring.cloud.nacos.config.import-check.enabled=false`, but it is not recommended to do so, this function can help you check whether to introduce unnecessary dependencies.
- If you want to keep the previous usage (bootstrap way), you only need to add the dependency `spring-cloud-starter-bootstrap` dependency and don't need modifying a line of code.
you can go https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-2.4.x-example[here] to see the complete example.
==== Nacos Failure Tolerance
Add new configuration item `spring.cloud.nacos.discovery.failure-tolerance-enabled`. Set to true (default false) to enable acos service discovery failure fault tolerance. This feature will return the last instance obtained when nacos fails to get instances. It can provide fault tolerance when the nacos server network is unstable, and will not cause all requests to hang up.
==== Support Feign Circuit Breaker Configuration
When Sentinel is implemented as a Spring Cloud circuit breaker, support for adding circuit breaker configuration for each FeignClient.
Add dependency.
```xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-circuitbreaker-sentinel</artifactId>
</dependency>
```
And here are two FeignClint
```java
@FeignClient(value = "user", fallback = UserFallback.class)
public interface UserClient {
@GetMapping("/{success}")
String success(@PathVariable Boolean success);
}
@FeignClient(value = "order", fallback = OrderFallback.class)
public interface OrderClient {
@GetMapping("/{success}")
String success(@PathVariable Boolean success);
@GetMapping("/{success}")
String error(@PathVariable Boolean success);
}
```
Now there are these requirements:
1. I want to configure a default circuit breaker for the global FeignClient.
2. I want to configure a circuit breaker rule for user FeignClient.
3. I want to configure a circuit breaker for the specified method (error) of order FeignClient.
Add the following configuration.
```yaml
feign:
circuitbreaker:
enabled: true
sentinel:
default-rule: default # global rule name
rules:
# global configuration, the meaning of these parameters, please see com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule
# you can configure multiple rules
default:
- grade: 2
count: 1
timeWindow: 1
statIntervalMs: 1000
minRequestAmount: 5
- grade: 2
count: 1
# for user FeignClient
user:
- grade: 2
count: 1
timeWindow: 1
statIntervalMs: 1000
minRequestAmount: 5
# for order FeignClient 'error' methodnote the square brackets, otherwise the parsed value will be inconsistent.
"[order#error(Boolean)]":
- grade: 2
count: 1
timeWindow: 1
statIntervalMs: 1000
minRequestAmount: 5
```
This feature also supports dynamic refresh from the configuration center. You can put the above configuration into the configuration center (nacos, consul), and the modified rules will take effect immediately. If you do not need this feature, you can set `feign.sentinel.enable-refresh-rules=false` to disable it.
*Note:* If you are using `spring-cloud-starter-alibaba-sentinel`, please *DO NOT* configure `feign.sentinel.enable=true`, it will invalidate the configuration.
You can go https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example[here] to see the complete example.
=== Little Advice For Upgrading
1. After Spring Boot 2.6, the prohibition of circular reference is enabled by default. It is recommended that you do not change it. This is a bad coding practice. If there is a circular reference in your project, please choose to refactor it.
2. Abandoning the way of importing configuration from the bootstrap way and using `spring.config.import` to import configuration, Spring Boot 2.4 has done a lot of optimization work on this, and it is no longer necessary to start a full container to refresh the environment.

@ -82,7 +82,7 @@ Job Description Empty
Custom Parameters Empty
----
The job above is a “Simple Single-Server Job”, and speficied a Cron expression of "0 * * * * ?" . This means that the job will be executed once and once only in every minute.
The job above is a “Simple Single-Server Job”, and specified a Cron expression of "0 * * * * ?" . This means that the job will be executed once and once only in every minute.
For more job types, refer to https://help.aliyun.com/document_detail/43136.html[SchedulerX Documentation].

@ -225,7 +225,7 @@ spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
#spring.cloud.sentinel.datasource.ds1.file.converter-class=JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.data-id=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json

@ -24,12 +24,6 @@
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

@ -20,13 +20,6 @@ Spring Boot 2.4.0 版本开始默认不启动 bootstrap 容器
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<!-- 不再需要 bootstrap 容器 -->
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</exclusion>
</exclusions>
</dependency>
```
@ -41,12 +34,13 @@ spring:
cloud:
nacos:
config:
name: test.yml
file-extension: yml
# 2.4.0 新增配置 spring.config.import
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
config:
import:
- optional:nacos:localhost:8848
- optional:nacos:test.yml
- optional:nacos:test01.yml?group=group_02
- optional:nacos:test02.yml?group=group_03&refreshEnabled=false
```
3. 在 nacos 创建 test.yml

@ -7,7 +7,7 @@ spring:
nacos:
config:
group: DEFAULT_GROUP
server-addr: localhost:8848
server-addr: 127.0.0.1:8848
config:
import:
- optional:nacos:test.yml

@ -25,6 +25,10 @@
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

@ -3,6 +3,7 @@
## 项目说明
本项目演示如何使用 Nacos Config Starter 完成 Spring Cloud 应用的配置管理。
注意: 适用于 spring boot 版本低于 2.4.0
[Nacos](https://github.com/alibaba/Nacos) 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
@ -153,7 +154,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息Nacos Config Sta
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18084/nacos_config 来查看 Nacos Endpoint 的信息。
Spring Boot 2.x 可以通过访问 http://127.0.0.1:18084/actuator/nacos-config 来访问。
Spring Boot 2.x 可以通过访问 http://127.0.0.1:18084/actuator/nacosconfig 来访问。
![actuator](https://cdn.nlark.com/lark/0/2018/png/54319/1536986344822-279e1edc-ebca-4201-8362-0ddeff240b85.png)
@ -164,8 +165,8 @@ Spring Boot 2.x 可以通过访问 http://127.0.0.1:18084/actuator/nacos-config
#### 更多配置项
配置项|key|默认值|说明
----|----|-----|-----
服务端地址|spring.cloud.nacos.config.server-addr||
DataId前缀|spring.cloud.nacos.config.prefix||spring.application.name
服务端地址|spring.cloud.nacos.config.server-addr||服务器ip和端口
DataId前缀|spring.cloud.nacos.config.prefix|${spring.application.name}|
Group|spring.cloud.nacos.config.group|DEFAULT_GROUP|
dataID后缀及内容文件格式|spring.cloud.nacos.config.file-extension|properties|dataId的后缀同时也是配置内容的文件格式目前只支持 properties
配置内容的编码方式|spring.cloud.nacos.config.encode|UTF-8|配置的编码
@ -174,8 +175,9 @@ dataID后缀及内容文件格式|spring.cloud.nacos.config.file-extension|prope
AccessKey|spring.cloud.nacos.config.access-key||
SecretKey|spring.cloud.nacos.config.secret-key||
相对路径|spring.cloud.nacos.config.context-path||服务端 API 的相对路径
接入点|spring.cloud.nacos.config.endpoint|UTF-8|地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
接入点|spring.cloud.nacos.config.endpoint||地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否开启监听和自动刷新|spring.cloud.nacos.config.refresh-enabled|true|
集群服务名|spring.cloud.nacos.config.cluster-name||

@ -3,6 +3,7 @@
## Project Instruction
This example illustrates how to use Nacos Config Starter implement externalized configuration for Spring Cloud applications.
Note: Applicable to spring boot version lower than 2.4.0
[Nacos](https://github.com/alibaba/Nacos) an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
@ -46,7 +47,7 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
2. Unzip the downloaded file and go to the nacos/bin folder(), And according to the actual situation of the operating system, execute the following command。[see reference for more detail](https://nacos.io/en-us/docs/quick-start.html)。
1. Linux/Unix/Mac , execute `sh startup.sh -m standalone`
2. Windows , execute `cmd startup.cmd`
2. Windows , execute `cmd startup.cmd -m standalone`
3. Execute the following command to add a configuration to Nacos Server.
@ -156,8 +157,8 @@ Spring Boot 1.x: Add configuration management.security.enabled=false
Spring Boot 2.x: Add configuration management.endpoints.web.exposure.include=*
To view the endpoint information, visit the following URLS:
Spring Boot1.x: Nacos Config Endpoint URL is http://127.0.0.1:18083/nacos_config.
Spring Boot2.x: Nacos Config Endpoint URL is http://127.0.0.1:18083/actuator/nacos-config.
Spring Boot 1.x: Nacos Config Endpoint URL is http://127.0.0.1:18084/nacos_config.
Spring Boot 2.x: Nacos Config Endpoint URL is http://127.0.0.1:18084/actuator/nacosconfig.
![actuator](https://cdn.nlark.com/lark/0/2018/png/54319/1536986344822-279e1edc-ebca-4201-8362-0ddeff240b85.png)
@ -169,8 +170,8 @@ As shown in the figure above, Sources indicates which Nacos Config configuration
Configuration item|key|default value|Description
----|----|-----|-----
server address|spring.cloud.nacos.config.server-addr||
DataId prefix|spring.cloud.nacos.config.prefix||spring.application.name
server address|spring.cloud.nacos.config.server-addr||server id and port
DataId prefix|spring.cloud.nacos.config.prefix||${spring.application.name}|
Group|spring.cloud.nacos.config.group|DEFAULT_GROUP|
dataID suffix|spring.cloud.nacos.config.file-extension|properties|the suffix of nacos config dataId, also the file extension of config content.
encoding |spring.cloud.nacos.config.encode|UTF-8|Content encoding
@ -179,8 +180,9 @@ namespace|spring.cloud.nacos.config.namespace||One of the common scenarios is th
AccessKey|spring.cloud.nacos.config.access-key||
SecretKey|spring.cloud.nacos.config.secret-key||
context-path|spring.cloud.nacos.config.context-path||Relative path of the server API
endpoint|spring.cloud.nacos.config.endpoint|UTF-8|The domain name of a service, through which the server address can be dynamically obtained.
endpoint|spring.cloud.nacos.config.endpoint||The domain name of a service, through which the server address can be dynamically obtained.
refresh|spring.cloud.nacos.config.refresh.enabled|true|enable auto refresh
cluster name|spring.cloud.nacos.config.cluster-name||

@ -34,5 +34,5 @@ spring.cloud.nacos.config.extension-configs[1].refresh= true
#spring.cloud.nacos.config.refresh-enabled=true
spring.cloud.nacos.config.refresh-enabled=true

@ -2,6 +2,7 @@ spring.application.name=service-consumer
server.port=18083
management.endpoints.web.exposure.include=*
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.fail-fast=true
spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

@ -77,8 +77,13 @@ public class ProviderApplication {
@GetMapping("/divide")
public String divide(@RequestParam Integer a, @RequestParam Integer b) {
if (b == 0) {
return String.valueOf(0);
}
else {
return String.valueOf(a / b);
}
}
@GetMapping("/zone")
public String zone() {

@ -1,6 +1,7 @@
server.port=18082
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
#spring.cloud.nacos.discovery.instance-enabled=true
spring.cloud.nacos.username=nacos
@ -8,3 +9,4 @@ spring.cloud.nacos.password=nacos
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

@ -6,7 +6,7 @@ spring:
username: nacos
password: nacos
discovery:
server-addr: localhost:8848
server-addr: 127.0.0.1:8848
config:
discovery:
enabled: true

@ -9,7 +9,7 @@ spring:
username: nacos
password: nacos
discovery:
server-addr: localhost:8848
server-addr: 127.0.0.1:8848
config:
server:
git:

@ -36,6 +36,7 @@
<module>seata-example/account-service</module>
<module>rocketmq-example/rocketmq-consume-example</module>
<module>rocketmq-example/rocketmq-produce-example</module>
<module>rocketmq-example/rocketmq-comprehensive-example</module>
<module>spring-cloud-bus-rocketmq-example</module>
<module>spring-cloud-alibaba-dubbo-examples</module>
<module>spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example</module>

@ -0,0 +1,52 @@
<?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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rocketmq-comprehensive-example</artifactId>
<name>Spring Cloud Starter Stream Alibaba RocketMQ Comprehensive Example</name>
<description>Example demonstrating how to use rocketmq to produce, process and consume</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,75 @@
/*
* Copyright 2013-2022 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 com.alibaba.cloud.examples;
import java.time.Duration;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.integration.support.StringObjectMapBuilder;
/**
* @author freeman
*/
@SpringBootApplication
public class RocketMQComprehensiveApplication {
private static final Logger log = LoggerFactory
.getLogger(RocketMQComprehensiveApplication.class);
public static void main(String[] args) {
SpringApplication.run(RocketMQComprehensiveApplication.class, args);
}
@Bean
public Supplier<Flux<User>> producer() {
return () -> Flux.interval(Duration.ofSeconds(2)).map(id -> {
User user = new User();
user.setId(id.toString());
user.setName("freeman");
user.setMeta(new StringObjectMapBuilder()
.put("hobbies", Arrays.asList("movies", "songs")).put("age", 21)
.get());
return user;
}).log();
}
@Bean
public Function<Flux<User>, Flux<User>> processor() {
return flux -> flux.map(user -> {
user.setId(String.valueOf(
Long.parseLong(user.getId()) * Long.parseLong(user.getId())));
user.setName("not freeman");
user.getMeta().put("hobbies", Arrays.asList("programming"));
return user;
});
}
@Bean
public Consumer<User> consumer() {
return num -> log.info(num.toString());
}
}

@ -0,0 +1,58 @@
/*
* Copyright 2013-2022 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 com.alibaba.cloud.examples;
import java.util.Map;
/**
* @author freeman
*/
public class User {
private String id;
private String name;
private Map<String, Object> meta;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, Object> getMeta() {
return meta;
}
public void setMeta(Map<String, Object> meta) {
this.meta = meta;
}
@Override
public String toString() {
return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", meta=" + meta
+ '}';
}
}

@ -0,0 +1,36 @@
server:
port: 28082
spring:
application:
name: rocketmq-comprehensive-example
cloud:
stream:
function:
definition: producer;consumer;processor
rocketmq:
binder:
name-server: 127.0.0.1:9876
bindings:
# TODO producer must have a group, need optimization !!!
producer-out-0:
producer:
group: output_1
processor-out-0:
producer:
group: output_2
bindings:
producer-out-0:
destination: num
processor-out-0:
destination: square
processor-in-0:
destination: num
group: processor_group
consumer-in-0:
destination: square
group: consumer_group
logging:
level:
org.springframework.context.support: debug

@ -3,20 +3,20 @@ spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
spring.cloud.stream.bindings.input1.destination=test-topic
spring.cloud.stream.bindings.input1.content-type=text/plain
spring.cloud.stream.bindings.input1.group=test-group1
spring.cloud.stream.rocketmq.bindings.input1.consumer.orderly=true
spring.cloud.stream.rocketmq.bindings.input1.consumer.push.orderly=true
spring.cloud.stream.bindings.input2.destination=test-topic
spring.cloud.stream.bindings.input2.content-type=text/plain
spring.cloud.stream.bindings.input2.group=test-group2
spring.cloud.stream.rocketmq.bindings.input2.consumer.orderly=false
spring.cloud.stream.rocketmq.bindings.input2.consumer.tags=tagStr
spring.cloud.stream.rocketmq.bindings.input2.consumer.push.orderly=false
spring.cloud.stream.rocketmq.bindings.input2.consumer.subscription=tagStr
spring.cloud.stream.bindings.input2.consumer.concurrency=20
spring.cloud.stream.bindings.input2.consumer.maxAttempts=1
spring.cloud.stream.bindings.input3.destination=test-topic
spring.cloud.stream.bindings.input3.content-type=application/json
spring.cloud.stream.bindings.input3.group=test-group3
spring.cloud.stream.rocketmq.bindings.input3.consumer.tags=tagObj
spring.cloud.stream.rocketmq.bindings.input3.consumer.subscription=tagObj
spring.cloud.stream.bindings.input3.consumer.concurrency=20
spring.cloud.stream.bindings.input4.destination=TransactionTopic

@ -20,8 +20,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.alibaba.cloud.examples.RocketMQProduceApplication.MySource;
import com.alibaba.cloud.stream.binder.rocketmq.constant.RocketMQConst;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
@ -62,7 +62,7 @@ public class SenderService {
MessageBuilder builder = MessageBuilder.withPayload(msg)
.setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
builder.setHeader("test", String.valueOf(num));
builder.setHeader(RocketMQHeaders.TAGS, "binder");
builder.setHeader(RocketMQConst.USER_TRANSACTIONAL_ARGS, "binder");
Message message = builder.build();
source.output2().send(message);
}

@ -16,43 +16,39 @@
package com.alibaba.cloud.examples;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
@RocketMQTransactionListener(txProducerGroup = "myTxProducerGroup", corePoolSize = 5,
maximumPoolSize = 10)
public class TransactionListenerImpl implements RocketMQLocalTransactionListener {
@Component("myTransactionListener")
public class TransactionListenerImpl implements TransactionListener {
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg,
Object arg) {
Object num = msg.getHeaders().get("test");
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Object num = msg.getProperty("test");
if ("1".equals(num)) {
System.out.println(
"executer: " + new String((byte[]) msg.getPayload()) + " unknown");
return RocketMQLocalTransactionState.UNKNOWN;
System.out.println("executer: " + new String(msg.getBody()) + " unknown");
return LocalTransactionState.UNKNOW;
}
else if ("2".equals(num)) {
System.out.println(
"executer: " + new String((byte[]) msg.getPayload()) + " rollback");
return RocketMQLocalTransactionState.ROLLBACK;
System.out.println("executer: " + new String(msg.getBody()) + " rollback");
return LocalTransactionState.ROLLBACK_MESSAGE;
}
System.out.println(
"executer: " + new String((byte[]) msg.getPayload()) + " commit");
return RocketMQLocalTransactionState.COMMIT;
System.out.println("executer: " + new String(msg.getBody()) + " commit");
return LocalTransactionState.COMMIT_MESSAGE;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
System.out.println("check: " + new String((byte[]) msg.getPayload()));
return RocketMQLocalTransactionState.COMMIT;
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
System.out.println("check: " + new String(msg.getBody()));
return LocalTransactionState.COMMIT_MESSAGE;
}
}

@ -9,8 +9,9 @@ spring.cloud.stream.rocketmq.bindings.output1.producer.sync=true
spring.cloud.stream.bindings.output2.destination=TransactionTopic
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.producerType=Trans
spring.cloud.stream.rocketmq.bindings.output2.producer.group=myTxProducerGroup
spring.cloud.stream.rocketmq.bindings.output2.producer.transactionListener=myTransactionListener
spring.cloud.stream.bindings.output3.destination=pull-topic
spring.cloud.stream.bindings.output3.content-type=text/plain

@ -1,6 +1,6 @@
spring.application.name=account-service
server.port=18084
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.datasource.name="accountDataSource"
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

@ -1,6 +1,6 @@
server.port=18081
spring.application.name=business-service
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
# The following configuration can be omitted.
#feign.hystrix.enabled=true

@ -1,6 +1,6 @@
spring.application.name=order-service
server.port=18083
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.datasource.name="orderDataSource"
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

@ -1,6 +1,6 @@
spring.application.name=storage-service
server.port=18082
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.datasource.name="storageDataSource"
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

@ -18,10 +18,6 @@
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@ -29,17 +25,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>3.0.4</version> <!-- version >= 3.0.4 -->
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>

@ -6,30 +6,9 @@ OpenFeign 整合 Sentinel 断路器实现
## 示例
1. 添加依赖
```xml
<!-- spring cloud alibaba 2021.0 暂时使用 spring cloud 2020.0.1 -->
<!-- 如果需要支持 Feign client 的配置, 需要升级 spring-cloud-openfeign-core 到 3.0.4 -->
<!-- 或者升级 spring cloud 到 2020.0.4 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>3.0.4</version> <!-- version >= 3.0.4 -->
</dependency>
```
2. 添加配置到配置中心
1. 添加配置到配置中心
dataId 为 `sentinel-circuitbreaker-rules.yml`
```yaml
feign:
circuitbreaker:
@ -61,6 +40,8 @@ feign:
minRequestAmount: 1
```
2. 启动 FeignCircuitBreakerApplication
## 验证配置生效
启动项目
@ -69,8 +50,8 @@ feign:
再访问 http://localhost/test/default/true 断路器处于打开状态
验证指定 feign client 生效
先访问 http://localhost/test/feign/true 2 次
再访问 http://localhost/test/feign/false 断路器处于打开状态
先访问 http://localhost/test/feign/false 2 次
再访问 http://localhost/test/feign/true 断路器处于打开状态
验证 feign client 指定方法生效
先访问 http://localhost/test/feignMethod/false 2次

@ -0,0 +1,60 @@
# Sentinel Feign Circuit Breaker Example
## Project description
OpenFeign integrates Sentinel circuit breaker implementation
## sample
1. add configuration to config center
```yaml
feign:
circuitbreaker:
enabled: true # Enable feign circuit breaker support
sentinel:
default-rule: default # Default rule name
rules:
# Default rule, valid for all feign clients
default:
- grade: 2 # Downgrade based on number of exceptions
count: 1
timeWindow: 15 # Time to half-open state after downgrade
statIntervalMs: 1000
minRequestAmount: 1
# Only valid for feign client user
user:
- grade: 2
count: 1
timeWindow: 15
statIntervalMs: 1000
minRequestAmount: 1
# Only valid for the method feignMethod of the feign client user
# Parentheses are parameter types, separated by multiple commas, such as user#method(boolean,String,Map)
"[user#feignMethod(boolean)]":
- grade: 2
count: 1
timeWindow: 10
statIntervalMs: 1000
minRequestAmount: 1
```
2. start FeignCircuitBreakerApplication
## Verify
Startup project
Verify that the default feign client takes effect.
First visit http:localhost/test/default/false 2 times
and then visit http:localhost/test/default/true, the circuit breaker is open
Verify that the specified feign client takes effect.
First visit http:localhost/test/feign/false 2 times
and then visit http:localhost/test/feign/true, the circuit breaker is open
Verify that the specified method of feign client takes effect.
First visit http://localhost/test/feignMethod/false 2 times
and then visit http://localhost/test/feignMethod/true, the circuit breaker is open
## Rules are dynamically refreshed
Modify the rules of the configuration center, and then access the above interface

@ -0,0 +1,11 @@
server:
port: 80
spring:
application:
name: circuit-breaker-app
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
config:
import: optional:nacos:sentinel-circuitbreaker-rules.yml

@ -1,11 +0,0 @@
server:
port: 80
spring:
application:
name: circuit-breaker-app
cloud:
nacos:
config:
server-addr: localhost:8848
name: sentinel-circuitbreaker-rules.yml
file-extension: yml

@ -65,7 +65,7 @@
1. 首先需要获取 Sentinel 控制台,支持直接下载和源码构建两种方式。
1. 直接下载:[下载 Sentinel 控制台](http://edas-public.oss-cn-hangzhou.aliyuncs.com/install_package/demo/sentinel-dashboard.jar)
1. 直接下载:[下载 Sentinel 控制台](https://edas-public.oss-cn-hangzhou.aliyuncs.com/install_package/demo/sentinel-dashboard.jar)
2. 源码构建:进入 Sentinel [Github 项目页面](https://github.com/alibaba/Sentinel),将代码 git clone 到本地自行编译打包,[参考此文档](https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard)。
2. 启动控制台,执行 Java 命令 `java -jar sentinel-dashboard.jar`完成 Sentinel 控制台的启动。
@ -206,7 +206,7 @@ Sentinel starter 整合了目前存在的几类 ReadableDataSource。只需要
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json

@ -181,7 +181,7 @@ If you want to define `FileRefreshableDataSource` and `NacosDataSource`, see the
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848
spring.cloud.sentinel.datasource.ds2.nacos.dataId=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.groupId=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json

@ -73,7 +73,7 @@ Provider端在application.properties文件中定义dubbo相关的配置比如
定义具体的服务:
@Service(
@DubboService(
version = "${foo.service.version}",
application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}",
@ -111,7 +111,7 @@ Consumer端在服务调用之前先定义限流规则。
根据Provider端中发布的定义使用Dubbo的@Reference注解注入服务对应的Bean
@Reference(version = "${foo.service.version}", application = "${dubbo.application.id}",
@DubboReference(version = "${foo.service.version}", application = "${dubbo.application.id}",
path = "dubbo://localhost:12345", timeout = 30000)
private FooService fooService;

@ -16,14 +16,14 @@
package com.alibaba.cloud.examples;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.DubboReference;
/**
* @author fangjian
*/
public class FooServiceConsumer {
@Reference(version = "${foo.service.version}",
@DubboReference(version = "${foo.service.version}",
application = "${dubbo.application.id}",
url = "dubbo://localhost:12345?version=1.0.0", timeout = 30000)
private FooService fooService;

@ -16,12 +16,12 @@
package com.alibaba.cloud.examples;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.config.annotation.DubboService;
/**
* @author fangjian
*/
@Service(version = "${foo.service.version}", application = "${dubbo.application.id}",
@DubboService(version = "${foo.service.version}", application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}", registry = "${dubbo.registry.id}")
public class FooServiceImpl implements FooService {

@ -16,19 +16,17 @@
在启动示例进行演示之前,我们先了解一下 Feign 如何接入 Sentinel。
**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。**
1. 首先,修改 pom.xml 文件,引入 Sentinel starter 和 Dubbo starter。
1. 首先,修改 pom.xml 文件,引入 Sentinel starter 和 Openfeign starter。
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
```
2. 其次, 使用nacos 注册中心
@ -114,6 +112,8 @@ public class EchoController {
- 启动nacos 注册中心
- 启动sentinel
- 启动服务提供方:
1. IDE直接启动找到主类 `ProviderApplication`,执行 main 方法启动应用。
@ -123,3 +123,5 @@ public class EchoController {
1. IDE直接启动找到主类 `ConsumerApplication`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-feign-consumer-example.jar`启动应用。
- 启动之后Sentinel Dashboard可能看不见service-consumer服务的详细信息多请求几次接口即可。

@ -16,7 +16,7 @@ Service consumer
Before launching the example, let's see how Feign can access Sentinel.
** note that this section is for your convenience only. The access has been completed in this sample code and you do not need to modify it. * *
First, modify the pom.xml file to introduce Sentinel starter and Dubbo starter.
First, modify the pom.xml file to introduce Sentinel starter and Openfeign starter.
```xml
<dependency>

@ -17,14 +17,16 @@
package com.alibaba.cloud.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @author lengleng
*/
@EnableFeignClients
@SpringCloudApplication
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
public static void main(String[] args) {

@ -8,6 +8,9 @@ spring:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
dashboard: 127.0.0.1:8081
feign:
sentinel:

@ -10,7 +10,6 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-client-sample</artifactId>
<name>Spring Cloud Dubbo Client Sample</name>

@ -12,7 +12,11 @@ spring:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
username: nacos
password: nacos
discovery:
server-addr: 127.0.0.1:8848
namespace: public
server:
port: 8080

@ -47,7 +47,6 @@ import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
@ -247,7 +246,7 @@ public class DubboSpringCloudConsumerBootstrap {
@PostMapping("/params")
String params(@RequestParam("b") String paramB, @RequestParam("a") int paramA);
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_UTF8_VALUE)
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_VALUE)
User requestBody(@RequestParam("param") String param,
@RequestBody Map<String, Object> data);

@ -85,7 +85,7 @@ public class SpringRestService implements RestService {
@Override
@PostMapping(value = "/request/body/map",
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
produces = MediaType.APPLICATION_JSON_VALUE)
public User requestBodyMap(@RequestBody Map<String, Object> data,
@RequestParam("param") String param) {
User user = new User();
@ -97,7 +97,7 @@ public class SpringRestService implements RestService {
}
@PostMapping(value = "/request/body/user",
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
consumes = MediaType.APPLICATION_JSON_VALUE)
@Override
public Map<String, Object> requestBodyUser(@RequestBody User user) {
Map<String, Object> map = new HashMap<>();

@ -1,4 +1,6 @@
dubbo:
cloud:
subscribed-services: ${spring.application.name}
scan:
base-packages: com.alibaba.cloud.dubbo.bootstrap
protocol:

@ -33,7 +33,7 @@ public class UserRemoteApplicationEvent extends RemoteApplicationEvent {
public UserRemoteApplicationEvent(Object source, User user, String originService,
String destinationService) {
super(source, originService, destinationService);
super(source, originService, DEFAULT_DESTINATION_FACTORY.getDestination(originService));
this.user = user;
}

@ -27,12 +27,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
@ -105,32 +99,6 @@
<optional>true</optional>
</dependency>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

@ -19,6 +19,7 @@ package com.alibaba.cloud.sentinel.datasource;
import java.util.Arrays;
import java.util.Optional;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.sentinel.datasource.config.AbstractDataSourceProperties;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
@ -27,8 +28,6 @@ import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import org.springframework.util.StringUtils;
/**
* Enum for {@link AbstractRule} class, using in
* {@link AbstractDataSourceProperties#ruleType}.

@ -16,9 +16,9 @@
package com.alibaba.cloud.sentinel.datasource.config;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.sentinel.datasource.factorybean.ConsulDataSourceFactoryBean;
import org.springframework.util.StringUtils;
/**
* Consul Properties class Using by {@link DataSourcePropertiesConfiguration} and

@ -132,7 +132,6 @@ public class DataSourcePropertiesConfiguration {
if (!ObjectUtils.isEmpty(field.get(this))) {
return field.getName();
}
return null;
}
catch (IllegalAccessException e) {
// won't happen

@ -18,10 +18,9 @@ package com.alibaba.cloud.sentinel.datasource.config;
import javax.validation.constraints.NotEmpty;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
import org.springframework.util.StringUtils;
/**
* Nacos Properties class Using by {@link DataSourcePropertiesConfiguration} and
* {@link NacosDataSourceFactoryBean}.
@ -32,6 +31,8 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
private String serverAddr;
private String contextPath;
private String username;
private String password;
@ -59,7 +60,7 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
if (StringUtils.isEmpty(serverAddr)) {
serverAddr = this.getEnv().getProperty(
"spring.cloud.sentinel.datasource.nacos.server-addr",
"localhost:8848");
"127.0.0.1:8848");
}
}
@ -71,6 +72,14 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
this.serverAddr = serverAddr;
}
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getUsername() {
return username;
}

@ -19,9 +19,9 @@ package com.alibaba.cloud.sentinel.datasource.config;
import java.time.Duration;
import java.util.List;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.sentinel.datasource.factorybean.RedisDataSourceFactoryBean;
import org.springframework.util.StringUtils;
/**
* Redis Properties class Using by {@link DataSourcePropertiesConfiguration} and

@ -16,9 +16,9 @@
package com.alibaba.cloud.sentinel.datasource.config;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
import org.springframework.util.StringUtils;
/**
* Zookeeper Properties class Using by {@link DataSourcePropertiesConfiguration} and

@ -24,6 +24,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
@ -35,8 +36,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* Convert sentinel rules for json or xml array Using strict mode to parse json or xml.
*
@ -86,9 +85,8 @@ public abstract class SentinelConverter<T extends Object>
});
for (Object obj : sourceArray) {
String item = null;
try {
item = objectMapper.writeValueAsString(obj);
String item = objectMapper.writeValueAsString(obj);
Optional.ofNullable(convertRule(item))
.ifPresent(convertRule -> ruleCollection.add(convertRule));
}

@ -18,12 +18,12 @@ package com.alibaba.cloud.sentinel.datasource.factorybean;
import java.util.Properties;
import com.alibaba.cloud.commons.lang.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;
/**
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
@ -35,6 +35,8 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
private String serverAddr;
private String contextPath;
private String username;
private String password;
@ -60,9 +62,17 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr);
}
else {
properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
}
if (!StringUtils.isEmpty(this.contextPath)) {
properties.setProperty(PropertyKeyConst.CONTEXT_PATH, this.contextPath);
}
if (!StringUtils.isEmpty(this.accessKey)) {
properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey);
}
if (!StringUtils.isEmpty(this.secretKey)) {
properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey);
properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
}
if (!StringUtils.isEmpty(this.namespace)) {
properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace);
@ -89,6 +99,14 @@ public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource>
this.serverAddr = serverAddr;
}
public String getContextPath() {
return contextPath;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getUsername() {
return username;
}

@ -37,7 +37,9 @@ public class NacosDataSourceFactoryBeanTests {
private String groupId = "DEFAULT_GROUP";
private String serverAddr = "localhost:8848";
private String serverAddr = "127.0.0.1:8848";
private String contextPath = "/my-nacos";
private String accessKey = "ak";
@ -56,6 +58,7 @@ public class NacosDataSourceFactoryBeanTests {
factoryBean.setDataId(dataId);
factoryBean.setGroupId(groupId);
factoryBean.setServerAddr(serverAddr);
factoryBean.setContextPath(contextPath);
factoryBean.setConverter(converter);
NacosDataSource nacosDataSource = mock(NacosDataSource.class);
@ -69,6 +72,7 @@ public class NacosDataSourceFactoryBeanTests {
assertThat(factoryBean.getDataId()).isEqualTo(dataId);
assertThat(factoryBean.getGroupId()).isEqualTo(groupId);
assertThat(factoryBean.getServerAddr()).isEqualTo(serverAddr);
assertThat(factoryBean.getContextPath()).isEqualTo(contextPath);
}
@Test

@ -31,11 +31,13 @@ public class NacosDataSourcePropertiesTests {
public void testNacosWithAddr() {
NacosDataSourceProperties nacosDataSourceProperties = new NacosDataSourceProperties();
nacosDataSourceProperties.setServerAddr("127.0.0.1:8848");
nacosDataSourceProperties.setContextPath("/my-nacos");
nacosDataSourceProperties.setRuleType(RuleType.FLOW);
nacosDataSourceProperties.setDataId("sentinel");
nacosDataSourceProperties.setGroupId("custom-group");
nacosDataSourceProperties.setDataType("xml");
assertThat(nacosDataSourceProperties.getContextPath()).isEqualTo("/my-nacos");
assertThat(nacosDataSourceProperties.getGroupId()).isEqualTo("custom-group");
assertThat(nacosDataSourceProperties.getDataId()).isEqualTo("sentinel");
assertThat(nacosDataSourceProperties.getDataType()).isEqualTo("xml");

@ -17,6 +17,7 @@
package com.alibaba.cloud.sentinel.datasource;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import com.alibaba.cloud.commons.io.FileUtils;
@ -107,7 +108,7 @@ public class SentinelConverterTests {
private String readFileContent(String file) {
try {
return FileUtils.readFileToString(
ResourceUtils.getFile(StringUtils.trimAllWhitespace(file)));
ResourceUtils.getFile(StringUtils.trimAllWhitespace(file)), Charset.defaultCharset());
}
catch (IOException e) {
return "";

@ -109,7 +109,7 @@ public class SentinelGatewayAutoConfiguration {
ApiPredicateGroupItem.class);
SimpleModule module = new SimpleModule(
"PolymorphicApiPredicateItemDeserializerModule",
new Version(1, 0, 0, null));
new Version(1, 0, 0, null, null, null));
module.addDeserializer(ApiPredicateItem.class, deserializer);
objectMapper.registerModule(module);
}
@ -142,7 +142,7 @@ public class SentinelGatewayAutoConfiguration {
ApiPredicateGroupItem.class);
SimpleModule module = new SimpleModule(
"PolymorphicGatewayDeserializerModule",
new Version(1, 0, 0, null));
new Version(1, 0, 0, null, null, null));
module.addDeserializer(ApiPredicateItem.class, deserializer);
xmlMapper.registerModule(module);
}

@ -50,19 +50,11 @@
<optional>true</optional>
</dependency>
<!-- support Feign client configuration start -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<version>3.0.4</version> <!-- need greater than 3.0.4, support CircuitBreakerNameResolver -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<optional>true</optional>
</dependency>
<!-- support Feign client configuration end -->
<!-- datasource rules -->
<dependency>
@ -101,23 +93,6 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
</exclusion>
<exclusion>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -30,6 +30,9 @@ import com.alibaba.cloud.circuitbreaker.sentinel.SentinelConfigBuilder;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -47,6 +50,7 @@ import org.springframework.core.annotation.AnnotationUtils;
* Sentinel circuit breaker config change listener.
*
* @author freeman
* @since 2021.0.1.0
*/
public class CircuitBreakerRuleChangeListener implements ApplicationContextAware,
ApplicationListener<RefreshScopeRefreshedEvent>, SmartInitializingSingleton {
@ -79,7 +83,8 @@ public class CircuitBreakerRuleChangeListener implements ApplicationContextAware
updateBackup();
LOGGER.info("sentinel circuit beaker rules refreshed.");
LOGGER.info("Sentinel circuit beaker rules refreshed: \n"
+ prettyPrint(properties.getRules()));
}
@Override
@ -170,6 +175,17 @@ public class CircuitBreakerRuleChangeListener implements ApplicationContextAware
this.propertiesBackup = this.properties.copy();
}
private String prettyPrint(Object o) {
try {
return new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)
.writeValueAsString(o);
}
catch (JsonProcessingException e) {
LOGGER.error("JSON serialization err.", e);
return "__JSON format err__";
}
}
// static method
public static void configureCustom(SentinelFeignClientProperties properties,

@ -30,10 +30,8 @@ import static com.alibaba.cloud.circuitbreaker.sentinel.feign.CircuitBreakerRule
/**
* Feign client circuit breaker name resolver.
*
* <p>
* <strong>note:</strong> spring cloud openfeign version need greater than 3.0.4.
*
* @author freeman
* @since 2021.0.1.0
* @see CircuitBreakerNameResolver
*/
public class FeignClientCircuitNameResolver implements CircuitBreakerNameResolver {

@ -42,6 +42,7 @@ import static com.alibaba.cloud.circuitbreaker.sentinel.feign.CircuitBreakerRule
* Auto configuration for feign client circuit breaker rules.
*
* @author freeman
* @since 2021.0.1.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Feign.class, FeignClientFactoryBean.class })
@ -50,7 +51,7 @@ import static com.alibaba.cloud.circuitbreaker.sentinel.feign.CircuitBreakerRule
public class SentinelFeignClientAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "feign.sentinel.refresh-rules", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(name = "feign.sentinel.enable-refresh-rules", havingValue = "true", matchIfMissing = true)
public static class CircuitBreakerListenerConfiguration {
@Bean
@ -61,7 +62,6 @@ public class SentinelFeignClientAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CircuitBreakerNameResolver.class)
public static class CircuitBreakerNameResolverConfiguration {
@Bean

@ -32,6 +32,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* Sentinel feign client properties.
*
* @author freeman
* @since 2021.0.1.0
*/
@ConfigurationProperties("feign.sentinel")
public class SentinelFeignClientProperties {
@ -44,7 +45,7 @@ public class SentinelFeignClientProperties {
/**
* enable refresh circuit breaker rules from config center.
*/
private boolean refreshRules = true;
private boolean enableRefreshRules = true;
private Map<String, List<DegradeRule>> rules = new HashMap<>();
@ -56,12 +57,12 @@ public class SentinelFeignClientProperties {
this.defaultRule = defaultRule;
}
public boolean isRefreshRules() {
return refreshRules;
public boolean isEnableRefreshRules() {
return enableRefreshRules;
}
public void setRefreshRules(boolean refreshRules) {
this.refreshRules = refreshRules;
public void setEnableRefreshRules(boolean enableRefreshRules) {
this.enableRefreshRules = enableRefreshRules;
}
public Map<String, List<DegradeRule>> getRules() {
@ -81,14 +82,14 @@ public class SentinelFeignClientProperties {
return false;
}
SentinelFeignClientProperties that = (SentinelFeignClientProperties) o;
return refreshRules == that.refreshRules
return enableRefreshRules == that.enableRefreshRules
&& Objects.equals(defaultRule, that.defaultRule)
&& Objects.equals(rules, that.rules);
}
@Override
public int hashCode() {
return Objects.hash(defaultRule, refreshRules, rules);
return Objects.hash(defaultRule, enableRefreshRules, rules);
}
public SentinelFeignClientProperties copy() {

@ -44,15 +44,15 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import static com.alibaba.cloud.circuitbreaker.sentinel.ReactiveSentinelCircuitBreakerIntegrationTest.Application;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT,
classes = ReactiveSentinelCircuitBreakerIntegrationTest.Application.class,
properties = { "spring.cloud.discovery.client.health-indicator.enabled=false" })
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = Application.class, properties = {
"spring.cloud.discovery.client.health-indicator.enabled=false" })
@DirtiesContext
public class ReactiveSentinelCircuitBreakerIntegrationTest {
@ -60,7 +60,7 @@ public class ReactiveSentinelCircuitBreakerIntegrationTest {
private int port = 0;
@Autowired
private ReactiveSentinelCircuitBreakerIntegrationTest.Application.DemoControllerService service;
private Application.DemoControllerService service;
@Before
public void setup() {

@ -43,17 +43,17 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"feign.sentinel.rules.default[0].grade=2",
"feign.sentinel.rules.default[0].count=2",
"feign.sentinel.rules.default[0].timeWindow=2",
"feign.sentinel.rules.default[0].statIntervalMs=1000",
"feign.sentinel.rules.default[0].statIntervalMs=30000",
"feign.sentinel.rules.default[0].minRequestAmount=5",
"feign.sentinel.rules.user[0].grade=2",
"feign.sentinel.rules.user[0].count=2",
"feign.sentinel.rules.user[0].timeWindow=2",
"feign.sentinel.rules.user[0].statIntervalMs=1000",
"feign.sentinel.rules.user[0].statIntervalMs=30000",
"feign.sentinel.rules.user[0].minRequestAmount=5",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].grade=2",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].count=1",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].timeWindow=2",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].statIntervalMs=1000",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].statIntervalMs=30000",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].minRequestAmount=5"
})
public class FeignClientCircuitBreakerRuleIntegrationTest {
@ -87,7 +87,7 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(orderClient.defaultConfig(true)).isEqualTo("fallback");
// longer than timeWindow, circuit breaker half open
Thread.sleep(2100L);
Thread.sleep(2500L);
// let circuit breaker close
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
@ -118,7 +118,7 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(userClient.specificFeign(true)).isEqualTo("fallback");
// longer than timeWindow, circuit breaker half open
Thread.sleep(2100L);
Thread.sleep(2500L);
// let circuit breaker close
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
@ -150,7 +150,7 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(userClient.specificFeignMethod(true)).isEqualTo("fallback");
// longer than timeWindow, circuit breaker half open
Thread.sleep(2100L);
Thread.sleep(2500L);
// let circuit breaker close
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");

@ -26,13 +26,6 @@
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
@ -54,6 +47,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

@ -13,12 +13,9 @@
<name>Spring Cloud Starter Alibaba Nacos Config</name>
<dependencies>
<!--spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<optional>true</optional>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-commons</artifactId>
</dependency>
<dependency>
@ -33,30 +30,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>

@ -18,7 +18,6 @@ package com.alibaba.cloud.nacos;
import com.alibaba.cloud.nacos.refresh.NacosContextRefresher;
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
import com.alibaba.cloud.nacos.refresh.NacosRefreshProperties;
import com.alibaba.cloud.nacos.refresh.SmartConfigurationPropertiesRebinder;
import org.springframework.beans.factory.BeanFactoryUtils;
@ -51,11 +50,6 @@ public class NacosConfigAutoConfiguration {
return new NacosConfigProperties();
}
@Bean
public NacosRefreshProperties nacosRefreshProperties() {
return new NacosRefreshProperties();
}
@Bean
public NacosRefreshHistory nacosRefreshHistory() {
return new NacosRefreshHistory();

@ -29,6 +29,7 @@ import java.util.stream.Stream;
import javax.annotation.PostConstruct;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.spring.util.PropertySourcesUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
@ -40,7 +41,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
@ -53,6 +53,7 @@ import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT;
import static com.alibaba.nacos.api.PropertyKeyConst.MAX_RETRY;
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD;
import static com.alibaba.nacos.api.PropertyKeyConst.RAM_ROLE_NAME;
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME;
@ -106,7 +107,7 @@ public class NacosConfigProperties {
.resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}");
if (StringUtils.isEmpty(serverAddr)) {
serverAddr = environment.resolvePlaceholders(
"${spring.cloud.nacos.server-addr:localhost:8848}");
"${spring.cloud.nacos.server-addr:127.0.0.1:8848}");
}
this.setServerAddr(serverAddr);
}
@ -205,6 +206,11 @@ public class NacosConfigProperties {
*/
private String secretKey;
/**
* access key for namespace.
*/
private String ramRoleName;
/**
* context path for nacos config server.
*/
@ -359,6 +365,14 @@ public class NacosConfigProperties {
this.secretKey = secretKey;
}
public String getRamRoleName() {
return ramRoleName;
}
public void setRamRoleName(String ramRoleName) {
this.ramRoleName = ramRoleName;
}
public String getEncode() {
return encode;
}
@ -428,12 +442,12 @@ public class NacosConfigProperties {
* @return string
*/
@Deprecated
@DeprecatedConfigurationProperty(
reason = "replaced to NacosConfigProperties#sharedConfigs and not use it at the same time.",
replacement = PREFIX + ".shared-configs[x]")
@DeprecatedConfigurationProperty(reason = "replaced to NacosConfigProperties#sharedConfigs and not use it at the same time.", replacement = PREFIX
+ ".shared-configs[x]")
public String getSharedDataids() {
return null == getSharedConfigs() ? null : getSharedConfigs().stream()
.map(Config::getDataId).collect(Collectors.joining(COMMAS));
return null == getSharedConfigs() ? null
: getSharedConfigs().stream().map(Config::getDataId)
.collect(Collectors.joining(COMMAS));
}
/**
@ -458,9 +472,8 @@ public class NacosConfigProperties {
* @return string
*/
@Deprecated
@DeprecatedConfigurationProperty(
reason = "replaced to NacosConfigProperties#sharedConfigs and not use it at the same time.",
replacement = PREFIX + ".shared-configs[x].refresh")
@DeprecatedConfigurationProperty(reason = "replaced to NacosConfigProperties#sharedConfigs and not use it at the same time.", replacement = PREFIX
+ ".shared-configs[x].refresh")
public String getRefreshableDataids() {
return null == getSharedConfigs() ? null
: getSharedConfigs().stream().filter(Config::isRefresh)
@ -506,9 +519,8 @@ public class NacosConfigProperties {
* @return extensionConfigs
*/
@Deprecated
@DeprecatedConfigurationProperty(
reason = "replaced to NacosConfigProperties#extensionConfigs and not use it at the same time .",
replacement = PREFIX + ".extension-configs[x]")
@DeprecatedConfigurationProperty(reason = "replaced to NacosConfigProperties#extensionConfigs and not use it at the same time .", replacement = PREFIX
+ ".extension-configs[x]")
public List<Config> getExtConfig() {
return this.getExtensionConfigs();
}
@ -551,6 +563,7 @@ public class NacosConfigProperties {
properties.put(NAMESPACE, Objects.toString(this.namespace, ""));
properties.put(ACCESS_KEY, Objects.toString(this.accessKey, ""));
properties.put(SECRET_KEY, Objects.toString(this.secretKey, ""));
properties.put(RAM_ROLE_NAME, Objects.toString(this.ramRoleName, ""));
properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
properties.put(MAX_RETRY, Objects.toString(this.maxRetry, ""));
properties.put(CONFIG_LONG_POLL_TIMEOUT,
@ -603,10 +616,10 @@ public class NacosConfigProperties {
+ ", enableRemoteSyncConfig=" + enableRemoteSyncConfig + ", endpoint='"
+ endpoint + '\'' + ", namespace='" + namespace + '\'' + ", accessKey='"
+ accessKey + '\'' + ", secretKey='" + secretKey + '\''
+ ", contextPath='" + contextPath + '\'' + ", clusterName='" + clusterName
+ '\'' + ", name='" + name + '\'' + '\'' + ", shares=" + sharedConfigs
+ ", extensions=" + extensionConfigs + ", refreshEnabled="
+ refreshEnabled + '}';
+ ", ramRoleName='" + ramRoleName + '\'' + ", contextPath='" + contextPath
+ '\'' + ", clusterName='" + clusterName + '\'' + ", name='" + name + '\''
+ '\'' + ", shares=" + sharedConfigs + ", extensions=" + extensionConfigs
+ ", refreshEnabled=" + refreshEnabled + '}';
}
public static class Config {

@ -16,8 +16,10 @@
package com.alibaba.cloud.nacos.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -80,12 +82,36 @@ public class NacosPropertySource extends MapPropertySource {
return (Map<String, Object>) propertySource.getSource();
}
}
// If it is multiple, it will be returned as it is, and the internal elements
// cannot be directly retrieved, so the user needs to implement the retrieval
// logic by himself
return Collections.singletonMap(
String.join(NacosConfigProperties.COMMAS, dataId, group),
propertySources);
Map<String, Object> sourceMap = new LinkedHashMap<>();
List<PropertySource<?>> otherTypePropertySources = new ArrayList<>();
for (PropertySource<?> propertySource : propertySources) {
if (propertySource == null) {
continue;
}
if (propertySource instanceof MapPropertySource) {
// If the Nacos configuration file uses "---" to separate property name,
// propertySources will be multiple documents, and every document is a
// map.
// see org.springframework.boot.env.YamlPropertySourceLoader#load
MapPropertySource mapPropertySource = (MapPropertySource) propertySource;
Map<String, Object> source = mapPropertySource.getSource();
sourceMap.putAll(source);
}
else {
otherTypePropertySources.add(propertySource);
}
}
// Other property sources which is not instanceof MapPropertySource will be put as
// it is,
// and the internal elements cannot be directly retrieved,
// so the user needs to implement the retrieval logic by himself
if (!otherTypePropertySources.isEmpty()) {
sourceMap.put(String.join(NacosConfigProperties.COMMAS, dataId, group),
otherTypePropertySources);
}
return sourceMap;
}
public String getGroup() {

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
import com.alibaba.cloud.nacos.parser.NacosDataParserHandler;
import com.alibaba.nacos.api.config.ConfigService;
@ -28,7 +29,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
/**
* @author xiaojing

@ -18,6 +18,7 @@ package com.alibaba.cloud.nacos.client;
import java.util.List;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
@ -33,7 +34,6 @@ import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* @author xiaojing

@ -36,6 +36,8 @@ import org.springframework.boot.context.config.ConfigDataResourceNotFoundExcepti
import org.springframework.core.env.PropertySource;
import static com.alibaba.cloud.nacos.configdata.NacosConfigDataResource.NacosItemConfig;
import static org.springframework.boot.context.config.ConfigData.Option.IGNORE_IMPORTS;
import static org.springframework.boot.context.config.ConfigData.Option.IGNORE_PROFILES;
/**
* Implementation of {@link ConfigDataLoader}.
@ -44,6 +46,7 @@ import static com.alibaba.cloud.nacos.configdata.NacosConfigDataResource.NacosIt
* Load {@link ConfigData} via {@link NacosConfigDataResource}
*
* @author freeman
* @since 2021.0.1.0
*/
public class NacosConfigDataLoader implements ConfigDataLoader<NacosConfigDataResource> {
@ -79,9 +82,7 @@ public class NacosConfigDataLoader implements ConfigDataLoader<NacosConfigDataRe
NacosPropertySourceRepository.collectNacosPropertySource(propertySource);
// TODO Currently based on 2.4.2,
// compatibility needs to be done when upgrading to boot version 2.4.5
return new ConfigData(propertySources);
return new ConfigData(propertySources, IGNORE_IMPORTS, IGNORE_PROFILES);
}
catch (Exception e) {
if (log.isDebugEnabled()) {

@ -24,9 +24,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.common.utils.StringUtils;
import org.apache.commons.logging.Log;
import org.springframework.boot.BootstrapRegistry.InstanceSupplier;
@ -50,6 +50,7 @@ import static com.alibaba.cloud.nacos.configdata.NacosConfigDataResource.NacosIt
* {@link ConfigDataResource}.
*
* @author freeman
* @since 2021.0.1.0
*/
public class NacosConfigDataLocationResolver
implements ConfigDataLocationResolver<NacosConfigDataResource>, Ordered {

@ -0,0 +1,89 @@
/*
* Copyright 2015-2022 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 com.alibaba.cloud.nacos.configdata;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
import org.springframework.cloud.commons.ConfigDataMissingEnvironmentPostProcessor;
import org.springframework.core.env.Environment;
import static com.alibaba.cloud.nacos.configdata.NacosConfigDataLocationResolver.PREFIX;
import static org.springframework.cloud.util.PropertyUtils.bootstrapEnabled;
import static org.springframework.cloud.util.PropertyUtils.useLegacyProcessing;
/**
*
* @author freeman
* @since 2021.0.1.0
*/
public class NacosConfigDataMissingEnvironmentPostProcessor
extends ConfigDataMissingEnvironmentPostProcessor {
/**
* after {@link ConfigDataEnvironmentPostProcessor}.
*/
public static final int ORDER = ConfigDataEnvironmentPostProcessor.ORDER + 1000;
@Override
public int getOrder() {
return ORDER;
}
@Override
protected boolean shouldProcessEnvironment(Environment environment) {
// don't run if using bootstrap or legacy processing
if (bootstrapEnabled(environment) || useLegacyProcessing(environment)) {
return false;
}
boolean configEnabled = environment.getProperty(
NacosConfigProperties.PREFIX + ".enabled", Boolean.class, true);
boolean importCheckEnabled = environment.getProperty(
NacosConfigProperties.PREFIX + ".import-check.enabled", Boolean.class,
true);
return configEnabled && importCheckEnabled;
}
@Override
protected String getPrefix() {
return PREFIX;
}
static class ImportExceptionFailureAnalyzer
extends AbstractFailureAnalyzer<ImportException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure, ImportException cause) {
String description;
if (cause.missingPrefix) {
description = "The spring.config.import property is missing a " + PREFIX
+ " entry";
}
else {
description = "No spring.config.import property has been defined";
}
String action = "Add a spring.config.import=nacos: property to your configuration.\n"
+ "\tIf configuration is not required add spring.config.import=optional:nacos: instead.\n"
+ "\tTo disable this check, set spring.cloud.nacos.config.import-check.enabled=false.";
return new FailureAnalysis(description, action, cause);
}
}
}

@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
/**
* @author freeman
* @since 2021.0.1.0
*/
public class NacosConfigDataResource extends ConfigDataResource {

@ -32,6 +32,16 @@ public class NacosConfigHealthIndicator extends AbstractHealthIndicator {
private final ConfigService configService;
/**
* status up .
*/
private final String STATUS_UP = "UP";
/**
* status down .
*/
private final String STATUS_DOWN = "DOWN";
public NacosConfigHealthIndicator(ConfigService configService) {
this.configService = configService;
}
@ -43,10 +53,10 @@ public class NacosConfigHealthIndicator extends AbstractHealthIndicator {
// Set the status to Builder
builder.status(status);
switch (status) {
case "UP":
case STATUS_UP:
builder.up();
break;
case "DOWN":
case STATUS_DOWN:
builder.down();
break;
default:

@ -0,0 +1,54 @@
/*
* Copyright 2013-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 com.alibaba.cloud.nacos.logging;
import com.alibaba.nacos.client.logging.NacosLogging;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
/**
* Reload nacos log configuration file, after
* {@link org.springframework.boot.context.logging.LoggingApplicationListener}.
*
* @author mai.jh
*/
public class NacosLoggingListener implements GenericApplicationListener {
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
Class<?> type = resolvableType.getRawClass();
if (type != null) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type);
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
NacosLogging.getInstance().loadConfiguration();
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 21;
}
}

@ -25,10 +25,11 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.alibaba.cloud.commons.lang.StringUtils;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
/**
* Nacos-specific loader, If need to support other methods of parsing,you need to do the

@ -65,10 +65,10 @@ public final class NacosDataParserHandler {
*/
public List<PropertySource<?>> parseNacosData(String configName, String configValue,
String extension) throws IOException {
if (StringUtils.isEmpty(configValue)) {
if (!StringUtils.hasLength(configValue)) {
return Collections.emptyList();
}
if (StringUtils.isEmpty(extension)) {
if (!StringUtils.hasLength(extension)) {
extension = this.getFileExtension(configName);
}
for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) {
@ -130,7 +130,7 @@ public final class NacosDataParserHandler {
* @return file extension, default {@code DEFAULT_EXTENSION} if don't get
*/
public String getFileExtension(String name) {
if (StringUtils.isEmpty(name)) {
if (!StringUtils.hasLength(name)) {
return DEFAULT_EXTENSION;
}
int idx = name.lastIndexOf(DOT);
@ -141,10 +141,10 @@ public final class NacosDataParserHandler {
}
private String getFileName(String name, String extension) {
if (StringUtils.isEmpty(extension)) {
if (!StringUtils.hasLength(extension)) {
return name;
}
if (StringUtils.isEmpty(name)) {
if (!StringUtils.hasLength(name)) {
return extension;
}
int idx = name.lastIndexOf(DOT);

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

Loading…
Cancel
Save