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

# Conflicts:
#	spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json
pull/2437/head
Freeman Lau 3 years ago
commit 9c4dc69cce

@ -27,5 +27,6 @@ jobs:
- name: Compile & Checkstyle
run: mvn clean compile
- name: Testing
run: mvn clean -Dit.enabled=true test
run: mvn clean test
# run: mvn clean -Dit.enabled=true test

@ -27,7 +27,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
* **阿里云短信服务**:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
更多功能请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/Roadmap-zh.md)
更多功能请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2021.x/Roadmap-zh.md)
除了上述所具有的功能外针对企业级用户的场景Spring Cloud Alibaba 配套的企业版微服务治理方案 [微服务引擎MSE](https://www.aliyun.com/product/aliware/mse?spm=github.spring.com.topbar) 还提供了企业级微服务治理中心,包括全链路灰度、服务预热、无损上下线和离群实例摘除等更多更强大的治理能力,同时还提供了企业级 Nacos 注册配置中心,企业级云原生网关等多种产品及解决方案。
@ -52,7 +52,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/2022.0/Roadmap-zh.md)。
## 如何构建
* 2022.x 分支对应的是 Spring Cloud 2022 与 Spring Boot 2.6.x最低支持 JDK 1.8。
* 2021.x 分支对应的是 Spring Cloud 2022 与 Spring Boot 2.6.x最低支持 JDK 1.8。
* 2020.0 分支对应的是 Spring Cloud 2020 与 Spring Boot 2.4.x最低支持 JDK 1.8。
* 2.2.x 分支对应的是 Spring Cloud Hoxton 与 Spring Boot 2.2.x最低支持 JDK 1.8。
* greenwich 分支对应的是 Spring Cloud Greenwich 与 Spring Boot 2.1.x最低支持 JDK 1.8。
@ -118,7 +118,7 @@ Example 列表:
* 2.1.x 版本适用于 Spring Boot 2.1.x
* 2.2.x 版本适用于 Spring Boot 2.2.x
* 2020.x 版本适用于 Spring Boot 2.4.x
* 2022.x 版本适用于 Spring Boot 2.6.x
* 2021.x 版本适用于 Spring Boot 2.6.x
## 社区交流

@ -53,7 +53,7 @@ In addition to the above-mentioned features, for the needs of enterprise users'
For more features please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md).
## How to build
* **2022.x branch**: Corresponds to Spring Cloud 2021 & Spring Boot 2.6.x. JDK 1.8 or later versions are supported.
* **2021.x branch**: Corresponds to Spring Cloud 2021 & Spring Boot 2.6.x. JDK 1.8 or later versions are supported.
* **2020.0 branch**: Corresponds to Spring Cloud 2020 & Spring Boot 2.4.x. JDK 1.8 or later versions are supported.
* **2.2.x branch**: Corresponds to Spring Cloud Hoxton & Spring Boot 2.2.x. JDK 1.8 or later versions are supported.
* **greenwich branch**: Corresponds to Spring Cloud Greenwich & Spring Boot 2.1.x. JDK 1.8 or later versions are supported.
@ -123,7 +123,7 @@ As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been c
* 2.1.x for Spring Boot 2.1.x
* 2.2.x for Spring Boot 2.2.x
* 2020.x for Spring Boot 2.4.x
* 2022.x for Spring Boot 2.6.x
* 2021.x for Spring Boot 2.6.x
## Code of Conduct
This project is a sub-project of Spring Cloud, it adheres to the Contributor Covenant [code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.

@ -80,13 +80,11 @@
<properties>
<!-- Project revision -->
<revision>2021.0.1.0</revision>
<revision>2021.0.1.1-SNAPSHOT</revision>
<!-- Spring Cloud -->
<spring.cloud.version>2021.0.1</spring.cloud.version>
<!-- Apache Dubbo -->
<dubbo.version>2.7.15</dubbo.version>
<curator.version>4.0.1</curator.version>
<!-- Apache RocketMQ -->
@ -142,45 +140,6 @@
<scope>import</scope>
</dependency>
<!-- Dubbo Dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-actuator</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>

@ -75,11 +75,6 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>

@ -18,7 +18,7 @@
<description>Spring Cloud Alibaba Dependencies</description>
<properties>
<revision>2021.0.1.0</revision>
<revision>2021.0.1.1-SNAPSHOT</revision>
<sentinel.version>1.8.3</sentinel.version>
<seata.version>1.4.2</seata.version>
<nacos.client.version>1.4.2</nacos.client.version>
@ -120,18 +120,6 @@
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-reactor-adapter</artifactId>
@ -246,13 +234,6 @@
<version>${revision}</version>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>

@ -0,0 +1,119 @@
=== 开发角色
Spring Cloud Alibaba项目开发者包含Steering Committee Member、Committer、Contributor三种角色每种角色的标准定义如下。
==== Steering Committee Member
Steering Committee 作为Spring Cloud Alibaba项目的技术发展指导委员会其成员是对Spring Cloud Alibaba项目的演进和发展做出显著贡献的个人。具体包含以下的标准
* 完成多个关键模块或者工程的设计与开发,是项目的核心开发人员;
* 持续的投入和激情能够积极参与社区、官网、issue、PR等项目相关事项的维护
* 在社区中具有有目共睹的影响力能够代表Spring Cloud Alibaba参加重要的社区会议和活动
* 具有培养Committer和Contributor的意识和能力
==== Committer
Committer是具有仓库写权限的个人包含以下的标准
* 能够在长时间内做持续贡献issue、PR的个人
* 参与issue列表的维护及重要feature的讨论
* 参与code review
==== Contributor
Contributor是对项目有贡献的个人标准为
* 提交过PR并被合并
=== 开发团队
本页面展示了Spring Cloud Alibaba 的开发团队成员,我们一直都在持续扩充中,欢迎加入社区:)
==== Steering Committee Member成员
|===
|姓名 |Github账号 |角色 |联系方式 |组织
|方剑
|fangjian0423
|Steering Committee Member
|fangjian0423@gmail.com
|阿里巴巴
|肖京
|flystar32
|Steering Committee Member
|flystar32@163.com
|阿里巴巴
|马昕曦
|mercyblitz
|Steering Committee Member
|mercyblitz@gmail.com
|自由职业
|任浩军
|HaojunRen
|Steering Committee Member
|1394997@qq.com
|Nepxion社区
|陈曦
|theonefx
|Steering Committee Member
|chenxilzx1@gmail.com
|阿里巴巴
|===
==== Committer成员
|===
|姓名 |Github账号 |角色 |联系方式 |组织
|廖春涛
|chuntaojun
|Committer
|liaochuntao@live.com
|腾讯
|余黄彬
|yuhuangbin
|Committer
|danielyu96@163.com
|~
|赵奕豪
|sczyh30
|Committer
|sczyh16@gmail.com
|阿里巴巴
|张开兆
|zkzlx
|Committer
|kiss_maple@163.com
|得物
|饶子昊
|steverao
|Committer
|zihaorao@126.com
|阿里巴巴
|刘梁文
|DanielLiu1123
|Committer
|llw599502537@gmail.com
|在校学生
|冷冷
|lltx
|Committer
|wangiegie@gmail.com
|~
|echooymxq
|echooymxq
|Committer
|echooy.mxq@gmail.com
|~
|===

@ -1,45 +0,0 @@
== Spring Cloud Alibaba Dubbo
=== 简介
Dubbo Spring Cloud 基于 Dubbo Spring Boot 2.7.3[1] 和 Spring Cloud 2.x 开发,无论开发人员是 Dubbo 用户还是 Spring Cloud 用户,
都能轻松地驾驭并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud 致力于简化 Cloud Native 开发成本,提高研发效能以及提升应用性能等目的。
=== 功能
由于 Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可认为是 Spring Cloud Plus
不仅完全覆盖 Spring Cloud 原生特性[5],而且提供更为稳定和成熟的实现,特性比对如下表所示:
|===
|功能组件 |Spring Cloud |Dubbo Spring Cloud
| 分布式配置Distributed configuration | Git、Zookeeper、Consul、JDBC | Spring Cloud 分布式配置 + Dubbo 配置中心[6]
| 服务注册与发现Service registration and discovery | Eureka、Zookeeper、Consul | Spring Cloud 原生注册中心[7] + Dubbo 原生注册中心[8]
| 负载均衡Load balancing | Ribbon随机、轮询等算法 | Dubbo 内建实现(随机、轮询等算法 + 权重等特性)
| 服务熔断Circuit Breakers | Spring Cloud Hystrix | Spring Cloud Hystrix + Alibaba Sentinel[9] 等
| 服务调用Service-to-service calls | Open Feign、`RestTemplate` | Spring Cloud 服务调用 + Dubbo `@Reference`
| 链路跟踪Tracing | Spring Cloud Sleuth[10] + Zipkin[11] | Zipkin、opentracing 等
|===
=== Reference 说明
[1]: 从 2.7.0 开始Dubbo Spring Boot 与 Dubbo 在版本上保持一致
[2]: Preview releases of Spring Cloud Alibaba are available: 0.9.0, 0.2.2, and 0.1.2 - https://spring.io/blog/2011/04/11/preview-releases-of-spring-cloud-alibaba-are-available-0-9-0-0-2-2-and-0-1-2
[3]: 目前最新的 Spring Cloud “F” 版的版本为:`Finchley.SR2` - https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html
[4]: 当前Spring Cloud “G” 版为 `Greenwich.RELEASE`
[5]: Spring Cloud 特性列表 - https://cloud.spring.io/spring-cloud-static/Greenwich.RELEASE/single/spring-cloud.html#_features
[6]: Dubbo 2.7 开始支持配置中心,可自定义适配 - http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html
[7]: Spring Cloud 原生注册中心,除 Eureka、Zookeeper、Consul 之外,还包括 Spring Cloud Alibaba 中的 Nacos
[8]: Dubbo 原生注册中心 - http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html
[9]: Alibaba SentinelSentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性 - https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D ,目前 Sentinel 已被 Spring Cloud 项目纳为 Circuit Breaker 的候选实现 - https://spring.io/blog/2011/04/8/introducing-spring-cloud-circuit-breaker
[10]:Spring Cloud Sleuth - https://spring.io/projects/spring-cloud-sleuth
[11]: Zipkin - https://github.com/apache/incubator-zipkin

@ -98,7 +98,7 @@ Add a spring.config.import=nacos: property to your configuration.
- 假如想保留以前的使用方式 (bootstrap引入配置),你只需要添加依赖 `spring-cloud-starter-bootstrap` 依赖,不需要修改一行代码
你可以前往 https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-2.4.x-example[这里] 查看具体example
你可以前往 https://github.com/alibaba/spring-cloud-alibaba/tree/2021.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-2.4.x-example[这里] 查看具体example
==== Nacos 容错能力
@ -178,7 +178,7 @@ feign:
*注意事项:* 如果你使用的是 `spring-cloud-starter-alibaba-sentinel`,请**不要**配置 `feign.sentinel.enable=true`,会使配置失效
你可以前往 https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example[这里] 查看具体 example
你可以前往 https://github.com/alibaba/spring-cloud-alibaba/tree/2021.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example[这里] 查看具体 example
=== 对升级的一点建议
1. 在 spring boot 2.6 之后默认开启了禁止循环引入,建议大家不要关闭,这是一种不好的编码习惯,如果你的项目里出现了循环引用,请选择重构它

@ -17,8 +17,6 @@ include::nacos-config.adoc[]
include::sentinel.adoc[]
include::dubbo.adoc[]
include::rocketmq-new.adoc[]
include::rocketmq.adoc[]

@ -0,0 +1,119 @@
=== Development Role
The Spring Cloud Alibaba project developer includes three roles: Steering Committee Member, Committer, and Contributor. The standard definitions of each role are as follows.
==== Steering Committee Member
Steering Committee, as the technical development steering committee of the Spring Cloud Alibaba project, its members are individuals who have made significant contributions to the evolution and development of the Spring Cloud Alibaba project. Specifically include the following standards:
* Complete the design and development of multiple key modules or projects, and be the core developer of the project;
* Continuous investment and passion, able to actively participate in the maintenance of community, official website, issue, PR and other project related matters;
* Has a visible influence in the community and can represent Spring Cloud Alibaba to participate in important community conferences and activities;
* Have the awareness and ability to cultivate Committer and Contributor;
==== Committer
A committer is an individual with write permissions to the repository, and includes the following criteria:
* Individuals who can make continuous contributions to issues and PRs for a long time;
* Participate in the maintenance of the issue list and the discussion of important features;
* Participate in code review;
==== Contributor
Contributors are individuals who contribute to the project, the standard is
* Submitted PR and merged;
=== Development Team
This page shows the development team members of Spring Cloud Alibaba. We are constantly expanding. Welcome to join the community :)
==== Steering Committee Member
|===
|Name |Github ID |Role |Email |Company
|Jian Fang
|fangjian0423
|Steering Committee Member
|fangjian0423@gmail.com
|Alibaba
|Jing Xiao
|flystar32
|Steering Committee Member
|flystar32@163.com
|Alibaba
|Xinxi Ma
|mercyblitz
|Steering Committee Member
|mercyblitz@gmail.com
|Freelance
|Haojun Ren
|HaojunRen
|Steering Committee Member
|1394997@qq.com
|Nepxion Community
|Xi Chen
|theonefx
|Steering Committee Member
|chenxilzx1@gmail.com
|Alibaba
|===
==== Committer
|===
|Name |Github账号 |Role |Email |Company
|Chuntao Niao
|chuntaojun
|Committer
|liaochuntao@live.com
|Tencent
|Huangbin Yu
|yuhuangbin
|Committer
|danielyu96@163.com
|~
|Yihao Zhao
|sczyh30
|Committer
|sczyh16@gmail.com
|Alibaba
|Kaizhao Zhang
|zkzlx
|Committer
|kiss_maple@163.com
|Poizon
|Zihao Rao
|steverao
|Committer
|zihaorao@126.com
|Alibaba
|Liangwen Liu
|DanielLiu1123
|Committer
|llw599502537@gmail.com
|Student
|Lengleng
|lltx
|Committer
|wangiegie@gmail.com
|~
|echooymxq
|echooymxq
|Committer
|echooy.mxq@gmail.com
|~
|===

@ -1,45 +0,0 @@
== Spring Cloud Alibaba Dubbo
=== Introduction
Dubbo Spring Cloud is based on Dubbo Spring Boot 2.7.3[1] and Spring Cloud 2.x development, whether the developer is a Dubbo user or a Spring Cloud user.
Easily navigate and move apps up at a cost close to “zero” costs. Dubbo Spring Cloud is designed to simplify Cloud Native development costs, improve R&D performance, and improve application performance.
=== Features
Since Dubbo Spring Cloud is built on top of the native Spring Cloud, its service governance capabilities are considered Spring Cloud Plus.
Not only does it fully cover the Spring Cloud native features [5], but it also provides a more stable and mature implementation, as shown in the following table:
|===
|Feature |Spring Cloud |Dubbo Spring Cloud
| Distributed configuration | Git、Zookeeper、Consul、JDBC | Spring Cloud Distributed Configuration + Dubbo Configuration Center[6]
| Service registration and discovery | Eureka、Zookeeper、Consul | Spring Cloud Native Registration Center[7] + Dubbo Native Registration Center[8]
| Load balancing | RibbonRandom, RoundRobin | Dubbo built-in implementation (random, polling, etc. + weights, etc.)
| Circuit Breakers | Spring Cloud Hystrix | Spring Cloud Hystrix + Alibaba Sentinel[9] etc.
| Service-to-service calls | Open Feign、`RestTemplate` | Spring Cloud service call + Dubbo `@Reference`.
| Tracing | Spring Cloud Sleuth[10] + Zipkin[11] | Zipkin、opentracing, etc.
|===
=== Reference
[1]: Starting with 2.7.0, Dubbo Spring Boot and Dubbo are consistent in version
[2]: Preview releases of Spring Cloud Alibaba are available: 0.9.0, 0.2.2, and 0.1.2 - https://spring.io/blog/2011/04/11/preview-releases-of-spring-cloud-alibaba-are-available-0-9-0-0-2-2-and-0-1-2
[3]: The current version of the Spring Cloud "F" is: `Finchley.SR2` - https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html
[4]: The current Spring Cloud "G" version is `Greenwich.RELEASE`
[5]: Spring Cloud feature list - https://cloud.spring.io/spring-cloud-static/Greenwich.RELEASE/single/spring-cloud.html#_features
[6]: Dubbo 2.7 starts supporting the configuration center and can be customized - http://dubbo.apache.org/en-us/docs/user/configuration/config-center.html
[7]: Spring Cloud native registry, in addition to Eureka, Zookeeper, and Consul, includes Nacos in Spring Cloud Alibaba
[8]: Dubbo Native Registration Center - http://dubbo.apache.org/en-us/docs/user/references/registry/introduction.html
[9]: Alibaba Sentinel: Sentinel uses traffic as an entry point to protect service stability from multiple dimensions such as flow control, blowdown, and system load protection - https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B %E7%BB%8D, currently Sentinel has been accepted as a candidate for Circuit Breaker by the Spring Cloud project - https://spring.io/blog/2011/04/8/introducing-spring-cloud-circuit-breaker
[10]:Spring Cloud Sleuth - https://spring.io/projects/spring-cloud-sleuth
[11]: Zipkin - https://github.com/apache/incubator-zipkin

@ -98,7 +98,7 @@ You can manually turn it off by setting `spring.cloud.nacos.config.import-check.
- If you want to keep the previous usage (bootstrap way), you only need to add the dependency `spring-cloud-starter-bootstrap` dependency and don't need modifying a line of code.
you can go https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-2.4.x-example[here] to see the complete example.
you can go https://github.com/alibaba/spring-cloud-alibaba/tree/2021.x/spring-cloud-alibaba-examples/nacos-example/nacos-config-2.4.x-example[here] to see the complete example.
==== Nacos Failure Tolerance
@ -177,7 +177,7 @@ This feature also supports dynamic refresh from the configuration center. You ca
*Note:* If you are using `spring-cloud-starter-alibaba-sentinel`, please *DO NOT* configure `feign.sentinel.enable=true`, it will invalidate the configuration.
You can go https://github.com/alibaba/spring-cloud-alibaba/tree/2022.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example[here] to see the complete example.
You can go https://github.com/alibaba/spring-cloud-alibaba/tree/2021.x/spring-cloud-alibaba-examples/sentinel-example/sentinel-circuitbreaker-example[here] to see the complete example.
=== Little Advice For Upgrading
1. After Spring Boot 2.6, the prohibition of circular reference is enabled by default. It is recommended that you do not change it. This is a bad coding practice. If there is a circular reference in your project, please choose to refactor it.

@ -17,8 +17,6 @@ include::nacos-config.adoc[]
include::sentinel.adoc[]
include::dubbo.adoc[]
include::rocketmq.adoc[]
include::ans.adoc[]

@ -63,7 +63,7 @@ class UserConfig {
private int age;
private String name;
private String nickname;
private String hr;
@ -79,12 +79,12 @@ class UserConfig {
this.age = age;
}
public String getName() {
return name;
public String getNickname() {
return nickname;
}
public void setName(String name) {
this.name = name;
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Map<String, Object> getMap() {
@ -113,7 +113,7 @@ class UserConfig {
@Override
public String toString() {
return "UserConfig{" + "age=" + age + ", name='" + name + '\'' + ", map=" + map
return "UserConfig{" + "age=" + age + ", nickname='" + nickname + '\'' + ", map=" + map
+ ", hr='" + hr + '\'' + ", users=" + users + '}';
}
@ -208,21 +208,21 @@ class SampleController {
@Autowired
private Environment environment;
@Value("${user.name:zz}")
String userName;
@Value("${user.nickname:zz}")
String nickname;
@Value("${user.age:25}")
Integer age;
@RequestMapping("/user")
public String simple() {
return "Hello Nacos Config!" + "Hello " + userName + " " + age + " [UserConfig]: "
return "Hello Nacos Config!" + "Hello " + nickname + " " + age + " [UserConfig]: "
+ userConfig + "!" + nacosConfigManager.getConfigService();
}
@RequestMapping("/get/{name}")
public String getValue(@PathVariable String name) {
return String.valueOf(environment.getProperty(name));
@RequestMapping("/get/{nickname}")
public String getValue(@PathVariable String nickname) {
return String.valueOf(environment.getProperty(nickname));
}
@RequestMapping("/bool")

@ -31,7 +31,8 @@ spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=test1.yml
spring.cloud.nacos.config.extension-configs[1].refresh=true
# the setting of reading config log print on stdout
logging.level.com.alibaba.cloud.nacos.client=debug
spring.cloud.nacos.config.refresh-enabled=true

@ -6,48 +6,32 @@
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../../pom.xml</relativePath>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-dubbo-provider-example</artifactId>
<name>Spring Cloud Starter Alibaba Sentinel x Dubbo - Provider Example</name>
<description>Example demonstrating how to use sentinel with dubbo</description>
<artifactId>nacos-config-preference-example</artifactId>
<name>Spring Cloud Starter Alibaba Nacos Config Preference Example</name>
<description>Example demonstrating how to use nacos config preference in spring boot</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>sentinel-dubbo-api</artifactId>
<version>${project.version}</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>

@ -0,0 +1,44 @@
# Nacos Config Preference
## 项目说明
本项目演示如何使用配置偏好配置
## 示例
1. 启动一个 Nacos server
添加配置 `test.yml`
```yaml
configdata:
user:
name: freeman
```
添加配置 `test2.yml`
```yaml
dev:
age: 22
```
2. 设置配置偏好
设置默认配置偏好
```yaml
spring:
cloud:
nacos:
config:
preference: remote
```
指定配置test2.yml设置配置偏好
```yaml
spring:
config:
import:
- optional:nacos:test.yml
- optional:nacos:test2.yml?preference=local
```
3. 验证
访问 `localhost`,应该能看到值为 `freeman: 20`,因为 `name` 优先使用了配置中心配置,`age` 优先使用本地配置。

@ -0,0 +1,44 @@
# Nacos Config Preference
## Project instruction
This project demonstrates how to use config preferences.
## Example
1. Start a Nacos server
add configuration `test.yml`
```yaml
configdata:
user:
name: freeman
```
add configuration `test2.yml`
```yaml
dev:
age: 22
```
2. Set configuration preference
Set default configuration preference
```yaml
spring:
cloud:
nacos:
config:
preference: remote
```
Specify configuration (test 2.yml) to set configuration preference
```yaml
spring:
config:
import:
- optional:nacos:test.yml
- optional:nacos:test2.yml?preference=local
```
3. Verify
Access `localhost`, you should see the value of `freeman: 20`, because `name` uses the configuration center configuration first, and `age` uses the local configuration first.

@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,22 +14,23 @@
* limitations under the License.
*/
package com.alibaba.cloud.examples;
package com.alibaba.cloud.configpreference.examples;
import org.springframework.boot.WebApplicationType;
import com.alibaba.cloud.configpreference.examples.model.UserProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* @author fangjian
* @author freeman
*/
@SpringBootApplication
public class SentinelDubboProviderApp {
@EnableConfigurationProperties(UserProperties.class)
public class ConfigPreferenceApplication {
public static void main(String[] args) {
SpringApplicationBuilder providerBuilder = new SpringApplicationBuilder();
providerBuilder.web(WebApplicationType.NONE)
.sources(SentinelDubboProviderApp.class).run(args);
SpringApplication.run(ConfigPreferenceApplication.class, args);
}
}

@ -0,0 +1,46 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.configpreference.examples.controller;
import com.alibaba.cloud.configpreference.examples.model.UserProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
*
*
* @author freeman
*/
@RestController
@RefreshScope
public class UserController {
@Autowired
private UserProperties userProperties;
@Value("${dev.age}")
private int age;
@GetMapping
public String getName() {
return userProperties.getName() + ": " + age;
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,29 +14,32 @@
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
package com.alibaba.cloud.configpreference.examples.model;
import java.util.List;
import java.util.Map;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Rest Service.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*
* @author freeman
*/
public interface RestService {
String param(String param);
String params(int a, String b);
String headers(String header, String header2, Integer param);
String pathVariables(String path1, String path2, String param);
String form(String form);
User requestBodyMap(Map<String, Object> data, String param);
Map<String, Object> requestBodyUser(User user);
@Data
@ConfigurationProperties(prefix = "configdata.user")
public class UserProperties {
private String name;
private Integer age;
private Map<String, Object> map;
private List<User> users;
@Data
public static class User {
private String name;
private Integer age;
}
}

@ -0,0 +1,31 @@
server:
port: 80
spring:
application:
name: nacos-config-import-example
cloud:
nacos:
config:
group: DEFAULT_GROUP
server-addr: 127.0.0.1:8848
preference: remote
config:
import:
- optional:nacos:test.yml
- optional:nacos:test2.yml?preference=local
profiles:
active: dev
logging:
level:
# print content
com.alibaba.cloud.nacos.configdata: debug
---
spring:
config:
activate:
on-profile: dev
configdata:
user:
name: bb
dev:
age: 20

@ -18,9 +18,6 @@
<modules>
<module>sentinel-example/sentinel-core-example</module>
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example</module>
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example</module>
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api</module>
<module>sentinel-example/sentinel-feign-example/sentinel-feign-consumer-example</module>
<module>sentinel-example/sentinel-feign-example/sentinel-feign-provider-example</module>
<module>sentinel-example/sentinel-circuitbreaker-example</module>
@ -29,6 +26,7 @@
<module>nacos-example/nacos-discovery-example</module>
<module>nacos-example/nacos-config-example</module>
<module>nacos-example/nacos-config-2.4.x-example</module>
<module>nacos-example/nacos-config-preference-example</module>
<module>nacos-example/nacos-gateway-example</module>
<module>seata-example/business-service</module>
<module>seata-example/order-service</module>
@ -38,7 +36,6 @@
<module>rocketmq-example/rocketmq-produce-example</module>
<module>rocketmq-example/rocketmq-comprehensive-example</module>
<module>spring-cloud-bus-rocketmq-example</module>
<module>spring-cloud-alibaba-dubbo-examples</module>
<module>spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-nacos-example</module>
<module>spring-cloud-alibaba-sidecar-examples/spring-cloud-alibaba-sidecar-consul-example</module>
</modules>

@ -1,148 +0,0 @@
# Sentinel Dubbo Example
## 项目说明
本项目演示如何使用 Sentinel starter 完成 Dubbo 应用的限流管理。
[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件Sentinel 把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。
[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/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example)。
## 示例
### 如何接入
在启动示例进行演示之前,我们先了解一下 Dubbo 如何接入 Sentinel。
**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。**
1. 首先,修改 pom.xml 文件,引入 Sentinel starter 和 Dubbo starter。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
2. 配置限流规则
Sentinel提供了[sentinel-dubbo-adapter](https://github.com/alibaba/Sentinel/tree/master/sentinel-adapter/sentinel-dubbo-adapter)模块用来支持Dubbo服务调用的限流降级。sentinel-starter默认也集成了该功能。
sentinel-dubbo-adapter内部的Dubbo Filter会根据资源名进行限流降级处理。只需要配置规则即可
FlowRule flowRule = new FlowRule();
flowRule.setResource("dubboResource");
flowRule.setCount(10);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
### 服务定义及发布
Provider端在application.properties文件中定义dubbo相关的配置比如协议注册中心
spring.application.name = dubbo-provider-demo
foo.service.version = 1.0.0
dubbo.scan.basePackages = com.alibaba.cloud.examples
dubbo.application.id = dubbo-provider-demo
dubbo.application.name = dubbo-provider-demo
dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 12345
dubbo.protocol.status = server
dubbo.registry.id = my-registry
dubbo.registry.address = N/A
`sentinel-dubbo-api`模块中定义了FooService服务内容如下
package com.alibaba.cloud.examples;
public interface FooService {
String hello(String name);
}
定义具体的服务:
@DubboService(
version = "${foo.service.version}",
application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}",
registry = "${dubbo.registry.id}"
)
public class FooServiceImpl implements FooService {
@Override
public String hello(String name) {
return "hello, " + name;
}
}
### 服务调用
Consumer端在服务调用之前先定义限流规则。
`sentinel-dubbo-api`模块中定义了FooService服务内容如下
package com.alibaba.cloud.examples;
public interface FooService {
String hello(String name);
}
该服务在Sentinel下对应的资源名是 `com.alibaba.cloud.examples.FooService:hello(java.lang.String)`
定义该资源名对应的限流规则:
FlowRule flowRule = new FlowRule();
flowRule.setResource("com.alibaba.cloud.examples.FooService:hello(java.lang.String)");
flowRule.setCount(10);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
根据Provider端中发布的定义使用Dubbo的@Reference注解注入服务对应的Bean
@DubboReference(version = "${foo.service.version}", application = "${dubbo.application.id}",
path = "dubbo://localhost:12345", timeout = 30000)
private FooService fooService;
由于设置的qps是10。调用15次查看是否被限流
FooServiceConsumer service = applicationContext.getBean(FooServiceConsumer.class);
for (int i = 0; i < 15; i++) {
try {
String message = service.hello("Jim");
System.out.println((i + 1) + " -> Success: " + message);
}
catch (SentinelRpcException ex) {
System.out.println("Blocked");
}
catch (Exception ex) {
ex.printStackTrace();
}
}
### 应用启动
支持 IDE 直接启动和编译打包后启动。
Provider端
1. IDE直接启动找到主类 `SentinelDubboProviderApp`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-dubbo-provider-example.jar`启动应用。
Consumer端
1. IDE直接启动找到主类 `SentinelDubboConsumerApp`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-dubbo-consumer-example.jar`启动应用。

@ -1,145 +0,0 @@
# Sentinel Dubbo Example
## Project Instruction
This example illustrates how to use Sentinel starter to implement flow control for Spring Cloud applications.
[Sentinel](https://github.com/alibaba/Sentinel) is an open-source project of Alibaba. Sentinel takes "traffic flow" as the breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability.
[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/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example).
## Demo
### Connect to Sentinel
Before we start the demo, let's learn how to connect Sentinel with Dubbo to a Spring Cloud application.
**Note: This section is to show you how to connect to Sentinel. The configurations have been completed in the following example, so you don't need modify the code any more.**
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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
2. Configure flow control rules
Sentinel provide [sentinel-dubbo-adapter](https://github.com/alibaba/Sentinel/tree/master/sentinel-adapter/sentinel-dubbo-adapter) module to support dubbo. to support dubbo. sentinel-starter integrates this feature by default.
sentinel-dubbo-adapter will using Sentinel to handle resource by Dubbo Filter. You just need to define rules.
FlowRule flowRule = new FlowRule();
flowRule.setResource("dubboResource");
flowRule.setCount(10);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
### Configure and Publish Service
Define some configs of dubbo in `application.properties` in provider side, like protocol, config registry :
spring.application.name = dubbo-provider-demo
foo.service.version = 1.0.0
dubbo.scan.basePackages = com.alibaba.cloud.examples
dubbo.application.id = dubbo-provider-demo
dubbo.application.name = dubbo-provider-demo
dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 12345
dubbo.protocol.status = server
dubbo.registry.id = my-registry
dubbo.registry.address = N/A
`sentinel-dubbo-api` define a service named FooService:
package com.alibaba.cloud.examples;
public interface FooService {
String hello(String name);
}
Define the implement Service annotated by `@Service`:
@Service(
version = "${foo.service.version}",
application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}",
registry = "${dubbo.registry.id}"
)
public class FooServiceImpl implements FooService {
@Override
public String hello(String name) {
return "hello, " + name;
}
}
### Service Invocation
We will configure flow control rules before service invocation in consumer side.
`sentinel-dubbo-api` define a service named FooService:
package com.alibaba.cloud.examples;
public interface FooService {
String hello(String name);
}
The resource name of this service's `hello` method is `com.alibaba.cloud.examples.FooService:hello(java.lang.String)` .
Configure rules:
FlowRule flowRule = new FlowRule();
flowRule.setResource("com.alibaba.cloud.examples.FooService:hello(java.lang.String)");
flowRule.setCount(10);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
Using the `@Reference` annotation to inject service:
@Reference(version = "${foo.service.version}", application = "${dubbo.application.id}",
path = "dubbo://localhost:12345", timeout = 30000)
private FooService fooService;
Because QPS is 10, we can see that flow control takes effect in this invocation:
FooServiceConsumer service = applicationContext.getBean(FooServiceConsumer.class);
for (int i = 0; i < 15; i++) {
try {
String message = service.hello("Jim");
System.out.println((i + 1) + " -> Success: " + message);
}
catch (SentinelRpcException ex) {
System.out.println("Blocked");
}
catch (Exception ex) {
ex.printStackTrace();
}
}
### Start Application
Start the application in IDE or by building a fatjar.
Provider side:
1. Start in IDE: Find main class `SentinelDubboProviderApp`, 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-provider-example.jar` to start the application.
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.

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-dubbo-api</artifactId>
<name>Spring Cloud Starter Alibaba Sentinel x Dubbo - API</name>
<description>api for sentinel dubbo example</description>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -1,26 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
/**
* @author fangjian
*/
public interface FooService {
String hello(String name);
}

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sentinel-dubbo-consumer-example</artifactId>
<name>Spring Cloud Starter Alibaba Sentinel x Dubbo - Consumer Example</name>
<description>Example demonstrating how to use sentinel with dubbo</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</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-apache-dubbo-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -1,35 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.apache.dubbo.config.annotation.DubboReference;
/**
* @author fangjian
*/
public class FooServiceConsumer {
@DubboReference(version = "${foo.service.version}",
application = "${dubbo.application.id}",
url = "dubbo://localhost:12345?version=1.0.0", timeout = 30000)
private FooService fooService;
public String hello(String name) {
return fooService.hello(name);
}
}

@ -1,74 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import java.util.Collections;
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.WebApplicationType;
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
*/
@SpringBootApplication(scanBasePackages = "com.alibaba.cloud.examples")
public class SentinelDubboConsumerApp {
@Bean
public FooServiceConsumer annotationDemoServiceConsumer() {
return new FooServiceConsumer();
}
public static void main(String[] args) {
FlowRule flowRule = new FlowRule();
flowRule.setResource(
"com.alibaba.cloud.examples.FooService:hello(java.lang.String)");
flowRule.setCount(10);
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRule.setLimitApp("default");
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
SpringApplicationBuilder consumerBuilder = new SpringApplicationBuilder();
ApplicationContext applicationContext = consumerBuilder
.web(WebApplicationType.NONE).sources(SentinelDubboConsumerApp.class)
.run(args);
FooServiceConsumer service = applicationContext.getBean(FooServiceConsumer.class);
for (int i = 0; i < 15; i++) {
try {
String message = service.hello("Jim");
System.out.println((i + 1) + " -> Success: " + message);
}
catch (SentinelRpcException ex) {
System.out.println("Blocked");
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
}

@ -1,11 +0,0 @@
spring.application.name = dubbo-consumer-demo
foo.service.version = 1.0.0
dubbo.application.id = dubbo-consumer-demo
dubbo.application.name = dubbo-consumer-demo
dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 12345

@ -1,33 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.examples;
import org.apache.dubbo.config.annotation.DubboService;
/**
* @author fangjian
*/
@DubboService(version = "${foo.service.version}", application = "${dubbo.application.id}",
protocol = "${dubbo.protocol.id}", registry = "${dubbo.registry.id}")
public class FooServiceImpl implements FooService {
@Override
public String hello(String name) {
return "hello, " + name;
}
}

@ -1,16 +0,0 @@
spring.application.name = dubbo-provider-demo
foo.service.version = 1.0.0
dubbo.scan.basePackages = com.alibaba.cloud.examples
dubbo.application.id = dubbo-provider-demo
dubbo.application.name = dubbo-provider-demo
dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 12345
dubbo.protocol.status = server
dubbo.registry.id = my-registry
dubbo.registry.address = N/A

@ -1,348 +0,0 @@
# Dubbo Spring Cloud 示例工程
## 快速开始
### 定义 Dubbo 服务接口
Dubbo 服务接口是服务提供方与消费方的远程通讯契约,通常由普通的 Java 接口interface来声明`EchoService` 接口:
```java
public interface EchoService {
String echo(String message);
}
```
为了确保契约的一致性,推荐的做法是将 Dubbo 服务接口打包在第二方或者第三方的 artifactjar如以上接口就存放在
artifact [spring-cloud-dubbo-sample-api](https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/spring-cloud-dubbo-sample-api) 之中。
对于服务提供方而言,不仅通过依赖 artifact 的形式引入 Dubbo 服务接口,而且需要将其实现。对应的服务消费端,同样地需要依赖该 artifact
并以接口调用的方式执行远程方法。接下来进一步讨论怎样实现 Dubbo 服务提供方和消费方。
### 实现 Dubbo 服务提供方
#### 初始化 `spring-cloud-dubbo-server-sample` Maven 工程
首先,创建 `artifactId` 名为 `spring-cloud-dubbo-server-sample` 的 Maven 工程,并在其 `pom.xml` 文件中增添
Dubbo Spring Cloud 必要的依赖:
```xml
<dependencies>
<!-- Sample API -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
```
以上依赖 artifact 说明如下:
- `spring-cloud-dubbo-sample-api` : 提供 `EchoService` 接口的 artifact
- `spring-boot-actuator` : Spring Boot Production-Ready artifact间接引入 `spring-boot` artifact
- `spring-cloud-starter-dubbo` : Dubbo Spring Cloud Starter `artifact`,间接引入 `dubbo-spring-boot-starter` 等 artifact
- `spring-cloud-starter-alibaba-nacos-discovery` : Nacos Spring Cloud 服务注册与发现 `artifact`
值得注意的是,以上 artifact 未指定版本(version),因此,还需显示地声明 `<dependencyManagement>` :
```xml
<dependencyManagement>
<dependencies>
<!-- Spring Cloud Alibaba dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
```
> 以上完整的 Maven 依赖配置,请参考 `spring-cloud-dubbo-server-sample` [`pom.xml`](spring-cloud-dubbo-server-sample/pom.xml) 文件
完成以上步骤之后,下一步则是实现 Dubbo 服务
#### 实现 Dubbo 服务
`EchoService` 作为暴露的 Dubbo 服务接口,服务提供方 `spring-cloud-dubbo-server-sample` 需要将其实现:
```java
@org.apache.dubbo.config.annotation.Service
class EchoServiceImpl implements EchoService {
@Override
public String echo(String message) {
return "[echo] Hello, " + message;
}
}
```
其中,`@org.apache.dubbo.config.annotation.Service` 是 Dubbo 服务注解,仅声明该 Java 服务(本地)实现为 Dubbo 服务。
因此,下一步需要将其配置 Dubbo 服务(远程)。
#### 配置 Dubbo 服务提供方
在暴露 Dubbo 服务方面,推荐开发人员外部化配置的方式,即指定 Java 服务实现类的扫描基准包。
> Dubbo Spring Cloud 继承了 Dubbo Spring Boot 的外部化配置特性,也可以通过标注 `@DubboComponentScan` 来实现基准包扫描。
同时Dubbo 远程服务需要暴露网络端口,并设定通讯协议,完整的 YAML 配置如下所示:
```yaml
dubbo:
scan:
# dubbo 服务扫描基准包
base-packages: com.alibaba.cloud.dubbo.bootstrap
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
port: -1
registry:
# 挂载到 Spring Cloud 注册中心
address: spring-cloud://localhost
spring:
application:
# Dubbo 应用名称
name: spring-cloud-alibaba-dubbo-server
main:
# Spring Boot 2.1 需要设定
allow-bean-definition-overriding: true
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: 127.0.0.1:8848
```
以上 YAML 内容,上半部分为 Dubbo 的配置:
- `dubbo.scan.base-packages` : 指定 Dubbo 服务实现类的扫描基准包
- `dubbo.protocol` : Dubbo 服务暴露的协议配置,其中子属性 `name` 为协议名称,`port` 为协议端口( -1 表示自增端口,从 20880 开始)
- `dubbo.registry` : Dubbo 服务注册中心配置,其中子属性 `address` 的值 "spring-cloud://localhost",说明挂载到 Spring Cloud 注册中心
> 当前 Dubbo Spring Cloud 实现必须配置 `dubbo.registry.address = spring-cloud://localhost`,下一个版本将其配置变为可选
(参考 [issue #592](https://github.com/alibaba/spring-cloud-alibaba/issues/592)
> 并且支持传统 Dubbo 协议的支持(参考 [issue #588](https://github.com/alibaba/spring-cloud-alibaba/issues/588)
下半部分则是 Spring Cloud 相关配置:
- `spring.application.name` : Spring 应用名称,用于 Spring Cloud 服务注册和发现。
> 该值在 Dubbo Spring Cloud 加持下被视作 `dubbo.application.name`,因此,无需再显示地配置 `dubbo.application.name`
- `spring.main.allow-bean-definition-overriding` : 在 Spring Boot 2.1 以及更高的版本增加该设定,
因为 Spring Boot 默认调整了 Bean 定义覆盖行为。(推荐一个好的 Dubbo 讨论 [issue #3193](https://github.com/apache/dubbo/issues/3193#issuecomment-474340165)
- `spring.cloud.nacos.discovery` : Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
> 以上完整的 YAML 配置文件,请参考 `spring-cloud-dubbo-server-sample` [`bootstrap.yaml`](spring-cloud-dubbo-server-sample/src/main/resources/bootstrap.yaml) 文件
完成以上步骤后,还需编写一个 Dubbo Spring Cloud 引导类。
#### 引导 Dubbo Spring Cloud 服务提供方应用
Dubbo Spring Cloud 引导类与普通 Spring Cloud 应用并无差别,如下所示:
```java
@EnableDiscoveryClient
@EnableAutoConfiguration
public class DubboSpringCloudServerBootstrap {
public static void main(String[] args) {
SpringApplication.run(DubboSpringCloudServerBootstrap.class);
}
}
```
在引导 `DubboSpringCloudServerBootstrap` 之前,请提前启动 Nacos 服务器。
`DubboSpringCloudServerBootstrap` 启动后,将应用 `spring-cloud-dubbo-server-sample` 将出现在 Nacos 控制台界面。
当 Dubbo 服务提供方启动后,下一步实现一个 Dubbo 服务消费方。
### 实现 Dubbo 服务消费方
由于 Java 服务就 `EchoService`、服务提供方应用 `spring-cloud-dubbo-server-sample` 以及 Nacos 服务器均已准备完毕。Dubbo 服务消费方
只需初始化服务消费方 Maven 工程 `spring-cloud-dubbo-client-sample` 以及消费 Dubbo 服务。
#### 初始化 `spring-cloud-dubbo-client-sample` Maven 工程
与服务提供方 Maven 工程类,需添加相关 Maven 依赖:
```xml
<dependencyManagement>
<dependencies>
<!-- Spring Cloud Alibaba dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Sample API -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
```
与应用 `spring-cloud-dubbo-server-sample` 不同的是,当前应用依赖 `spring-boot-starter-web`,表明它属于 Web Servlet 应用。
> 以上完整的 Maven 依赖配置,请参考 `spring-cloud-dubbo-client-sample` [`pom.xml`](spring-cloud-dubbo-client-sample/pom.xml) 文件
#### 配置 Dubbo 服务消费方
Dubbo 服务消费方配置与服务提供方类似,当前应用 `spring-cloud-dubbo-client-sample` 属于纯服务消费方,因此,所需的外部化配置更精简:
```yaml
dubbo:
registry:
# 挂载到 Spring Cloud 注册中心
address: spring-cloud://localhost
cloud:
subscribed-services: spring-cloud-alibaba-dubbo-server
spring:
application:
# Dubbo 应用名称
name: spring-cloud-alibaba-dubbo-client
main:
# Spring Boot 2.1 需要设定
allow-bean-definition-overriding: true
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: 127.0.0.1:8848
```
对比应用 `spring-cloud-dubbo-server-sample`,除应用名称 `spring.application.name` 存在差异外,`spring-cloud-dubbo-client-sample`
新增了属性 `dubbo.cloud.subscribed-services` 的设置。并且该值为服务提供方应用 "spring-cloud-dubbo-server-sample"。
- `dubbo.cloud.subscribed-services` : 用于服务消费方订阅服务提供方的应用名称的列表,若需订阅多应用,使用 "," 分割。
不推荐使用默认值为 "*",它将订阅所有应用。
> 当应用使用属性 `dubbo.cloud.subscribed-services` 默认值时,日志中将会输出一行警告:
> > Current application will subscribe all services(size:x) in registry, a lot of memory and CPU cycles may be used,
> > thus it's strongly recommend you using the externalized property 'dubbo.cloud.subscribed-services' to specify the services
由于当前应用属于 Web 应用,它会默认地使用 8080 作为 Web 服务端口,如果需要自定义,可通过属性 `server.port` 调整。
> 以上完整的 YAML 配置文件,请参考 `spring-cloud-dubbo-client-sample` [`bootstrap.yaml`](spring-cloud-dubbo-client-sample/src/main/resources/bootstrap.yaml) 文件
#### 引导 Dubbo Spring Cloud 服务消费方应用
为了减少实现步骤,以下引导类将 Dubbo 服务消费以及引导功能合二为一:
```java
@EnableDiscoveryClient
@EnableAutoConfiguration
@RestController
public class DubboSpringCloudClientBootstrap {
@Reference
private EchoService echoService;
@GetMapping("/echo")
public String echo(String message) {
return echoService.echo(message);
}
public static void main(String[] args) {
SpringApplication.run(DubboSpringCloudClientBootstrap.class);
}
}
```
不仅如此,`DubboSpringCloudClientBootstrap` 也作为 REST Endpoint通过暴露 `/echo` Web 服务,消费 Dubbo `EchoService` 服务。因此,
可通过 `curl` 命令执行 HTTP GET 方法:
```
$ curl http://127.0.0.1:8080/echo?message=%E5%B0%8F%E9%A9%AC%E5%93%A5%EF%BC%88mercyblitz%EF%BC%89
```
HTTP 响应为:
```
[echo] Hello, 小马哥mercyblitz
```
以上结果说明应用 `spring-cloud-dubbo-client-sample` 通过消费 Dubbo 服务,返回服务提供方 `spring-cloud-dubbo-server-sample`
运算后的内容。
以上操作就一套完整的 Dubbo 服务提供方和消费方的运用,更多的详情请直接参考模块:
- [`spring-cloud-dubbo-server-sample` ](spring-cloud-dubbo-server-sample)
- [`spring-cloud-dubbo-client-sample`](spring-cloud-dubbo-client-sample)
## 模块说明
- [spring-cloud-dubbo-sample-api](spring-cloud-dubbo-sample-api)API 模块,存放 Dubbo 服务接口和模型定义
- [spring-cloud-dubbo-provider-web-sample](spring-cloud-dubbo-provider-web-sample)Dubbo Spring Cloud 服务提供方示例Web 应用)
- [spring-cloud-dubbo-provider-sample](spring-cloud-dubbo-provider-sample)Dubbo Spring Cloud 服务提供方示例(非 Web 应用)
- [spring-cloud-dubbo-consumer-sample](spring-cloud-dubbo-consumer-sample)Dubbo Spring Cloud 服务消费方示例
- [spring-cloud-dubbo-servlet-gateway](spring-cloud-dubbo-servlet-gateway-sample)Dubbo Spring Cloud Servlet 网关简易实现示例

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<name>Spring Cloud Alibaba Dubbo Examples</name>
<packaging>pom</packaging>
<modules>
<module>spring-cloud-dubbo-sample-api</module>
<module>spring-cloud-dubbo-server-sample</module>
<module>spring-cloud-dubbo-client-sample</module>
<module>spring-cloud-dubbo-provider-sample</module>
<module>spring-cloud-dubbo-consumer-sample</module>
<module>spring-cloud-dubbo-provider-web-sample</module>
<module>spring-cloud-dubbo-servlet-gateway-sample</module>
</modules>
</project>

@ -1,56 +0,0 @@
<?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">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-dubbo-client-sample</artifactId>
<name>Spring Cloud Dubbo Client Sample</name>
<dependencies>
<!-- Sample API -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -1,50 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.bootstrap;
import com.alibaba.cloud.dubbo.service.EchoService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Dubbo Spring Cloud Client Bootstrap.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@RestController
public class DubboSpringCloudClientBootstrap {
@DubboReference
private EchoService echoService;
@GetMapping("/echo")
public String echo(String message) {
return echoService.echo(message);
}
public static void main(String[] args) {
SpringApplication.run(DubboSpringCloudClientBootstrap.class);
}
}

@ -1,22 +0,0 @@
dubbo:
cloud:
subscribed-services: spring-cloud-alibaba-dubbo-server
protocols:
dubbo:
port: -1
spring:
application:
name: spring-cloud-alibaba-dubbo-client
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
username: nacos
password: nacos
server-addr: 127.0.0.1:8848
namespace: public
server:
port: 8080

@ -1,118 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-dubbo-consumer-sample</artifactId>
<name>Spring Cloud Dubbo Consumer Sample</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Spring Cloud Open Feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Spring Retry -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<!-- Sample API -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- List all Spring Cloud starters for Service Discovery -->
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Zookeeper Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<!-- Spring Cloud Consul Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -1,263 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.bootstrap;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.cloud.dubbo.annotation.DubboTransported;
import com.alibaba.cloud.dubbo.service.RestService;
import com.alibaba.cloud.dubbo.service.User;
import com.alibaba.cloud.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* Dubbo Spring Cloud Consumer Bootstrap.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableFeignClients
@EnableScheduling
@EnableCaching
public class DubboSpringCloudConsumerBootstrap {
@DubboReference
private UserService userService;
@DubboReference(version = "1.0.0", protocol = "dubbo")
private RestService restService;
@Autowired
@Lazy
private FeignRestService feignRestService;
@Autowired
@Lazy
private DubboFeignRestService dubboFeignRestService;
@Value("${provider.application.name}")
private String providerApplicationName;
@Autowired
@LoadBalanced
private RestTemplate restTemplate;
@Bean
public ApplicationRunner userServiceRunner() {
return arguments -> {
User user = new User();
user.setId(1L);
user.setName("小马哥");
user.setAge(33);
// save User
System.out.printf("UserService.save(%s) : %s\n", user,
userService.save(user));
// find all Users
System.out.printf("UserService.findAll() : %s\n", user,
userService.findAll());
// remove User
System.out.printf("UserService.remove(%d) : %s\n", user.getId(),
userService.remove(user.getId()));
};
}
@Bean
public ApplicationRunner callRunner() {
return arguments -> {
callAll();
};
}
private void callAll() {
// To call /path-variables
callPathVariables();
// To call /headers
callHeaders();
// To call /param
callParam();
// To call /params
callParams();
// To call /request/body/map
callRequestBodyMap();
}
@Scheduled(fixedDelay = 10 * 1000L)
public void onScheduled() {
callAll();
}
private void callPathVariables() {
// Dubbo Service call
System.out.println(restService.pathVariables("a", "b", "c"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.pathVariables("c", "b", "a"));
// Spring Cloud Open Feign REST Call
// System.out.println(feignRestService.pathVariables("b", "a", "c"));
// RestTemplate call
System.out.println(restTemplate.getForEntity(
"http://" + providerApplicationName + "//path-variables/{p1}/{p2}?v=c",
String.class, "a", "b"));
}
private void callHeaders() {
// Dubbo Service call
System.out.println(restService.headers("a", "b", 10));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.headers("b", 10, "a"));
// Spring Cloud Open Feign REST Call
// System.out.println(feignRestService.headers("b", "a", 10));
}
private void callParam() {
// Dubbo Service call
System.out.println(restService.param("mercyblitz"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.param("mercyblitz"));
// Spring Cloud Open Feign REST Call
// System.out.println(feignRestService.param("mercyblitz"));
}
private void callParams() {
// Dubbo Service call
System.out.println(restService.params(1, "1"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.params("1", 1));
// Spring Cloud Open Feign REST Call
// System.out.println(feignRestService.params("1", 1));
// RestTemplate call
System.out.println(restTemplate.getForEntity(
"http://" + providerApplicationName + "/param?param=小马哥", String.class));
}
private void callRequestBodyMap() {
Map<String, Object> data = new HashMap<>();
data.put("id", 1);
data.put("name", "小马哥");
data.put("age", 33);
// Dubbo Service call
System.out.println(restService.requestBodyMap(data, "Hello,World"));
// Spring Cloud Open Feign REST Call (Dubbo Transported)
System.out.println(dubboFeignRestService.requestBody("Hello,World", data));
// Spring Cloud Open Feign REST Call
// System.out.println(feignRestService.requestBody("Hello,World", data));
// RestTemplate call
System.out.println(restTemplate.postForObject(
"http://" + providerApplicationName + "/request/body/map?param=小马哥", data,
User.class));
}
@Bean
@LoadBalanced
@DubboTransported
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudConsumerBootstrap.class)
.properties("spring.profiles.active=nacos").run(args);
}
@FeignClient("${provider.application.name}")
public interface FeignRestService {
@GetMapping("/param")
String param(@RequestParam("param") String param);
@PostMapping("/params")
String params(@RequestParam("b") String b, @RequestParam("a") int a);
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_VALUE)
User requestBody(@RequestParam("param") String param,
@RequestBody Map<String, Object> data);
@GetMapping("/headers")
String headers(@RequestHeader("h2") String header2,
@RequestHeader("h") String header, @RequestParam("v") Integer value);
@GetMapping("/path-variables/{p1}/{p2}")
String pathVariables(@PathVariable("p2") String path2,
@PathVariable("p1") String path1, @RequestParam("v") String param);
}
@FeignClient("${provider.application.name}")
@DubboTransported(protocol = "dubbo")
public interface DubboFeignRestService {
@GetMapping("/param")
String param(@RequestParam("param") String param);
@PostMapping("/params")
String params(@RequestParam("b") String paramB, @RequestParam("a") int paramA);
@PostMapping(value = "/request/body/map", produces = APPLICATION_JSON_VALUE)
User requestBody(@RequestParam("param") String param,
@RequestBody Map<String, Object> data);
@GetMapping("/headers")
String headers(@RequestHeader("h2") String header2,
@RequestParam("v") Integer value, @RequestHeader("h") String header);
@GetMapping("/path-variables/{p1}/{p2}")
String pathVariables(@RequestParam("v") String param,
@PathVariable("p2") String path2, @PathVariable("p1") String path1);
}
}

@ -1,16 +0,0 @@
dubbo:
cloud:
# The subscribed services in consumer side
subscribed-services: ${provider.application.name}
protocols:
dubbo:
port: -1
consumer:
check: false
server:
port: 0
provider:
application:
name: spring-cloud-alibaba-dubbo-provider

@ -1,72 +0,0 @@
spring:
application:
name: spring-cloud-alibaba-dubbo-consumer
main:
allow-bean-definition-overriding: true
# default disable all
cloud:
nacos:
username: nacos
password: nacos
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: false
consul:
enabled: false
eureka:
client:
enabled: false
ribbon:
nacos:
enabled: false
---
spring:
profiles: nacos
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: 127.0.0.1:8848
ribbon:
nacos:
enabled: true
---
spring:
profiles: eureka
eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
---
spring:
profiles: zookeeper
cloud:
zookeeper:
enabled: true
connect-string: 127.0.0.1:2181
---
spring:
profiles: consul
cloud:
consul:
enabled: true
host: 127.0.0.1
port: 8500

@ -1,152 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-dubbo-provider-sample</artifactId>
<name>Spring Cloud Dubbo Provider Sample</name>
<dependencies>
<!-- Resolve the Dubbo REST RPC issue -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Resolve the Spring Cloud registration issue -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- Sample API -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- List all Spring Cloud starters for Service Discovery -->
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Zookeeper Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<!-- Spring Cloud Consul Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- REST support dependencies -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-netty4</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson-provider</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -1,39 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.bootstrap;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Dubbo Spring Cloud Provider Bootstrap.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
public class DubboSpringCloudProviderBootstrap {
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudProviderBootstrap.class)
.properties("spring.profiles.active=nacos").web(WebApplicationType.NONE)
.run(args);
}
}

@ -1,48 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.dubbo.config.annotation.DubboService;
/**
* In-Memory {@link UserService} implementation.
*/
@DubboService(protocol = "dubbo")
public class InMemoryUserService implements UserService {
private Map<Long, User> usersRepository = new HashMap<>();
@Override
public boolean save(User user) {
return usersRepository.put(user.getId(), user) == null;
}
@Override
public boolean remove(Long userId) {
return usersRepository.remove(userId) != null;
}
@Override
public Collection<User> findAll() {
return usersRepository.values();
}
}

@ -1,123 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.alibaba.cloud.dubbo.util.LoggerUtils.log;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
/**
* Default {@link RestService}.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@DubboService(version = "1.0.0", protocol = { "dubbo", "rest" })
@Path("/")
public class StandardRestService implements RestService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
@Path("param")
@GET
public String param(@QueryParam("param") String param) {
log("/param", param);
return param;
}
@Override
@Path("params")
@POST
public String params(@QueryParam("a") int a, @QueryParam("b") String b) {
log("/params", a + b);
return a + b;
}
@Override
@Path("headers")
@GET
public String headers(@HeaderParam("h") String header,
@HeaderParam("h2") String header2, @QueryParam("v") Integer param) {
String result = header + " , " + header2 + " , " + param;
log("/headers", result);
return result;
}
@Override
@Path("path-variables/{p1}/{p2}")
@GET
public String pathVariables(@PathParam("p1") String path1,
@PathParam("p2") String path2, @QueryParam("v") String param) {
String result = path1 + " , " + path2 + " , " + param;
log("/path-variables", result);
return result;
}
// @CookieParam does not support : https://github.com/OpenFeign/feign/issues/913
// @CookieValue also does not support
@Override
@Path("form")
@POST
public String form(@FormParam("f") String form) {
return String.valueOf(form);
}
@Override
@Path("request/body/map")
@POST
@Produces(APPLICATION_JSON_VALUE)
public User requestBodyMap(Map<String, Object> data,
@QueryParam("param") String param) {
User user = new User();
user.setId(((Integer) data.get("id")).longValue());
user.setName((String) data.get("name"));
user.setAge((Integer) data.get("age"));
log("/request/body/map", param);
return user;
}
@Path("request/body/user")
@POST
@Override
@Consumes(MediaType.APPLICATION_JSON)
public Map<String, Object> requestBodyUser(User user) {
Map<String, Object> map = new HashMap<>();
map.put("id", user.getId());
map.put("name", user.getName());
map.put("age", user.getAge());
return map;
}
}

@ -1,14 +0,0 @@
dubbo:
scan:
base-packages: com.alibaba.cloud.dubbo.service
protocols:
dubbo:
name: dubbo
port: -1
rest:
name: rest
port: 9090
server: netty
feign:
hystrix:
enabled: true

@ -1,67 +0,0 @@
spring:
application:
name: spring-cloud-alibaba-dubbo-provider
main:
allow-bean-definition-overriding: true
# default disable all
cloud:
nacos:
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: false
consul:
enabled: false
eureka:
client:
enabled: false
---
spring:
profiles: nacos
cloud:
nacos:
username: nacos
password: nacos
discovery:
enabled: true
register-enabled: true
server-addr: 127.0.0.1:8848
ephemeral: false
---
spring:
profiles: eureka
eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
---
spring:
profiles: zookeeper
cloud:
zookeeper:
enabled: true
connect-string: 127.0.0.1:2181
---
spring:
profiles: consul
cloud:
consul:
enabled: true
host: 127.0.0.1
port: 8500

@ -1,105 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-dubbo-provider-web-sample</artifactId>
<name>Spring Cloud Dubbo Provider Web Sample</name>
<dependencies>
<!-- Production Ready features -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sample API -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- List all Spring Cloud starters for Service Discovery -->
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Eureka Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Zookeeper Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<!-- Spring Cloud Consul Service Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -1,37 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.bootstrap;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Dubbo Spring Cloud Provider Bootstrap.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
public class DubboSpringCloudWebProviderBootstrap {
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudWebProviderBootstrap.class)
.properties("spring.profiles.active=nacos").run(args);
}
}

@ -1,48 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.dubbo.config.annotation.DubboService;
/**
* In-Memory {@link UserService} implementation.
*/
@DubboService(protocol = "dubbo")
public class InMemoryUserService implements UserService {
private Map<Long, User> usersRepository = new HashMap<>();
@Override
public boolean save(User user) {
return usersRepository.put(user.getId(), user) == null;
}
@Override
public boolean remove(Long userId) {
return usersRepository.remove(userId) != null;
}
@Override
public Collection<User> findAll() {
return usersRepository.values();
}
}

@ -1,110 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
import java.util.HashMap;
import java.util.Map;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static com.alibaba.cloud.dubbo.util.LoggerUtils.log;
/**
* Spring MVC {@link RestService}.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@DubboService(version = "1.0.0")
@RestController
public class SpringRestService implements RestService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
@GetMapping("/param")
public String param(@RequestParam String param) {
log("/param", param);
return param;
}
@Override
@PostMapping("/params")
public String params(@RequestParam int a, @RequestParam String b) {
log("/params", a + b);
return a + b;
}
@Override
@GetMapping("/headers")
public String headers(@RequestHeader("h") String header,
@RequestHeader("h2") String header2, @RequestParam("v") Integer param) {
String result = header + " , " + header2 + " , " + param;
log("/headers", result);
return result;
}
@Override
@GetMapping("/path-variables/{p1}/{p2}")
public String pathVariables(@PathVariable("p1") String path1,
@PathVariable("p2") String path2, @RequestParam("v") String param) {
String result = path1 + " , " + path2 + " , " + param;
log("/path-variables", result);
return result;
}
@Override
@PostMapping("/form")
public String form(@RequestParam("f") String form) {
return String.valueOf(form);
}
@Override
@PostMapping(value = "/request/body/map",
produces = MediaType.APPLICATION_JSON_VALUE)
public User requestBodyMap(@RequestBody Map<String, Object> data,
@RequestParam("param") String param) {
User user = new User();
user.setId(((Integer) data.get("id")).longValue());
user.setName((String) data.get("name"));
user.setAge((Integer) data.get("age"));
log("/request/body/map", param);
return user;
}
@PostMapping(value = "/request/body/user",
consumes = MediaType.APPLICATION_JSON_VALUE)
@Override
public Map<String, Object> requestBodyUser(@RequestBody User user) {
Map<String, Object> map = new HashMap<>();
map.put("id", user.getId());
map.put("name", user.getName());
map.put("age", user.getAge());
return map;
}
}

@ -1,19 +0,0 @@
dubbo:
scan:
base-packages: com.alibaba.cloud.dubbo.service
protocols:
dubbo:
port: -1
feign:
hystrix:
enabled: true
server:
port: 8080
management:
endpoints:
web:
exposure:
include: dubborestmetadata

@ -1,66 +0,0 @@
spring:
application:
name: spring-cloud-alibaba-dubbo-provider
main:
allow-bean-definition-overriding: true
# default disable all
cloud:
nacos:
username: nacos
password: nacos
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: false
consul:
enabled: false
eureka:
client:
enabled: false
---
spring:
profiles: nacos
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: 127.0.0.1:8848
---
spring:
profiles: eureka
eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
---
spring:
profiles: zookeeper
cloud:
zookeeper:
enabled: true
connect-string: 127.0.0.1:2181
---
spring:
profiles: consul
cloud:
consul:
enabled: true
host: 127.0.0.1
port: 8500

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<name>Spring Cloud Dubbo Sample API</name>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
</dependencies>
</project>

@ -1,26 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
/**
* Echo Service.
*/
public interface EchoService {
String echo(String message);
}

@ -1,63 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
import java.io.Serializable;
/**
* User Entity.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class User implements Serializable {
private Long id;
private String name;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';
}
}

@ -1,34 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.service;
import java.util.Collection;
/**
* {@link User} Service.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public interface UserService {
boolean save(User user);
boolean remove(Long userId);
Collection<User> findAll();
}

@ -1,42 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.util;
import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Logger Utilities.
*/
public abstract class LoggerUtils {
private static final Logger logger = LoggerFactory.getLogger(LoggerUtils.class);
public static void log(String url, Object result) {
String message = String
.format("The client[%s] uses '%s' protocol to call %s : %s",
RpcContext.getContext().getRemoteHostName(),
RpcContext.getContext().getUrl() == null ? "N/A"
: RpcContext.getContext().getUrl().getProtocol(),
url, result);
if (logger.isInfoEnabled()) {
logger.info(message);
}
}
}

@ -1,55 +0,0 @@
<?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">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-server-sample</artifactId>
<name>Spring Cloud Dubbo Server Sample</name>
<version>${revision}</version>
<dependencies>
<!-- Sample API -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring Boot dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -1,49 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.bootstrap;
import com.alibaba.cloud.dubbo.service.EchoService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Dubbo Spring Cloud Server Bootstrap.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
public class DubboSpringCloudServerBootstrap {
public static void main(String[] args) {
SpringApplication.run(DubboSpringCloudServerBootstrap.class);
}
}
@DubboService
class EchoServiceImpl implements EchoService {
@Override
public String echo(String message) {
return "[echo] Hello, " + message;
}
}

@ -1,18 +0,0 @@
dubbo:
cloud:
subscribed-services: ${spring.application.name}
scan:
base-packages: com.alibaba.cloud.dubbo.bootstrap
protocol:
name: dubbo
port: -1
spring:
application:
name: spring-cloud-alibaba-dubbo-server
main:
allow-bean-definition-overriding: true
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848

@ -1,68 +0,0 @@
<?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">
<parent>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dubbo-examples</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-dubbo-servlet-gateway-sample</artifactId>
<name>Spring Cloud Dubbo Servlet Gateway Sample</name>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Sample API -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dubbo-sample-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Dubbo Spring Cloud Starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<!-- Spring Cloud Nacos Service Discovery -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -1,41 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.bootstrap;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* Dubbo Spring Cloud Servlet Gateway Bootstrap.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@EnableDiscoveryClient
@EnableAutoConfiguration
@EnableFeignClients
@ServletComponentScan(basePackages = "com.alibaba.cloud.dubbo.gateway")
public class DubboSpringCloudServletGatewayBootstrap {
public static void main(String[] args) {
new SpringApplicationBuilder(DubboSpringCloudServletGatewayBootstrap.class)
.properties("spring.profiles.active=nacos").run(args);
}
}

@ -1,212 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.gateway;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.cloud.dubbo.http.MutableHttpServerRequest;
import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata;
import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContext;
import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory;
import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
import org.apache.dubbo.rpc.service.GenericException;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StreamUtils;
import org.springframework.web.servlet.HttpServletBean;
import org.springframework.web.util.UriComponents;
import static com.alibaba.cloud.commons.lang.StringUtils.substringAfter;
import static com.alibaba.cloud.commons.lang.StringUtils.substringBetween;
import static org.springframework.web.util.UriComponentsBuilder.fromUriString;
@WebServlet(urlPatterns = "/dsc/*")
public class DubboGatewayServlet extends HttpServletBean {
private final DubboServiceMetadataRepository repository;
private final DubboGenericServiceFactory serviceFactory;
private final DubboGenericServiceExecutionContextFactory contextFactory;
private final PathMatcher pathMatcher = new AntPathMatcher();
private final Map<String, Object> dubboTranslatedAttributes = new HashMap<>();
public DubboGatewayServlet(DubboServiceMetadataRepository repository,
DubboGenericServiceFactory serviceFactory,
DubboGenericServiceExecutionContextFactory contextFactory) {
this.repository = repository;
this.serviceFactory = serviceFactory;
this.contextFactory = contextFactory;
dubboTranslatedAttributes.put("protocol", "dubbo");
dubboTranslatedAttributes.put("cluster", "failover");
}
private String resolveServiceName(HttpServletRequest request) {
// /g/{app-name}/{rest-path}
String requestURI = request.getRequestURI();
// /g/
String servletPath = request.getServletPath();
String part = substringAfter(requestURI, servletPath);
String serviceName = substringBetween(part, "/", "/");
return serviceName;
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String serviceName = resolveServiceName(request);
String restPath = substringAfter(request.getRequestURI(), serviceName);
// 初始化 serviceName 的 REST 请求元数据
repository.initializeMetadata(serviceName);
// 将 HttpServletRequest 转化为 RequestMetadata
RequestMetadata clientMetadata = buildRequestMetadata(request, restPath);
DubboRestServiceMetadata dubboRestServiceMetadata = repository.get(serviceName,
clientMetadata);
if (dubboRestServiceMetadata == null) {
// if DubboServiceMetadata is not found, executes next
throw new ServletException("DubboServiceMetadata can't be found!");
}
RestMethodMetadata dubboRestMethodMetadata = dubboRestServiceMetadata
.getRestMethodMetadata();
GenericService genericService = serviceFactory.create(dubboRestServiceMetadata,
dubboTranslatedAttributes);
// TODO: Get the Request Body from HttpServletRequest
byte[] body = getRequestBody(request);
MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(
new HttpRequestAdapter(request), body);
DubboGenericServiceExecutionContext context = contextFactory
.create(dubboRestMethodMetadata, httpServerRequest);
Object result = null;
GenericException exception = null;
try {
result = genericService.$invoke(context.getMethodName(),
context.getParameterTypes(), context.getParameters());
}
catch (GenericException e) {
exception = e;
}
response.getWriter().println(result);
}
private byte[] getRequestBody(HttpServletRequest request) throws IOException {
ServletInputStream inputStream = request.getInputStream();
return StreamUtils.copyToByteArray(inputStream);
}
private RequestMetadata buildRequestMetadata(HttpServletRequest request,
String restPath) {
UriComponents uriComponents = fromUriString(request.getRequestURI()).build(true);
RequestMetadata requestMetadata = new RequestMetadata();
requestMetadata.setPath(restPath);
requestMetadata.setMethod(request.getMethod());
requestMetadata.setParams(getParams(request));
requestMetadata.setHeaders(getHeaders(request));
return requestMetadata;
}
private Map<String, List<String>> getHeaders(HttpServletRequest request) {
Map<String, List<String>> map = new LinkedHashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
Enumeration<String> headerValues = request.getHeaders(headerName);
map.put(headerName, Collections.list(headerValues));
}
return map;
}
private Map<String, List<String>> getParams(HttpServletRequest request) {
Map<String, List<String>> map = new LinkedHashMap<>();
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
map.put(entry.getKey(), Arrays.asList(entry.getValue()));
}
return map;
}
private final static class HttpRequestAdapter implements HttpRequest {
private final HttpServletRequest request;
private HttpRequestAdapter(HttpServletRequest request) {
this.request = request;
}
@Override
public String getMethodValue() {
return request.getMethod();
}
@Override
public URI getURI() {
try {
return new URI(request.getRequestURL().toString() + "?"
+ request.getQueryString());
}
catch (URISyntaxException e) {
e.printStackTrace();
}
throw new RuntimeException();
}
@Override
public HttpHeaders getHeaders() {
return new HttpHeaders();
}
}
}

@ -1,12 +0,0 @@
dubbo:
registry:
# The Spring Cloud Dubbo's registry extension
address: spring-cloud://localhost
# The traditional Dubbo's registry
# address: zookeeper://127.0.0.1:2181
server:
port: 0
provider:
application:
name: spring-cloud-alibaba-dubbo-web-provider

@ -1,70 +0,0 @@
spring:
application:
name: spring-cloud-alibaba-dubbo-servlet-gateway
main:
allow-bean-definition-overriding: true
# default disable all
cloud:
nacos:
discovery:
enabled: false
register-enabled: false
zookeeper:
enabled: false
consul:
enabled: false
eureka:
client:
enabled: false
ribbon:
nacos:
enabled: false
---
spring:
profiles: nacos
cloud:
nacos:
discovery:
enabled: true
register-enabled: true
server-addr: 127.0.0.1:8848
ribbon:
nacos:
enabled: true
---
spring:
profiles: eureka
eureka:
client:
enabled: true
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
---
spring:
profiles: zookeeper
cloud:
zookeeper:
enabled: true
connect-string: 127.0.0.1:2181
---
spring:
profiles: consul
cloud:
consul:
enabled: true
host: 127.0.0.1
port: 8500

@ -21,7 +21,6 @@
<module>spring-cloud-starter-alibaba-seata</module>
<module>spring-cloud-starter-stream-rocketmq</module>
<module>spring-cloud-starter-bus-rocketmq</module>
<module>spring-cloud-starter-dubbo</module>
<module>spring-cloud-starter-alibaba-sidecar</module>
<module>spring-cloud-circuitbreaker-sentinel</module>
<module>spring-cloud-starter-alibaba-sentinel</module>

@ -104,13 +104,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -76,7 +76,7 @@ public abstract class SentinelConverter<T extends Object>
}
if (StringUtils.isEmpty(source)) {
log.warn("converter can not convert rules because source is empty");
log.info("converter can not convert rules because source is empty");
return ruleCollection;
}
try {

@ -20,7 +20,7 @@ import com.alibaba.cloud.sentinel.datasource.converter.JsonConverter;
import com.alibaba.cloud.sentinel.datasource.factorybean.ApolloDataSourceFactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;

@ -31,12 +31,13 @@ import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
@ -117,11 +118,13 @@ public class DataSourcePropertiesTests {
assertThat(fileDataSourceProperties.getBufSize()).isEqualTo(1024);
}
@Test(expected = RuntimeException.class)
@Test
public void testFileException() {
FileDataSourceProperties fileDataSourceProperties = new FileDataSourceProperties();
fileDataSourceProperties.setFile("classpath: 1.json");
fileDataSourceProperties.preCheck("test-ds");
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {
FileDataSourceProperties fileDataSourceProperties = new FileDataSourceProperties();
fileDataSourceProperties.setFile("classpath: 1.json");
fileDataSourceProperties.preCheck("test-ds");
});
}
@Test

@ -26,7 +26,7 @@ import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

@ -20,7 +20,7 @@ import com.alibaba.cloud.sentinel.datasource.converter.SentinelConverter;
import com.alibaba.cloud.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;

@ -18,7 +18,7 @@ package com.alibaba.cloud.sentinel.datasource;
import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties;
import com.alibaba.cloud.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

@ -22,7 +22,7 @@ import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

@ -27,12 +27,13 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
@ -67,16 +68,22 @@ public class SentinelConverterTests {
assertThat(flowRules.size()).isEqualTo(0);
}
@Test(expected = RuntimeException.class)
@Test
public void testConverterErrorFormat() {
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
jsonConverter.convert(readFileContent("classpath: flowrule-errorformat.json"));
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
jsonConverter
.convert(readFileContent("classpath: flowrule-errorformat.json"));
});
}
@Test(expected = RuntimeException.class)
@Test
public void testConverterErrorContent() {
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
jsonConverter.convert(readFileContent("classpath: flowrule-errorcontent.json"));
assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {
JsonConverter jsonConverter = new JsonConverter(objectMapper, FlowRule.class);
jsonConverter
.convert(readFileContent("classpath: flowrule-errorcontent.json"));
});
}
@Test
@ -108,7 +115,8 @@ public class SentinelConverterTests {
private String readFileContent(String file) {
try {
return FileUtils.readFileToString(
ResourceUtils.getFile(StringUtils.trimAllWhitespace(file)), Charset.defaultCharset());
ResourceUtils.getFile(StringUtils.trimAllWhitespace(file)),
Charset.defaultCharset());
}
catch (IOException e) {
return "";

@ -20,7 +20,7 @@ import com.alibaba.cloud.sentinel.datasource.converter.XmlConverter;
import com.alibaba.cloud.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.zookeeper.ZookeeperDataSource;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;

@ -87,12 +87,6 @@
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -21,9 +21,8 @@ import java.util.Collections;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ -38,8 +37,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
@ -50,10 +47,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
/**
* @author Ryan Baxter
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = Application.class, properties = {
"spring.cloud.discovery.client.health-indicator.enabled=false" })
@DirtiesContext
public class ReactiveSentinelCircuitBreakerIntegrationTest {
@LocalServerPort
@ -62,7 +57,7 @@ public class ReactiveSentinelCircuitBreakerIntegrationTest {
@Autowired
private Application.DemoControllerService service;
@Before
@BeforeEach
public void setup() {
service.setPort(port);
}

@ -20,7 +20,7 @@ import java.util.Arrays;
import java.util.Collections;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@ -23,9 +23,8 @@ import java.util.List;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -36,8 +35,6 @@ import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@ -48,11 +45,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
/**
* @author Eric Zhao
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT,
classes = SentinelCircuitBreakerIntegrationTest.Application.class,
properties = { "spring.cloud.discovery.client.health-indicator.enabled=false" })
@DirtiesContext
public class SentinelCircuitBreakerIntegrationTest {
@Autowired
@ -85,12 +80,12 @@ public class SentinelCircuitBreakerIntegrationTest {
assertThat(service.normal()).isEqualTo("normal");
}
@Before
@BeforeEach
public void setUp() {
DegradeRuleManager.loadRules(new ArrayList<>());
}
@Before
@BeforeEach
public void tearDown() {
DegradeRuleManager.loadRules(new ArrayList<>());
}

@ -21,8 +21,8 @@ import java.util.Collections;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.junit.After;
import org.junit.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class SentinelCircuitBreakerTest {
@After
@AfterEach
public void tearDown() {
// Clear the rules.
DegradeRuleManager.loadRules(new ArrayList<>());

@ -42,17 +42,17 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"feign.sentinel.default-rule=default",
"feign.sentinel.rules.default[0].grade=2",
"feign.sentinel.rules.default[0].count=2",
"feign.sentinel.rules.default[0].timeWindow=2",
"feign.sentinel.rules.default[0].timeWindow=1",
"feign.sentinel.rules.default[0].statIntervalMs=30000",
"feign.sentinel.rules.default[0].minRequestAmount=5",
"feign.sentinel.rules.user[0].grade=2",
"feign.sentinel.rules.user[0].count=2",
"feign.sentinel.rules.user[0].timeWindow=2",
"feign.sentinel.rules.user[0].timeWindow=1",
"feign.sentinel.rules.user[0].statIntervalMs=30000",
"feign.sentinel.rules.user[0].minRequestAmount=5",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].grade=2",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].count=1",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].timeWindow=2",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].timeWindow=1",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].statIntervalMs=30000",
"feign.sentinel.rules.[user#specificFeignMethod(boolean)][0].minRequestAmount=5"
})
@ -71,14 +71,12 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
// occur exception
assertThat(orderClient.defaultConfig(false)).isEqualTo("fallback");
assertThat(orderClient.defaultConfig(false)).isEqualTo("fallback");
// test circuit breaker close
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
// the 3rd exception, circuit breaker open
assertThat(orderClient.defaultConfig(false)).isEqualTo("fallback");
@ -87,7 +85,7 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(orderClient.defaultConfig(true)).isEqualTo("fallback");
// longer than timeWindow, circuit breaker half open
Thread.sleep(2500L);
Thread.sleep(1200L);
// let circuit breaker close
assertThat(orderClient.defaultConfig(true)).isEqualTo("ok");
@ -102,14 +100,12 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
// occur exception
assertThat(userClient.specificFeign(false)).isEqualTo("fallback");
assertThat(userClient.specificFeign(false)).isEqualTo("fallback");
// test circuit breaker close
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
// the 3rd exception, circuit breaker open
assertThat(userClient.specificFeign(false)).isEqualTo("fallback");
@ -118,7 +114,7 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(userClient.specificFeign(true)).isEqualTo("fallback");
// longer than timeWindow, circuit breaker half open
Thread.sleep(2500L);
Thread.sleep(1200L);
// let circuit breaker close
assertThat(userClient.specificFeign(true)).isEqualTo("ok");
@ -134,14 +130,10 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");
// occur exception
assertThat(userClient.specificFeignMethod(false)).isEqualTo("fallback");
// 1 time exception, circuit breaker is closed(configuration is 1, but we need 2
// to make it open)
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");
// occur the 2nd exception, circuit breaker open
assertThat(userClient.specificFeignMethod(false)).isEqualTo("fallback");
@ -150,7 +142,7 @@ public class FeignClientCircuitBreakerRuleIntegrationTest {
assertThat(userClient.specificFeignMethod(true)).isEqualTo("fallback");
// longer than timeWindow, circuit breaker half open
Thread.sleep(2500L);
Thread.sleep(1200L);
// let circuit breaker close
assertThat(userClient.specificFeignMethod(true)).isEqualTo("ok");

@ -63,22 +63,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock.modules.test.powermockito/powermock-modules-test-powermockito -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,41 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.configdata;
/**
* Config preference.
* <p>
* When configured profile specific configuration, local config will override the remote,
* because the local config is <strong>profile specific</strong>, it has higher priority.
* <p>
* So give remote config a chance to "win", we treat remote config as profile specific, it
* should be included after profile specific sibling imports. Finally, it will override
* the local profile specific config.
*
* @author freeman
* @since 2021.0.1.1
*/
public enum ConfigPreference {
/**
* Prefer local configuration.
*/
LOCAL,
/**
* Prefer remote configuration.
*/
REMOTE
}

@ -17,6 +17,7 @@
package com.alibaba.cloud.nacos.configdata;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -33,11 +34,17 @@ import org.springframework.boot.context.config.ConfigData;
import org.springframework.boot.context.config.ConfigDataLoader;
import org.springframework.boot.context.config.ConfigDataLoaderContext;
import org.springframework.boot.context.config.ConfigDataResourceNotFoundException;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.logging.DeferredLogFactory;
import org.springframework.core.env.PropertySource;
import static com.alibaba.cloud.nacos.configdata.ConfigPreference.LOCAL;
import static com.alibaba.cloud.nacos.configdata.ConfigPreference.REMOTE;
import static com.alibaba.cloud.nacos.configdata.NacosConfigDataResource.NacosItemConfig;
import static org.springframework.boot.context.config.ConfigData.Option;
import static org.springframework.boot.context.config.ConfigData.Option.IGNORE_IMPORTS;
import static org.springframework.boot.context.config.ConfigData.Option.IGNORE_PROFILES;
import static org.springframework.boot.context.config.ConfigData.Option.PROFILE_SPECIFIC;
/**
* Implementation of {@link ConfigDataLoader}.
@ -52,8 +59,8 @@ public class NacosConfigDataLoader implements ConfigDataLoader<NacosConfigDataRe
private final Log log;
public NacosConfigDataLoader(Log log) {
this.log = log;
public NacosConfigDataLoader(DeferredLogFactory logFactory) {
this.log = logFactory.getLog(getClass());
}
@Override
@ -82,12 +89,10 @@ public class NacosConfigDataLoader implements ConfigDataLoader<NacosConfigDataRe
NacosPropertySourceRepository.collectNacosPropertySource(propertySource);
return new ConfigData(propertySources, IGNORE_IMPORTS, IGNORE_PROFILES);
return new ConfigData(propertySources, getOptions(context, resource));
}
catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Error getting properties from nacos: " + resource, e);
}
log.warn("Error getting properties from nacos: " + resource, e);
if (!resource.isOptional()) {
throw new ConfigDataResourceNotFoundException(resource, e);
}
@ -95,14 +100,65 @@ public class NacosConfigDataLoader implements ConfigDataLoader<NacosConfigDataRe
return null;
}
private Option[] getOptions(ConfigDataLoaderContext context,
NacosConfigDataResource resource) {
List<Option> options = new ArrayList<>();
options.add(IGNORE_IMPORTS);
options.add(IGNORE_PROFILES);
if (getPreference(context, resource) == REMOTE) {
// mark it as 'PROFILE_SPECIFIC' config, it has higher priority,
// will override the none profile specific config.
// fixed https://github.com/alibaba/spring-cloud-alibaba/issues/2455
options.add(PROFILE_SPECIFIC);
}
return options.toArray(new Option[0]);
}
private ConfigPreference getPreference(ConfigDataLoaderContext context,
NacosConfigDataResource resource) {
Binder binder = context.getBootstrapContext().get(Binder.class);
ConfigPreference preference = binder
.bind("spring.cloud.nacos.config.preference", ConfigPreference.class)
.orElse(LOCAL);
String specificPreference = resource.getConfig().getPreference();
if (specificPreference != null) {
try {
preference = ConfigPreference.valueOf(specificPreference.toUpperCase());
}
catch (IllegalArgumentException ignore) {
// illegal preference value, just ignore.
log.warn(String.format(
"illegal preference value: %s, using default preference: %s",
specificPreference, preference));
}
}
return preference;
}
private List<PropertySource<?>> pullConfig(ConfigService configService, String group,
String dataId, String suffix, long timeout)
throws NacosException, IOException {
String config = configService.getConfig(dataId, group, timeout);
logLoadInfo(group, dataId, config);
return NacosDataParserHandler.getInstance().parseNacosData(dataId, config,
suffix);
}
private void logLoadInfo(String group, String dataId, String config) {
if (config != null) {
log.info(String.format(
"[Nacos Config] Load config[dataId=%s, group=%s] success", dataId,
group));
}
else {
log.warn(String.format("[Nacos Config] config[dataId=%s, group=%s] is empty",
dataId, group));
}
log.debug(
String.format("[Nacos Config] config[dataId=%s, group=%s] content: \n%s",
dataId, group, config));
}
protected <T> T getBean(ConfigDataLoaderContext context, Class<T> type) {
if (context.getBootstrapContext().isRegistered(type)) {
return context.getBootstrapContext().get(type);

@ -67,6 +67,8 @@ public class NacosConfigDataLocationResolver
private static final String REFRESH_ENABLED = "refreshEnabled";
private static final String PREFERENCE = "preference";
public NacosConfigDataLocationResolver(Log log) {
this.log = log;
}
@ -166,12 +168,17 @@ public class NacosConfigDataLocationResolver
location.isOptional(), profiles, log,
new NacosItemConfig().setGroup(groupFor(uri, properties))
.setDataId(dataIdFor(uri)).setSuffix(suffixFor(uri, properties))
.setRefreshEnabled(refreshEnabledFor(uri, properties)));
.setRefreshEnabled(refreshEnabledFor(uri, properties))
.setPreference(preferenceFor(uri)));
result.add(resource);
return result;
}
private String preferenceFor(URI uri) {
return getQueryMap(uri).get(PREFERENCE);
}
private URI getUri(ConfigDataLocation location, NacosConfigProperties properties) {
String path = location.getNonPrefixedValue(getPrefix());
if (StringUtils.isBlank(path)) {

@ -105,16 +105,18 @@ public class NacosConfigDataResource extends ConfigDataResource {
private String dataId;
private String suffix;
private boolean refreshEnabled;
private String preference;
public NacosItemConfig() {
}
public NacosItemConfig(String group, String dataId, String suffix,
boolean refreshEnabled) {
boolean refreshEnabled, String preference) {
this.group = group;
this.dataId = dataId;
this.suffix = suffix;
this.refreshEnabled = refreshEnabled;
this.preference = preference;
}
public NacosItemConfig setGroup(String group) {
@ -137,6 +139,11 @@ public class NacosConfigDataResource extends ConfigDataResource {
return this;
}
public NacosItemConfig setPreference(String preference) {
this.preference = preference;
return this;
}
public String getGroup() {
return group;
}
@ -153,6 +160,10 @@ public class NacosConfigDataResource extends ConfigDataResource {
return refreshEnabled;
}
public String getPreference() {
return preference;
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -165,19 +176,20 @@ public class NacosConfigDataResource extends ConfigDataResource {
return refreshEnabled == that.refreshEnabled
&& Objects.equals(group, that.group)
&& Objects.equals(dataId, that.dataId)
&& Objects.equals(suffix, that.suffix);
&& Objects.equals(suffix, that.suffix)
&& Objects.equals(preference, that.preference);
}
@Override
public int hashCode() {
return Objects.hash(group, dataId, suffix, refreshEnabled);
return Objects.hash(group, dataId, suffix, refreshEnabled, preference);
}
@Override
public String toString() {
return "NacosItemConfig{" + "group='" + group + '\'' + ", dataId='" + dataId
+ '\'' + ", suffix='" + suffix + '\'' + ", refreshEnabled="
+ refreshEnabled + '}';
+ refreshEnabled + ", preference=" + preference + '}';
}
}

@ -126,6 +126,8 @@ public class NacosContextRefresher
});
try {
configService.addListener(dataKey, groupKey, listener);
log.info("[Nacos Config] Listening config: dataId={}, group={}", dataKey,
groupKey);
}
catch (NacosException e) {
log.warn(String.format(

@ -100,6 +100,12 @@
"type": "com.alibaba.cloud.nacos.refresh.RefreshBehavior",
"defaultValue": "all_beans",
"description": "ConfigurationPropertiesBean refresh behavior."
},
{
"name": "spring.cloud.nacos.config.preference",
"type": "com.alibaba.cloud.nacos.configdata.ConfigPreference",
"defaultValue": "local",
"description": "Config preference."
}
]
}

@ -16,20 +16,14 @@
package com.alibaba.cloud.nacos;
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.api.exception.NacosException;
import com.alibaba.nacos.client.config.NacosConfigService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
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.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -37,23 +31,20 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static com.alibaba.cloud.nacos.NacosConfigurationExtConfigTests.TestConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* TODO refactor, remove powermock.
*
* @author xiaojing
* @author freeman
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = TestConfig.class, webEnvironment = NONE, properties = {
"spring.application.name=myTestService1", "spring.profiles.active=dev,test",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
@ -66,63 +57,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.config.shared-dataids=common1.properties,common2.properties",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey",
"spring.cloud.bootstrap.enabled=true"
})
"spring.cloud.bootstrap.enabled=true" })
public class NacosConfigurationExtConfigTests {
static {
try {
// when(any(ConfigService.class).getConfig(eq("test-name.properties"),
// eq("test-group"), any())).thenReturn("user.name=hello");
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common2=common2";
}
return "";
}
});
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
@Autowired
private Environment environment;
@ -132,16 +69,69 @@ public class NacosConfigurationExtConfigTests {
@Autowired
private NacosConfigProperties properties;
static {
try {
NacosConfigService mockedNacosConfigService = Mockito
.mock(NacosConfigService.class);
when(mockedNacosConfigService.getConfig(any(), any(), anyLong()))
.thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocationOnMock)
throws Throwable {
String dataId = invocationOnMock.getArgument(0, String.class);
String group = invocationOnMock.getArgument(1, String.class);
if ("test-name.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(dataId)
&& "GLOBAL_GROUP".equals(group)) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-common2=common2";
}
return "";
}
});
ReflectionTestUtils.setField(NacosConfigManager.class, "service",
mockedNacosConfigService);
}
catch (NacosException ignored) {
ignored.printStackTrace();
}
}
@Test
public void contextLoads() throws Exception {
assertThat(locator).isNotNull();
assertThat(properties).isNotNull();
assertThat("config1").isEqualTo(environment.getProperty("test-ext-config1"));
assertThat("config2").isEqualTo(environment.getProperty("test-ext-config2"));
assertThat("common1").isEqualTo(environment.getProperty("test-common1"));
assertThat("common2").isEqualTo(environment.getProperty("test-common2"));
assertThat(environment.getProperty("test-ext-config1")).isEqualTo("config1");
assertThat(environment.getProperty("test-ext-config2")).isEqualTo("config2");
assertThat(environment.getProperty("test-common1")).isEqualTo("common1");
assertThat(environment.getProperty("test-common2")).isEqualTo("common2");
}
@Configuration

@ -16,8 +16,6 @@
package com.alibaba.cloud.nacos;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.cloud.nacos.NacosConfigProperties.Config;
@ -26,14 +24,10 @@ 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.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
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.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -41,21 +35,19 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* TODO refactor, remove powermock.
*
* @author xiaojing
* @author freeman
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationNewTest.TestConfig.class, webEnvironment = NONE, properties = {
"spring.application.name=myTestService1", "spring.profiles.active=dev,test",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
@ -74,58 +66,61 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.config.shared-configs[1]=common2.properties",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey",
"spring.cloud.bootstrap.enabled=true"
})
"spring.cloud.bootstrap.enabled=true" })
public class NacosConfigurationNewTest {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common2=common2";
}
return "";
}
});
NacosConfigService mockedNacosConfigService = Mockito
.mock(NacosConfigService.class);
when(mockedNacosConfigService.getConfig(any(), any(), anyLong()))
.thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocationOnMock)
throws Throwable {
String dataId = invocationOnMock.getArgument(0, String.class);
String group = invocationOnMock.getArgument(1, String.class);
if ("test-name.properties".equals(dataId)
&& "test-group".equals(group)) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(dataId)
&& "test-group".equals(group)) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(dataId)
&& "GLOBAL_GROUP".equals(group)) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-common2=common2";
}
return "";
}
});
ReflectionTestUtils.setField(NacosConfigManager.class, "service",
mockedNacosConfigService);
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}

@ -16,8 +16,6 @@
package com.alibaba.cloud.nacos;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
@ -25,14 +23,10 @@ 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.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
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.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -40,23 +34,19 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* TODO refactor, remove powermock.
*
* @author zkz
* @author freeman
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*",
"com.sun.org.apache.xerces.internal.jaxp.*", "org.w3c.dom.*" })
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationNoSuffixTest.TestConfig.class, webEnvironment = NONE, properties = {
"spring.application.name=app-no-suffix", "spring.profiles.active=dev",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
@ -73,87 +63,93 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.config.shared-dataids=shared-data1.properties,shared-data2.xml",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey",
"spring.cloud.bootstrap.enabled=true"
})
"spring.cloud.bootstrap.enabled=true" })
public class NacosConfigurationNoSuffixTest {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("app-no-suffix".equals(args[0]) && "test-group".equals(args[1])) {
return "test-no-suffix=value-no-suffix-1";
}
if ("app-no-suffix.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "test-no-suffix=value-no-suffix-2";
}
if ("test-no-suffix-name".equals(args[0])
&& "test-group".equals(args[1])) {
return "test-no-suffix-assign=assign-value-no-suffix-111";
}
if ("test-no-suffix-name.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "test-no-suffix-assign=assign-value-no-suffix-222";
}
if ("test-no-suffix-name-dev.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "test-no-suffix-assign=assign-dev-value-no-suffix-333";
}
if ("ext-json-test.json".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "{\n" + " \"people\":{\n"
+ " \"firstName\":\"Brett\",\n"
+ " \"lastName\":\"McLaughlin\"\n" + " }\n"
+ "}";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "global-ext-config=global-config-value-2";
}
if ("shared-data1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "shared-name=shared-value-1";
}
if ("shared-data2.xml".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
+ " <Service name=\"Catalina\"> \n"
+ " <Connector value=\"第二个连接器\"> \n"
+ " <open>开启服务</open> \n"
+ " <init>初始化一下</init> \n"
+ " <process>\n" + " <top>\n"
+ " <first>one</first>\n"
+ " <sencond value=\"two\">\n"
+ " <third>three</third>\n"
+ " </sencond>\n"
+ " </top>\n" + " </process> \n"
+ " <destory>销毁一下</destory> \n"
+ " <close>关闭服务</close> \n"
+ " </Connector> \n" + " </Service> \n"
+ "</Server> ";
}
return "";
}
});
NacosConfigService mockedNacosConfigService = Mockito
.mock(NacosConfigService.class);
when(mockedNacosConfigService.getConfig(any(), any(), anyLong()))
.thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocationOnMock)
throws Throwable {
String dataId = invocationOnMock.getArgument(0, String.class);
String group = invocationOnMock.getArgument(1, String.class);
if ("app-no-suffix".equals(dataId)
&& "test-group".equals(group)) {
return "test-no-suffix=value-no-suffix-1";
}
if ("app-no-suffix.properties".equals(dataId)
&& "test-group".equals(group)) {
return "test-no-suffix=value-no-suffix-2";
}
if ("test-no-suffix-name".equals(dataId)
&& "test-group".equals(group)) {
return "test-no-suffix-assign=assign-value-no-suffix-111";
}
if ("test-no-suffix-name.properties".equals(dataId)
&& "test-group".equals(group)) {
return "test-no-suffix-assign=assign-value-no-suffix-222";
}
if ("test-no-suffix-name-dev.properties".equals(dataId)
&& "test-group".equals(group)) {
return "test-no-suffix-assign=assign-dev-value-no-suffix-333";
}
if ("ext-json-test.json".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "{\n" + " \"people\":{\n"
+ " \"firstName\":\"Brett\",\n"
+ " \"lastName\":\"McLaughlin\"\n"
+ " }\n" + "}";
}
if ("ext-config-common02.properties".equals(dataId)
&& "GLOBAL_GROUP".equals(group)) {
return "global-ext-config=global-config-value-2";
}
if ("shared-data1.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "shared-name=shared-value-1";
}
if ("shared-data2.xml".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
+ " <Service name=\"Catalina\"> \n"
+ " <Connector value=\"第二个连接器\"> \n"
+ " <open>开启服务</open> \n"
+ " <init>初始化一下</init> \n"
+ " <process>\n"
+ " <top>\n"
+ " <first>one</first>\n"
+ " <sencond value=\"two\">\n"
+ " <third>three</third>\n"
+ " </sencond>\n"
+ " </top>\n"
+ " </process> \n"
+ " <destory>销毁一下</destory> \n"
+ " <close>关闭服务</close> \n"
+ " </Connector> \n" + " </Service> \n"
+ "</Server> ";
}
return "";
}
});
ReflectionTestUtils.setField(NacosConfigManager.class, "service",
mockedNacosConfigService);
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}

@ -16,8 +16,6 @@
package com.alibaba.cloud.nacos;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
@ -25,14 +23,10 @@ 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.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
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.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -40,21 +34,19 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* TODO refactor, remove powermock.
*
* @author xiaojing
* @author freeman
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationTests.TestConfig.class, webEnvironment = NONE, properties = {
"spring.application.name=myTestService1", "spring.profiles.active=dev,test",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
@ -72,53 +64,57 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.config.shared-dataids=common1.properties,common2.properties",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey",
"spring.cloud.bootstrap.enabled=true"
})
"spring.cloud.bootstrap.enabled=true" })
public class NacosConfigurationTests {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(args[0])
&& "test-group".equals(args[1])) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "test-common2=common2";
}
return "";
}
});
NacosConfigService mockedNacosConfigService = Mockito
.mock(NacosConfigService.class);
when(mockedNacosConfigService.getConfig(any(), any(), anyLong()))
.thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocationOnMock)
throws Throwable {
String dataId = invocationOnMock.getArgument(0, String.class);
String group = invocationOnMock.getArgument(1, String.class);
if ("test-name.properties".equals(dataId)
&& "test-group".equals(group)) {
return "user.name=hello\nuser.age=12";
}
if ("test-name-dev.properties".equals(dataId)
&& "test-group".equals(group)) {
return "user.name=dev";
}
if ("ext-config-common01.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-ext-config1=config1\ntest-ext-config2=config1";
}
if ("ext-config-common02.properties".equals(dataId)
&& "GLOBAL_GROUP".equals(group)) {
return "test-ext-config2=config2";
}
if ("common1.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-common1=common1\ntest-common2=common1";
}
if ("common2.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "test-common2=common2";
}
return "";
}
});
ReflectionTestUtils.setField(NacosConfigManager.class, "service",
mockedNacosConfigService);
}
catch (Exception ignore) {

@ -16,8 +16,6 @@
package com.alibaba.cloud.nacos;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
@ -25,14 +23,10 @@ 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.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
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.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -40,22 +34,19 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* TODO refactor, remove powermock.
*
* @author zkz
* @author freeman
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({ "javax.management.*", "javax.xml.parsers.*",
"com.sun.org.apache.xerces.internal.jaxp.*", "org.w3c.dom.*" })
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosConfigurationXmlJsonTest.TestConfig.class, webEnvironment = NONE, properties = {
"spring.application.name=xmlApp", "spring.profiles.active=dev",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
@ -73,97 +64,106 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
"spring.cloud.nacos.config.shared-dataids=shared-data1.properties,shared-data.json",
"spring.cloud.nacos.config.accessKey=test-accessKey",
"spring.cloud.nacos.config.secretKey=test-secretKey",
"spring.cloud.bootstrap.enabled=true"
})
"spring.cloud.bootstrap.enabled=true" })
public class NacosConfigurationXmlJsonTest {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("xmlApp.xml".equals(args[0]) && "test-group".equals(args[1])) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<top>\n"
+ " <first>one</first>\n"
+ " <sencond value=\"two\">\n"
+ " <third>three</third>\n" + " </sencond>\n"
+ "</top>";
}
if ("test-name.xml".equals(args[0]) && "test-group".equals(args[1])) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
+ " <Service name=\"Catalina\"> \n"
+ " <Connector value=\"第二个连接器\"> \n"
+ " <open>开启服务</open> \n"
+ " <init>初始化一下</init> \n"
+ " <process>\n" + " <top>\n"
+ " <first>one</first>\n"
+ " <sencond value=\"two\">\n"
+ " <third>three</third>\n"
+ " </sencond>\n"
+ " </top>\n" + " </process> \n"
+ " <destory>销毁一下</destory> \n"
+ " <close>关闭服务</close> \n"
+ " </Connector> \n" + " </Service> \n"
+ "</Server> ";
}
if ("test-name-dev.xml".equals(args[0])
&& "test-group".equals(args[1])) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<application android:label=\"@string/app_name\" android:icon=\"@drawable/osg\">\n"
+ " <activity android:name=\".osgViewer\"\n"
+ " android:label=\"@string/app_name\" android:screenOrientation=\"landscape\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.MAIN\" />\n"
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
+ " </intent-filter>\n" + " </activity>\n"
+ "</application>";
}
if ("ext-json-test.json".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "{\n" + " \"people\":{\n"
+ " \"firstName\":\"Brett\",\n"
+ " \"lastName\":\"McLaughlin\"\n" + " }\n"
+ "}";
}
if ("ext-config-common02.properties".equals(args[0])
&& "GLOBAL_GROUP".equals(args[1])) {
return "global-ext-config=global-config-value-2";
}
if ("shared-data1.properties".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "shared-name=shared-value-1";
}
if ("shared-data.json".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "{\n" + " \"test\" : {\n"
+ " \"name\" : \"test\",\n"
+ " \"list\" : [\n" + " {\n"
+ " \"name\" :\"listname1\",\n"
+ " \"age\":1\n" + " },\n"
+ " {\n"
+ " \"name\" :\"listname2\",\n"
+ " \"age\":2\n" + " }\n"
+ " ],\n" + " \"metadata\" : {\n"
+ " \"intKey\" : 123,\n"
+ " \"booleanKey\" : true\n" + " }\n"
+ " }\n" + "}";
}
return "";
}
});
NacosConfigService mockedNacosConfigService = Mockito
.mock(NacosConfigService.class);
when(mockedNacosConfigService.getConfig(any(), any(), anyLong()))
.thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocationOnMock)
throws Throwable {
String dataId = invocationOnMock.getArgument(0, String.class);
String group = invocationOnMock.getArgument(1, String.class);
if ("xmlApp.xml".equals(dataId)
&& "test-group".equals(group)) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<top>\n" + " <first>one</first>\n"
+ " <sencond value=\"two\">\n"
+ " <third>three</third>\n"
+ " </sencond>\n" + "</top>";
}
if ("test-name.xml".equals(dataId)
&& "test-group".equals(group)) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<Server port=\"8005\" shutdown=\"SHUTDOWN\"> \n"
+ " <Service name=\"Catalina\"> \n"
+ " <Connector value=\"第二个连接器\"> \n"
+ " <open>开启服务</open> \n"
+ " <init>初始化一下</init> \n"
+ " <process>\n"
+ " <top>\n"
+ " <first>one</first>\n"
+ " <sencond value=\"two\">\n"
+ " <third>three</third>\n"
+ " </sencond>\n"
+ " </top>\n"
+ " </process> \n"
+ " <destory>销毁一下</destory> \n"
+ " <close>关闭服务</close> \n"
+ " </Connector> \n" + " </Service> \n"
+ "</Server> ";
}
if ("test-name-dev.xml".equals(dataId)
&& "test-group".equals(group)) {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<application android:label=\"@string/app_name\" android:icon=\"@drawable/osg\">\n"
+ " <activity android:name=\".osgViewer\"\n"
+ " android:label=\"@string/app_name\" android:screenOrientation=\"landscape\">\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.MAIN\" />\n"
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n" + "</application>";
}
if ("ext-json-test.json".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "{\n" + " \"people\":{\n"
+ " \"firstName\":\"Brett\",\n"
+ " \"lastName\":\"McLaughlin\"\n"
+ " }\n" + "}";
}
if ("ext-config-common02.properties".equals(dataId)
&& "GLOBAL_GROUP".equals(group)) {
return "global-ext-config=global-config-value-2";
}
if ("shared-data1.properties".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "shared-name=shared-value-1";
}
if ("shared-data.json".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "{\n" + " \"test\" : {\n"
+ " \"name\" : \"test\",\n"
+ " \"list\" : [\n" + " {\n"
+ " \"name\" :\"listname1\",\n"
+ " \"age\":1\n"
+ " },\n" + " {\n"
+ " \"name\" :\"listname2\",\n"
+ " \"age\":2\n"
+ " }\n" + " ],\n"
+ " \"metadata\" : {\n"
+ " \"intKey\" : 123,\n"
+ " \"booleanKey\" : true\n"
+ " }\n" + " }\n" + "}";
}
return "";
}
});
ReflectionTestUtils.setField(NacosConfigManager.class, "service",
mockedNacosConfigService);
}
catch (Exception ignore) {

@ -16,20 +16,13 @@
package com.alibaba.cloud.nacos;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
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;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.api.support.MethodProxy;
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.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -37,45 +30,48 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
/**
* TODO refactor, remove powermock.
*
* @author xiaojing
* @author freeman
*/
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("javax.management.*")
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ NacosConfigService.class })
@SpringBootTest(classes = NacosFileExtensionTest.TestConfig.class, webEnvironment = NONE, properties = {
"spring.application.name=test-name",
"spring.cloud.nacos.config.server-addr=127.0.0.1:8848",
"spring.cloud.nacos.config.file-extension=yaml",
"spring.cloud.bootstrap.enabled=true"
})
"spring.cloud.bootstrap.enabled=true" })
public class NacosFileExtensionTest {
static {
try {
Method method = PowerMockito.method(NacosConfigService.class, "getConfig",
String.class, String.class, long.class);
MethodProxy.proxy(method, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("test-name.yaml".equals(args[0])
&& "DEFAULT_GROUP".equals(args[1])) {
return "user:\n name: hello\n age: 12\n---\nuser:\n gender: male";
}
return "";
}
});
NacosConfigService mockedNacosConfigService = Mockito
.mock(NacosConfigService.class);
when(mockedNacosConfigService.getConfig(any(), any(), anyLong()))
.thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocationOnMock)
throws Throwable {
String dataId = invocationOnMock.getArgument(0, String.class);
String group = invocationOnMock.getArgument(1, String.class);
if ("test-name.yaml".equals(dataId)
&& "DEFAULT_GROUP".equals(group)) {
return "user:\n name: hello\n age: 12\n---\nuser:\n gender: male";
}
return "";
}
});
ReflectionTestUtils.setField(NacosConfigManager.class, "service",
mockedNacosConfigService);
}
catch (Exception ignore) {
@ -90,9 +86,9 @@ public class NacosFileExtensionTest {
@Test
public void contextLoads() throws Exception {
Assert.assertEquals(environment.getProperty("user.name"), "hello");
Assert.assertEquals(environment.getProperty("user.age"), "12");
Assert.assertEquals(environment.getProperty("user.gender"), "male");
Assertions.assertEquals(environment.getProperty("user.name"), "hello");
Assertions.assertEquals(environment.getProperty("user.age"), "12");
Assertions.assertEquals(environment.getProperty("user.gender"), "male");
}
@Configuration

@ -17,11 +17,9 @@
package com.alibaba.cloud.nacos.configdata;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.springframework.boot.SpringApplication;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@ -32,14 +30,8 @@ import static org.mockito.Mockito.mock;
* @author Ryan Baxter
* @author freeman
*/
@DisabledIf("existBootstrapMarker")
class NacosConfigDataMissingEnvironmentPostProcessorTest {
static boolean existBootstrapMarker() {
return ClassUtils.isPresent("org.springframework.cloud.bootstrap.marker.Marker",
null);
}
@Test
void noSpringConfigImport() {
MockEnvironment environment = new MockEnvironment();

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

Loading…
Cancel
Save