mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
sync & commit in edgware
This commit is contained in:
parent
6cfb700ed5
commit
cdca82393a
55
README-zh.md
55
README-zh.md
@ -1,21 +1,21 @@
|
||||
# Spring Cloud Alibaba
|
||||
|
||||
[](https://circleci.com/gh/alibaba/spring-cloud-alibaba/tree/master)
|
||||
[](https://search.maven.org/search?q=g:org.springframework.cloud%20AND%20a:spring-cloud-alibaba-dependencies)
|
||||
[](https://codecov.io/gh/spring-cloud-incubator/spring-cloud-alibaba)
|
||||
[](https://search.maven.org/search?q=g:com.alibaba.cloud%20AND%20a:spring-cloud-alibaba-dependencies)
|
||||
[](https://codecov.io/gh/alibaba/spring-cloud-alibaba)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
|
||||
|
||||
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。
|
||||
|
||||
参考文档 请查看 [WIKI](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/wiki) 。
|
||||
参考文档 请查看 [WIKI](https://github.com/alibaba/spring-cloud-alibaba/wiki) 。
|
||||
|
||||
为 Spring Cloud Alibaba 贡献代码请参考 [如何贡献](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/wiki/%E5%A6%82%E4%BD%95%E8%B4%A1%E7%8C%AE%E4%BB%A3%E7%A0%81) 。
|
||||
为 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) 。
|
||||
|
||||
## 主要功能
|
||||
|
||||
* **服务限流降级**:默认支持 Servlet、Feign、RestTemplate、Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
|
||||
* **服务限流降级**:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
|
||||
* **服务注册与发现**:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
|
||||
* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。
|
||||
* **消息驱动能力**:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
|
||||
@ -25,7 +25,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
||||
* **阿里云短信服务**:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
|
||||
|
||||
|
||||
更多功能请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
|
||||
更多功能请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
|
||||
|
||||
## 组件
|
||||
|
||||
@ -35,7 +35,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
||||
|
||||
**[RocketMQ](https://rocketmq.apache.org/)**:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
|
||||
|
||||
**[Dubbo](https://github.com/apache/incubator-dubbo)**:Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。
|
||||
**[Dubbo](https://github.com/apache/dubbo)**:Apache Dubbo™ 是一款高性能 Java RPC 框架。
|
||||
|
||||
**[Seata](https://github.com/seata/seata)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
|
||||
|
||||
@ -47,14 +47,15 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
||||
|
||||
**[Alibaba Cloud SMS](https://www.aliyun.com/product/sms)**: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
|
||||
|
||||
更多组件请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
|
||||
更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
|
||||
|
||||
## 如何构建
|
||||
|
||||
* master 分支对应的是 Spring Cloud Finchley,最低支持 JDK 1.8。
|
||||
* master 分支对应的是 Spring Cloud Greenwich,最低支持 JDK 1.8。
|
||||
* finchley 分支对应的是 Spring Cloud Finchley,最低支持 JDK 1.8。
|
||||
* 1.x 分支对应的是 Spring Cloud Edgware,最低支持 JDK 1.7。
|
||||
|
||||
Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目clone到本地,然后执行以下命令:
|
||||
Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone 到本地,然后执行以下命令:
|
||||
|
||||
./mvnw install
|
||||
|
||||
@ -63,14 +64,13 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目clone
|
||||
## 如何使用
|
||||
|
||||
### 如何引入依赖
|
||||
项目的最新版本是 0.2.1.RELEASE 和 0.1.1.RELEASE,版本 0.2.1.RELEASE 对应的是 Spring Cloud Finchley 版本,版本 0.1.1.RELEASE 对应的是 Spring Cloud Edgware 版本。
|
||||
|
||||
如果需要使用已发布的版本,在 `dependencyManagement` 中添加如下配置。
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>0.2.1.RELEASE</version>
|
||||
<type>pom</type>
|
||||
@ -100,34 +100,33 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目clone
|
||||
|
||||
Example 列表:
|
||||
|
||||
[Sentinel Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md)
|
||||
[Sentinel Example](https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md)
|
||||
|
||||
[Nacos Config Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md)
|
||||
[Nacos Config Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md)
|
||||
|
||||
[Nacos Discovery Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md)
|
||||
[Nacos Discovery Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md)
|
||||
|
||||
[RocketMQ Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md)
|
||||
[RocketMQ Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md)
|
||||
|
||||
[Seata Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/sms-example/readme-zh.md)
|
||||
[Seata Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/seata-example/readme-zh.md)
|
||||
|
||||
[Alibaba Cloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme-zh.md)
|
||||
[Alibaba Cloud OSS Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme-zh.md)
|
||||
|
||||
[Alibaba Cloud ANS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/ans-example/ans-provider-example/readme-zh.md)
|
||||
[Alibaba Cloud ANS Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/ans-example/ans-provider-example/readme-zh.md)
|
||||
|
||||
[Alibaba Cloud ACM Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/acm-example/acm-local-example/readme-zh.md)
|
||||
[Alibaba Cloud ACM Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/acm-example/acm-local-example/readme-zh.md)
|
||||
|
||||
[Alibaba Cloud SchedulerX Example](https://github.com/xiaolongzuo/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/readme-zh.md)
|
||||
[Alibaba Cloud SchedulerX Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/readme-zh.md)
|
||||
|
||||
## 版本管理规范
|
||||
|
||||
项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从 0 开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用 0,即版本号为 0.x.x 的格式。
|
||||
|
||||
由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且 spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们使用了两个不同分支来分别支持 Spring Boot 1 和 Spring Boot 2:
|
||||
* 0.1.x 版本适用于 Spring Boot 1
|
||||
* 0.2.x 版本适用于 Spring Boot 2
|
||||
|
||||
项目孵化阶段,项目版本升级机制如下:
|
||||
* 功能改动的升级会增加第三位版本号的数值,例如 0.1.0 的下一个版本为0.1.1。
|
||||
由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且 spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们采取跟 SpringBoot 版本号一致的版本:
|
||||
|
||||
* 1.5.x 版本适用于 Spring Boot 1.5.x
|
||||
* 2.0.x 版本适用于 Spring Boot 2.0.x
|
||||
* 2.1.x 版本适用于 Spring Boot 2.1.x
|
||||
|
||||
|
||||
## 社区交流
|
||||
@ -138,4 +137,4 @@ spring-cloud-alibaba@googlegroups.com,欢迎通过此邮件列表讨论与 spr
|
||||
|
||||
### 钉钉群
|
||||
|
||||

|
||||

|
||||
|
69
README.md
69
README.md
@ -1,13 +1,13 @@
|
||||
# Spring Cloud Alibaba
|
||||
|
||||
[](https://circleci.com/gh/alibaba/spring-cloud-alibaba/tree/master)
|
||||
[](https://search.maven.org/search?q=g:org.springframework.cloud%20AND%20a:spring-cloud-alibaba-dependencies)
|
||||
[](https://codecov.io/gh/spring-cloud-incubator/spring-cloud-alibaba)
|
||||
[](https://search.maven.org/search?q=g:com.alibaba.cloud%20AND%20a:spring-cloud-alibaba-dependencies)
|
||||
[](https://codecov.io/gh/alibaba/spring-cloud-alibaba)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
A project maintained by Alibaba.
|
||||
|
||||
See the [中文文档](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/README-zh.md) for Chinese readme.
|
||||
See the [中文文档](https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md) for Chinese readme.
|
||||
|
||||
Spring Cloud Alibaba provides a one-stop solution for distributed application development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications using Spring Cloud.
|
||||
|
||||
@ -25,7 +25,7 @@ With Spring Cloud Alibaba, you only need to add some annotations and a small amo
|
||||
* **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/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap.md).
|
||||
For more features, please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md).
|
||||
|
||||
## Components
|
||||
|
||||
@ -35,7 +35,7 @@ For more features, please refer to [Roadmap](https://github.com/spring-cloud-inc
|
||||
|
||||
**[RocketMQ](https://rocketmq.apache.org/)**:A distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.
|
||||
|
||||
**[Dubbo](https://github.com/apache/incubator-dubbo)**:A high-performance, Java based open source RPC framework.
|
||||
**[Dubbo](https://github.com/apache/dubbo)**:A high-performance, Java based open source RPC framework.
|
||||
|
||||
**[Seata](https://github.com/seata/seata)**:A distributed transaction solution with high performance and ease of use for microservices architecture.
|
||||
|
||||
@ -47,12 +47,13 @@ For more features, please refer to [Roadmap](https://github.com/spring-cloud-inc
|
||||
|
||||
**[Alibaba Cloud SchedulerX](https://www.aliyun.com/product/SchedulerX)**: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/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap.md).
|
||||
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 Boot 2.x. JDK 1.8 or later versions are supported.
|
||||
* **1.x branch**: Corresponds to Spring Boot 1.x, JDK 1.7 or later versions are supported.
|
||||
* **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.
|
||||
* **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:
|
||||
|
||||
@ -61,17 +62,16 @@ Spring Cloud uses Maven for most build-related activities, and you should be abl
|
||||
|
||||
## How to Use
|
||||
|
||||
### Add maven dependency
|
||||
Version 0.2.1.RELEASE is compatible with the Spring Cloud Finchley. Version 0.1.1.RELEASE is compatible with the Spring Cloud Edgware.
|
||||
### Add maven dependency
|
||||
|
||||
These artifacts are available from Maven Central and Spring Release repository via BOM:
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>0.2.1.RELEASE</version>
|
||||
<version>1.5.0.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@ -80,29 +80,16 @@ These artifacts are available from Maven Central and Spring Release repository v
|
||||
|
||||
add the module in `dependencies`.
|
||||
|
||||
If you want to use the latest BUILD-SNAPSHOT version, add `Spring Snapshot Repository` in pom.xml , **Attention: BUILD-SNAPSHOT may be updated in any time**
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-snapshot</id>
|
||||
<name>Spring Snapshot Repository</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
### Reference Doc
|
||||
|
||||
[Contents](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/spring-cloud-alibaba.adoc)
|
||||
[Contents](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/spring-cloud-alibaba.adoc)
|
||||
|
||||
[Nacos Config](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-config.adoc)
|
||||
[Nacos Config](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-config.adoc)
|
||||
|
||||
[Nacos Discovery](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc)
|
||||
[Nacos Discovery](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-discovery.adoc)
|
||||
|
||||
[ACM](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/acm.adoc)
|
||||
[ACM](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/acm.adoc)
|
||||
|
||||
|
||||
## Examples
|
||||
@ -111,26 +98,26 @@ A `spring-cloud-alibaba-examples` module is included in our project for you to g
|
||||
|
||||
Examples:
|
||||
|
||||
[Sentinel Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md)
|
||||
[Sentinel Example](https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md)
|
||||
|
||||
[Nacos Config Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md)
|
||||
[Nacos Config Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md)
|
||||
|
||||
[Nacos Discovery Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme.md)
|
||||
[Nacos Discovery Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme.md)
|
||||
|
||||
[RocketMQ Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme.md)
|
||||
[RocketMQ Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme.md)
|
||||
|
||||
[Alibaba Cloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme.md)
|
||||
[Alibaba Cloud OSS Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme.md)
|
||||
|
||||
[Duboo Spring Cloud Example](https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/README_CN.md)
|
||||
|
||||
## Version control guidelines
|
||||
The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the first version number is fixed to 0, that is, the version number is 0.x.x.
|
||||
The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the version number is 0.x.x.
|
||||
|
||||
As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been changed significantly in the Actuator module, and spring-cloud-commons is also changed quite a lot from 1.x.x to 2.0.0, we maintain two different branches to support Spring Boot 1 and Spring Boot 2:
|
||||
* 0.1.x for Spring Boot 1
|
||||
* 0.2.x for Spring Boot 2
|
||||
|
||||
During the incubation period, the version management of the project will follow these rules:
|
||||
* Functional updates will be reflected in the 3rd number of the version, for example, the next version of 0.1.0 will be 0.1.1.
|
||||
As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been changed significantly in the Actuator module, and spring-cloud-commons is also changed quite a lot from 1.x.x to 2.0.0, we take the same version rule as SpringBoot version number.
|
||||
|
||||
* 1.5.x for Spring Boot 1.5.x
|
||||
* 2.0.x for Spring Boot 2.0.x
|
||||
* 2.1.x for Spring Boot 2.1.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.
|
||||
|
@ -23,7 +23,7 @@ Apache RocketMQ™ 基于 Java 的高性能、高吞吐量的分布式消息和
|
||||
|
||||
**Dubbo**
|
||||
|
||||
Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。
|
||||
Apache Dubbo™ 是一款高性能 Java RPC 框架。
|
||||
|
||||
**Seata**
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Roadmap
|
||||
|
||||
See the [中文文档](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/Roadmap-zh.md) for Chinese Roadmap.
|
||||
See the [中文文档](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md) for Chinese Roadmap.
|
||||
|
||||
|
||||
Spring Cloud Alibaba provides a one-stop solution for distributed application development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications using Spring Cloud.
|
||||
@ -26,7 +26,7 @@ Apache RocketMQ™ is an open source distributed messaging and streaming data pl
|
||||
|
||||
**Dubbo**
|
||||
|
||||
Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC framework.
|
||||
Apache Dubbo™ is a high-performance, Java based open source RPC framework.
|
||||
|
||||
**Seata**
|
||||
|
||||
|
21
pom.xml
21
pom.xml
@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>1.3.11.RELEASE</version>
|
||||
<version>1.3.12.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
@ -28,12 +28,12 @@
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/spring-cloud-incubator/spring-cloud-alibaba</url>
|
||||
<url>https://github.com/alibaba/spring-cloud-alibaba</url>
|
||||
<connection>
|
||||
scm:git:git://github.com/spring-cloud-incubator/spring-cloud-alibaba.git
|
||||
scm:git:git://github.com/alibaba/spring-cloud-alibaba.git
|
||||
</connection>
|
||||
<developerConnection>
|
||||
scm:git:ssh://git@github.com/spring-cloud-incubator/spring-cloud-alibaba.git
|
||||
scm:git:ssh://git@github.com/alibaba/spring-cloud-alibaba.git
|
||||
</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
@ -66,14 +66,16 @@
|
||||
|
||||
<properties>
|
||||
<!-- Dependency Versions -->
|
||||
<spring-cloud-commons.version>1.3.5.RELEASE</spring-cloud-commons.version>
|
||||
<spring-cloud-netflix.version>1.4.6.RELEASE</spring-cloud-netflix.version>
|
||||
<spring-cloud-bus.version>1.3.4.RELEASE</spring-cloud-bus.version>
|
||||
<spring-cloud-commons.version>1.3.6.RELEASE</spring-cloud-commons.version>
|
||||
<spring-cloud-netflix.version>1.4.7.RELEASE</spring-cloud-netflix.version>
|
||||
<spring-cloud-bus.version>1.3.5.RELEASE</spring-cloud-bus.version>
|
||||
|
||||
<junit.version>4.12</junit.version>
|
||||
<javax-servlet-api>3.0</javax-servlet-api>
|
||||
<slf4j-api.version>1.7.25</slf4j-api.version>
|
||||
|
||||
<!-- Apache RocketMQ -->
|
||||
<rocketmq.starter.version>2.0.2</rocketmq.starter.version>
|
||||
|
||||
<!-- Maven Plugin Versions -->
|
||||
<maven-compiler-plugin.version>3.5</maven-compiler-plugin.version>
|
||||
@ -138,6 +140,11 @@
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
<version>${rocketmq.starter.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>1.3.11.RELEASE</version>
|
||||
<version>1.3.12.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
@ -19,19 +19,19 @@
|
||||
<properties>
|
||||
<sentinel.version>1.6.3</sentinel.version>
|
||||
<oss.version>3.1.0</oss.version>
|
||||
<seata.version>0.7.1</seata.version>
|
||||
<nacos.version>1.1.1</nacos.version>
|
||||
<seata.version>0.9.0</seata.version>
|
||||
<nacos.client.version>1.1.4</nacos.client.version>
|
||||
<acm.version>1.0.9</acm.version>
|
||||
<ans.version>1.0.1</ans.version>
|
||||
<aliyun.sdk.version>4.4.1</aliyun.sdk.version>
|
||||
<alicloud.context.version>1.0.5</alicloud.context.version>
|
||||
<aliyun.sdk.edas.version>2.44.0</aliyun.sdk.edas.version>
|
||||
<rocketmq.starter.version>2.0.2</rocketmq.starter.version>
|
||||
<schedulerX.client.version>2.1.6</schedulerX.client.version>
|
||||
<dubbo.version>2.7.1</dubbo.version>
|
||||
<dubbo.version>2.7.3</dubbo.version>
|
||||
<dubbo-spring-boot.version>2.7.1</dubbo-spring-boot.version>
|
||||
<aliyun.java.sdk.dysmsapi>1.1.0</aliyun.java.sdk.dysmsapi>
|
||||
<aliyun.sdk.mns>1.1.8.6</aliyun.sdk.mns>
|
||||
<aliyun.java.sdk.dyvmsapi>1.1.1</aliyun.java.sdk.dyvmsapi>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -90,14 +90,7 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-client</artifactId>
|
||||
<version>${nacos.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Apache RocketMQ-->
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
<version>${rocketmq.starter.version}</version>
|
||||
<version>${nacos.client.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Sentinel-->
|
||||
@ -131,6 +124,11 @@
|
||||
<artifactId>sentinel-datasource-nacos</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-redis</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-web-servlet</artifactId>
|
||||
@ -166,11 +164,6 @@
|
||||
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>sentinel-dubbo-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-cluster-server-default</artifactId>
|
||||
@ -188,8 +181,6 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--Alibaba Seata-->
|
||||
<dependency>
|
||||
<groupId>io.seata</groupId>
|
||||
@ -197,6 +188,13 @@
|
||||
<version>${seata.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo Spring Boot Starter -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
<version>${dubbo-spring-boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
@ -218,13 +216,6 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo Spring Boot Starter -->
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
<version>${dubbo-spring-boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Aliyun OSS dependencies -->
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
@ -373,9 +364,9 @@
|
||||
|
||||
<!-- Testing Dependencies -->
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>spring</id>
|
||||
|
@ -93,3 +93,4 @@ access-key 和 secret-key 则是阿里云账号的 AK/SK,需要首先注册阿
|
||||
namespace 是阿里云 EDAS 产品的概念,用于隔离不同的环境,比如测试环境和生产环境。要获取 namespace 需要 https://common-buy.aliyun.com/?spm=5176.11451019.0.0.6f5965c0Uq5tue&commodityCode=edaspostpay#/buy[开通 EDAS 服务],按量计费模式下开通是免费的,开通以后进入 https://edas.console.aliyun.com/#/namespaces?regionNo=cn-hangzhou[EDAS控制台],即可看到对应的 namespace,比如 cn-hangzhou。
|
||||
|
||||
NOTE: EDAS 提供应用托管服务,如果你将应用托管到 EDAS,那么 EDAS 将会自动为你填充所有配置。
|
||||
|
||||
|
@ -412,10 +412,8 @@ Endpoint 暴露的 json 中包含了三种属性:
|
||||
|
||||
更多关于 Nacos Config Starter 的配置项如下所示:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|配置项 ^|Key ^|默认值 ^|说明
|
||||
|===
|
||||
|配置项 |Key |默认值 |说明
|
||||
|服务端地址|`spring.cloud.nacos.config.server-addr`|| Nacos Server 启动监听的ip地址和端口
|
||||
|配置对应的 DataId|`spring.cloud.nacos.config.name`|| 先取 prefix,再去 name,最后取 spring.application.name
|
||||
|配置对应的 DataId|`spring.cloud.nacos.config.prefix`|| 先取 prefix,再去 name,最后取 spring.application.name
|
||||
@ -432,4 +430,4 @@ Endpoint 暴露的 json 中包含了三种属性:
|
||||
|共享配置|`spring.cloud.nacos.config.sharedDataids`||共享配置的 DataId, "," 分割
|
||||
|共享配置动态刷新|`spring.cloud.nacos.config.refreshableDataids`||共享配置中需要动态刷新的 DataId, "," 分割
|
||||
|自定义 Data Id 配置|`spring.cloud.nacos.config.extConfig`||属性是个集合,内部由 `Config` POJO 组成。`Config` 有 3 个属性,分别是 `dataId`, `group` 以及 `refresh`
|
||||
|====
|
||||
|===
|
||||
|
@ -42,7 +42,9 @@ image::https://img.alicdn.com/tfs/TB1dyWJbQL0gK0jSZFtXXXQCXXa-2788-1086.png[]
|
||||
以下步骤向您展示了如何将一个服务注册到 Nacos。
|
||||
|
||||
* pom.xml的配置。一个完整的 pom.xml 配置如下所示:
|
||||
[source,xml,indent=0]
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<?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"
|
||||
@ -115,11 +117,12 @@ image::https://img.alicdn.com/tfs/TB1dyWJbQL0gK0jSZFtXXXQCXXa-2788-1086.png[]
|
||||
----
|
||||
|
||||
* application.properties 配置。一些关于 Nacos 基本的配置也必须在 application.properties(也可以是application.yaml)配置,如下所示:
|
||||
application.properties
|
||||
|
||||
.application.properties
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
server.port=8081
|
||||
spring.application.name=nacos-producer
|
||||
spring.application.name=nacos-provider
|
||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
||||
management.endpoints.web.exposure.include=*
|
||||
----
|
||||
@ -128,6 +131,7 @@ management.endpoints.web.exposure.include=*
|
||||
NOTE: 如果不想使用 Nacos 作为您的服务注册与发现,可以将 `spring.cloud.nacos.discovery` 设置为 `false`。
|
||||
|
||||
* 启动 Provider 示例。如下所示:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@ -135,7 +139,7 @@ NOTE: 如果不想使用 Nacos 作为您的服务注册与发现,可以将 `sp
|
||||
public class NacosProviderDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(NacosProducerDemoApplication.class, args);
|
||||
SpringApplication.run(NacosProviderDemoApplication.class, args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
@ -177,7 +181,7 @@ public class NacosConsumerApp {
|
||||
|
||||
@GetMapping("/echo/app-name")
|
||||
public String echoAppName(){
|
||||
//使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问
|
||||
//使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问
|
||||
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
|
||||
String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
|
||||
System.out.println("request url:"+url);
|
||||
@ -261,7 +265,7 @@ Endpoint 暴露的 json 中包含了两种属性:
|
||||
"lastRefTime": 1541755293119,
|
||||
"checksum": "e5a699c9201f5328241c178e804657e11541755293119",
|
||||
"allIPs": false,
|
||||
"key": "nacos-producer",
|
||||
"key": "nacos-provider",
|
||||
"valid": true
|
||||
}
|
||||
],
|
||||
@ -291,10 +295,8 @@ Endpoint 暴露的 json 中包含了两种属性:
|
||||
|
||||
更多关于 Nacos Discovery Starter 的配置项如下所示:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|配置项 ^|Key ^|默认值 ^|说明
|
||||
|===
|
||||
|配置项 |Key |默认值 |说明
|
||||
|服务端地址|`spring.cloud.nacos.discovery.server-addr`|| Nacos Server 启动监听的ip地址和端口
|
||||
|服务名|`spring.cloud.nacos.discovery.service`|`${spring.application.name}`|注册的服务名
|
||||
|权重|`spring.cloud.nacos.discovery.weight`|`1`|取值范围 1 到 100,数值越大,权重越大
|
||||
@ -306,8 +308,9 @@ Endpoint 暴露的 json 中包含了两种属性:
|
||||
|SecretKey|`spring.cloud.nacos.discovery.secret-key`||当要上阿里云时,阿里云上面的一个云账号密码
|
||||
|Metadata|`spring.cloud.nacos.discovery.metadata`||使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息
|
||||
|日志文件名|`spring.cloud.nacos.discovery.log-name`||
|
||||
|集群|`spring.cloud.nacos.discovery.cluster-name`|`DEFAULT`|配置成Nacos集群名称
|
||||
|集群|`spring.cloud.nacos.discovery.cluster-name`|`DEFAULT`|Nacos集群名称
|
||||
|接入点|`spring.cloud.nacos.discovery.endpoint`||地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
|
||||
|是否集成Ribbon|`ribbon.nacos.enabled`|`true`|一般都设置成true即可
|
||||
|是否开启Nacos Watch|`spring.cloud.nacos.discovery.watch.enabled`|`true`|可以设置成false来关闭 watch
|
||||
|====
|
||||
|===
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
== Spring Cloud Alibaba RocketMQ Binder
|
||||
|
||||
### RocketMQ 介绍
|
||||
=== RocketMQ 介绍
|
||||
|
||||
https://rocketmq.apache.org[RocketMQ] 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
|
||||
|
||||
@ -16,7 +16,7 @@ https://rocketmq.apache.org[RocketMQ] 是一款开源的分布式消息系统,
|
||||
|
||||
* 亿级消息堆积能力
|
||||
|
||||
### RocketMQ 基本使用
|
||||
=== RocketMQ 基本使用
|
||||
|
||||
* 下载 RocketMQ
|
||||
|
||||
@ -74,7 +74,7 @@ sh bin/mqshutdown broker
|
||||
sh bin/mqshutdown namesrv
|
||||
```
|
||||
|
||||
### Spring Cloud Stream 介绍
|
||||
=== Spring Cloud Stream 介绍
|
||||
|
||||
Spring Cloud Stream 是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot 来创建具有生产级别的单机 Spring 应用,并且使用 `Spring Integration` 与 Broker 进行连接。
|
||||
|
||||
@ -135,7 +135,7 @@ messageChannel.send(MessageBuilder.withPayload("simple msg").build());
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Spring Cloud Alibaba RocketMQ Binder 实现
|
||||
=== Spring Cloud Alibaba RocketMQ Binder 实现
|
||||
|
||||
这是 Spring Cloud Stream RocketMQ Binder 的实现架构:
|
||||
|
||||
@ -166,14 +166,14 @@ NOTE: 在使用 RocketMQ Binder 的同时也可以配置 rocketmq.** 用于触
|
||||
MessageBuilder builder = MessageBuilder.withPayload(msg)
|
||||
.setHeader(RocketMQHeaders.TAGS, "binder")
|
||||
.setHeader(RocketMQHeaders.KEYS, "my-key")
|
||||
.setHeader("DELAY", "1");
|
||||
.setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "1");
|
||||
Message message = builder.build();
|
||||
output().send(message);
|
||||
```
|
||||
|
||||
### 配置选项
|
||||
=== 配置选项
|
||||
|
||||
#### RocketMQ Binder Properties
|
||||
==== RocketMQ Binder Properties
|
||||
|
||||
spring.cloud.stream.rocketmq.binder.name-server::
|
||||
RocketMQ NameServer 地址(老版本使用 namesrv-addr 配置项)。
|
||||
@ -197,7 +197,7 @@ spring.cloud.stream.rocketmq.binder.customized-trace-topic::
|
||||
Default: `RMQ_SYS_TRACE_TOPIC`.
|
||||
|
||||
|
||||
#### RocketMQ Consumer Properties
|
||||
==== RocketMQ Consumer Properties
|
||||
|
||||
下面的这些配置是以 `spring.cloud.stream.rocketmq.bindings.<channelName>.consumer.` 为前缀的 RocketMQ Consumer 相关的配置。
|
||||
|
||||
@ -233,7 +233,7 @@ suspendCurrentQueueTimeMillis::
|
||||
+
|
||||
默认值: `1000`.
|
||||
|
||||
#### RocketMQ Provider Properties
|
||||
==== RocketMQ Provider Properties
|
||||
|
||||
下面的这些配置是以 `spring.cloud.stream.rocketmq.bindings.<channelName>.producer.` 为前缀的 RocketMQ Producer 相关的配置。
|
||||
|
||||
@ -282,7 +282,7 @@ retryNextServer::
|
||||
+
|
||||
默认值: `false`.
|
||||
|
||||
### 阿里云 MQ 服务
|
||||
=== 阿里云 MQ 服务
|
||||
|
||||
使用阿里云 MQ 服务需要配置 AccessKey、SecretKey 以及云上的 NameServer 地址。
|
||||
|
||||
@ -297,4 +297,4 @@ 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[]
|
||||
image::https://spring-cloud-alibaba.oss-cn-beijing.aliyuncs.com/MQ.png[]
|
||||
|
@ -1,6 +1,6 @@
|
||||
== Spring Cloud Alibaba Sentinel
|
||||
|
||||
### Sentinel 介绍
|
||||
=== Sentinel 介绍
|
||||
|
||||
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 https://github.com/alibaba/Sentinel[Sentinel] 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
|
||||
|
||||
@ -11,11 +11,12 @@ https://github.com/alibaba/Sentinel[Sentinel] 具有以下特征:
|
||||
* *广泛的开源生态*: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
|
||||
* *完善的 SPI 扩展点*: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
|
||||
|
||||
### 如何使用 Sentinel
|
||||
=== 如何使用 Sentinel
|
||||
|
||||
如果要在您的项目中引入 Sentinel,使用 group ID 为 `com.alibaba.cloud` 和 artifact ID 为 `spring-cloud-starter-alibaba-sentinel` 的 starter。
|
||||
|
||||
```xml
|
||||
[source,yaml]
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
@ -50,7 +51,7 @@ public class TestController {
|
||||
|
||||
@SentinelResource 还提供了其它额外的属性如 `blockHandler`,`blockHandlerClass`,`fallback` 用于表示限流或降级的操作,更多内容可以参考 https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81[Sentinel注解支持]。
|
||||
|
||||
##### Sentinel 控制台
|
||||
===== Sentinel 控制台
|
||||
|
||||
Sentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。您只需要对应用进行简单的配置,就可以使用这些功能。
|
||||
|
||||
@ -61,7 +62,7 @@ image::https://github.com/alibaba/Sentinel/wiki/image/dashboard.png[]
|
||||
|
||||
开启该功能需要3个步骤:
|
||||
|
||||
###### 获取控制台
|
||||
====== 获取控制台
|
||||
|
||||
您可以从 https://github.com/alibaba/Sentinel/releases[release 页面] 下载最新版本的控制台 jar 包。
|
||||
|
||||
@ -71,7 +72,7 @@ image::https://github.com/alibaba/Sentinel/wiki/image/dashboard.png[]
|
||||
* 使用以下命令将代码打包成一个 fat jar: `mvn clean package`
|
||||
|
||||
|
||||
###### 启动控制台
|
||||
====== 启动控制台
|
||||
|
||||
Sentinel 控制台是一个标准的 SpringBoot 应用,以 SpringBoot 的方式运行 jar 包即可。
|
||||
|
||||
@ -81,7 +82,7 @@ java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject
|
||||
|
||||
如若8080端口冲突,可使用 `-Dserver.port=新端口` 进行设置。
|
||||
|
||||
#### 配置控制台信息
|
||||
==== 配置控制台信息
|
||||
|
||||
.application.yml
|
||||
----
|
||||
@ -97,7 +98,7 @@ spring:
|
||||
|
||||
更多 Sentinel 控制台的使用及问题参考: https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0[Sentinel控制台]
|
||||
|
||||
### OpenFeign 支持
|
||||
=== OpenFeign 支持
|
||||
|
||||
Sentinel 适配了 https://github.com/OpenFeign/feign[OpenFeign] 组件。如果想使用,除了引入 `sentinel-starter` 的依赖外还需要 2 个步骤:
|
||||
|
||||
@ -115,7 +116,7 @@ Sentinel 适配了 https://github.com/OpenFeign/feign[OpenFeign] 组件。如果
|
||||
```java
|
||||
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
|
||||
public interface EchoService {
|
||||
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo/{str}")
|
||||
String echo(@PathVariable("str") String str);
|
||||
}
|
||||
|
||||
@ -138,7 +139,7 @@ NOTE: Feign 对应的接口中的资源名策略定义:httpmethod:protocol://r
|
||||
|
||||
`EchoService` 接口中方法 `echo` 对应的资源名为 `GET:http://service-provider/echo/{str}`。
|
||||
|
||||
### RestTemplate 支持
|
||||
=== RestTemplate 支持
|
||||
|
||||
Spring Cloud Alibaba Sentinel 支持对 `RestTemplate` 的服务调用使用 Sentinel 进行保护,在构造 `RestTemplate` bean的时候需要加上 `@SentinelRestTemplate` 注解。
|
||||
|
||||
@ -180,13 +181,14 @@ Sentinel RestTemplate 限流的资源规则提供两种粒度:
|
||||
|
||||
NOTE: 以 `https://www.taobao.com/test` 这个 url 并使用 GET 方法为例。对应的资源名有两种粒度,分别是 `GET:https://www.taobao.com` 以及 `GET:https://www.taobao.com/test`
|
||||
|
||||
### 动态数据源支持
|
||||
=== 动态数据源支持
|
||||
|
||||
`SentinelProperties` 内部提供了 `TreeMap` 类型的 `datasource` 属性用于配置数据源信息。
|
||||
|
||||
比如配置 4 个数据源:
|
||||
|
||||
```
|
||||
[source,properties]
|
||||
----
|
||||
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
|
||||
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
|
||||
|
||||
@ -209,8 +211,7 @@ spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application
|
||||
spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel
|
||||
spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test
|
||||
spring.cloud.sentinel.datasource.ds4.apollo.rule-type=param-flow
|
||||
|
||||
```
|
||||
----
|
||||
|
||||
这种配置方式参考了 Spring Cloud Stream Binder 的配置,内部使用了 `TreeMap` 进行存储,comparator 为 `String.CASE_INSENSITIVE_ORDER` 。
|
||||
|
||||
@ -228,7 +229,7 @@ NOTE: 默认情况下,xml 格式是不支持的。需要添加 `jackson-datafo
|
||||
|
||||
关于 Sentinel 动态数据源的实现原理,参考: https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95[动态规则扩展]
|
||||
|
||||
### Zuul 支持
|
||||
=== Zuul 支持
|
||||
|
||||
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[参考 Sentinel 网关限流]
|
||||
|
||||
@ -251,7 +252,7 @@ https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Sentinel 对外暴露的 Endpoint
|
||||
=== Sentinel 对外暴露的 Endpoint
|
||||
|
||||
Sentinel 内部提供了一个 Endpoint, 对应的 endpoint id 为 `sentinel`。
|
||||
|
||||
@ -355,26 +356,22 @@ Endpoint 暴露的 json 中包含了多种属性:
|
||||
}
|
||||
----
|
||||
|
||||
### 关于 Sentinel Starter 更多的配置项信息
|
||||
=== 关于 Sentinel Starter 更多的配置项信息
|
||||
|
||||
下表显示当应用的 `ApplicationContext` 中存在对应的Bean的类型时,会进行自动化设置:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|存在Bean的类型 ^|操作 ^|作用
|
||||
|===
|
||||
|存在Bean的类型 |操作 |作用
|
||||
|`UrlCleaner`|`WebCallbackManager.setUrlCleaner(urlCleaner)`|资源清理(资源(比如将满足 /foo/:id 的 URL 都归到 /foo/* 资源下))
|
||||
|`UrlBlockHandler`|`WebCallbackManager.setUrlBlockHandler(urlBlockHandler)`|自定义限流处理逻辑
|
||||
|`RequestOriginParser`|`WebCallbackManager.setRequestOriginParser(requestOriginParser)`|设置来源信息
|
||||
|====
|
||||
|===
|
||||
|
||||
|
||||
Spring Cloud Alibaba Sentinel 提供了这些配置选项
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|配置项 ^|含义 ^|默认值
|
||||
|===
|
||||
|配置项 |含义 |默认值
|
||||
|`spring.application.name` or `project.name`|Sentinel项目名|
|
||||
|`spring.cloud.sentinel.enabled`|Sentinel自动化配置是否生效|true
|
||||
|`spring.cloud.sentinel.eager`|是否提前触发 Sentinel 初始化|false
|
||||
@ -396,6 +393,6 @@ Spring Cloud Alibaba Sentinel 提供了这些配置选项
|
||||
|`spring.cloud.sentinel.zuul.order.pre`| SentinelZuulPreFilter 的 order | 10000
|
||||
|`spring.cloud.sentinel.zuul.order.post`| SentinelZuulPostFilter 的 order | 1000
|
||||
|`spring.cloud.sentinel.zuul.order.error`| SentinelZuulErrorFilter 的 order | -1
|
||||
|====
|
||||
|===
|
||||
|
||||
NOTE: 请注意。这些配置只有在 Servlet 环境下才会生效,RestTemplate 和 Feign 针对这些配置都无法生效
|
@ -186,6 +186,7 @@ public QuerySendDetailsResponse querySendDetailsResponse(
|
||||
1、在 `application.properties` 配置文件中(也可以是 application.yaml)配置 SmsReport 的队列名称。
|
||||
|
||||
.application.properties
|
||||
[source,properties]
|
||||
----
|
||||
spring.cloud.alicloud.sms.report-queue-name=Alicom-Queue-********-SmsReport
|
||||
----
|
||||
|
@ -93,3 +93,4 @@ Access-key and secret-key are the AK/SK of your Alibaba Cloud account. Register
|
||||
Namespace is a concept in EDAS, which is used to isolate environments, such as testing environment and production environment. To find your namespace, click to https://common-buy.aliyun.com/?spm=5176.11451019.0.0.6f5965c0Uq5tue&commodityCode=edaspostpay#/buy[Sign up for EDAS] first. You will not be charged under the pay-as-you-go mode. Then log on to the https://edas.console.aliyun.com/#/namespaces?regionNo=cn-hangzhou[EDAS Console] and you will be able to see your namespace, for example cn-hangzhou.
|
||||
|
||||
NOTE: EDAS provides application hosting service and will fill in all configurations automatically for the hosted applications.
|
||||
|
||||
|
@ -100,7 +100,7 @@ user name :nacos-config-properties; age: 90
|
||||
|
||||
Nacos Config supports yaml format as well. You only need to complete the following 2 steps.
|
||||
|
||||
1. In the bootstrap.properties file, add the following line to claim that the format of DataId is yaml. As follows:
|
||||
1、In the bootstrap.properties file, add the following line to claim that the format of DataId is yaml. As follows:
|
||||
|
||||
.bootstrap.properties
|
||||
[source,yaml]
|
||||
@ -108,7 +108,7 @@ Nacos Config supports yaml format as well. You only need to complete the followi
|
||||
spring.cloud.nacos.config.file-extension=yaml
|
||||
----
|
||||
|
||||
2. Add a configuration with the DataId in yaml format on the Nacos console, as shown below:
|
||||
2、Add a configuration with the DataId in yaml format on the Nacos console, as shown below:
|
||||
|
||||
[source,subs="normal"]
|
||||
----
|
||||
@ -401,10 +401,8 @@ set spring.cloud.nacos.config.enabled = false to disable Spring Cloud Nacos Conf
|
||||
|
||||
The following shows the other configurations of the starter of Nacos Config:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|Configuration ^|Key ^|Default Value ^|Description
|
||||
|===
|
||||
|Configuration |Key |Default Value |Description
|
||||
|Server address|`spring.cloud.nacos.config.server-addr`|| IP and port of the Nacos Server listener
|
||||
|Dataid from nacos config|`spring.cloud.nacos.config.name`|| First take the prefix, then go to the name, and finally take spring.application.name
|
||||
|Dataid from nacos config|`spring.cloud.nacos.config.prefix`|| First take the prefix, then go to the name, and finally take spring.application.name
|
||||
@ -421,4 +419,4 @@ The following shows the other configurations of the starter of Nacos Config:
|
||||
|Dataid for Shared Configuration|`spring.cloud.nacos.config.sharedDataids`||Dataid for Shared Configuration, split by ","
|
||||
|Dynamic refresh dataid for Shared Configuration|`spring.cloud.nacos.config.refreshableDataids`||Dynamic refresh dataid for Shared Configuration, split by ","
|
||||
|custom dataid|`spring.cloud.nacos.config.extConfig`||It's a List,build up by `Config` POJO. `Config` has 3 attributes, `dataId`, `group` and `refresh`
|
||||
|====
|
||||
|===
|
||||
|
@ -41,10 +41,12 @@ For more Nacos Server versions, you can download the latest version from https:/
|
||||
|
||||
The following sample illustrates how to register a service to Nacos.
|
||||
|
||||
* Configuration of pom.xml The following is a complete example of pom.xml:
|
||||
[source, xml]
|
||||
* Configuration of pom.xml The following is a complete example of pom.xml:
|
||||
|
||||
.pom.xml
|
||||
[source,xml]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"? >
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -115,11 +117,12 @@ The following sample illustrates how to register a service to Nacos.
|
||||
----
|
||||
|
||||
* Configuration of application.properties Some of the basic configurations of Nacos must be included in application.properties(or application.yaml), as shown below:
|
||||
application.properties
|
||||
|
||||
.application.properties
|
||||
[source,properties]
|
||||
----
|
||||
server.port=8081
|
||||
spring.application.name=nacos-producer
|
||||
spring.application.name=nacos-provider
|
||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
||||
management.endpoints.web.exposure.include=*
|
||||
----
|
||||
@ -128,6 +131,7 @@ management.endpoints.web.exposure.include=*
|
||||
NOTE: If you do not want to use Nacos for service registration and discovery, you can set `spring.cloud.nacos.discovery` to `false`.
|
||||
|
||||
* The following is a sample for starting Provider:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@ -135,7 +139,7 @@ NOTE: If you do not want to use Nacos for service registration and discovery, yo
|
||||
public class NacosProviderDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(NacosProducerDemoApplication.class, args);
|
||||
SpringApplication.run(NacosProviderDemoApplication.class, args);
|
||||
}
|
||||
|
||||
@RestController
|
||||
@ -179,7 +183,7 @@ public class NacosConsumerApp {
|
||||
|
||||
@GetMapping("/echo/app-name")
|
||||
public String echoAppName(){
|
||||
//Access through the combination of LoadBalanceClient and RestTemolate
|
||||
//Access through the combination of LoadBalanceClient and RestTemplate
|
||||
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
|
||||
String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
|
||||
System.out.println("request path:" +path);
|
||||
@ -264,7 +268,7 @@ The followings shows how a service instance accesses the Endpoint:
|
||||
"lastRefTime": 1541755293119,
|
||||
"checksum": "e5a699c9201f5328241c178e804657e11541755293119",
|
||||
"allIPs": false,
|
||||
"key": "nacos-producer",
|
||||
"key": "nacos-provider",
|
||||
"valid": true
|
||||
}
|
||||
],
|
||||
@ -294,10 +298,8 @@ The followings shows how a service instance accesses the Endpoint:
|
||||
|
||||
The following shows the other configurations of the starter of Nacos Discovery:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|Configuration ^|Key ^|Default Value ^|Description
|
||||
|===
|
||||
|Configuration |Key |Default Value |Description
|
||||
|Server address|`spring.cloud.nacos.discovery.server-addr`||IP and port of the Nacos Server listener
|
||||
|Service name|`spring.cloud.nacos.discovery.service`|`${spring.application.name}`|Name the current service
|
||||
|Weight|`spring.cloud.nacos.discovery.weight`|`1`|Value range: 1 to 100. The bigger the value, the greater the weight
|
||||
@ -309,7 +311,9 @@ The following shows the other configurations of the starter of Nacos Discovery:
|
||||
|SecretKey|`spring.cloud.nacos.discovery.secret-key`||Alibaba Cloud account secretkey
|
||||
|Metadata|`spring.cloud.nacos.discovery.metadata`||You can define some of the metadata for your services in the Map format
|
||||
|Log file name|`spring.cloud.nacos.discovery.log-name`||
|
||||
|Cluster Name|`spring.cloud.nacos.discovery.cluster-name`|`DEFAULT`|Cluster name of Nacos
|
||||
|Endpoint|`spring.cloud.nacos.discovery.endpoint`||The domain name of a certain service in a specific region. You can retrieve the server address dynamically with this domain name
|
||||
|Integrate Ribbon or not|`ribbon.nacos.enabled`|`true`|Set to true in most cases
|
||||
|Enable Nacos Watch|`spring.cloud.nacos.discovery.watch.enabled`|`true`|set to false to close watch
|
||||
|====
|
||||
|===
|
||||
|
||||
|
@ -154,4 +154,4 @@ spring.cloud.alicloud.oss.config.max-connections=1000
|
||||
|
||||
For more configurations, refer to the table at the bottom of https://help.aliyun.com/document_detail/32010.html[OSSClient Configurations].
|
||||
|
||||
NOTE: In most cases, you need to connect the parameter names with “-” for the parameters in the table of https://help.aliyun.com/document_detail/32010.html[OSSClient Configurations] with “-”, and all letters should be in lowercase. For example, ConnectionTimeout should be changed to connection-timeout.
|
||||
NOTE: In most cases, you need to connect the parameter names with “-” for the parameters in the table of https://help.aliyun.com/document_detail/32010.html[OSSClient Configurations] with “-”, and all letters should be in lowercase. For example, ConnectionTimeout should be changed to connection-timeout.
|
||||
|
@ -1,6 +1,6 @@
|
||||
== Spring Cloud Alibaba RocketMQ Binder
|
||||
|
||||
### Introduction of RocketMQ
|
||||
=== 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.
|
||||
|
||||
@ -16,7 +16,7 @@ It has the following features:
|
||||
|
||||
* Billion-level message accumulation capability
|
||||
|
||||
### RocketMQ Usages
|
||||
=== RocketMQ Usages
|
||||
|
||||
* Download RocketMQ
|
||||
|
||||
@ -74,7 +74,7 @@ sh bin/mqshutdown broker
|
||||
sh bin/mqshutdown namesrv
|
||||
```
|
||||
|
||||
### Introduction of Spring Cloud Stream
|
||||
=== Introduction of Spring Cloud Stream
|
||||
|
||||
Spring Cloud Stream is a microservice framework used to build architectures based on messages. It helps you to create production-ready single-server Spring applications based on SpringBoot, and connects with Broker using `Spring Integration`.
|
||||
|
||||
@ -114,7 +114,7 @@ All the message types in this code are provided by the `spring-messaging`module.
|
||||
|
||||
**The lower layer of Spring Cloud Stream also implements various code abstractions based on the previous code.**
|
||||
|
||||
### How to use Spring Cloud Alibaba RocketMQ Binder ###
|
||||
=== How to use Spring Cloud Alibaba RocketMQ Binder
|
||||
|
||||
For using the Spring Cloud Alibaba RocketMQ Binder, you just need to add it to your Spring Cloud Stream application, using the following Maven coordinates:
|
||||
|
||||
@ -134,7 +134,7 @@ Alternatively, you can also use the Spring Cloud Stream RocketMQ Starter:
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### How Spring Cloud Alibaba RocketMQ Binder Works
|
||||
=== How Spring Cloud Alibaba RocketMQ Binder Works
|
||||
|
||||
This is the implementation architecture of Spring Cloud Stream RocketMQ Binder:
|
||||
|
||||
@ -165,14 +165,14 @@ For example, `TAGS`, `DELAY`, `TRANSACTIONAL_ARG`, `KEYS`, `WAIT_STORE_MSG_OK`,
|
||||
MessageBuilder builder = MessageBuilder.withPayload(msg)
|
||||
.setHeader(RocketMQHeaders.TAGS, "binder")
|
||||
.setHeader(RocketMQHeaders.KEYS, "my-key")
|
||||
.setHeader("DELAY", "1");
|
||||
.setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "1");
|
||||
Message message = builder.build();
|
||||
output().send(message);
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
=== Configuration Options
|
||||
|
||||
#### RocketMQ Binder Properties
|
||||
==== RocketMQ Binder Properties
|
||||
|
||||
spring.cloud.stream.rocketmq.binder.name-server::
|
||||
The name server of RocketMQ Server(Older versions use the namesrv-addr configuration item).
|
||||
@ -196,7 +196,7 @@ The trace topic for message trace.
|
||||
Default: `RMQ_SYS_TRACE_TOPIC`.
|
||||
|
||||
|
||||
#### RocketMQ Consumer Properties
|
||||
==== RocketMQ Consumer Properties
|
||||
|
||||
The following properties are available for RocketMQ producers only and must be prefixed with `spring.cloud.stream.rocketmq.bindings.<channelName>.consumer.`.
|
||||
|
||||
@ -232,7 +232,7 @@ Time interval of message consume retry for orderly consume.
|
||||
+
|
||||
Default: `1000`.
|
||||
|
||||
#### RocketMQ Provider Properties
|
||||
==== RocketMQ Provider Properties
|
||||
|
||||
The following properties are available for RocketMQ producers only and must be prefixed with `spring.cloud.stream.rocketmq.bindings.<channelName>.producer.`.
|
||||
|
||||
|
@ -111,4 +111,4 @@ NOTE: Group-id must be created within a namespace.
|
||||
|
||||
Access-key and secret-key are the AK/SK of your Alibaba Cloud account. If you deploy you applications on EDAS, then you do not need to fill in this information. Otherwise please go to https://usercenter.console.aliyun.com/#/manage/ak[Security Information] to get your AccessKeys.
|
||||
|
||||
Domain-name is not mandatory. You can refer to https://help.aliyun.com/document_detail/35359.html[SchedulerX Documentation] for details.
|
||||
Domain-name is not mandatory. You can refer to https://help.aliyun.com/document_detail/35359.html[SchedulerX Documentation] for details.
|
||||
|
@ -1,6 +1,6 @@
|
||||
== Spring Cloud Alibaba Sentinel
|
||||
|
||||
### Introduction of Sentinel
|
||||
=== Introduction of Sentinel
|
||||
|
||||
As microservices become popular, the stability of service calls is becoming increasingly important. https://github.com/alibaba/Sentinel[Sentinel] takes "flow" as the breakthrough point, and works on multiple fields including flow control, circuit breaking and load protection to protect service reliability.
|
||||
|
||||
@ -12,7 +12,7 @@ https://github.com/alibaba/Sentinel[Sentinel] has the following features:
|
||||
* *Extensive Open-Source Ecosystem*: Sentinel provides out-of-box modules that can be easily integrated with other open-source frameworks/libraries, such as Spring Cloud, Dubbo, and gRPC. To use Sentinel, you only need to introduce the related dependency and make a few simple configurations.
|
||||
* *Sound SPI Extensions*: Sentinel provides easy-to-use and sound SPI extension interfaces. You can customize logics with the SPI extensions quickly, for example, you can define your own rule management, or adapt to specific data sources.
|
||||
|
||||
### How to Use Sentinel
|
||||
=== How to Use Sentinel
|
||||
|
||||
If you want to use Sentinel in your project, please use the starter with the group ID as `com.alibaba.cloud` and the artifact ID as `spring-cloud-starter-alibaba-sentinel`.
|
||||
|
||||
@ -51,7 +51,7 @@ The @SentinelResource annotation is used to identify if a resource is rate limit
|
||||
|
||||
@SentinelResource also provides attributes such as `blockHandler`, `blockHandlerClass`, and `fallback` to identify rate limiting or degradation operations. For more details, refer to https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81[Sentinel Annotation Support].
|
||||
|
||||
##### Sentinel Dashboard
|
||||
===== Sentinel Dashboard
|
||||
|
||||
Sentinel dashboard is a lightweight console that provides functions such as machine discovery, single-server resource monitoring, overview of cluster resource data, as well as rule management. To use these features, you only need to complete a few steps.
|
||||
|
||||
@ -62,7 +62,7 @@ image::https://github.com/alibaba/Sentinel/wiki/image/dashboard.png[]
|
||||
|
||||
To use the Sentinel dashboard, simply complete the following 3 steps.
|
||||
|
||||
###### Get the Dashboard
|
||||
====== Get the Dashboard
|
||||
|
||||
You can download the latest dashboard JAR file from the https://github.com/alibaba/Sentinel/releases[Release Page].
|
||||
|
||||
@ -72,7 +72,7 @@ You can also get the latest source code to build your own Sentinel dashboard:
|
||||
* Run the following command to package the code into a FatJar: `mvn clean package`
|
||||
|
||||
|
||||
###### Start the Dashboard
|
||||
====== Start the Dashboard
|
||||
|
||||
Sentinel dashboard is a standard SpringBoot application, and you can run the JAR file in the Spring Boot mode.
|
||||
|
||||
@ -98,7 +98,7 @@ The port number specified in `spring.cloud.sentinel.transport.port` will start a
|
||||
|
||||
For more information about Sentinel dashboard, please refer to https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0[Sentinel Dashboard].
|
||||
|
||||
### OpenFeign Support
|
||||
=== OpenFeign Support
|
||||
|
||||
Sentinel is compatible with the https://github.com/OpenFeign/feign[OpenFeign] component. To use it, in addition to introducing the `sentinel-starter` dependency, complete the following 2 steps:
|
||||
|
||||
@ -116,7 +116,7 @@ This is a simple usage of `FeignClient`:
|
||||
```java
|
||||
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
|
||||
public interface EchoService {
|
||||
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo/{str}")
|
||||
String echo(@PathVariable("str") String str);
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ NOTE: The resource name policy in the corresponding interface of Feign is:http
|
||||
|
||||
The corresponding resource name of the `echo` method in the `EchoService` interface is `GET:http://service-provider/echo/{str}`.
|
||||
|
||||
### RestTemplate Support
|
||||
=== RestTemplate Support
|
||||
|
||||
Spring Cloud Alibaba Sentinel supports the protection of `RestTemplate` service calls using Sentinel. To do this, you need to add the `@SentinelRestTemplate` annotation when constructing the `RestTemplate` bean.
|
||||
|
||||
@ -183,13 +183,14 @@ Sentinel RestTemplate provides two granularities for resource rate limiting:
|
||||
|
||||
NOTE: Take Http GET `https://www.taobao.com/test` as an example. The corresponding resource names have two levels of granularities, `GET:https://www.taobao.com` and `GET:https://www.taobao.com/test`.
|
||||
|
||||
### Dynamic Data Source Support
|
||||
=== Dynamic Data Source Support
|
||||
|
||||
`SentinelProperties` provide `datasource` attribute to configure datasource.
|
||||
|
||||
For example, 4 data sources are configures:
|
||||
|
||||
```
|
||||
[source,properties]
|
||||
----
|
||||
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
|
||||
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
|
||||
|
||||
@ -212,7 +213,7 @@ spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application
|
||||
spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel
|
||||
spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test
|
||||
spring.cloud.sentinel.datasource.ds4.apollo.rule-type=param-flow
|
||||
```
|
||||
----
|
||||
|
||||
This method follows the configuration of Spring Cloud Stream Binder. `TreeMap` is used for storage internally, and comparator is `String.CASE_INSENSITIVE_ORDER`.
|
||||
|
||||
@ -228,9 +229,9 @@ NOTE: XML format is not supported by default. To make it effective, you need to
|
||||
|
||||
To learn more about how dynamic data sources work in Sentinel, refer to https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95[Dynamic Rule Extension].
|
||||
|
||||
### Support Zuul
|
||||
=== Support Zuul
|
||||
|
||||
https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81[参考 Sentinel 网关限流]
|
||||
Refer https://github.com/alibaba/Sentinel/wiki/API-Gateway-Flow-Control[API Gateway Flow Control]
|
||||
|
||||
If you want to use Sentinel Starter with Zuul, you need to add the `spring-cloud-alibaba-sentinel-gateway` dependency, and you need to add the `spring-cloud-starter-netflix-zuul` dependency to let Zuul AutoConfiguration class in the gateway module takes effect:
|
||||
|
||||
@ -251,7 +252,7 @@ If you want to use Sentinel Starter with Zuul, you need to add the `spring-cloud
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Sentinel Endpoint
|
||||
=== Sentinel Endpoint
|
||||
|
||||
Sentinel provides an Endpoint internally with a corresponding endpoint id of `sentinel`.
|
||||
|
||||
@ -354,25 +355,21 @@ The followings shows how a service instance accesses the Endpoint:
|
||||
}
|
||||
----
|
||||
|
||||
### Configuration
|
||||
=== Configuration
|
||||
|
||||
The following table shows that when there are corresponding bean types in `ApplicationContext`, some actions will be taken:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|Existing Bean Type ^|Action ^|Function
|
||||
|===
|
||||
|Existing Bean Type |Action |Function
|
||||
|`UrlCleaner`|`WebCallbackManager.setUrlCleaner(urlCleaner)`|Resource cleaning(resource(for example, classify all URLs of /foo/:id to the /foo/* resource))
|
||||
|`UrlBlockHandler`|`WebCallbackManager.setUrlBlockHandler(urlBlockHandler)`|Customize rate limiting logic
|
||||
|`RequestOriginParser`|`WebCallbackManager.setRequestOriginParser(requestOriginParser)`|Setting the origin
|
||||
|====
|
||||
|===
|
||||
|
||||
The following table shows all the configurations of Spring Cloud Alibaba Sentinel:
|
||||
|
||||
:frame: topbot
|
||||
[width="60%",options="header"]
|
||||
|====
|
||||
^|Configuration ^|Description ^|Default Value
|
||||
|===
|
||||
|Configuration |Description |Default Value
|
||||
|`spring.application.name` or `project.name`|Project Name Of Sentinel|
|
||||
|`spring.cloud.sentinel.enabled`|Whether Sentinel automatic configuration takes effect|true
|
||||
|`spring.cloud.sentinel.eager`|Whether to trigger Sentinel initialization in advance|false
|
||||
@ -393,7 +390,7 @@ The following table shows all the configurations of Spring Cloud Alibaba Sentine
|
||||
|`spring.cloud.sentinel.zuul.order.pre`| The order of SentinelZuulPreFilter | 10000
|
||||
|`spring.cloud.sentinel.zuul.order.post`| The order of SentinelZuulPostFilter | 1000
|
||||
|`spring.cloud.sentinel.zuul.order.error`| The order of SentinelZuulErrorFilter | -1
|
||||
|====
|
||||
|===
|
||||
|
||||
|
||||
NOTE: These configurations will only take effect in servlet environment. RestTemplate and Feign will not take effect for these configurations.
|
||||
NOTE: These configurations will only take effect in servlet environment. RestTemplate and Feign will not take effect for these configurations.
|
||||
|
@ -185,6 +185,7 @@ By subscribing to the SmsUp upstream SMS message, you can know the content of th
|
||||
1、Configure the queue name for SmsReport in the `application.properties` configuration file (which can also be application.yaml).
|
||||
|
||||
.application.properties
|
||||
[source,properties]
|
||||
----
|
||||
spring.cloud.alicloud.sms.up-queue-name=Alicom-Queue-********-SmsUp
|
||||
----
|
||||
@ -206,4 +207,4 @@ public class SmsUpMessageListener
|
||||
}
|
||||
----
|
||||
|
||||
More message body format for Message can be https://help.aliyun.com/document_detail/55496.html?spm=a2c4g.11186623.6.570.7f792c78rOiWXO[reference here].
|
||||
More message body format for Message can be https://help.aliyun.com/document_detail/55496.html?spm=a2c4g.11186623.6.570.7f792c78rOiWXO[reference here].
|
||||
|
@ -18,7 +18,9 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@ -26,6 +28,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
* @author xiaolongzuo
|
||||
*/
|
||||
@RestController
|
||||
@RefreshScope
|
||||
public class EchoController {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EchoController.class);
|
||||
|
@ -18,6 +18,7 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -18,6 +18,7 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -18,6 +18,7 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -15,7 +15,7 @@
|
||||
1. 首先,修改 pom.xml 文件,引入 Nacos Config Starter。
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -43,12 +43,10 @@
|
||||
1. 直接下载:[Nacos Server 下载页](https://github.com/alibaba/nacos/releases)
|
||||
2. 源码构建:进入 Nacos [Github 项目页面](https://github.com/alibaba/nacos),将代码 git clone 到本地自行编译打包,[参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。
|
||||
|
||||
|
||||
|
||||
2. 启动 Server,进入下载到本地并解压完成后的文件夹(使用源码构建的方式则进入编译打包好的文件夹),再进去其相对文件夹 nacos/bin,并对照操作系统实际情况执行如下命令。[详情参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。
|
||||
|
||||
1. Linux/Unix/Mac 操作系统,执行命令 `sh startup.sh -m standalone`
|
||||
1. Windows 操作系统,执行命令 `cmd startup.cmd`
|
||||
2. Windows 操作系统,执行命令 `cmd startup.cmd`
|
||||
|
||||
3. 在命令行执行如下命令,向 Nacos Server 中添加一条配置。
|
||||
|
||||
@ -113,11 +111,11 @@ Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 `Config
|
||||
|
||||
在 Nacos Config Starter 中,dataId 的拼接格式如下
|
||||
|
||||
${prefix} - ${spring.active.profile} . ${file-extension}
|
||||
${prefix} - ${spring.profiles.active} . ${file-extension}
|
||||
|
||||
* `prefix` 默认为 `spring.application.name` 的值,也可以通过配置项 `spring.cloud.nacos.config.prefix`来配置。
|
||||
|
||||
* `spring.active.profile` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
|
||||
* `spring.profiles.active` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
|
||||
|
||||
**注意,当 activeprofile 为空时,对应的连接符 `-` 也将不存在,dataId 的拼接格式变成 `${prefix}`.`${file-extension}`**
|
||||
|
||||
|
@ -15,7 +15,7 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
|
||||
1. Add dependency spring-cloud-starter-alibaba-nacos-config in the pom.xml file in your Spring Cloud project.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -42,12 +42,10 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
|
||||
1. Download: Download Nacos Server [download page](https://github.com/alibaba/nacos/releases)
|
||||
2. Build from source code: Get source code by git clone git@github.com:alibaba/Nacos.git from Github Nacos and build your code. See [build reference](https://nacos.io/en-us/docs/quick-start.html) for details.
|
||||
|
||||
|
||||
|
||||
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`
|
||||
1. Windows , execute `cmd startup.cmd`
|
||||
2. Windows , execute `cmd startup.cmd`
|
||||
|
||||
3. Execute the following command to add a configuration to Nacos Server.
|
||||
|
||||
@ -114,11 +112,11 @@ Nacos Client gets data from Nacos Server through this method. `ConfigService.get
|
||||
|
||||
In Nacos Config Starter, the splicing format of dataId is as follows
|
||||
|
||||
${prefix} - ${spring.active.profile} . ${file-extension}
|
||||
${prefix} - ${spring.profiles.active} . ${file-extension}
|
||||
|
||||
* `prefix` default value is `spring.application.name` value, which can also be configured via the configuration item `spring.cloud.nacos.config.prefix`.
|
||||
|
||||
* `spring.active.profile` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
|
||||
* `spring.profiles.active` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
|
||||
|
||||
**Note: when the activeprofile is empty, the corresponding connector `-` will also not exist, and the splicing format of the dataId becomes `${prefix}`.`${file-extension}`**
|
||||
|
||||
|
@ -1,5 +1,14 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigManager;
|
||||
import com.alibaba.nacos.api.config.listener.Listener;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
@ -11,11 +20,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
* @author xiaojing, Jianwei Mao
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
@ -27,13 +35,47 @@ class SampleRunner implements ApplicationRunner {
|
||||
@Value("${user.name}")
|
||||
String userName;
|
||||
|
||||
@Value("${user.age}")
|
||||
@Value("${user.age:25}")
|
||||
int userAge;
|
||||
|
||||
@Autowired
|
||||
private NacosConfigManager nacosConfigManager;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
System.out.println(userName);
|
||||
System.out.println(userAge);
|
||||
System.out.println(
|
||||
String.format("Initial username=%s, userAge=%d", userName, userAge));
|
||||
|
||||
nacosConfigManager.getConfigService().addListener(
|
||||
"nacos-config-example.properties", "DEFAULT_GROUP", new Listener() {
|
||||
|
||||
/**
|
||||
* Callback with latest config data.
|
||||
*
|
||||
* For example, config data in Nacos is:
|
||||
*
|
||||
* user.name=Nacos user.age=25
|
||||
*
|
||||
* @param configInfo latest config data for specific dataId in Nacos
|
||||
* server
|
||||
*/
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(new StringReader(configInfo));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("config changed: " + properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getExecutor() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +86,7 @@ class SampleController {
|
||||
@Value("${user.name}")
|
||||
String userName;
|
||||
|
||||
@Value("${user.age}")
|
||||
@Value("${user.age:25}")
|
||||
int age;
|
||||
|
||||
@RequestMapping("/user")
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.cloud.examples.ConsumerApplication.EchoService;
|
||||
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
@ -13,9 +16,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.cloud.examples.ConsumerApplication.EchoService;
|
||||
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.cloud.examples.ConsumerApplication.EchoService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@ -9,8 +11,6 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.cloud.examples.ConsumerApplication.EchoService;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -14,8 +14,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class ProviderApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
@ -24,6 +24,7 @@ public class ProviderApplication {
|
||||
|
||||
@RestController
|
||||
class EchoController {
|
||||
|
||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
||||
public ResponseEntity index() {
|
||||
return new ResponseEntity("index error", HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
|
@ -27,8 +27,8 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
@EnableDiscoveryClient
|
||||
public class SpringCloudConfigClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringCloudConfigClientApplication.class, args);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringCloudConfigClientApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -1 +1 @@
|
||||
config: config-from-yml
|
||||
config: config-from-yml
|
@ -15,7 +15,7 @@
|
||||
1. 首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
@RestController
|
||||
class EchoController {
|
||||
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo/{string}")
|
||||
public String echo(@PathVariable String string) {
|
||||
return string;
|
||||
}
|
||||
@ -70,7 +70,7 @@
|
||||
### 验证
|
||||
|
||||
#### 查询服务
|
||||
在浏览器输入此地址 `http://127.0.0.1:8848/nacos/v1/ns/instances?serviceName=service-provider`,并点击跳转,可以看到服务节点已经成功注册到 Nacos Server。
|
||||
在浏览器输入此地址 `http://127.0.0.1:8848/nacos/v1/ns/catalog/instances?serviceName=service-provider&clusterName=DEFAULT&pageSize=10&pageNo=1&namespaceId=`,并点击跳转,可以看到服务节点已经成功注册到 Nacos Server。
|
||||
|
||||

|
||||
|
||||
@ -102,7 +102,7 @@ Nacos Discovery Starter 默认集成了 Ribbon ,所以对于使用了 Ribbon
|
||||
|
||||
@FeignClient(name = "service-provider")
|
||||
public interface EchoService {
|
||||
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo/{str}")
|
||||
String echo(@PathVariable("str") String str);
|
||||
}
|
||||
|
||||
@ -120,11 +120,11 @@ Nacos Discovery Starter 默认集成了 Ribbon ,所以对于使用了 Ribbon
|
||||
@Autowired
|
||||
private EchoService echoService;
|
||||
|
||||
@RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo-rest/{str}")
|
||||
public String rest(@PathVariable String str) {
|
||||
return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);
|
||||
}
|
||||
@RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo-feign/{str}")
|
||||
public String feign(@PathVariable String str) {
|
||||
return echoService.echo(str);
|
||||
}
|
||||
@ -141,11 +141,11 @@ Nacos Discovery Starter 默认集成了 Ribbon ,所以对于使用了 Ribbon
|
||||
2. 打包编译后启动:在 nacos-discovery-consumer-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-discovery-consumer-example.jar`启动应用。
|
||||
|
||||
#### 验证
|
||||
1. 在流量器地址栏中输入 http://127.0.0.1:18083/echo-rest/1234,点击跳转,可以看到浏览器显示了 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 1234",证明服务发现生效。
|
||||
1. 在浏览器地址栏中输入 http://127.0.0.1:18083/echo-rest/1234,点击跳转,可以看到浏览器显示了 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 1234",证明服务发现生效。
|
||||
|
||||

|
||||
|
||||
1. 在流量器地址栏中输入 http://127.0.0.1:18083/echo-feign/12345,点击跳转,可以看到浏览器显示 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 12345",证明服务发现生效。
|
||||
1. 在浏览器地址栏中输入 http://127.0.0.1:18083/echo-feign/12345,点击跳转,可以看到浏览器显示 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 12345",证明服务发现生效。
|
||||
|
||||

|
||||
## 原理
|
||||
|
@ -14,7 +14,7 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
|
||||
1. Add dependency spring-cloud-starter-alibaba-nacos-discovery in the pom.xml file in your Spring Cloud project.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -34,7 +34,7 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
|
||||
|
||||
@RestController
|
||||
class EchoController {
|
||||
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
|
||||
@GetMapping(value = "/echo/{string}")
|
||||
public String echo(@PathVariable String string) {
|
||||
return string;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Storage Example
|
||||
# OSS Example
|
||||
|
||||
## 项目说明
|
||||
|
||||
@ -11,33 +11,33 @@
|
||||
### 接入 OSS
|
||||
在启动示例进行演示之前,我们先了解一下如何接入 OSS。
|
||||
|
||||
**注意:本节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您只需修改 accessKeyId、secretAccessKey、region 即可。**
|
||||
**注意:本节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您只需修改 accessKey、secretKey、endpoint 即可。**
|
||||
|
||||
1. 修改 pom.xml 文件,引入 OSS starter。
|
||||
1. 修改 pom.xml 文件,引入 alicloud-oss starter。
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
2. 在配置文件中配置 OSS 服务对应的 accessKeyId、secretAccessKey 和 region。
|
||||
2. 在配置文件中配置 OSS 服务对应的 accessKey、secretKey 和 endpoint。
|
||||
|
||||
// application.properties
|
||||
spring.cloud.alibaba.oss.accessKeyId=your-ak
|
||||
spring.cloud.alibaba.oss.secretAccessKey=your-sk
|
||||
spring.cloud.alibaba.oss.region=cn-beijing
|
||||
spring.cloud.alicloud.access-key=your-ak
|
||||
spring.cloud.alicloud.secret-key=your-sk
|
||||
spring.cloud.alicloud.oss.endpoint=***
|
||||
|
||||
以阿里云 accessKeyId、secretAccessKey 为例,获取方式如下。
|
||||
以阿里云 accessKey、secretKey 为例,获取方式如下。
|
||||
|
||||
i. 在阿里云控制台界面,单击右上角头像,选择 accesskeys,或者直接登录[用户信息管理界面](https://usercenter.console.aliyun.com/):
|
||||
|
||||

|
||||
|
||||
ii. 获取 accessKeyId、secretAccessKey:
|
||||
ii. 获取 accessKey、secretKey:
|
||||
|
||||

|
||||
|
||||
**注意:**如果您使用了阿里云 [STS服务](https://help.aliyun.com/document_detail/28756.html) 进行短期访问权限管理,则除了 accessKeyId、secretAccessKey、region 以外,还需配置 securityToken。
|
||||
**注意:**如果您使用了阿里云 [STS服务](https://help.aliyun.com/document_detail/28756.html) 进行短期访问权限管理,则除了 accessKey、secretKey、endpoint 以外,还需配置 securityToken。
|
||||
|
||||
3. 注入 OSSClient 并进行文件上传下载等操作。
|
||||
|
||||
@ -61,9 +61,9 @@
|
||||
|
||||
spring.application.name=oss-example
|
||||
server.port=18084
|
||||
spring.cloud.alibaba.oss.accessKeyId=your-ak
|
||||
spring.cloud.alibaba.oss.secretAccessKey=your-sk
|
||||
spring.cloud.alibaba.oss.region=cn-beijing
|
||||
spring.cloud.alicloud.access-key=your-ak
|
||||
spring.cloud.alicloud.secret-key=your-sk
|
||||
spring.cloud.alicloud.oss.endpoint=***
|
||||
|
||||
2. 通过 IDE 直接启动或者编译打包后启动应用。
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
1. 执行 `mvn clean package` 将工程编译打包;
|
||||
2. 执行 `java -jar oss-example.jar`启动应用。
|
||||
|
||||
应用启动后会自动在 OSS 上创建一个名为 `spring-cloud-alibaba` 的 Bucket。
|
||||
应用启动后会自动在 OSS 上创建一个名为 `spring-cloud-alibaba-test` 的 Bucket。
|
||||
|
||||
### 上传或下载文件
|
||||
|
||||
@ -96,7 +96,7 @@
|
||||
显示结果:
|
||||
|
||||
// 如果配置正确,则输出
|
||||
download success, content: { "name": "spring-cloud-alibaba", "github": "https://github.com/spring-cloud-incubator/spring-cloud-alibaba", "authors": ["Jim", "flystar32"], "emails": ["fangjian0423@gmail.com", "flystar32@163.com"] }
|
||||
download success, content: { "name": "oss-test" }
|
||||
// 下载的过程中如果发生异常,则会输出download fail: fail reason。比如accessKeyId配置错误,则fail reason内容如下
|
||||
download fail: The OSS Access Key Id you provided does not exist in our records. [ErrorCode]: InvalidAccessKeyId [RequestId]: RequestId [HostId]: xxx.oss-cn-beijing.aliyuncs.com [ResponseError]: InvalidAccessKeyId The OSS Access Key Id you provided does not exist in our records. RequestId sxxx.oss-cn-beijing.aliyuncs.com xxx-accessKeyId
|
||||
|
||||
@ -106,11 +106,11 @@
|
||||
|
||||
完成文件上传或者下载操作后,可以登录 OSS 控制台进行验证。
|
||||
|
||||
1. 登陆[OSS控制台](https://oss.console.aliyun.com/),可以看到左侧 Bucket 列表新增一个名字为`spring-cloud-alibaba`的 Bucket。
|
||||
1. 登陆[OSS控制台](https://oss.console.aliyun.com/),可以看到左侧 Bucket 列表新增一个名字为`spring-cloud-alibaba-test`的 Bucket。
|
||||
|
||||

|
||||
|
||||
2. 单击`spring-cloud-alibaba` Bucket,选择 `文件管理` 页签,发现上传的 oss-test 文件在 custom-dir 目录中。上传的 objectName 为`custom-dir/oss-test`。目录和文件以'/'符号分割。
|
||||
2. 单击`spring-cloud-alibaba-test` Bucket,选择 `文件管理` 页签,发现上传的 oss-test 文件。上传的 objectName 为`oss-test.json`。目录和文件以'/'符号分割。
|
||||
|
||||

|
||||
|
||||
@ -128,30 +128,12 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,OSS Starter 也
|
||||
|
||||
Spring Boot1.x 可以通过访问 http://127.0.0.1:18084/oss 来查看 OSS Endpoint 的信息。
|
||||
|
||||
Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/acutator/oss 来访问。
|
||||
Spring Boot2.x 可以通过访问 http://127.0.0.1:18084/actuator/oss 来访问。
|
||||
|
||||
Endpoint 内部会显示所有的 OSSClient 配置信息,以及该 OSSClient 对应的 Bucket 列表。
|
||||
|
||||

|
||||
|
||||
|
||||
## 多个 OSSClient 场景
|
||||
|
||||
如果您需要配置多个 OSSClient,类似多数据源的配置,则可以先构造 `OSSProperties`,再构造 `OSSClient`,并分别为每个 OSSClient 配置相应的 accessKeyId、secretAccessKey 等信息。
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "spring.cloud.alibaba.oss1")
|
||||
public OSSProperties ossProperties1() {
|
||||
return new OSSProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OSS ossClient1(@Qualifier("ossProperties1") OSSProperties ossProperties) {
|
||||
return new OSSClientBuilder().build(ossProperties.getEndpoint(),
|
||||
ossProperties.getAccessKeyId(), ossProperties.getSecretAccessKey(),
|
||||
ossProperties.getSecurityToken(), ossProperties.getConfiguration());
|
||||
}
|
||||
|
||||
<h2 id="1"> 以 Resource 的形式读取文件 </h2>
|
||||
|
||||
OSS Starter 支持以 Resource 的形式得到文件对象。如果只需读取少量文件,您可以使用这种方式。
|
||||
@ -171,3 +153,4 @@ OSS Starter 支持以 Resource 的形式得到文件对象。如果只需读取
|
||||
|
||||
|
||||
如果您对 Spring Cloud OSS Starter 有任何建议或想法,欢迎提交 issue 中或者通过其他社区渠道向我们反馈。
|
||||
|
||||
|
@ -11,33 +11,33 @@ If your applications are Spring Cloud applications and you need to use Alibaba C
|
||||
### Connect to OSS
|
||||
|
||||
Before we start the demo, let's learn how to connect OSS to a Spring Cloud application.
|
||||
**Note: This section is to show you how to connect to oss. The actual configurations have been completed in the following example, and you only need to specify your accessKeyId, secretAccessKey and region.**
|
||||
**Note: This section is to show you how to connect to oss. The actual configurations have been completed in the following example, and you only need to specify your accessKey, secretKey and endpoint.**
|
||||
|
||||
1. Add dependency spring-cloud-starter-alicloud-oss in the pom.xml file in your Spring Cloud project.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
2. Configure accessKeyId, secretAccessKey and region in application.properties.
|
||||
|
||||
// application.properties
|
||||
spring.cloud.alibaba.oss.accessKeyId=your-ak
|
||||
spring.cloud.alibaba.oss.secretAccessKey=your-sk
|
||||
spring.cloud.alibaba.oss.region=cn-beijing
|
||||
spring.cloud.alicloud.access-key=your-ak
|
||||
spring.cloud.alicloud.secret-key=your-sk
|
||||
spring.cloud.alicloud.oss.endpoint=***
|
||||
|
||||
To get accessKeyId, secretAccessKey, follow these steps:
|
||||
To get accessKey, secretKey, follow these steps:
|
||||
|
||||
1. On the Alibaba Cloud console, click your avatar on the upper-right corner and click accesskeys. Or visit [User Management](https://usercenter.console.aliyun.com/) page directly:
|
||||
|
||||

|
||||
|
||||
2. Get your accessKeyId、secretAccessKey:
|
||||
2. Get your accessKey、secretKey:
|
||||
|
||||

|
||||
|
||||
**Note:** If you are using [STS](https://www.alibabacloud.com/help/doc-detail/28756.html), you should configure securityToken in addition to accessKeyId, secretAccessKey, and region.
|
||||
**Note:** If you are using [STS](https://www.alibabacloud.com/help/doc-detail/28756.html), you should configure securityToken in addition to accessKey, secretKey, and endpoint.
|
||||
|
||||
3. Inject OSSClient and use it to upload files to the OSS server and download a file from OSS server.
|
||||
|
||||
@ -60,9 +60,9 @@ Before we start the demo, let's learn how to connect OSS to a Spring Cloud appli
|
||||
|
||||
spring.application.name=oss-example
|
||||
server.port=18084
|
||||
spring.cloud.alibaba.oss.accessKeyId=your-ak
|
||||
spring.cloud.alibaba.oss.secretAccessKey=your-sk
|
||||
spring.cloud.alibaba.oss.region=cn-beijing
|
||||
spring.cloud.alicloud.access-key=your-ak
|
||||
spring.cloud.alicloud.secret-key=your-sk
|
||||
spring.cloud.alicloud.oss.endpoint=***
|
||||
|
||||
2. Start the application in IDE or by building a fatjar.
|
||||
|
||||
@ -71,7 +71,7 @@ Before we start the demo, let's learn how to connect OSS to a Spring Cloud appli
|
||||
1. Execute command `mvn clean package` to build a fatjar.
|
||||
2. Run command `java -jar oss-example.jar` to start the application.
|
||||
|
||||
After startup, a bucket called 'spring-cloud-alibaba' is automatically created in OSS.
|
||||
After startup, a bucket called 'spring-cloud-alibaba-test' is automatically created in OSS.
|
||||
|
||||
### Upload or download files
|
||||
|
||||
@ -88,14 +88,14 @@ Results:
|
||||
upload fail: The OSS Access Key Id you provided does not exist in our records. [ErrorCode]: InvalidAccessKeyId [RequestId]: RequestId [HostId]: xxx.oss-cn-beijing.aliyuncs.com [ResponseError]: InvalidAccessKeyId The OSS Access Key Id you provided does not exist in our records. RequestId xxx.oss-cn-beijing.aliyuncs.com xxx-accessKeyId
|
||||
|
||||
#### Download files
|
||||
Use `curl` command to download files. It will download the oss-test.json file that you uploaded just now and print in result):
|
||||
Use `curl` command to download files. It will download the oss-test.json file that you uploaded just now and print in result:
|
||||
|
||||
curl http://localhost:18084/download
|
||||
|
||||
Results:
|
||||
|
||||
// If configurations are correct, the output will be as follows
|
||||
download success, content: { "name": "spring-cloud-alibaba", "github": "https://github.com/spring-cloud-incubator/spring-cloud-alibaba", "authors": ["Jim", "flystar32"], "emails": ["fangjian0423@gmail.com", "flystar32@163.com"] }
|
||||
download success, content: { "name": "oss-tes" }
|
||||
// If an error occurs during downloading, the output will be 'download fail: fail reason'. For example, if accessKeyId is wrong,fail reason will be as follows
|
||||
download fail: The OSS Access Key Id you provided does not exist in our records. [ErrorCode]: InvalidAccessKeyId [RequestId]: RequestId [HostId]: xxx.oss-cn-beijing.aliyuncs.com [ResponseError]: InvalidAccessKeyId The OSS Access Key Id you provided does not exist in our records. RequestId sxxx.oss-cn-beijing.aliyuncs.com xxx-accessKeyId
|
||||
|
||||
@ -103,18 +103,18 @@ Results:
|
||||
### Verify results on OSS
|
||||
|
||||
You can verify results on the OSS console when you finish uploading or downloading files.
|
||||
1. Log on to the [OSS console](https://oss.console.aliyun.com/),and you will find a bucket named `spring-cloud-alibaba`.
|
||||
1. Log on to the [OSS console](https://oss.console.aliyun.com/),and you will find a bucket named `spring-cloud-alibaba-test`.
|
||||
|
||||

|
||||
|
||||
2. Click the `spring-cloud-alibaba` bucket, select the Files tab, and you will find the oss-test file. The file 'oss-test' is located in directory 'custom-dir'. The objectName of the file is 'custom-dir/oss-test'. File directory and file is separated by '/'.
|
||||
2. Click the `spring-cloud-alibaba-test` bucket, select the Files tab, and you will find the oss-test.json file. The objectName of the file is 'oss-test.json'. File directory and file is separated by '/'.
|
||||
|
||||

|
||||
|
||||
|
||||
## Endpoint
|
||||
|
||||
OSS starter also supports the implmentation of Spring Boot acutator endpoints.
|
||||
OSS starter also supports the implementation of Spring Boot actuator endpoints.
|
||||
|
||||
**Prerequisite:**
|
||||
|
||||
@ -127,32 +127,12 @@ To view the endpoint information, visit the following URLs:
|
||||
|
||||
Spring Boot1.x: OSS Endpoint URL is http://127.0.0.1:18084/oss.
|
||||
|
||||
Spring Boot2.x: OSS Endpoint URL is http://127.0.0.1:18084/acutator/oss.
|
||||
Spring Boot2.x: OSS Endpoint URL is http://127.0.0.1:18084/actuator/oss.
|
||||
|
||||
Endpoint will show the configurations and the list of buckets of all OSSClients.
|
||||
|
||||

|
||||
|
||||
## Multiple OSSClients
|
||||
|
||||
If you need multiple OSSClients,like Multi DataSources, build `OSSProperties` first,and then build `OSSClient`. Specify information such as assessKeyId and secrectAccessKey for each OSSClient.
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "spring.cloud.alibaba.oss1")
|
||||
public OSSProperties ossProperties1() {
|
||||
return new OSSProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OSS ossClient1(@Qualifier("ossProperties1") OSSProperties ossProperties) {
|
||||
return new OSSClientBuilder().build(ossProperties.getEndpoint(),
|
||||
ossProperties.getAccessKeyId(), ossProperties.getSecretAccessKey(),
|
||||
ossProperties.getSecurityToken(), ossProperties.getConfiguration());
|
||||
}
|
||||
|
||||
|
||||
* OSSClient shutdown:You do not need to shutdown OSSClient. It will be done in `OSSApplicationListener`.
|
||||
|
||||
<h2 id="1">Read file using resource mode</h2>
|
||||
|
||||
OSS Starter supports getting file objects by `Spring Resource`. Simply configure OSS protocol of the resource:
|
||||
@ -167,3 +147,4 @@ OSS Starter supports getting file objects by `Spring Resource`. Simply configure
|
||||
You do not need to manually shut down OSSClient. OSS Starter calls all OSSClient shutdown methods in the `OSSApplicationListener` during ApplicationContext close.
|
||||
|
||||
If you have any feedback or suggestions for Spring Cloud OSS Starter, please don't hesitate to tell us by submitting github issues or via other community channels.
|
||||
|
||||
|
@ -2,6 +2,8 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import com.aliyun.oss.OSS;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
@ -9,8 +11,6 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.aliyun.oss.OSS;
|
||||
|
||||
/**
|
||||
* OSS Application
|
||||
*
|
||||
|
@ -2,7 +2,11 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.common.utils.IOUtils;
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
@ -10,10 +14,6 @@ import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.common.utils.IOUtils;
|
||||
import com.aliyun.oss.model.OSSObject;
|
||||
|
||||
/**
|
||||
* OSS Controller
|
||||
*
|
||||
|
@ -6,25 +6,25 @@
|
||||
|
||||
[RocketMQ](https://rocketmq.apache.org/) 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
|
||||
|
||||
在说明RocketMQ的示例之前,我们先了解一下 Spring Cloud Stream。
|
||||
在说明 RocketMQ 的示例之前,我们先了解一下 Spring Cloud Stream。
|
||||
|
||||
这是官方对Spring Cloud Stream的一段介绍:
|
||||
这是官方对 Spring Cloud Stream 的一段介绍:
|
||||
|
||||
Spring Cloud Stream是一个用于构建基于消息的微服务应用框架。它基于SpringBoot来创建具有生产级别的单机Spring应用,并且使用 `Spring Integration` 与Broker进行连接。
|
||||
Spring Cloud Stream 是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot 来创建具有生产级别的单机 Spring 应用,并且使用 `Spring Integration` 与 Broker 进行连接。
|
||||
|
||||
Spring Cloud Stream提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。
|
||||
Spring Cloud Stream 提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。
|
||||
|
||||
Spring Cloud Stream 内部有2个概念:Binder 和 Binding。
|
||||
Spring Cloud Stream 内部有两个概念:Binder 和 Binding。
|
||||
|
||||
* Binder: 跟外部消息中间件集成的组件,用来创建Binding,各消息中间件都有自己的Binder实现。
|
||||
* Binder: 跟外部消息中间件集成的组件,用来创建 Binding,各消息中间件都有自己的 Binder 实现。
|
||||
|
||||
比如 `Kafka` 的实现 `KafkaMessageChannelBinder` ,`RabbitMQ` 的实现 `RabbitMessageChannelBinder` 以及 `RocketMQ` 的实现 `RocketMQMessageChannelBinder` 。
|
||||
比如 `Kafka` 的实现 `KafkaMessageChannelBinder`,`RabbitMQ` 的实现 `RabbitMessageChannelBinder` 以及 `RocketMQ` 的实现 `RocketMQMessageChannelBinder`。
|
||||
|
||||
* Binding: 包括Input Binding和Output Binding。
|
||||
* Binding: 包括 Input Binding 和 Output Binding。
|
||||
|
||||
Binding在消息中间件与应用程序提供的Provider和Consumer之间提供了一个桥梁,实现了开发者只需使用应用程序的Provider或Consumer生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。
|
||||
Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁,实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。
|
||||
|
||||
下图是Spring Cloud Stream的架构设计。
|
||||
下图是 Spring Cloud Stream 的架构设计。
|
||||
|
||||

|
||||
|
||||
@ -40,12 +40,12 @@ Binding在消息中间件与应用程序提供的Provider和Consumer之间提供
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. 配置Input和Output的Binding信息并配合`@EnableBinding`注解使其生效
|
||||
2. 配置 Input 和 Output 的 Binding 信息并配合 `@EnableBinding` 注解使其生效
|
||||
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@ -57,10 +57,10 @@ public class RocketMQApplication {
|
||||
}
|
||||
```
|
||||
|
||||
配置Binding信息:
|
||||
配置 Binding 信息:
|
||||
```properties
|
||||
# 配置rocketmq的nameserver地址
|
||||
spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876
|
||||
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
|
||||
# 定义name为output的binding
|
||||
spring.cloud.stream.bindings.output.destination=test-topic
|
||||
spring.cloud.stream.bindings.output.content-type=application/json
|
||||
@ -75,7 +75,7 @@ spring.cloud.stream.bindings.input.group=test-group
|
||||
|
||||
### 下载并启动 RocketMQ
|
||||
|
||||
在接入RocketMQ Binder之前,首先需要启动RocketMQ的Name Server和Broker。
|
||||
**在接入 RocketMQ Binder 之前,首先需要启动 RocketMQ 的 Name Server 和 Broker。**
|
||||
|
||||
1. 下载[RocketMQ最新的二进制文件](https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip),并解压
|
||||
|
||||
@ -85,13 +85,13 @@ spring.cloud.stream.bindings.input.group=test-group
|
||||
sh bin/mqnamesrv
|
||||
```
|
||||
|
||||
3. 启动Broker
|
||||
3. 启动 Broker
|
||||
|
||||
```bash
|
||||
sh bin/mqbroker -n localhost:9876
|
||||
```
|
||||
|
||||
4. 创建Topic: test-topic
|
||||
4. 创建 Topic: test-topic
|
||||
|
||||
```bash
|
||||
sh bin/mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t test-topic
|
||||
@ -108,24 +108,24 @@ server.port=28081
|
||||
|
||||
2. 启动应用,支持 IDE 直接启动和编译打包后启动。
|
||||
|
||||
1. IDE直接启动:找到主类 `RocketMQApplication`,执行 main 方法启动应用。
|
||||
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar rocketmq-example.jar`启动应用。
|
||||
1. IDE 直接启动:找到主类 `RocketMQApplication`,执行 main 方法启动应用。
|
||||
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar rocketmq-example.jar` 启动应用。
|
||||
|
||||
|
||||
### 消息处理
|
||||
|
||||
使用name为output对应的binding发送消息到test-topic这个topic。
|
||||
使用 name 为 output 对应的 binding 发送消息到 test-topic 这个 topic。
|
||||
|
||||
使用2个input binding订阅数据。
|
||||
使用2个 input binding 订阅数据。
|
||||
|
||||
* input1:订阅topic为test-topic的消息,顺序消费所有消息(顺序消费的前提是所有消息都在一个MessageQueue中)
|
||||
* input1: 订阅 topic 为 test-topic 的消息,顺序消费所有消息(顺序消费的前提是所有消息都在一个 MessageQueue 中)
|
||||
|
||||
* input2:订阅topic为test-topic的消息,异步消费tags为tagStr的消息,Consumer端线程池个数为20
|
||||
* input2: 订阅 topic 为 test-topic 的消息,异步消费 tags 为 tagStr 的消息,Consumer 端线程池个数为20
|
||||
|
||||
配置信息如下:
|
||||
|
||||
```properties
|
||||
spring.cloud.stream.rocketmq.binder.namesrv-addr=127.0.0.1:9876
|
||||
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
|
||||
|
||||
spring.cloud.stream.bindings.output.destination=test-topic
|
||||
spring.cloud.stream.bindings.output.content-type=application/json
|
||||
@ -146,7 +146,7 @@ spring.cloud.stream.bindings.input2.consumer.concurrency=20
|
||||
|
||||
#### 消息发送
|
||||
|
||||
使用MessageChannel进行消息发送:
|
||||
使用 MessageChannel 进行消息发送:
|
||||
|
||||
```java
|
||||
public class ProducerRunner implements CommandLineRunner {
|
||||
@ -162,7 +162,7 @@ public class ProducerRunner implements CommandLineRunner {
|
||||
}
|
||||
```
|
||||
|
||||
或者使用RocketMQ原生的API进行消息发送:
|
||||
或者使用 RocketMQ 原生的 API 进行消息发送:
|
||||
|
||||
```java
|
||||
public class RocketMQProducer {
|
||||
@ -177,7 +177,7 @@ public class RocketMQProducer {
|
||||
|
||||
#### 消息接收
|
||||
|
||||
使用`@StreamListener`注解接收消息:
|
||||
使用 `@StreamListener` 注解接收消息:
|
||||
|
||||
```java
|
||||
@Service
|
||||
@ -204,7 +204,7 @@ Spring Boot 应用支持通过 Endpoint 来暴露相关信息,RocketMQ Stream
|
||||
* Spring Boot 1.x 中添加配置 `management.security.enabled=false`
|
||||
* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*`
|
||||
|
||||
Spring Boot 1.x 可以通过访问 http://127.0.0.1:28081/rocketmq_binder 来查看 RocketMQ Binder Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:28081/actuator/rocketmq-binder 来访问。
|
||||
Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/rocketmq_binder 来查看 RocketMQ Binder Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:28081/actuator/rocketmq-binder 来访问。
|
||||
|
||||
这里会统计消息最后一次发送的数据,消息发送成功或失败的次数,消息消费成功或失败的次数等数据。
|
||||
|
||||
@ -258,7 +258,7 @@ Spring Boot 1.x 可以通过访问 http://127.0.0.1:28081/rocketmq_binder 来查
|
||||
}
|
||||
```
|
||||
|
||||
注意:要想查看统计数据需要在pom里加上 [metrics-core依赖](https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core) 。如若不加,endpoint将会显示warning信息而不会显示统计信息:
|
||||
注意:要想查看统计数据需要在pom里加上 [metrics-core依赖](https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core)。如若不加,endpoint 将会显示 warning 信息而不会显示统计信息:
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -1,13 +1,13 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.cloud.examples.RocketMQConsumerApplication.MySink;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.Input;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
|
||||
import com.alibaba.cloud.examples.RocketMQConsumerApplication.MySink;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.cloud.examples.RocketMQProduceApplication.MySource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
@ -9,8 +11,6 @@ import org.springframework.cloud.stream.annotation.Output;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
import com.alibaba.cloud.examples.RocketMQProduceApplication.MySource;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
|
@ -3,8 +3,11 @@ package com.alibaba.cloud.examples;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.cloud.examples.RocketMQProduceApplication.MySource;
|
||||
|
||||
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;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
@ -12,8 +15,6 @@ import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
import com.alibaba.cloud.examples.RocketMQProduceApplication.MySource;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@ 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.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
|
@ -16,12 +16,12 @@
|
||||
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.alibaba.edas.schedulerx.ProcessResult;
|
||||
import com.alibaba.edas.schedulerx.ScxSimpleJobContext;
|
||||
import com.alibaba.edas.schedulerx.ScxSimpleJobProcessor;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author xiaolongzuo
|
||||
*/
|
||||
|
@ -17,14 +17,13 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
@ -45,7 +44,7 @@ public class AccountController {
|
||||
this.random = new Random();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/account", method = RequestMethod.POST, produces = "application/json")
|
||||
@PostMapping(value = "/account", produces = "application/json")
|
||||
public String account(String userId, int money) {
|
||||
LOGGER.info("Account Service ... xid: " + RootContext.getXID());
|
||||
|
||||
|
@ -17,6 +17,10 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -24,10 +28,6 @@ import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ transport {
|
||||
#NIO NATIVE
|
||||
server = "NIO"
|
||||
#enable heartbeat
|
||||
heartbeat = true
|
||||
heartbeat = false
|
||||
#thread factory for netty
|
||||
thread-factory {
|
||||
boss-thread-prefix = "NettyBoss"
|
||||
@ -28,7 +28,7 @@ transport {
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.account-service-fescar-service-group = "default"
|
||||
vgroup_mapping.account-service-seata-service-group = "default"
|
||||
#only support single node
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
@ -46,17 +46,22 @@ client {
|
||||
retry.times = 30
|
||||
}
|
||||
report.retry.count = 5
|
||||
tm.commit.retry.count = 1
|
||||
tm.rollback.retry.count = 1
|
||||
}
|
||||
transaction {
|
||||
undo.data.validation = true
|
||||
undo.log.serialization = "jackson"
|
||||
undo.log.save.days = 7
|
||||
#schedule delete expired undo_log in milliseconds
|
||||
undo.log.delete.period = 86400000
|
||||
undo.log.table = "undo_log"
|
||||
}
|
||||
|
||||
## metrics settings
|
||||
metrics {
|
||||
enabled = false
|
||||
registry-type = "compact"
|
||||
# multi exporters use comma divided
|
||||
exporter-list = "prometheus"
|
||||
exporter-prometheus-port = 9898
|
||||
support {
|
||||
## spring
|
||||
spring {
|
||||
# auto proxy the DataSource bean
|
||||
datasource.autoproxy = false
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ registry {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
@ -50,8 +50,7 @@ config {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
namespace = ""
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
|
@ -16,8 +16,13 @@
|
||||
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.cloud.examples.BusinessApplication.OrderService;
|
||||
import com.alibaba.cloud.examples.BusinessApplication.StorageService;
|
||||
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -29,11 +34,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.cloud.examples.BusinessApplication.OrderService;
|
||||
import com.alibaba.cloud.examples.BusinessApplication.StorageService;
|
||||
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ transport {
|
||||
#NIO NATIVE
|
||||
server = "NIO"
|
||||
#enable heartbeat
|
||||
heartbeat = true
|
||||
heartbeat = false
|
||||
#thread factory for netty
|
||||
thread-factory {
|
||||
boss-thread-prefix = "NettyBoss"
|
||||
@ -28,7 +28,7 @@ transport {
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.business-service-fescar-service-group = "default"
|
||||
vgroup_mapping.business-service-seata-service-group = "default"
|
||||
#only support single node
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
@ -46,17 +46,22 @@ client {
|
||||
retry.times = 30
|
||||
}
|
||||
report.retry.count = 5
|
||||
tm.commit.retry.count = 1
|
||||
tm.rollback.retry.count = 1
|
||||
}
|
||||
transaction {
|
||||
undo.data.validation = true
|
||||
undo.log.serialization = "jackson"
|
||||
undo.log.save.days = 7
|
||||
#schedule delete expired undo_log in milliseconds
|
||||
undo.log.delete.period = 86400000
|
||||
undo.log.table = "undo_log"
|
||||
}
|
||||
|
||||
## metrics settings
|
||||
metrics {
|
||||
enabled = false
|
||||
registry-type = "compact"
|
||||
# multi exporters use comma divided
|
||||
exporter-list = "prometheus"
|
||||
exporter-prometheus-port = 9898
|
||||
support {
|
||||
## spring
|
||||
spring {
|
||||
# auto proxy the DataSource bean
|
||||
datasource.autoproxy = false
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ registry {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
@ -50,8 +50,7 @@ config {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
namespace = ""
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
|
@ -17,6 +17,10 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -24,10 +28,6 @@ import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -21,8 +21,10 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Random;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -38,8 +40,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ transport {
|
||||
#NIO NATIVE
|
||||
server = "NIO"
|
||||
#enable heartbeat
|
||||
heartbeat = true
|
||||
heartbeat = false
|
||||
#thread factory for netty
|
||||
thread-factory {
|
||||
boss-thread-prefix = "NettyBoss"
|
||||
@ -28,7 +28,7 @@ transport {
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.order-service-fescar-service-group = "default"
|
||||
vgroup_mapping.order-service-seata-service-group = "default"
|
||||
#only support single node
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
@ -46,17 +46,22 @@ client {
|
||||
retry.times = 30
|
||||
}
|
||||
report.retry.count = 5
|
||||
tm.commit.retry.count = 1
|
||||
tm.rollback.retry.count = 1
|
||||
}
|
||||
transaction {
|
||||
undo.data.validation = true
|
||||
undo.log.serialization = "jackson"
|
||||
undo.log.save.days = 7
|
||||
#schedule delete expired undo_log in milliseconds
|
||||
undo.log.delete.period = 86400000
|
||||
undo.log.table = "undo_log"
|
||||
}
|
||||
|
||||
## metrics settings
|
||||
metrics {
|
||||
enabled = false
|
||||
registry-type = "compact"
|
||||
# multi exporters use comma divided
|
||||
exporter-list = "prometheus"
|
||||
exporter-prometheus-port = 9898
|
||||
support {
|
||||
## spring
|
||||
spring {
|
||||
# auto proxy the DataSource bean
|
||||
datasource.autoproxy = false
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ registry {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
@ -50,8 +50,7 @@ config {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
namespace = ""
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
|
@ -99,12 +99,16 @@ CREATE TABLE `account_tbl` (
|
||||
点击这个页面 [https://github.com/seata/seata/releases](https://github.com/seata/seata/releases),下载最新版本的 Seata Server 端.
|
||||
|
||||
|
||||
进入解压之后的 bin 目录,执行如下命令来启动
|
||||
进入解压之后的 bin 目录,执行如下命令来启动, 所有启动参数为可选项。
|
||||
|
||||
```$shell
|
||||
sh seata-server.sh -p $LISTEN_PORT -m $MODE(file or db)
|
||||
sh seata-server.sh -p $LISTEN_PORT -m $MODE(file or db) -h $HOST -e $ENV
|
||||
```
|
||||
|
||||
-p seata-server 监听服务端口号
|
||||
-m 存储模式,可选值:file、db。file 用于单点模式,db用于ha模式,当使用db存储模式,需要修改配置中store配置节点的数据库配置,同时在数据库中初始化[global_table、branch_table和
|
||||
lock_table](https://github.com/seata/seata/blob/develop/server/src/main/resources/db_store.sql)
|
||||
-h 用于解决seata-server和业务侧跨网络问题,其配置的host值直接显示到注册中心的服务可用地址host,当跨网络时这里需要配置为公网IP或NATIP,若都在同一局域网则无需配置
|
||||
-e 用于解决多环境配置中心隔离问题
|
||||
在这个示例中,采用如下命令来启动 Seata Server
|
||||
|
||||
```$shell
|
||||
@ -130,7 +134,7 @@ http://127.0.0.1:18081/seata/rest
|
||||
|
||||
### Xid 信息是否成功传递
|
||||
|
||||
在 `account-server`、`order-service` 和 `storage-service` 三个 服务的 Controller 中,第一个执行的逻辑都是输出 RootContext 中的 Xid 信息,如果看到都输出了正确的 Xid 信息,即每次都发生变化,且同一次调用中所有服务的 Xid 都一致。则表明 Fescar 的 Xid 的传递和还原是正常的。
|
||||
在 `account-server`、`order-service` 和 `storage-service` 三个 服务的 Controller 中,第一个执行的逻辑都是输出 RootContext 中的 Xid 信息,如果看到都输出了正确的 Xid 信息,即每次都发生变化,且同一次调用中所有服务的 Xid 都一致。则表明 Seata 的 Xid 的传递和还原是正常的。
|
||||
|
||||
### 数据库中数据是否一致
|
||||
|
||||
|
@ -18,6 +18,10 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -25,10 +29,6 @@ import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -16,16 +16,16 @@
|
||||
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.seata.core.context.RootContext;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -4,7 +4,7 @@ transport {
|
||||
#NIO NATIVE
|
||||
server = "NIO"
|
||||
#enable heartbeat
|
||||
heartbeat = true
|
||||
heartbeat = false
|
||||
#thread factory for netty
|
||||
thread-factory {
|
||||
boss-thread-prefix = "NettyBoss"
|
||||
@ -28,7 +28,7 @@ transport {
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.storage-service-fescar-service-group = "default"
|
||||
vgroup_mapping.storage-service-seata-service-group = "default"
|
||||
#only support single node
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
@ -46,17 +46,22 @@ client {
|
||||
retry.times = 30
|
||||
}
|
||||
report.retry.count = 5
|
||||
tm.commit.retry.count = 1
|
||||
tm.rollback.retry.count = 1
|
||||
}
|
||||
transaction {
|
||||
undo.data.validation = true
|
||||
undo.log.serialization = "jackson"
|
||||
undo.log.save.days = 7
|
||||
#schedule delete expired undo_log in milliseconds
|
||||
undo.log.delete.period = 86400000
|
||||
undo.log.table = "undo_log"
|
||||
}
|
||||
|
||||
## metrics settings
|
||||
metrics {
|
||||
enabled = false
|
||||
registry-type = "compact"
|
||||
# multi exporters use comma divided
|
||||
exporter-list = "prometheus"
|
||||
exporter-prometheus-port = 9898
|
||||
support {
|
||||
## spring
|
||||
spring {
|
||||
# auto proxy the DataSource bean
|
||||
datasource.autoproxy = false
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ registry {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
namespace = ""
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
@ -50,8 +50,7 @@ config {
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
namespace = ""
|
||||
}
|
||||
consul {
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
@ -122,28 +122,30 @@
|
||||
|
||||
## 自定义限流处理逻辑
|
||||
|
||||
1. URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。
|
||||
* 默认限流异常处理
|
||||
|
||||
URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。
|
||||
如果需要自定义处理逻辑,实现的方式如下:
|
||||
|
||||
```java
|
||||
public class CustomUrlBlockHandler implements UrlBlockHandler {
|
||||
@Override
|
||||
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
|
||||
// todo add your logic
|
||||
}
|
||||
}
|
||||
```java
|
||||
public class CustomUrlBlockHandler implements UrlBlockHandler {
|
||||
@Override
|
||||
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
|
||||
// todo add your logic
|
||||
}
|
||||
}
|
||||
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
```
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
```
|
||||
|
||||
2. 自定义限流触发后,默认的处理逻辑是抛出异常。
|
||||
* 使用 `@SentinelResource` 注解下的限流异常处理
|
||||
|
||||
如果需要自定义处理逻辑,填写 `@SentinelResource` 注解的 `blockHandler` 属性(针对所有类型的 `BlockException`,需自行判断)或 `fallback` 属性(针对熔断降级异常),注意**对应方法的签名和位置有限制**,详情见 [Sentinel 注解支持文档](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3)。示例实现如下:
|
||||
|
||||
```java
|
||||
public class TestService {
|
||||
|
||||
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
|
||||
// blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制.
|
||||
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
|
||||
public void test() {
|
||||
System.out.println("Test");
|
||||
@ -172,7 +174,7 @@ public final class ExceptionUtil {
|
||||
}
|
||||
```
|
||||
|
||||
一个简单的示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。
|
||||
一个简单的 `@SentinelResource` 示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。
|
||||
|
||||
## Endpoint 信息查看
|
||||
|
||||
@ -212,9 +214,9 @@ spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
|
||||
|
||||
`ds1` 和 `ds2` 表示ReadableDataSource的名称,可随意编写。`ds1` 和 `ds2` 后面的 `file` 和 `nacos` 表示ReadableDataSource的类型。
|
||||
|
||||
目前支持`file`, `nacos`, `zk`, `apollo` 这4种类型。
|
||||
目前支持`file`, `nacos`, `zk`, `apollo`,`redis` 这5种类型。
|
||||
|
||||
其中`nacos`,`zk`,`apollo`这3种类型的使用需要加上对应的依赖`sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`, `sentinel-datasource-apollo`。
|
||||
其中`nacos`,`zk`,`apollo`,`redis` 这4种类型的使用需要加上对应的依赖`sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`, `sentinel-datasource-apollo`, `sentinel-datasource-redis`。
|
||||
|
||||
当ReadableDataSource加载规则数据成功的时候,控制台会打印出相应的日志信息:
|
||||
|
||||
|
@ -15,7 +15,7 @@ Before we start the demo, let's learn how to connect Sentinel to a Spring Cloud
|
||||
1. Add dependency spring-cloud-starter-alibaba-sentinel in the pom.xml file in your Spring Cloud project.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -108,7 +108,9 @@ The screenshot belows shows invoke success:
|
||||
|
||||
## Customize Flow Control Logic
|
||||
|
||||
1. When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)".
|
||||
* Flow control exception handle by default
|
||||
|
||||
When a URL resource is blocked by Sentinel, the default logic is return HTTP response "Blocked by Sentinel (flow limiting)".
|
||||
|
||||
If you want to customize your flow control logic, see the code below:
|
||||
|
||||
@ -123,7 +125,9 @@ The screenshot belows shows invoke success:
|
||||
WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler());
|
||||
|
||||
|
||||
2. When a custom resource is blocked by Sentinel, the default logic is throw BlockException.
|
||||
* Flow control exception handle by using `@SentinelResource`
|
||||
|
||||
When a custom resource is blocked by Sentinel, the default logic is throw BlockException.
|
||||
|
||||
If you want to customize your flow control logic, implement interface `SentinelExceptionHandler`, set @SentinelResource's blockHandler() and blockHandlerClass(). See the code below:
|
||||
|
||||
@ -185,9 +189,9 @@ spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
|
||||
|
||||
`ds1` and `ds2` means the name of ReadableDataSource, you can write whatever you want. The `file` and `nacos` after name `ds1` and `ds2` means the type of ReadableDataSource.
|
||||
|
||||
Now ReadableDataSource type support 4 categories: `file`, `nacos`, `zk` and `apollo`.
|
||||
Now ReadableDataSource type support 5 categories: `file`, `nacos`, `zk`, `apollo` and `redis`.
|
||||
|
||||
If you want to use `nacos`, `zk` or `apollo` ReadableDataSource, you could add `sentinel-datasource-nacos`, `sentinel-datasource-zookeeper` or `sentinel-datasource-apollo` dependency.
|
||||
If you want to use `nacos`, `zk`, `apollo` or `redis` ReadableDataSource, you could add `sentinel-datasource-nacos`, `sentinel-datasource-zookeeper`,`sentinel-datasource-apollo` or `sentinel-datasource-redis` dependency.
|
||||
|
||||
When ReadableDataSource load rule data successfully, console will print some logs:
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
|
||||
import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
|
@ -1,13 +1,13 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
|
||||
import com.alibaba.csp.sentinel.datasource.Converter;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -1,13 +1,13 @@
|
||||
package com.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
|
@ -6,9 +6,9 @@
|
||||
|
||||
[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件,Sentinel 把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。
|
||||
|
||||
[Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架,有对应的[SpringBoot工程](https://github.com/apache/incubator-dubbo-spring-boot-project)。
|
||||
[Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架,有对应的[SpringBoot工程](https://github.com/apache/dubbo-spring-boot-project)。
|
||||
|
||||
本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-core-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example)。
|
||||
本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-core-example](https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example)。
|
||||
|
||||
## 示例
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
1. 首先,修改 pom.xml 文件,引入 Sentinel starter 和 Dubbo starter。
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -112,7 +112,7 @@ Consumer端在服务调用之前,先定义限流规则。
|
||||
根据Provider端中发布的定义,使用Dubbo的@Reference注解注入服务对应的Bean:
|
||||
|
||||
@Reference(version = "${foo.service.version}", application = "${dubbo.application.id}",
|
||||
url = "dubbo://localhost:12345", timeout = 30000)
|
||||
path = "dubbo://localhost:12345", timeout = 30000)
|
||||
private FooService fooService;
|
||||
|
||||
由于设置的qps是10。调用15次查看是否被限流:
|
||||
@ -146,4 +146,3 @@ Consumer端:
|
||||
|
||||
1. IDE直接启动:找到主类 `SentinelDubboConsumerApp`,执行 main 方法启动应用。
|
||||
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-dubbo-consumer-example.jar`启动应用。
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Sentinel Provider Example
|
||||
# Sentinel Dubbo Example
|
||||
## Project Instruction
|
||||
|
||||
This example illustrates how to use Sentinel starter to implement flow control for Spring Cloud applications.
|
||||
@ -7,7 +7,7 @@ This example illustrates how to use Sentinel starter to implement flow control f
|
||||
|
||||
[Dubbo](http://dubbo.apache.org/) is a high-performance, java based open source RPC framework.
|
||||
|
||||
This example focus on the integration of Sentinel and Dubbo. You can see more features on [sentinel-core-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example).
|
||||
This example focus on the integration of Sentinel and Dubbo. You can see more features on [sentinel-core-example](https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example).
|
||||
|
||||
## Demo
|
||||
|
||||
@ -18,7 +18,7 @@ Before we start the demo, let's learn how to connect Sentinel with Dubbo to a Sp
|
||||
1. Add dependency spring-cloud-starter-alibaba-sentinel and dubbo-spring-boot-starter in the pom.xml file in your Spring Cloud project.
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
@ -110,7 +110,7 @@ Configure rules:
|
||||
Using the `@Reference` annotation to inject service:
|
||||
|
||||
@Reference(version = "${foo.service.version}", application = "${dubbo.application.id}",
|
||||
url = "dubbo://localhost:12345", timeout = 30000)
|
||||
path = "dubbo://localhost:12345", timeout = 30000)
|
||||
private FooService fooService;
|
||||
|
||||
Because QPS is 10, we can see that flow control takes effect in this invocation:
|
||||
@ -143,4 +143,3 @@ Consumer side:
|
||||
|
||||
1. Start in IDE: Find main class `SentinelDubboConsumerApp`, and execute the main method.
|
||||
2. Build a fatjar: Execute command `mvn clean package` to build a fatjar, and run command `java -jar sentinel-dubbo-consumer-example.jar` to start the application.
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>sentinel-dubbo-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -2,16 +2,16 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
@ -26,7 +26,8 @@ public class SentinelDubboConsumerApp {
|
||||
public static void main(String[] args) {
|
||||
|
||||
FlowRule flowRule = new FlowRule();
|
||||
flowRule.setResource("com.alibaba.cloud.examples.FooService:hello(java.lang.String)");
|
||||
flowRule.setResource(
|
||||
"com.alibaba.cloud.examples.FooService:hello(java.lang.String)");
|
||||
flowRule.setCount(10);
|
||||
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
flowRule.setLimitApp("default");
|
||||
|
@ -25,6 +25,7 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>sentinel-dubbo-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -19,9 +19,6 @@ package com.alibaba.cloud.examples;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||
@ -29,6 +26,9 @@ import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
|
@ -18,13 +18,13 @@ package com.alibaba.cloud.examples;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.callback.RequestOriginParser;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.BlockResponse;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.zuul.fallback.ZuulBlockFallbackProvider;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
|
@ -3,11 +3,6 @@ package com.alibaba.cloud.example;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.alicloud.sms.ISmsService;
|
||||
|
||||
import com.aliyun.mns.model.Message;
|
||||
@ -21,6 +16,11 @@ import com.aliyuncs.exceptions.ClientException;
|
||||
import com.aliyuncs.http.MethodType;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class SmsController {
|
||||
|
||||
|
@ -3,10 +3,10 @@ package com.alibaba.cloud.example;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.aliyun.mns.model.Message;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author 如果需要监听短信是否被对方成功接收,只需实现这个接口并初始化一个 Spring Bean 即可。
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.alibaba.cloud.example;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.aliyun.mns.model.Message;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author 如果发送的短信需要接收对方回复的状态消息,只需实现该接口并初始化一个 Spring Bean 即可。
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@ -14,8 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.examples.rocketmq;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@ -28,9 +31,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* RocketMQ Bus Spring Application
|
||||
*
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@ -14,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.examples.rocketmq;
|
||||
|
||||
/**
|
||||
|
@ -1,12 +1,11 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@ -14,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.examples.rocketmq;
|
||||
|
||||
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
|
||||
|
@ -16,16 +16,16 @@
|
||||
|
||||
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 org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.alibaba.cloud.nacos.refresh.NacosContextRefresher;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshProperties;
|
||||
|
||||
/**
|
||||
* @author juven.xuxb
|
||||
*/
|
||||
@ -41,8 +41,12 @@ public class NacosConfigAutoConfiguration {
|
||||
return BeanFactoryUtils.beanOfTypeIncludingAncestors(context.getParent(),
|
||||
NacosConfigProperties.class);
|
||||
}
|
||||
NacosConfigProperties nacosConfigProperties = new NacosConfigProperties();
|
||||
return nacosConfigProperties;
|
||||
return new NacosConfigProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NacosConfigManager nacosConfigManager() {
|
||||
return new NacosConfigManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ -57,10 +61,10 @@ public class NacosConfigAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public NacosContextRefresher nacosContextRefresher(
|
||||
NacosConfigProperties nacosConfigProperties,
|
||||
NacosConfigManager nacosConfigManager,
|
||||
NacosRefreshProperties nacosRefreshProperties,
|
||||
NacosRefreshHistory refreshHistory) {
|
||||
return new NacosContextRefresher(nacosRefreshProperties, refreshHistory,
|
||||
nacosConfigProperties.configServiceInstance());
|
||||
nacosConfigManager.getConfigService());
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,13 @@
|
||||
|
||||
package com.alibaba.cloud.nacos;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@ -36,10 +36,17 @@ public class NacosConfigBootstrapConfiguration {
|
||||
return new NacosConfigProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public NacosConfigManager nacosConfigManager() {
|
||||
return new NacosConfigManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NacosPropertySourceLocator nacosPropertySourceLocator(
|
||||
NacosConfigManager nacosConfigManager,
|
||||
NacosConfigProperties nacosConfigProperties) {
|
||||
return new NacosPropertySourceLocator(nacosConfigProperties);
|
||||
return new NacosPropertySourceLocator(nacosConfigManager, nacosConfigProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos;
|
||||
|
||||
import com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureException;
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class NacosConfigManager {
|
||||
|
||||
private static ConfigService service = null;
|
||||
|
||||
@Autowired
|
||||
private NacosConfigProperties properties;
|
||||
|
||||
public ConfigService getConfigService() {
|
||||
if (service == null) {
|
||||
try {
|
||||
service = NacosFactory
|
||||
.createConfigService(properties.getConfigServiceProperties());
|
||||
properties.initConfigService(service);
|
||||
}
|
||||
catch (NacosException e) {
|
||||
throw new NacosConnectionFailureException(properties.getServerAddr(),
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
}
|
@ -16,44 +16,76 @@
|
||||
|
||||
package com.alibaba.cloud.nacos;
|
||||
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ACCESS_KEY;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.CLUSTER_NAME;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT_PORT;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.SECRET_KEY;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
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;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.CONFIG_RETRY_TIME;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.CONTEXT_PATH;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ENCODE;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.ENDPOINT;
|
||||
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.SECRET_KEY;
|
||||
import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
|
||||
|
||||
/**
|
||||
* nacos properties
|
||||
* Nacos properties.
|
||||
*
|
||||
* @author leijuan
|
||||
* @author xiaojing
|
||||
* @author pbting
|
||||
* @author <a href="mailto:lyuzb@lyuzb.com">lyuzb</a>
|
||||
*/
|
||||
@ConfigurationProperties(NacosConfigProperties.PREFIX)
|
||||
public class NacosConfigProperties {
|
||||
|
||||
/**
|
||||
* Prefix of {@link NacosConfigProperties}.
|
||||
*/
|
||||
public static final String PREFIX = "spring.cloud.nacos.config";
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(NacosConfigProperties.class);
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.overrideFromEnv();
|
||||
}
|
||||
|
||||
private void overrideFromEnv() {
|
||||
if (StringUtils.isEmpty(this.getServerAddr())) {
|
||||
String serverAddr = environment
|
||||
.resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}");
|
||||
if (StringUtils.isEmpty(serverAddr)) {
|
||||
serverAddr = environment
|
||||
.resolvePlaceholders("${spring.cloud.nacos.server-addr:}");
|
||||
}
|
||||
this.setServerAddr(serverAddr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nacos config server address
|
||||
* nacos config server address.
|
||||
*/
|
||||
private String serverAddr;
|
||||
|
||||
@ -68,9 +100,10 @@ public class NacosConfigProperties {
|
||||
private String group = "DEFAULT_GROUP";
|
||||
|
||||
/**
|
||||
* nacos config dataId prefix
|
||||
* nacos config dataId prefix.
|
||||
*/
|
||||
private String prefix;
|
||||
|
||||
/**
|
||||
* the suffix of nacos config dataId, also the file extension of config content.
|
||||
*/
|
||||
@ -81,6 +114,30 @@ public class NacosConfigProperties {
|
||||
*/
|
||||
private int timeout = 3000;
|
||||
|
||||
/**
|
||||
* nacos maximum number of tolerable server reconnection errors.
|
||||
*/
|
||||
private String maxRetry;
|
||||
|
||||
/**
|
||||
* nacos get config long poll timeout.
|
||||
*/
|
||||
private String configLongPollTimeout;
|
||||
|
||||
/**
|
||||
* nacos get config failure retry time.
|
||||
*/
|
||||
private String configRetryTime;
|
||||
|
||||
/**
|
||||
* If you want to pull it yourself when the program starts to get the configuration
|
||||
* for the first time, and the registered Listener is used for future configuration
|
||||
* updates, you can keep the original code unchanged, just add the system parameter:
|
||||
* enableRemoteSyncConfig = "true" ( But there is network overhead); therefore we
|
||||
* recommend that you use {@link ConfigService#getConfigAndSignListener} directly.
|
||||
*/
|
||||
private boolean enableRemoteSyncConfig = false;
|
||||
|
||||
/**
|
||||
* endpoint for Nacos, the domain name of a service, through which the server address
|
||||
* can be dynamically obtained.
|
||||
@ -108,10 +165,13 @@ public class NacosConfigProperties {
|
||||
private String contextPath;
|
||||
|
||||
/**
|
||||
* nacos config cluster name
|
||||
* nacos config cluster name.
|
||||
*/
|
||||
private String clusterName;
|
||||
|
||||
/**
|
||||
* nacos config dataId name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
@ -174,6 +234,38 @@ public class NacosConfigProperties {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public String getMaxRetry() {
|
||||
return maxRetry;
|
||||
}
|
||||
|
||||
public void setMaxRetry(String maxRetry) {
|
||||
this.maxRetry = maxRetry;
|
||||
}
|
||||
|
||||
public String getConfigLongPollTimeout() {
|
||||
return configLongPollTimeout;
|
||||
}
|
||||
|
||||
public void setConfigLongPollTimeout(String configLongPollTimeout) {
|
||||
this.configLongPollTimeout = configLongPollTimeout;
|
||||
}
|
||||
|
||||
public String getConfigRetryTime() {
|
||||
return configRetryTime;
|
||||
}
|
||||
|
||||
public void setConfigRetryTime(String configRetryTime) {
|
||||
this.configRetryTime = configRetryTime;
|
||||
}
|
||||
|
||||
public Boolean getEnableRemoteSyncConfig() {
|
||||
return enableRemoteSyncConfig;
|
||||
}
|
||||
|
||||
public void setEnableRemoteSyncConfig(Boolean enableRemoteSyncConfig) {
|
||||
this.enableRemoteSyncConfig = enableRemoteSyncConfig;
|
||||
}
|
||||
|
||||
public String getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
@ -262,15 +354,71 @@ public class NacosConfigProperties {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see NacosConfigManager#getConfigService() .
|
||||
* @return ConfigService
|
||||
*/
|
||||
@Deprecated
|
||||
public ConfigService configServiceInstance() {
|
||||
return configService;
|
||||
}
|
||||
|
||||
public void initConfigService(ConfigService configService) {
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
public Properties getConfigServiceProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.put(SERVER_ADDR, Objects.toString(this.serverAddr, ""));
|
||||
properties.put(ENCODE, Objects.toString(this.encode, ""));
|
||||
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(CONTEXT_PATH, Objects.toString(this.contextPath, ""));
|
||||
properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
|
||||
properties.put(MAX_RETRY, Objects.toString(this.maxRetry, ""));
|
||||
properties.put(CONFIG_LONG_POLL_TIMEOUT,
|
||||
Objects.toString(this.configLongPollTimeout, ""));
|
||||
properties.put(CONFIG_RETRY_TIME, Objects.toString(this.configRetryTime, ""));
|
||||
properties.put(ENABLE_REMOTE_SYNC_CONFIG,
|
||||
Objects.toString(this.enableRemoteSyncConfig, ""));
|
||||
String endpoint = Objects.toString(this.endpoint, "");
|
||||
if (endpoint.contains(":")) {
|
||||
int index = endpoint.indexOf(":");
|
||||
properties.put(ENDPOINT, endpoint.substring(0, index));
|
||||
properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
|
||||
}
|
||||
else {
|
||||
properties.put(ENDPOINT, endpoint);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NacosConfigProperties{" + "serverAddr='" + serverAddr + '\''
|
||||
+ ", encode='" + encode + '\'' + ", group='" + group + '\'' + ", prefix='"
|
||||
+ prefix + '\'' + ", fileExtension='" + fileExtension + '\''
|
||||
+ ", timeout=" + timeout + ", endpoint='" + endpoint + '\''
|
||||
+ ", namespace='" + namespace + '\'' + ", accessKey='" + accessKey + '\''
|
||||
+ ", secretKey='" + secretKey + '\'' + ", contextPath='" + contextPath
|
||||
+ '\'' + ", clusterName='" + clusterName + '\'' + ", name='" + name + '\''
|
||||
+ ", sharedDataids='" + sharedDataids + '\'' + ", refreshableDataids='"
|
||||
+ refreshableDataids + '\'' + ", extConfig=" + extConfig + '}';
|
||||
}
|
||||
|
||||
public static class Config {
|
||||
|
||||
/**
|
||||
* the data id of extended configuration
|
||||
* the data id of extended configuration.
|
||||
*/
|
||||
private String dataId;
|
||||
|
||||
/**
|
||||
* the group of extended configuration, the default value is DEFAULT_GROUP
|
||||
* the group of extended configuration, the default value is DEFAULT_GROUP.
|
||||
*/
|
||||
private String group = "DEFAULT_GROUP";
|
||||
|
||||
/**
|
||||
* whether to support dynamic refresh, the default does not support .
|
||||
*/
|
||||
@ -299,53 +447,7 @@ public class NacosConfigProperties {
|
||||
public void setRefresh(boolean refresh) {
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NacosConfigProperties{" + "serverAddr='" + serverAddr + '\''
|
||||
+ ", encode='" + encode + '\'' + ", group='" + group + '\'' + ", prefix='"
|
||||
+ prefix + '\'' + ", fileExtension='" + fileExtension + '\''
|
||||
+ ", timeout=" + timeout + ", endpoint='" + endpoint + '\''
|
||||
+ ", namespace='" + namespace + '\'' + ", accessKey='" + accessKey + '\''
|
||||
+ ", secretKey='" + secretKey + '\'' + ", contextPath='" + contextPath
|
||||
+ '\'' + ", clusterName='" + clusterName + '\'' + ", name='" + name + '\''
|
||||
+ ", sharedDataids='" + sharedDataids + '\'' + ", refreshableDataids='"
|
||||
+ refreshableDataids + '\'' + ", extConfig=" + extConfig + '}';
|
||||
}
|
||||
|
||||
public ConfigService configServiceInstance() {
|
||||
|
||||
if (null != configService) {
|
||||
return configService;
|
||||
}
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.put(SERVER_ADDR, Objects.toString(this.serverAddr, ""));
|
||||
properties.put(ENCODE, Objects.toString(this.encode, ""));
|
||||
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(CONTEXT_PATH, Objects.toString(this.contextPath, ""));
|
||||
properties.put(CLUSTER_NAME, Objects.toString(this.clusterName, ""));
|
||||
|
||||
String endpoint = Objects.toString(this.endpoint, "");
|
||||
if (endpoint.contains(":")) {
|
||||
int index = endpoint.indexOf(":");
|
||||
properties.put(ENDPOINT, endpoint.substring(0, index));
|
||||
properties.put(ENDPOINT_PORT, endpoint.substring(index + 1));
|
||||
}
|
||||
else {
|
||||
properties.put(ENDPOINT, endpoint);
|
||||
}
|
||||
|
||||
try {
|
||||
configService = NacosFactory.createConfigService(properties);
|
||||
return configService;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("create config service error!properties={},e=,", this, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,11 @@
|
||||
|
||||
package com.alibaba.cloud.nacos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySource;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
@ -28,25 +28,23 @@ import com.alibaba.cloud.nacos.client.NacosPropertySource;
|
||||
*/
|
||||
public class NacosPropertySourceRepository {
|
||||
|
||||
private final static ConcurrentHashMap<String, NacosPropertySource> nacosPropertySourceRepository = new ConcurrentHashMap<>();
|
||||
private final static ConcurrentHashMap<String, NacosPropertySource> NACOS_PROPERTY_SOURCE_REPOSITORY = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* @return all nacos properties from application context
|
||||
*/
|
||||
public static List<NacosPropertySource> getAll() {
|
||||
List<NacosPropertySource> result = new ArrayList<>();
|
||||
result.addAll(nacosPropertySourceRepository.values());
|
||||
return result;
|
||||
return Lists.newArrayList(NACOS_PROPERTY_SOURCE_REPOSITORY.values());
|
||||
}
|
||||
|
||||
public static void collectNacosPropertySources(
|
||||
NacosPropertySource nacosPropertySource) {
|
||||
nacosPropertySourceRepository.putIfAbsent(nacosPropertySource.getDataId(),
|
||||
NACOS_PROPERTY_SOURCE_REPOSITORY.putIfAbsent(nacosPropertySource.getDataId(),
|
||||
nacosPropertySource);
|
||||
}
|
||||
|
||||
public static NacosPropertySource getNacosPropertySource(String dataId) {
|
||||
|
||||
return nacosPropertySourceRepository.get(dataId);
|
||||
return NACOS_PROPERTY_SOURCE_REPOSITORY.get(dataId);
|
||||
}
|
||||
}
|
||||
|
@ -16,23 +16,22 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.client;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.parser.NacosDataParserHandler;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
* @author pbting
|
||||
@ -83,24 +82,19 @@ public class NacosPropertySourceBuilder {
|
||||
String data = null;
|
||||
try {
|
||||
data = configService.getConfig(dataId, group, timeout);
|
||||
if (!StringUtils.isEmpty(data)) {
|
||||
log.info(String.format("Loading nacos data, dataId: '%s', group: '%s'",
|
||||
dataId, group));
|
||||
|
||||
if (fileExtension.equalsIgnoreCase("properties")) {
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.load(new StringReader(data));
|
||||
return properties;
|
||||
}
|
||||
else if (fileExtension.equalsIgnoreCase("yaml")
|
||||
|| fileExtension.equalsIgnoreCase("yml")) {
|
||||
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
|
||||
yamlFactory.setResources(new ByteArrayResource(data.getBytes()));
|
||||
return yamlFactory.getObject();
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
log.warn(
|
||||
"Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]",
|
||||
dataId, group);
|
||||
return EMPTY_PROPERTIES;
|
||||
}
|
||||
log.info(String.format(
|
||||
"Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId,
|
||||
group, data));
|
||||
|
||||
Properties properties = NacosDataParserHandler.getInstance()
|
||||
.parseNacosData(data, fileExtension);
|
||||
return properties == null ? EMPTY_PROPERTIES : properties;
|
||||
}
|
||||
catch (NacosException e) {
|
||||
log.error("get data from Nacos error,dataId:{}, ", dataId, e);
|
||||
@ -117,9 +111,9 @@ public class NacosPropertySourceBuilder {
|
||||
Enumeration<String> keys = (Enumeration<String>) properties.propertyNames();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
Object value = properties.getProperty(key);
|
||||
String value = properties.getProperty(key);
|
||||
if (value != null) {
|
||||
result.put(key, ((String) value).trim());
|
||||
result.put(key, value.trim());
|
||||
}
|
||||
else {
|
||||
result.put(key, null);
|
||||
|
@ -16,23 +16,26 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigManager;
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.parser.NacosDataParserHandler;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosContextRefresher;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
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;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosContextRefresher;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
* @author pbting
|
||||
@ -42,25 +45,31 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private static final Logger log = LoggerFactory
|
||||
.getLogger(NacosPropertySourceLocator.class);
|
||||
|
||||
private static final String NACOS_PROPERTY_SOURCE_NAME = "NACOS";
|
||||
|
||||
private static final String SEP1 = "-";
|
||||
|
||||
private static final String DOT = ".";
|
||||
|
||||
private static final String SHARED_CONFIG_SEPARATOR_CHAR = "[,]";
|
||||
private static final List<String> SUPPORT_FILE_EXTENSION = Arrays.asList("properties",
|
||||
"yaml", "yml");
|
||||
|
||||
private NacosPropertySourceBuilder nacosPropertySourceBuilder;
|
||||
|
||||
private NacosConfigProperties nacosConfigProperties;
|
||||
|
||||
public NacosPropertySourceLocator(NacosConfigProperties nacosConfigProperties) {
|
||||
private NacosConfigManager nacosConfigManager;
|
||||
|
||||
public NacosPropertySourceLocator(NacosConfigManager nacosConfigManager,
|
||||
NacosConfigProperties nacosConfigProperties) {
|
||||
this.nacosConfigManager = nacosConfigManager;
|
||||
this.nacosConfigProperties = nacosConfigProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertySource<?> locate(Environment env) {
|
||||
|
||||
ConfigService configService = nacosConfigProperties.configServiceInstance();
|
||||
ConfigService configService = nacosConfigManager.getConfigService();
|
||||
|
||||
if (null == configService) {
|
||||
log.warn("no instance of config service found, can't load config from nacos");
|
||||
@ -99,14 +108,14 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] sharedDataIdArry = sharedDataIds.split(SHARED_CONFIG_SEPARATOR_CHAR);
|
||||
checkDataIdFileExtension(sharedDataIdArry);
|
||||
String[] sharedDataIdArray = sharedDataIds.split(SHARED_CONFIG_SEPARATOR_CHAR);
|
||||
checkDataIdFileExtension(sharedDataIdArray);
|
||||
|
||||
for (int i = 0; i < sharedDataIdArry.length; i++) {
|
||||
String dataId = sharedDataIdArry[i];
|
||||
for (int i = 0; i < sharedDataIdArray.length; i++) {
|
||||
String dataId = sharedDataIdArray[i];
|
||||
String fileExtension = dataId.substring(dataId.lastIndexOf(".") + 1);
|
||||
boolean isRefreshable = checkDataIdIsRefreshbable(refreshDataIds,
|
||||
sharedDataIdArry[i]);
|
||||
boolean isRefreshable = checkDataIdIsRefreshable(refreshDataIds,
|
||||
sharedDataIdArray[i]);
|
||||
|
||||
loadNacosDataIfPresent(compositePropertySource, dataId, "DEFAULT_GROUP",
|
||||
fileExtension, isRefreshable);
|
||||
@ -114,18 +123,18 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
}
|
||||
|
||||
private void loadExtConfiguration(CompositePropertySource compositePropertySource) {
|
||||
if (nacosConfigProperties.getExtConfig() == null
|
||||
|| nacosConfigProperties.getExtConfig().isEmpty()) {
|
||||
List<NacosConfigProperties.Config> extConfigs = nacosConfigProperties
|
||||
.getExtConfig();
|
||||
|
||||
if (CollectionUtils.isEmpty(extConfigs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<NacosConfigProperties.Config> extConfigs = nacosConfigProperties
|
||||
.getExtConfig();
|
||||
checkExtConfiguration(extConfigs);
|
||||
|
||||
for (NacosConfigProperties.Config config : extConfigs) {
|
||||
String dataId = config.getDataId();
|
||||
String fileExtension = dataId.substring(dataId.lastIndexOf(".") + 1);
|
||||
String fileExtension = dataId.substring(dataId.lastIndexOf(DOT) + 1);
|
||||
loadNacosDataIfPresent(compositePropertySource, dataId, config.getGroup(),
|
||||
fileExtension, config.isRefresh());
|
||||
}
|
||||
@ -137,7 +146,7 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
String dataId = extConfigs.get(i).getDataId();
|
||||
if (dataId == null || dataId.trim().length() == 0) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"the [ spring.cloud.nacos.config.ext-config[%s] ] must give a dataid",
|
||||
"the [ spring.cloud.nacos.config.ext-config[%s] ] must give a dataId",
|
||||
i));
|
||||
}
|
||||
dataIds[i] = dataId;
|
||||
@ -152,8 +161,13 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
String fileExtension = properties.getFileExtension();
|
||||
String nacosGroup = properties.getGroup();
|
||||
|
||||
// load directly once by default
|
||||
loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
|
||||
fileExtension, true);
|
||||
// load with suffix, which have a higher priority than the default
|
||||
loadNacosDataIfPresent(compositePropertySource,
|
||||
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
|
||||
// Loaded with profile, which have a higher priority than the suffix
|
||||
for (String profile : environment.getActiveProfiles()) {
|
||||
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
|
||||
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
|
||||
@ -164,56 +178,58 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
|
||||
private void loadNacosDataIfPresent(final CompositePropertySource composite,
|
||||
final String dataId, final String group, String fileExtension,
|
||||
boolean isRefreshable) {
|
||||
if (NacosContextRefresher.getRefreshCount() != 0) {
|
||||
NacosPropertySource ps;
|
||||
if (!isRefreshable) {
|
||||
ps = NacosPropertySourceRepository.getNacosPropertySource(dataId);
|
||||
}
|
||||
else {
|
||||
ps = nacosPropertySourceBuilder.build(dataId, group, fileExtension, true);
|
||||
}
|
||||
if (null == dataId || dataId.trim().length() < 1) {
|
||||
return;
|
||||
}
|
||||
if (null == group || group.trim().length() < 1) {
|
||||
return;
|
||||
}
|
||||
NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group,
|
||||
fileExtension, isRefreshable);
|
||||
this.addFirstPropertySource(composite, propertySource, false);
|
||||
}
|
||||
|
||||
composite.addFirstPropertySource(ps);
|
||||
private NacosPropertySource loadNacosPropertySource(final String dataId,
|
||||
final String group, String fileExtension, boolean isRefreshable) {
|
||||
if (NacosContextRefresher.getRefreshCount() != 0) {
|
||||
if (!isRefreshable) {
|
||||
return NacosPropertySourceRepository.getNacosPropertySource(dataId);
|
||||
}
|
||||
}
|
||||
else {
|
||||
NacosPropertySource ps = nacosPropertySourceBuilder.build(dataId, group,
|
||||
fileExtension, isRefreshable);
|
||||
composite.addFirstPropertySource(ps);
|
||||
return nacosPropertySourceBuilder.build(dataId, group, fileExtension,
|
||||
isRefreshable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the nacos configuration to the first place and maybe ignore the empty
|
||||
* configuration.
|
||||
*/
|
||||
private void addFirstPropertySource(final CompositePropertySource composite,
|
||||
NacosPropertySource nacosPropertySource, boolean ignoreEmpty) {
|
||||
if (null == nacosPropertySource || null == composite) {
|
||||
return;
|
||||
}
|
||||
if (ignoreEmpty && nacosPropertySource.getSource().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
composite.addFirstPropertySource(nacosPropertySource);
|
||||
}
|
||||
|
||||
private static void checkDataIdFileExtension(String[] dataIdArray) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < dataIdArray.length; i++) {
|
||||
boolean isLegal = false;
|
||||
for (String fileExtension : SUPPORT_FILE_EXTENSION) {
|
||||
if (dataIdArray[i].indexOf(fileExtension) > 0) {
|
||||
isLegal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add tips
|
||||
if (!isLegal) {
|
||||
stringBuilder.append(dataIdArray[i] + ",");
|
||||
}
|
||||
}
|
||||
|
||||
if (stringBuilder.length() > 0) {
|
||||
String result = stringBuilder.substring(0, stringBuilder.length() - 1);
|
||||
throw new IllegalStateException(String.format(
|
||||
"[%s] must contains file extension with properties|yaml|yml",
|
||||
result));
|
||||
if (dataIdArray == null || dataIdArray.length < 1) {
|
||||
throw new IllegalStateException("The dataId cannot be empty");
|
||||
}
|
||||
// Just decide that the current dataId must have a suffix
|
||||
NacosDataParserHandler.getInstance().checkDataId(dataIdArray);
|
||||
}
|
||||
|
||||
private boolean checkDataIdIsRefreshbable(String refreshDataIds,
|
||||
String sharedDataId) {
|
||||
if (refreshDataIds == null || "".equals(refreshDataIds)) {
|
||||
private boolean checkDataIdIsRefreshable(String refreshDataIds, String sharedDataId) {
|
||||
if (StringUtils.isEmpty(refreshDataIds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] refreshDataIdArry = refreshDataIds.split(SHARED_CONFIG_SEPARATOR_CHAR);
|
||||
for (String refreshDataId : refreshDataIdArry) {
|
||||
String[] refreshDataIdArray = refreshDataIds.split(SHARED_CONFIG_SEPARATOR_CHAR);
|
||||
for (String refreshDataId : refreshDataIdArray) {
|
||||
if (refreshDataId.equals(sharedDataId)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -31,7 +31,10 @@ public class NacosConnectionFailureAnalyzer
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure,
|
||||
NacosConnectionFailureException cause) {
|
||||
return new FailureAnalysis("Application failed to connect to Nacos server",
|
||||
"check your nacos server config", cause);
|
||||
return new FailureAnalysis(
|
||||
"Application failed to connect to Nacos server: \""
|
||||
+ cause.getServerAddr() + "\"",
|
||||
"Please check your Nacos server config", cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,29 +24,21 @@ package com.alibaba.cloud.nacos.diagnostics.analyzer;
|
||||
*/
|
||||
public class NacosConnectionFailureException extends RuntimeException {
|
||||
|
||||
private final String domain;
|
||||
private final String serverAddr;
|
||||
|
||||
private final String port;
|
||||
|
||||
public NacosConnectionFailureException(String domain, String port, String message) {
|
||||
public NacosConnectionFailureException(String serverAddr, String message) {
|
||||
super(message);
|
||||
this.domain = domain;
|
||||
this.port = port;
|
||||
this.serverAddr = serverAddr;
|
||||
}
|
||||
|
||||
public NacosConnectionFailureException(String domain, String port, String message,
|
||||
public NacosConnectionFailureException(String serverAddr, String message,
|
||||
Throwable cause) {
|
||||
super(message, cause);
|
||||
this.domain = domain;
|
||||
this.port = port;
|
||||
this.serverAddr = serverAddr;
|
||||
}
|
||||
|
||||
String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
String getPort() {
|
||||
return port;
|
||||
public String getServerAddr() {
|
||||
return serverAddr;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,13 +23,13 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySource;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
|
||||
/**
|
||||
* Endpoint for Nacos, contains config data and refresh history
|
||||
* @author xiaojing
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.endpoint;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigManager;
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@ -23,9 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@ -37,6 +38,9 @@ public class NacosConfigEndpointAutoConfiguration {
|
||||
@Autowired
|
||||
private NacosConfigProperties nacosConfigProperties;
|
||||
|
||||
@Autowired
|
||||
private NacosConfigManager nacosConfigManager;
|
||||
|
||||
@Autowired
|
||||
private NacosRefreshHistory nacosRefreshHistory;
|
||||
|
||||
@ -48,7 +52,6 @@ public class NacosConfigEndpointAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public NacosConfigHealthIndicator nacosConfigHealthIndicator() {
|
||||
return new NacosConfigHealthIndicator(nacosConfigProperties,
|
||||
nacosConfigProperties.configServiceInstance());
|
||||
return new NacosConfigHealthIndicator(nacosConfigManager.getConfigService());
|
||||
}
|
||||
}
|
||||
|
@ -16,58 +16,27 @@
|
||||
|
||||
package com.alibaba.cloud.nacos.endpoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigProperties;
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySource;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
public class NacosConfigHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private final NacosConfigProperties nacosConfigProperties;
|
||||
|
||||
private final List<String> dataIds;
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
public NacosConfigHealthIndicator(NacosConfigProperties nacosConfigProperties,
|
||||
ConfigService configService) {
|
||||
this.nacosConfigProperties = nacosConfigProperties;
|
||||
public NacosConfigHealthIndicator(ConfigService configService) {
|
||||
this.configService = configService;
|
||||
|
||||
this.dataIds = new ArrayList<>();
|
||||
for (NacosPropertySource nacosPropertySource : NacosPropertySourceRepository
|
||||
.getAll()) {
|
||||
this.dataIds.add(nacosPropertySource.getDataId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
for (String dataId : dataIds) {
|
||||
try {
|
||||
String config = configService.getConfig(dataId,
|
||||
nacosConfigProperties.getGroup(),
|
||||
nacosConfigProperties.getTimeout());
|
||||
if (StringUtils.isEmpty(config)) {
|
||||
builder.down().withDetail(String.format("dataId: '%s', group: '%s'",
|
||||
dataId, nacosConfigProperties.getGroup()), "config is empty");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
builder.down().withDetail(String.format("dataId: '%s', group: '%s'",
|
||||
dataId, nacosConfigProperties.getGroup()), e.getMessage());
|
||||
}
|
||||
}
|
||||
builder.up().withDetail("dataIds", dataIds);
|
||||
builder.up();
|
||||
|
||||
String status = configService.getServerStatus();
|
||||
builder.status(status);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.alibaba.nacos.client.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public abstract class AbstractNacosDataParser {
|
||||
|
||||
protected static final String DOT = ".";
|
||||
|
||||
protected static final String VALUE = "value";
|
||||
|
||||
private String extension;
|
||||
|
||||
private AbstractNacosDataParser nextParser;
|
||||
|
||||
protected AbstractNacosDataParser(String extension) {
|
||||
if (StringUtils.isEmpty(extension)) {
|
||||
throw new IllegalArgumentException("extension cannot be empty");
|
||||
}
|
||||
this.extension = extension.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify dataId extensions.
|
||||
* @param extension file extension. json or xml or yml or yaml or properties
|
||||
* @return valid or not
|
||||
*/
|
||||
public final boolean checkFileExtension(String extension) {
|
||||
if (this.isLegal(extension.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
if (this.nextParser == null) {
|
||||
return false;
|
||||
}
|
||||
return this.nextParser.checkFileExtension(extension);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsing nacos configuration content.
|
||||
* @param data config data from Nacos
|
||||
* @param extension file extension. json or xml or yml or yaml or properties
|
||||
* @return result of Properties
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
public final Properties parseNacosData(String data, String extension)
|
||||
throws IOException {
|
||||
if (extension == null || extension.length() < 1) {
|
||||
throw new IllegalStateException("The file extension cannot be empty");
|
||||
}
|
||||
if (this.isLegal(extension.toLowerCase())) {
|
||||
return this.doParse(data);
|
||||
}
|
||||
if (this.nextParser == null) {
|
||||
throw new IllegalStateException(getTips(extension));
|
||||
}
|
||||
return this.nextParser.parseNacosData(data, extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Core logic for parsing.
|
||||
* @param data config from Nacos
|
||||
* @return result of Properties
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
protected abstract Properties doParse(String data) throws IOException;
|
||||
|
||||
protected AbstractNacosDataParser setNextParser(AbstractNacosDataParser nextParser) {
|
||||
this.nextParser = nextParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractNacosDataParser addNextParser(AbstractNacosDataParser nextParser) {
|
||||
if (this.nextParser == null) {
|
||||
this.nextParser = nextParser;
|
||||
}
|
||||
else {
|
||||
this.nextParser.addNextParser(nextParser);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
protected boolean isLegal(String extension) {
|
||||
return this.extension.equalsIgnoreCase(extension)
|
||||
|| this.extension.contains(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate key-value pairs from the map.
|
||||
*/
|
||||
protected Properties generateProperties(Map<String, String> map) {
|
||||
if (null == map || map.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Properties properties = new Properties();
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (StringUtils.isBlank(key)) {
|
||||
continue;
|
||||
}
|
||||
key = key.startsWith(DOT) ? key.replaceFirst("\\.", "") : key;
|
||||
properties.put(key, entry.getValue());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the key ending in `value` if need.
|
||||
*/
|
||||
protected Map<String, String> reloadMap(Map<String, String> map) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> result = new HashMap<>(map);
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.contains(DOT)) {
|
||||
int idx = key.lastIndexOf(DOT);
|
||||
String suffix = key.substring(idx + 1);
|
||||
if (VALUE.equalsIgnoreCase(suffix)) {
|
||||
result.put(key.substring(0, idx), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getTips(String fileName) {
|
||||
return String.format(
|
||||
"[%s] must contains file extension with properties|yaml|yml|xml|json",
|
||||
fileName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.alibaba.nacos.client.utils.StringUtils;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataJsonParser extends AbstractNacosDataParser {
|
||||
protected NacosDataJsonParser() {
|
||||
super("json");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties doParse(String data) throws IOException {
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> map = parseJSON2Map(data);
|
||||
return this.generateProperties(this.reloadMap(map));
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON to Map.
|
||||
* @param json json data
|
||||
* @return the map convert by json string
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
public static Map<String, String> parseJSON2Map(String json) throws IOException {
|
||||
Map<String, String> map = new HashMap<>(32);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode jsonNode = mapper.readTree(json);
|
||||
if (null == jsonNode) {
|
||||
return map;
|
||||
}
|
||||
parseJsonNode(map, jsonNode, "");
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void parseJsonNode(Map<String, String> jsonMap, JsonNode jsonNode,
|
||||
String parentKey) {
|
||||
Iterator<String> fieldNames = jsonNode.fieldNames();
|
||||
while (fieldNames.hasNext()) {
|
||||
String name = fieldNames.next();
|
||||
String fullKey = StringUtils.isEmpty(parentKey) ? name
|
||||
: parentKey + DOT + name;
|
||||
JsonNode resultValue = jsonNode.findValue(name);
|
||||
if (null == resultValue) {
|
||||
continue;
|
||||
}
|
||||
if (resultValue.isArray()) {
|
||||
Iterator<JsonNode> iterator = resultValue.elements();
|
||||
while (iterator != null && iterator.hasNext()) {
|
||||
JsonNode next = iterator.next();
|
||||
if (null == next) {
|
||||
continue;
|
||||
}
|
||||
parseJsonNode(jsonMap, next, fullKey);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (resultValue.isObject()) {
|
||||
parseJsonNode(jsonMap, resultValue, fullKey);
|
||||
continue;
|
||||
}
|
||||
jsonMap.put(fullKey, resultValue.asText());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public final class NacosDataParserHandler {
|
||||
|
||||
private AbstractNacosDataParser parser;
|
||||
|
||||
private NacosDataParserHandler() {
|
||||
parser = this.createParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsing nacos configuration content.
|
||||
* @param data config from Nacos
|
||||
* @param extension file extension. json or xml or yml or yaml or properties
|
||||
* @return result of properties
|
||||
* @throws IOException thrown if there is a problem parsing config.
|
||||
*/
|
||||
public Properties parseNacosData(String data, String extension) throws IOException {
|
||||
if (null == parser) {
|
||||
parser = this.createParser();
|
||||
}
|
||||
return parser.parseNacosData(data, extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* check the validity of file extensions in dataid.
|
||||
* @param dataIdAry array of dataId
|
||||
* @return dataId handle success or not
|
||||
*/
|
||||
public boolean checkDataId(String... dataIdAry) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (String dataId : dataIdAry) {
|
||||
int idx = dataId.lastIndexOf(AbstractNacosDataParser.DOT);
|
||||
if (idx > 0 && idx < dataId.length() - 1) {
|
||||
String extension = dataId.substring(idx + 1);
|
||||
if (parser.checkFileExtension(extension)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add tips
|
||||
stringBuilder.append(dataId).append(",");
|
||||
}
|
||||
if (stringBuilder.length() > 0) {
|
||||
String result = stringBuilder.substring(0, stringBuilder.length() - 1);
|
||||
throw new IllegalStateException(AbstractNacosDataParser.getTips(result));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private AbstractNacosDataParser createParser() {
|
||||
return new NacosDataPropertiesParser().addNextParser(new NacosDataYamlParser())
|
||||
.addNextParser(new NacosDataXmlParser())
|
||||
.addNextParser(new NacosDataJsonParser());
|
||||
}
|
||||
|
||||
public static NacosDataParserHandler getInstance() {
|
||||
return ParserHandler.HANDLER;
|
||||
}
|
||||
|
||||
private static class ParserHandler {
|
||||
|
||||
private static final NacosDataParserHandler HANDLER = new NacosDataParserHandler();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataPropertiesParser extends AbstractNacosDataParser {
|
||||
|
||||
public NacosDataPropertiesParser() {
|
||||
super("properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties doParse(String data) throws IOException {
|
||||
Properties properties = new Properties();
|
||||
properties.load(new StringReader(data));
|
||||
return properties;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import com.alibaba.nacos.client.utils.StringUtils;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* With relatively few usage scenarios, only simple parsing is performed to reduce jar
|
||||
* dependencies.
|
||||
*
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataXmlParser extends AbstractNacosDataParser {
|
||||
|
||||
public NacosDataXmlParser() {
|
||||
super("xml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties doParse(String data) throws IOException {
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
Map<String, String> map = parseXml2Map(data);
|
||||
return this.generateProperties(this.reloadMap(map));
|
||||
}
|
||||
|
||||
private Map<String, String> parseXml2Map(String xml) throws IOException {
|
||||
xml = xml.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll("\\t", "");
|
||||
Map<String, String> map = new HashMap<>(32);
|
||||
try {
|
||||
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
|
||||
.newDocumentBuilder();
|
||||
Document document = documentBuilder
|
||||
.parse(new InputSource(new StringReader(xml)));
|
||||
if (null == document) {
|
||||
return null;
|
||||
}
|
||||
parseNodeList(document.getChildNodes(), map, "");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IOException("The xml content parse error.", e.getCause());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void parseNodeList(NodeList nodeList, Map<String, String> map,
|
||||
String parentKey) {
|
||||
if (nodeList == null || nodeList.getLength() < 1) {
|
||||
return;
|
||||
}
|
||||
parentKey = parentKey == null ? "" : parentKey;
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node = nodeList.item(i);
|
||||
String value = node.getNodeValue();
|
||||
value = value == null ? "" : value.trim();
|
||||
String name = node.getNodeName();
|
||||
name = name == null ? "" : name.trim();
|
||||
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = StringUtils.isEmpty(parentKey) ? name : parentKey + DOT + name;
|
||||
NamedNodeMap nodeMap = node.getAttributes();
|
||||
parseNodeAttr(nodeMap, map, key);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE && node.hasChildNodes()) {
|
||||
parseNodeList(node.getChildNodes(), map, key);
|
||||
continue;
|
||||
}
|
||||
if (value.length() < 1) {
|
||||
continue;
|
||||
}
|
||||
map.put(parentKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseNodeAttr(NamedNodeMap nodeMap, Map<String, String> map,
|
||||
String parentKey) {
|
||||
if (null == nodeMap || nodeMap.getLength() < 1) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < nodeMap.getLength(); i++) {
|
||||
Node node = nodeMap.item(i);
|
||||
if (null == node) {
|
||||
continue;
|
||||
}
|
||||
if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
|
||||
if (StringUtils.isEmpty(node.getNodeName())) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.isEmpty(node.getNodeValue())) {
|
||||
continue;
|
||||
}
|
||||
map.put(parentKey + DOT + node.getNodeName(), node.getNodeValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.nacos.parser;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
/**
|
||||
* @author zkz
|
||||
*/
|
||||
public class NacosDataYamlParser extends AbstractNacosDataParser {
|
||||
|
||||
public NacosDataYamlParser() {
|
||||
super(",yml,yaml,");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties doParse(String data) {
|
||||
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
|
||||
yamlFactory.setResources(new ByteArrayResource(data.getBytes()));
|
||||
return yamlFactory.getObject();
|
||||
}
|
||||
}
|
@ -26,8 +26,15 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySource;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.config.listener.Listener;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.cloud.endpoint.event.RefreshEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@ -35,12 +42,6 @@ import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySource;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.config.listener.Listener;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
|
||||
/**
|
||||
* On application start up, NacosContextRefresher add nacos listeners to all application
|
||||
* level dataIds, when there is a change in the data, listeners will refresh
|
||||
|
@ -1,5 +1,16 @@
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.cloud.nacos.server-addr",
|
||||
"type": "java.lang.String",
|
||||
"description": "nacos server address."
|
||||
},
|
||||
{
|
||||
"name": "spring.cloud.nacos.config.server-addr",
|
||||
"type": "java.lang.String",
|
||||
"defaultValue": "${spring.cloud.nacos.server-addr}",
|
||||
"description": "nacos config server address."
|
||||
},
|
||||
{
|
||||
"name": "spring.cloud.nacos.config.encode",
|
||||
"type": "java.lang.String",
|
||||
|
@ -16,12 +16,13 @@
|
||||
|
||||
package com.alibaba.cloud.nacos;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
|
||||
import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
|
||||
import com.alibaba.nacos.client.config.NacosConfigService;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -31,6 +32,7 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
@ -39,9 +41,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
|
||||
import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
|
||||
import com.alibaba.nacos.client.config.NacosConfigService;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
|
@ -16,14 +16,16 @@
|
||||
|
||||
package com.alibaba.cloud.nacos;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
|
||||
import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpoint;
|
||||
import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
|
||||
import com.alibaba.nacos.client.config.NacosConfigService;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -33,6 +35,7 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
@ -41,11 +44,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
|
||||
import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpoint;
|
||||
import com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
|
||||
import com.alibaba.cloud.nacos.refresh.NacosRefreshHistory;
|
||||
import com.alibaba.nacos.client.config.NacosConfigService;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user