diff --git a/README-zh.md b/README-zh.md index 603b78922..32b4098f1 100644 --- a/README-zh.md +++ b/README-zh.md @@ -8,14 +8,22 @@ Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解 ## 主要功能 * **服务限流降级**:默认支持为 HTTP 服务的提供限流保护,也支持添加注解实现方法的自定义限流降级,且支持动态修改限流降级规则。 +* **服务注册与发现**:适配 sprig cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。 +* **分布式配置管理**:支持分布式系统中的外部化配置,配置更改时自动刷新。 +* **阿里云对象存储**:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。 -更多功能请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/Roadmap-zh.md)。 + +更多功能请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 ## 组件: **[Sentinel](https://github.com/alibaba/Sentinel)**:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 -更多组件请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/Roadmap-zh.md)。 +**[Nacos](https://github.com/alibaba/Nacos)**:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 + +**[AliCloud OSS](https://www.aliyun.com/product/oss)**: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 + +更多组件请参考 [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 ## 如何构建 @@ -34,8 +42,13 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目clone Example 列表: -[sentinel example](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/spring-cloud-alibaba-examples/sentinel-example/readme-zh.md) +[Sentinel Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md) + +[Nacos Config Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md) + +[Nacos Discovery Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md) +[AliCloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/storage-example/readme-zh.md) ## 版本管理规范 项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从0开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用0,即版本号为 0.x.x 的格式。 @@ -46,7 +59,6 @@ Example 列表: 项目孵化阶段,项目版本升级机制如下: * 功能改动的升级会增加第三位版本号的数值,例如 0.1.0 的下一个版本为0.1.1。 -* 如果遇到阻碍主业务流程的 bug,需要进行少量修改进行紧急修复,会出现类似于 0.1.1.fix 这样的版本。我们会尽量完善测试回归流程,避免此类场景出现。 diff --git a/README.md b/README.md index f37bbea40..0811db0af 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Spring Cloud Alibaba -See the [中文文档](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/README-zh.md) for Chinese readme. +See the [中文文档](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/README-zh.md) for Chinese readme. Spring Cloud Alibaba provides a one-stop solution for distributed application development. It contains all the components required to develop distributed applications, making it easy for you to develop your applications using Spring Cloud. @@ -10,14 +10,20 @@ With Spring Cloud Alibaba,you only need to add some annotations and a small am ## Features * **Flow control and service degradation**:Flow control for HTTP services is supported by default. You can also customize flow control and service degradation rules using annotations. The rules can be changed dynamically. - -For more features, please refer to [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/Roadmap.md). +* **Service registration and discovery**:Service can be registered and clients can discover the instances using Spring-managed beans, auto integration Ribbon. +* **Distributed configuration**:support for externalized configuration in a distributed system, auto refresh when configuration changes. +* **AliCloud Object Storage**:massive, secure, low-cost, and highly reliable cloud storage services. Support for storing and accessing any type of data in any application, anytime, anywhere. +For more features, please refer to [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap.md). ## Components **[Sentinel](https://github.com/alibaba/Sentinel)**: 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. -For more features please refer to [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/Roadmap.md). +**[Nacos](https://github.com/alibaba/Nacos)**: an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. + +**[AliCloud OSS](https://www.aliyun.com/product/oss)**: An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world. + +For more features please refer to [Roadmap](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/Roadmap.md). ## How to build @@ -35,8 +41,13 @@ A `spring-cloud-alibaba-examples` module is included in our project for you to g Examples: -[Sentinel example](https://github.com/spring-cloud-incubator/spring-cloud-alibabacloud/blob/master/spring-cloud-alibaba-examples/sentinel-example/readme.md) +[Sentinel Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md) +[Nacos Config Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md) + +[Nacos Discovery Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme.md) + +[AliCloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/storage-example/readme.md) ## Version control guidelines The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the first version number is fixed to 0, that is, the version number is 0.x.x. @@ -47,8 +58,6 @@ As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been c During the incubation period,the version management of the project will follow these rules: * Functional updates will be reflected in the 3rd number of the version, for example, the next version of 0.1.0 will be 0.1.1。 -* Emergency fixes for bugs that block the main business process will be reflected in version numbers such as 0.1.1.fix. However, it is our duty to improve the test regression process to avoid such scenarios. - ## Contact Us diff --git a/Roadmap-zh.md b/Roadmap-zh.md index 989acc841..53ac35f2c 100644 --- a/Roadmap-zh.md +++ b/Roadmap-zh.md @@ -10,8 +10,13 @@ Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解 ## 已包含的组件 **Sentinel** -阿里巴巴开源项目,把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。 +阿里巴巴开源产品,把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。 +**Nacos** +阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 + +**Aliyun OSS** +阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 ## 即将加入的组件 **Dubbo** @@ -20,14 +25,8 @@ Apache Dubbo™ (incubating) 是一款高性能Java RPC框架。 **RocketMQ** Apache RocketMQ™ 基于Java的高性能、高吞吐量的分布式消息和流计算平台。 -**Nacos** -阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 - **Schedulerx** 阿里中间件团队开发的一款分布式任务调度产品,支持周期性的任务与固定时间点触发任务。 -**Aliyun OSS** -阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。 - -**Aliyun SLS** +**AliCloud SLS** 针对日志类数据的一站式服务,在阿里巴巴集团经历大量大数据场景锤炼而成。您无需开发就能快捷完成日志数据采集、消费、投递以及查询分析等功能,提升运维、运营效率,建立 DT 时代海量日志处理能力。 \ No newline at end of file diff --git a/Roadmap.md b/Roadmap.md index f3ad2175e..4bcf2943e 100644 --- a/Roadmap.md +++ b/Roadmap.md @@ -16,6 +16,14 @@ If you have any suggestions on our roadmap, feel free to submit issues or contac An open-source project of Alibaba, Sentinel takes "flow" as breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability. +**Nacos** + +An opensource project of Alibaba, an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. + +**AliCloud OSS** + +AliCloud Object Storage Service, An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world. + More components will be supported by Spring Cloud Alibaba in the future, which may include but are not limited to the following: **Dubbo** @@ -24,14 +32,8 @@ Apache Dubbo™ (incubating) is a high-performance, Java based open source RPC f **RocketMQ** Apache RocketMQ™ is an open source distributed messaging and streaming data platform. -**Nacos** -An opensource project of Alibaba, an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. - **Schedulerx** A distributed task scheduling product developed by Alibaba Middleware team. It supports both periodical tasks and tasks to be triggered at specified time points. -**Aliyun OSS** -Aliyun Object Storage Service, An encrypted and secure cloud storage service which stores, processes and accesses massive amounts of data from anywhere in the world. - -**Aliyun SLS** +**AliCloud SLS** Aliyun Log Service is an all-in-one service for log-type data. It helps increase Operations & Management and operational efficiency, as well as build the processing capability to deal with massive logs. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 379791867..b5e447e0b 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ 2.0.0.RELEASE 2.0.0.RELEASE + 2.0.0.RELEASE 4.12 3.0 @@ -72,11 +73,13 @@ spring-cloud-alibaba-dependencies - spring-cloud-alibaba-sentinel-autoconfigure - spring-cloud-starter-sentinel - spring-cloud-alibaba-storage-autoconfigure - spring-cloud-starter-storage + spring-cloud-alibaba-sentinel + spring-cloud-alibaba-storage + spring-cloud-alibaba-nacos-config + spring-cloud-alibaba-nacos-discovery spring-cloud-alibaba-examples + spring-cloud-alibaba-test + spring-cloud-starter-alibaba @@ -98,6 +101,29 @@ import + + org.springframework.cloud + spring-cloud-test-support + test + ${spring-cloud-commons.version} + + + + org.springframework.cloud + spring-cloud-netflix + ${spring-cloud-netflix.version} + pom + import + + + + org.springframework.cloud + spring-cloud-openfeign-dependencies + ${spring-cloud-openfeign.version} + pom + import + + diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml index e7bcdbfdc..9c7e4126f 100644 --- a/spring-cloud-alibaba-dependencies/pom.xml +++ b/spring-cloud-alibaba-dependencies/pom.xml @@ -18,10 +18,17 @@ 0.1.1 3.1.0 + 0.2.0 + + + com.alibaba.nacos + nacos-client + ${nacos.version} + com.alibaba.csp sentinel-core @@ -67,6 +74,14 @@ sentinel-dubbo-adapter ${sentinel.version} + + org.springframework.cloud + sentinel-dubbo-api + ${project.version} + + + + com.aliyun.oss aliyun-sdk-oss @@ -74,37 +89,55 @@ - + + + org.springframework.cloud + spring-cloud-alibaba-sentinel + ${project.version} + org.springframework.cloud - spring-cloud-alibaba-sentinel-autoconfigure + spring-cloud-alibaba-storage ${project.version} org.springframework.cloud - spring-cloud-alibaba-storage-autoconfigure + spring-cloud-alibaba-nacos-discovery + ${project.version} + + + org.springframework.cloud + spring-cloud-alibaba-nacos-config ${project.version} org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel ${project.version} org.springframework.cloud - spring-cloud-starter-storage + spring-cloud-starter-alibaba-storage ${project.version} - org.springframework.cloud - sentinel-dubbo-api + spring-cloud-starter-alibaba-nacos-discovery ${project.version} + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-config + ${project.version} + + + + + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/pom.xml new file mode 100644 index 000000000..f7cedc41a --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/pom.xml @@ -0,0 +1,53 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba-examples + 0.2.0.BUILD-SNAPSHOT + ../../pom.xml + + 4.0.0 + + + nacos-config-example + jar + Example demonstrating how to use nacos config + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-config + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md new file mode 100644 index 000000000..bc79f6f85 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md @@ -0,0 +1,187 @@ +# Nacos Config Example + +## 项目说明 + +本项目演示如何使用 Nacos Config Starter 完成 Spring Cloud 应用的配置管理。 + +[Nacos](https://github.com/alibaba/Nacos) 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 + +## 示例 + +### 如何接入 +在启动示例进行演示之前,我们先了解一下 Spring Cloud 应用如何接入 Nacos Config。 +**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。** + +1. 首先,修改 pom.xml 文件,引入 Nacos Config Starter。 + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-config + + +2. 在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 地址 + + spring.cloud.nacos.config.server-addr=127.0.0.1:8080 + +3. 完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment 的 PropertySources 中。这里我们使用 @Value 注解来将对应的配置注入到 SampleController 的 userName 和 age 字段,并添加 @RefreshScope 打开动态刷新功能 + + @RefreshScope + class SampleController { + + @Value("${user.name}") + String userName; + + @Value("${user.age}") + int age; + } + +### 启动 Nacos Server 并添加配置 + +1. 首先需要获取 Nacos Server,支持直接下载和源码构建两种方式。**推荐使用最新版本 Nacos Server** + + 1. 直接下载:[Nacos Server 下载页](https://github.com/alibaba/nacos/releases) + 2. 源码构建:进入 Nacos [Github 项目页面](https://github.com/alibaba/nacos),将代码 git clone 到本地自行编译打包,[参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。 + + + +2. 启动 Server,进入下载到本地并解压完成后的文件夹(使用源码构建的方式则进入编译打包好的文件夹),再进去其相对文件夹 nacos/bin,并对照操作系统实际情况执行如下命令。[详情参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。 + + 1. Linux/Unix/Mac 操作系统,执行命令 `sh startup.sh -m standalone` + 1. Windows 操作系统,执行命令 `cmd startup.cmd` + +3. 在命令行执行如下命令,向 Nacos Server 中添加一条配置。 + + curl -X POST "http://127.0.0.1:8080/nacos/v1/cs/configs?dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=user.id=1%0Auser.name=james%0Auser.age=17" + + **注:你也可以使用其他方式添加,遵循 HTTP API 规范即可,若您使用的 Nacos 版本自带控制台,建议直接使用控制台进行配置** + + 添加的配置的详情如下 + + dataId 为 nacos-config-example.properties + group 为 DEFAULT_GROUP + + 内容如下 + + user.id=1 + user.name=james + user.age=17 + +### 应用启动 + +1. 增加配置,在应用的 /src/main/resources/application.properties 中添加基本配置信息 + + spring.application.name=nacos-config-example + server.port=18084 + + +2. 启动应用,支持 IDE 直接启动和编译打包后启动。 + + 1. IDE直接启动:找到主类 `Application`,执行 main 方法启动应用。 + 2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-config-example.jar`启动应用。 + +### 验证 + +#### 验证自动注入 +在浏览器地址栏输入 `http://127.0.0.1:18084/user`,并点击调转,可以看到成功从 Nacos Config Server 中获取了数据。 + +![get](https://cdn.nlark.com/lark/0/2018/png/54319/1536986328663-5e3503c2-7e14-4c56-b5f9-72fecc6898d2.png) + +#### 验证动态刷新 +1. 执行如下命令,修改 Nacos Server 端的配置数据 + + curl -X POST "http://127.0.0.1:8080/nacos/v1/cs/configs?dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=user.id=1%0Auser.name=james%0Auser.age=18" + +2. 在浏览器地址栏输入 `http://127.0.0.1:18084/user`,并点击调转,可以看到应用从 Nacos Server 中获取了最新的数据,age 变成了 18。 + +![refresh](https://cdn.nlark.com/lark/0/2018/png/54319/1536986336535-c0efdf6d-a5d3-4f33-8d26-fe3a36cdacf6.png) + + +## 原理 + + +### Nacos Config 数据结构 + +Nacos Config 主要通过 dataId 和 group 来唯一确定一条配置,我们假定你已经了解此背景。如果不了解,请参考 [Nacos 文档](https://nacos.io/zh-cn/docs/concepts.html)。 + +Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 `ConfigService.getConfig(String dataId, String group, long timeoutMs)`。 + + +### Spring Cloud 应用获取数据 + +#### dataID + +在 Nacos Config Starter 中,dataId 的拼接格式如下 + + ${prefix} - ${spring.active.profile} . ${content-type} + +* `prefix` 默认为 `spring.application.name` 的值,也可以通过配置项 `spring.cloud.nacos.config.prefix`来配置。 + +* `spring.active.profile` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles) + + **注意,当 activeprofile 为空时,对应的连接符 `-` 也将不存在,dataId 的拼接格式变成 `${prefix}`.`${context.type}`** + +* `content-type` 为配置内容的数据格式,可以通过配置项 `spring.cloud.nacos.config.content-type`来配置。 +目前只支持 `properties` 类型。 + +#### group +* `group` 默认为 `DEFAULT_GROUP`,可以通过 `spring.cloud.nacos.config.group` 配置。 + + +### 自动注入 +Nacos Config Starter 实现了 `org.springframework.cloud.bootstrap.config.PropertySourceLocator`接口,并将优先级设置成了最高。 + +在 Spring Cloud 应用启动阶段,会主动从 Nacos Server 端获取对应的数据,并将获取到的数据转换成 PropertySource 且注入到 Environment 的 PropertySources 属性中,所以使用 @Value 注解也能直接获取 Nacos Server 端配置的内容。 + +### 动态刷新 + +Nacos Config Starter 默认为所有获取数据成功的 Nacos 的配置项添加了监听功能,在监听到服务端配置发生变化时会实时触发 `org.springframework.cloud.context.refresh.ContextRefresher` 的 refresh 方法 。 + +如果需要对 Bean 进行动态刷新,请参照 Spring 和 Spring Cloud 规范。推荐给类添加 `@RefreshScope` 或 `@ConfigurationProperties ` 注解, + +更多详情请参考 [ContextRefresher Java Doc](http://static.javadoc.io/org.springframework.cloud/spring-cloud-context/2.0.0.RELEASE/org/springframework/cloud/context/refresh/ContextRefresher.html)。 + + + + +## Endpoint 信息查看 + +Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Nacos Config Starter 也支持这一点。 + +在使用之前需要在 maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。 + +* Spring Boot 1.x 中添加配置 management.security.enabled=false +* Spring Boot 2.x 中添加配置 management.endpoints.web.exposure.include=* + +Spring Boot 1.x 可以通过访问 http://127.0.0.1:18084/nacos_config 来查看 Nacos Endpoint 的信息。 + +Spring Boot 2.x 可以通过访问 http://127.0.0.1:18084/actuator/nacos-config 来访问。 + +![actuator](https://cdn.nlark.com/lark/0/2018/png/54319/1536986344822-279e1edc-ebca-4201-8362-0ddeff240b85.png) + +如上图所示,Sources 表示此客户端从哪些 Nacos Config 配置项中获取了信息,RefreshHistory 表示动态刷新的历史记录,最多保存20条,NacosConfigProperties 则为 Nacos Config Starter 本身的配置。 + +## More + +#### 更多配置项 +配置项|key|默认值|说明 +----|----|-----|----- +服务端地址|spring.cloud.nacos.config.server-addr|| +DataId前缀|spring.cloud.nacos.config.prefix||spring.application.name +Group|spring.cloud.nacos.config.group|DEFAULT_GROUP| +dataID后缀及数据格式|spring.cloud.nacos.config.content-type|properties|目前只支持 properties +配置内容的编码方式|spring.cloud.nacos.config.encode|UTF-8|配置的编码 +获取配置的超时时间|spring.cloud.nacos.config.timeout|3000|单位为 ms +配置的命名空间|spring.cloud.nacos.config.namespace||常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源隔离等。 +AccessKey|spring.cloud.nacos.config.access-key|| +SecretKey|spring.cloud.nacos.config.secret-key|| +相对路径|spring.cloud.nacos.config.context-path||服务端 API 的相对路径 +接入点|spring.cloud.nacos.config.endpoint|UTF-8|地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 +是否开启监听和自动刷新|spring.cloud.nacos.config.refresh.enabled|true| + + + +#### 更多介绍 +Nacos为用户提供包括动态服务发现,配置管理,服务管理等服务基础设施,帮助用户更灵活,更轻松地构建,交付和管理他们的微服务平台,基于Nacos, 用户可以更快速的构建以“服务”为中心的现代云原生应用。Nacos可以和Spring Cloud、Kubernetes/CNCF、Dubbo 等微服务生态无缝融合,为用户提供更卓越的体验。更多 Nacos 相关的信息,请参考 [Nacos 项目](https://github.com/alibaba/Nacos)。 + +如果您对 Spring Cloud Nacos Config Starter 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。 + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md new file mode 100644 index 000000000..4d72ef943 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md @@ -0,0 +1,193 @@ +# Nacos Config Example + +## Project Instruction + +This example illustrates how to use Nacos Config Starter implement externalized configuration for Spring Cloud applications. + +[Nacos](https://github.com/alibaba/Nacos) an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. + +## Demo + +### Connect to Nacos Config +Before we start the demo, let's learn how to connect Nacos Config to a Spring Cloud application. **Note: This section is to show you how to connect to Nacos Config. 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-nacos-config in the pom.xml file in your Spring Cloud project. + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-config + + +2. Add Nacos server address configurations to file /src/main/resources/bootstrap.properties + + spring.cloud.nacos.config.server-addr=127.0.0.1:8080 + +3. After completing the above two steps, the application will get the externalized configuration from Nacos Server and put it in the Spring Environment's PropertySources.We use the @Value annotation to inject the corresponding configuration into the userName and age fields of the SampleController, and add @RefreshScope to turn on dynamic refresh . + @RefreshScope + class SampleController { + + @Value("${user.name}") + String userName; + + @Value("${user.age}") + int age; + } + +### Start Nacos Server + +1. Install Nacos Server by downloading or build from source code.**Recommended latest version Nacos Server** + + 1. Download: Download Nacos Server [download page](https://github.com/alibaba/nacos/releases) + 2. Build from source code: Get source code by git clone git@github.com:alibaba/Nacos.git from Github Nacos and build your code. See [build reference](https://nacos.io/en-us/docs/quick-start.html) for details. + + + +2. Unzip the downloaded file and go to the nacos/bin folder(), And according to the actual situation of the operating system, execute the following command。[see reference for more detail](https://nacos.io/en-us/docs/quick-start.html)。 + + 1. Linux/Unix/Mac , execute `sh startup.sh -m standalone` + 1. Windows , execute `cmd startup.cmd` + +3. Execute the following command to add a configuration to Nacos Server. + + curl -X POST "http://127.0.0.1:8080/nacos/v1/cs/configs?dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=user.id=1%0Auser.name=james%0Auser.age=17" + + **Note: You can also add it in other ways. If you are using the Nacos version with its own console, it is recommended to configure it directly using the console.** + + + Details of the added configuration are as follows + + dataId is nacos-config-example.properties + group is DEFAULT_GROUP + + content is + + user.id=1 + user.name=james + user.age=17 + +### Start Application + +1. Add necessary configurations to file /src/main/resources/application.properties + + spring.application.name=nacos-config-example + server.port=18084 + + +2. Start the application in IDE or by building a fatjar. + + 1. Start in IDE: Find main class `Application`, and execute the main method. + 2. Build a fatjar:Execute command `mvn clean package` to build a fatjar,and run command `java -jar nacos-config-example.jar` to start the application. + +### Verification + +#### Automatic Injection +Enter `http://127.0.0.1:18084/user` in the browser address bar and click Go to, we can see the data successfully obtained from Nacos Config Server. + +![get](https://cdn.nlark.com/lark/0/2018/png/54319/1536986328663-5e3503c2-7e14-4c56-b5f9-72fecc6898d2.png) + +#### Dynamic Refresh +1. Run the following command to modify the configuration data on the Nacos Server side. + + curl -X POST "http://127.0.0.1:8080/nacos/v1/cs/configs?dataId=nacos-config-example.properties&group=DEFAULT_GROUP&content=user.id=1%0Auser.name=james%0Auser.age=18" + +2. Enter `http://127.0.0.1:18084/user` in the browser address bar and click Go to, +We can see that the app got the latest data from Nacos Server and the age becomes 18. + +![refresh](https://cdn.nlark.com/lark/0/2018/png/54319/1536986336535-c0efdf6d-a5d3-4f33-8d26-fe3a36cdacf6.png) + + +## Principle + + +### Nacos Config Data Structure + +Nacos Config primarily determines a piece of config through dataId and group, and we assume that you already know this background. If you don't understand, please refer to [Nacos Doc](https://nacos.io/en-us/docs/concepts.html)。 + +Nacos Client gets data from Nacos Server through this method. `ConfigService.getConfig(String dataId, String group, long timeoutMs)`。 + + +### Spring Cloud Retrieve Data + +#### dataID + +In Nacos Config Starter, the splicing format of dataId is as follows + + ${prefix} - ${spring.active.profile} . ${content-type} + +* `prefix` default value is `spring.application.name` value, which can also be configured via the configuration item `spring.cloud.nacos.config.prefix`. + +* `spring.active.profile` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles) + + **Note: when the activeprofile is empty, the corresponding connector `-` will also not exist, and the splicing format of the dataId becomes `${prefix}`.`${context.type}`** + +* `content-type` is the data format of the configuration content, which can be configured by the configuration item `spring.cloud.nacos.config.content-type`. +Currently only the `properties` type is supported. + +#### group +* `group` defaults to `DEFAULT_GROUP` and can be configured via `spring.cloud.nacos.config.group`. + + +### Automatic Injection +Nacos Config Starter implement `org.springframework.cloud.bootstrap.config.PropertySourceLocator` interface, and set order to 0. + +In the startup phase of the Spring Cloud application, the corresponding data is obtained from the Nacos Server side, and the acquired data is converted into a PropertySource and injected into the PropertySources property of the Spring Environment. so the @Value annotation can also directly obtain the configuration of the Nacos Server side. + +### Dynamic Refresh + +By default, Nacos Config Starter adds a listening function to all Nacos configuration items that have successfully acquired data. It will trigger `org.springframework.cloud.context.refresh.ContextRefresher` 's refresh method in real time when it detects changes in the server configuration. + +If you need to dynamically refresh a bean, please refer to the Spring and Spring Cloud specifications. It is recommended to add `@RefreshScope` or `@ConfigurationProperties ` annotations to the class. + +Please refer to[ContextRefresher Java Doc](http://static.javadoc.io/org.springframework.cloud/spring-cloud-context/2.0.0.RELEASE/org/springframework/cloud/context/refresh/ContextRefresher.html) for more details. + + + + +## Endpoint + +Nacos Config starter also supports the implementation of Spring Boot actuator endpoints. + +**Prerequisite:** + +Add dependency spring-boot-starter-actuator to your pom.xml file, and configure your endpoint security strategy. + +Spring Boot 1.x: Add configuration management.security.enabled=false +Spring Boot 2.x: Add configuration management.endpoints.web.exposure.include=* +To view the endpoint information, visit the following URLS: + +Spring Boot1.x: Nacos Config Endpoint URL is http://127.0.0.1:18083/nacos_config. +Spring Boot2.x: Nacos Config Endpoint URL is http://127.0.0.1:18083/actuator/nacos-config. + +![actuator](https://cdn.nlark.com/lark/0/2018/png/54319/1536986344822-279e1edc-ebca-4201-8362-0ddeff240b85.png) + +As shown in the figure above, Sources indicates which Nacos Config configuration items the client has obtained information, RefreshHistory indicates the dynamic refresh history, and up to 20, and NacosConfigProperties is the configuration of Nacos Config Starter itself. + +## More + +#### More configuration items + +Configuration item|key|default value|Description +----|----|-----|----- +server address|spring.cloud.nacos.config.server-addr|| +DataId prefix|spring.cloud.nacos.config.prefix||spring.application.name +Group|spring.cloud.nacos.config.group|DEFAULT_GROUP| +dataID content type|spring.cloud.nacos.config.content-type|properties|currently only support properties +encoding |spring.cloud.nacos.config.encode|UTF-8|Content encoding +timeout|spring.cloud.nacos.config.timeout|3000|Get the configuration timeout period,unit is ms +namespace|spring.cloud.nacos.config.namespace||One of the common scenarios is the separation of the configuration of different environments, such as the development of the test environment and the resource isolation of the production environment. +AccessKey|spring.cloud.nacos.config.access-key|| +SecretKey|spring.cloud.nacos.config.secret-key|| +context-path|spring.cloud.nacos.config.context-path||Relative path of the server API +endpoint|spring.cloud.nacos.config.endpoint|UTF-8|The domain name of a service, through which the server address can be dynamically obtained. +refresh|spring.cloud.nacos.config.refresh.enabled|true|enable auto refresh + + + +#### More introduction +[Nacos](https://github.com/alibaba/Nacos) is committed to help you discover, configure, and manage your microservices. It provides a set of simple and useful features enabling you to realize dynamic service discovery, service configuration, service metadata and traffic management. + +Nacos makes it easier and faster to construct, deliver and manage your microservices platform. It is the infrastructure that supports a service-centered modern application architecture with a microservices or cloud-native approach. + +If you have any ideas or suggestions for Nacos Config starter, please don't hesitate to tell us by submitting github issues. + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Application.java b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Application.java new file mode 100644 index 000000000..b11681077 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Application.java @@ -0,0 +1,54 @@ +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author xiaojing + */ +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} + +@Component +class SampleRunner implements ApplicationRunner { + + @Value("${user.name}") + String userName; + + @Value("${user.age}") + int userAge; + + @Override + public void run(ApplicationArguments args) throws Exception { + System.out.println(userName); + System.out.println(userAge); + } +} + +@RestController +@RefreshScope +class SampleController { + + @Value("${user.name}") + String userName; + + @Value("${user.age}") + int age; + + @RequestMapping("/user") + public String simple() { + return "Hello Nacos Config!" + "Hello " + userName + " " + age + "!"; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/application.properties new file mode 100644 index 000000000..a0e934e2a --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=nacos-config-example +server.port=18084 +management.endpoints.web.exposure.include=* \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/bootstrap.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/bootstrap.properties new file mode 100644 index 000000000..aca756fe4 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/src/main/resources/bootstrap.properties @@ -0,0 +1 @@ +spring.cloud.nacos.config.server-addr=127.0.0.1:8080 \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml new file mode 100644 index 000000000..ec343d5c5 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/pom.xml @@ -0,0 +1,62 @@ + + + + + org.springframework.cloud + nacos-discovery-example + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + + nacos-discovery-consumer-example + jar + Example demonstrating how to use nacos discovery + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java new file mode 100644 index 000000000..bc9c687e9 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ConsumerApplication.java @@ -0,0 +1,41 @@ +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +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.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +public class ConsumerApplication { + + @LoadBalanced + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + + + + public static void main(String[] args) { + SpringApplication.run(ConsumerApplication.class, args); + } + + @FeignClient(name = "service-provider") + public interface EchoService { + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); + } +} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java new file mode 100644 index 000000000..b896691bb --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java @@ -0,0 +1,45 @@ +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.cloud.examples.ConsumerApplication.EchoService; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * @author xiaojing + */ +@RestController +public class TestController { + + @Autowired + private RestTemplate restTemplate; + @Autowired + private EchoService echoService; + + + @Autowired + private DiscoveryClient discoveryClient; + + @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) + public String rest(@PathVariable String str) { + return restTemplate.getForObject("http://service-provider/echo/" + str, String.class); + } + @RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET) + public String feign(@PathVariable String str) { + return echoService.echo(str); + } + + + @RequestMapping(value="/services/{service}",method = RequestMethod.GET) + public Object client(@PathVariable String service){ + return discoveryClient.getInstances(service); + } + @RequestMapping(value="/services",method = RequestMethod.GET) + public Object services(){ + return discoveryClient.getServices(); + } +} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties new file mode 100644 index 000000000..bbd505914 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties @@ -0,0 +1,4 @@ +spring.application.name=service-consumer +server.port=18083 +management.endpoints.web.exposure.include=* +spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080 \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/pom.xml new file mode 100644 index 000000000..294a44b94 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/pom.xml @@ -0,0 +1,52 @@ + + + + + org.springframework.cloud + nacos-discovery-example + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + + nacos-discovery-provider-example + jar + Example demonstrating how to use nacos discovery + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java new file mode 100644 index 000000000..169bccd67 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java @@ -0,0 +1,29 @@ +package org.springframework.cloud.alibaba.cloud.examples; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author xiaojing + */ +@SpringBootApplication +@EnableDiscoveryClient +public class ProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(ProviderApplication.class, args); + } + + @RestController + class EchoController { + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) + public String echo(@PathVariable String string) { + return "hello Nacos Discovery " + string; + } + } +} diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties new file mode 100644 index 000000000..044964020 --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/resources/application.properties @@ -0,0 +1,4 @@ +server.port=18082 +spring.application.name=service-provider +spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080 +management.endpoints.web.exposure.include=* \ No newline at end of file diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml new file mode 100644 index 000000000..e56d92d4a --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/pom.xml @@ -0,0 +1,25 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba-examples + 0.2.0.BUILD-SNAPSHOT + ../../pom.xml + + 4.0.0 + + + nacos-discovery-example + pom + Example demonstrating how to use nacos discovery + + + + nacos-discovery-consumer-example + nacos-discovery-provider-example + + + + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md new file mode 100644 index 000000000..9420eefad --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md @@ -0,0 +1,209 @@ +# Nacos Discovery Example + +## 项目说明 + +本项目演示如何使用 Nacos Discovery Starter 完成 Spring Cloud 应用的服务注册与发现。 + +[Nacos](https://github.com/alibaba/Nacos) 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 + +## 示例 + +### 如何接入 +在启动示例进行演示之前,我们先了解一下 Spring Cloud 应用如何接入 Nacos Discovery。 +**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。** + +1. 首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。 + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-discovery + + +2. 在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址 + + spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080 + +3. 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能 + + @SpringBootApplication + @EnableDiscoveryClient + public class ProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @RestController + class EchoController { + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) + public String echo(@PathVariable String string) { + return string; + } + } + } + +### 启动 Nacos Server + +1. 首先需要获取 Nacos Server,支持直接下载和源码构建两种方式。 + + 1. 直接下载:[Nacos Server 下载页](https://github.com/alibaba/nacos/releases) + 2. 源码构建:进入 Nacos [Github 项目页面](https://github.com/alibaba/nacos),将代码 git clone 到本地自行编译打包,[参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。**推荐使用源码构建方式以获取最新版本** + +2. 启动 Server,进入解压后文件夹或编译打包好的文件夹,找到如下相对文件夹 nacos/bin,并对照操作系统实际情况之下如下命令。 + + 1. Linux/Unix/Mac 操作系统,执行命令 `sh startup.sh -m standalone` + 1. Windows 操作系统,执行命令 `cmd startup.cmd` + +### 应用启动 + +1. 增加配置,在 nacos-discovery-provider-example 项目的 /src/main/resources/application.properties 中添加基本配置信息 + + spring.application.name=service-provider + server.port=18082 + + +2. 启动应用,支持 IDE 直接启动和编译打包后启动。 + + 1. IDE直接启动:找到 nacos-discovery-provider-example 项目的主类 `ProviderApplication`,执行 main 方法启动应用。 + 2. 打包编译后启动:在 nacos-discovery-provider-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-discovery-provider-example.jar`启动应用。 + +### 验证 + +#### 查询服务 +在浏览器输入此地址 `http://127.0.0.1:8080/nacos/v1/ns/instances?serviceName=service-provider`,并点击跳转,可以看到服务节点已经成功注册到 Nacos Server。 + +![查询服务](https://cdn.nlark.com/lark/0/2018/png/54319/1536986288092-5cf96af9-9a26-466b-85f6-39ad1d92dfdc.png) + + +### 服务发现 + + +#### 集成 Ribbon +为了便于使用,NacosServerList 实现了 com.netflix.loadbalancer.ServerList 接口,并在 @ConditionOnMissingBean 的条件下进行自动注入。如果您有定制化的需求,可以自己实现自己的 ServerList。 + +Nacos Discovery Starter 默认集成了 Ribbon ,所以对于使用了 Ribbon 做负载均衡的组件,可以直接使用 Nacos 的服务发现。 + + +#### 使用 RestTemplate 和 FeignClient + +下面将分析 nacos-discovery-consumer-example 项目的代码,演示如何 RestTemplate 与 FeignClient。 + +**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。此处只涉及Ribbon、RestTemplate、FeignClient相关的内容,如果已经使用了其他服务发现组件,可以通过直接替换依赖来接入 Nacos Discovery。** + +1. 添加 @LoadBlanced 注解,使得 RestTemplate 接入 Ribbon + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +1. FeignClient 已经默认集成了 Ribbon ,此处演示如何配置一个 FeignClient。 + + @FeignClient(name = "service-provider") + public interface EchoService { + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); + } + + 使用 @FeignClient 注解将 EchoService 这个接口包装成一个 FeignClient,属性 name 对应服务名 service-provider。 + + echo 方法上的 @RequestMapping 注解将 echo 方法与 URL "/echo/{str}" 相对应,@PathVariable 注解将 URL 路径中的 `{str}` 对应成 echo 方法的参数 str。 + +1. 完成以上配置后,将两者自动注入到 TestController 中。 + + @RestController + public class TestController { + + @Autowired + private RestTemplate restTemplate; + @Autowired + private EchoService echoService; + + @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) + public String rest(@PathVariable String str) { + return restTemplate.getForObject("http://service-provider/echo/" + str, String.class); + } + @RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET) + public String feign(@PathVariable String str) { + return echoService.echo(str); + } + } + +1. 配置必要的配置,在 nacos-discovery-consumer-example 项目的 /src/main/resources/application.properties 中添加基本配置信息 + + spring.application.name=service-consumer + server.port=18083 + +1. 启动应用,支持 IDE 直接启动和编译打包后启动。 + + 1. IDE直接启动:找到 nacos-discovery-consumer-example 项目的主类 `ConsumerApplication`,执行 main 方法启动应用。 + 2. 打包编译后启动:在 nacos-discovery-consumer-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-discovery-consumer-example.jar`启动应用。 + +#### 验证 +1. 在流量器地址栏中输入 http://127.0.0.1:18083/echo-rest/1234,点击跳转,可以看到浏览器显示了 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 1234",证明服务发现生效。 + +![rest](https://cdn.nlark.com/lark/0/2018/png/54319/1536986302124-ee27670d-bdcc-4210-9f5d-875acec6d3ea.png) + +1. 在流量器地址栏中输入 http://127.0.0.1:18083/echo-feign/12345,点击跳转,可以看到浏览器显示 nacos-discovery-provider-example 返回的消息 "hello Nacos Discovery 12345",证明服务发现生效。 + +![feign](https://cdn.nlark.com/lark/0/2018/png/54319/1536986311685-6d0c1f9b-a453-4ec3-88ab-f7922d210f65.png) +## 原理 + + +### 服务注册 +Spring Cloud Nacos Discovery 遵循了 spring cloud common 标准,实现了 AutoServiceRegistration、ServiceRegistry、Registration 这三个接口。 + +在 spring cloud 应用的启动阶段,监听了 WebServerInitializedEvent 事件,当Web容器初始化完成后,即收到 WebServerInitializedEvent 事件后,会触发注册的动作,调用 ServiceRegistry 的 register 方法,将服务注册到 Nacos Server。 + + + +### 服务发现 +NacosServerList 实现了 com.netflix.loadbalancer.ServerList 接口,并在 @ConditionOnMissingBean 的条件下进行自动注入,默认集成了Ribbon。 + +如果需要有更加自定义的可以使用 @Autowired 注入一个 NacosRegistration 实例,通过其持有的 NamingService 字段内容直接调用 Nacos API。 + + +## Endpoint 信息查看 + +Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Nacos Discovery Starter 也支持这一点。 + +在使用之前需要在 maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。 + +* Spring Boot 1.x 中添加配置 management.security.enabled=false +* Spring Boot 2.x 中添加配置 management.endpoints.web.exposure.include=* + +Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/nacos_discovery 来查看 Nacos Endpoint 的信息。 + +Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/actuator/nacos-discovery 来访问。 + +![actuator](https://cdn.nlark.com/lark/0/2018/png/54319/1536986319285-d542dc5f-5dff-462a-9f52-7254776bcd99.png) + +如上图所示,NacosDiscoveryProperties 则为 Spring Cloud Nacos Discovery 本身的配置,也包括本机注册的内容,subscribe 为本机已订阅的服务信息。 + +## More + +#### 更多配置项 +配置项|key|默认值|说明 +----|----|-----|----- +服务端地址|spring.cloud.nacos.discovery.server-addr|| +服务名|spring.cloud.nacos.discovery.service|spring.application.name| +权重|spring.cloud.nacos.discovery.weight|1|取值范围 1 到 100,数值越大,权重越大 +网卡名|spring.cloud.nacos.discovery.network-interface||当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址 +注册的IP地址|spring.cloud.nacos.discovery.ip||优先级最高 +注册的端口|spring.cloud.nacos.discovery.port|-1|默认情况下不用配置,会自动探测 +命名空间|spring.cloud.nacos.discovery.namespace||常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 +AccessKey|spring.cloud.nacos.discovery.access-key|| +SecretKey|spring.cloud.nacos.discovery.secret-key|| +Metadata|spring.cloud.nacos.discovery.metadata||使用Map格式配置 +日志文件名|spring.cloud.nacos.discovery.log-name|| +接入点|spring.cloud.nacos.discovery.enpoint|UTF-8|地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 +是否集成Ribbon|ribbon.nacos.enabled|true| + + + +#### 更多介绍 +Nacos为用户提供包括动态服务发现,配置管理,服务管理等服务基础设施,帮助用户更灵活,更轻松地构建,交付和管理他们的微服务平台,基于Nacos, 用户可以更快速的构建以“服务”为中心的现代云原生应用。Nacos可以和Spring Cloud、Kubernetes/CNCF、Dubbo 等微服务生态无缝融合,为用户提供更卓越的体验。更多 Nacos 相关的信息,请参考 [Nacos 项目](https://github.com/alibaba/Nacos)。 + +如果您对 Spring Cloud Nacos Discovery 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。 + diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme.md b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme.md new file mode 100644 index 000000000..355cf19ae --- /dev/null +++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme.md @@ -0,0 +1,220 @@ +# Nacos Discovery Example + +## Project Instruction + +This example illustrates how to use Nacos Discovery Starter implement Service discovery for Spring Cloud applications. + +[Nacos](https://github.com/alibaba/Nacos) an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. + +## Demo + +### Connect to Nacos Discovery +Before we start the demo, let's learn how to connect Nacos Config to a Spring Cloud application. **Note: This section is to show you how to connect to Nacos Discovery. 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-nacos-discovery in the pom.xml file in your Spring Cloud project. + + + org.springframework.cloud + spring-cloud-starter-alibaba-nacos-discovery + + +2. Add Nacos server address configurations to file /src/main/resources/application.properties. + + spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080 + +3. Use the @EnableDiscoveryClient annotation to turn on service registration and discovery. + + @SpringBootApplication + @EnableDiscoveryClient + public class ProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @RestController + class EchoController { + @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) + public String echo(@PathVariable String string) { + return string; + } + } + } + +### Start Nacos Server + +1. Install Nacos Server by downloading or build from source code.**Recommended latest version Nacos Server** + + 1. Download: Download Nacos Server [download page](https://github.com/alibaba/nacos/releases) + 2. Build from source code: Get source code by git clone git@github.com:alibaba/Nacos.git from Github Nacos and build your code. See [build reference](https://nacos.io/en-us/docs/quick-start.html) for details. + + + +2. Unzip the downloaded file and go to the nacos/bin folder(), And according to the actual situation of the operating system, execute the following command。[see reference for more detail](https://nacos.io/en-us/docs/quick-start.html)。 + + 1. Linux/Unix/Mac , execute `sh startup.sh -m standalone` + 1. Windows , execute `cmd startup.cmd` + +### Start Application + +1. Add necessary configurations to project `nacos-discovery-provider-example`, file /src/main/resources/application.properties. + + spring.application.name=service-provider + server.port=18082 + + +2. Start the application in IDE or by building a fatjar. + + 1. Start in IDE: Find main class `ProviderApplication ` in project `nacos-discovery-provider-example`, and execute the main method. + 2. Build a fatjar:Execute command `mvn clean package` in project ` nacos-discovery-provider-example ` to build a fatjar,and run command `java -jar nacos-discovery-provider-example.jar` to start the application. + +### Verification + +#### Query Service + +Enter `http://127.0.0.1:8080/nacos/v1/ns/instances?serviceName=service-provider` in the browser address bar and click Go to, we can see that the service node has been successfully registered to Nacos Server. + +![查询服务](https://cdn.nlark.com/lark/0/2018/png/54319/1536986288092-5cf96af9-9a26-466b-85f6-39ad1d92dfdc.png) + + +### Service Discovery + + +#### Integration Ribbon + +For ease of use, NacosServerList implements the com.netflix.loadbalancer.ServerList interface and auto-injects under the @ConditionOnMissingBean condition. If you have customized requirements, you can implement your own ServerList yourself. + +Nacos Discovery Starter integrates Ribbon by default, so for components that use Ribbon for load balancing, you can use Nacos Service discovery directly. + + +#### Use RestTemplate and FeignClient + +The code of `nacos-discovery-consumer-example` project will be analyzed below, demonstrating how RestTemplate and FeignClient. + +**Note This section is to show you how to connect to Nacos Discovery. The configurations have been completed in the following example, so you don't need modify the code any more.Only the contents related to Ribbon, RestTemplate, and FeignClient are involved here. If other service discovery components have been used, you can access Nacos Discovery by directly replacing the dependencies.** + +1. Add the @LoadBlanced annotation to make RestTemplate accessible to the Ribbon + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +1. FeignClient has integrated the Ribbon by default, which shows how to configure a FeignClient. + + @FeignClient(name = "service-provider") + public interface EchoService { + @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET) + String echo(@PathVariable("str") String str); + } + + Use the @FeignClient annotation to wrap the `EchoService` interface as a FeignClient with the attribute name corresponding to the service name `service-provider`. + + The `@RequestMapping` annotation on the `echo` method corresponds the echo method to the URL `/echo/{str}`, and the `@PathVariable` annotation maps `{str}` in the URL path to the argument `str` of the echo method. + +1. After completing the above configuration, injected them into the TestController. + + @RestController + public class TestController { + + @Autowired + private RestTemplate restTemplate; + @Autowired + private EchoService echoService; + + @RequestMapping(value = "/echo-rest/{str}", method = RequestMethod.GET) + public String rest(@PathVariable String str) { + return restTemplate.getForObject("http://service-provider/echo/" + str, String.class); + } + @RequestMapping(value = "/echo-feign/{str}", method = RequestMethod.GET) + public String feign(@PathVariable String str) { + return echoService.echo(str); + } + } + +1. Add necessary configurations to project `nacos-discovery-consumer-example` file /src/main/resources/application.properties. + + spring.application.name=service-consumer + server.port=18083 + +1. Start the application in IDE or by building a fatjar. + + 1. Start in IDE: Find main class `ConsumerApplication ` in project `nacos-discovery-consumer-example`, and execute the main method. + 2. Build a fatjar:Execute command `mvn clean package` in project ` nacos-discovery-consumer-example ` to build a fatjar,and run command `java -jar nacos-discovery-consumer-example.jar` to start the application. + +#### Verification +1. Enter `http://127.0.0.1:18083/echo-rest/1234` in the browser address bar and click Go to, we can see that the browser displays the message "hello Nacos Discovery 1234" returned by nacos-discovery-provider-example to prove that the service discovery is in effect. + +![rest](https://cdn.nlark.com/lark/0/2018/png/54319/1536986302124-ee27670d-bdcc-4210-9f5d-875acec6d3ea.png) + +1. Enter `http://127.0.0.1:18083/echo-feign/12345` in the browser address bar and click Go to, we can see that the browser displays the message "hello Nacos Discovery 12345" returned by nacos-discovery-provider-example to prove that the service discovery is in effect. + +![feign](https://cdn.nlark.com/lark/0/2018/png/54319/1536986311685-6d0c1f9b-a453-4ec3-88ab-f7922d210f65.png) + +## Principle + +### Service Registry + +Spring Cloud Nacos Discovery follows the spring cloud common standard and implements three interfaces: AutoServiceRegistration, ServiceRegistry, and Registration. + +During the startup phase of the spring cloud application, the WebServerInitializedEvent event is watched. When the WebServerInitializedEvent event is received after the Web container is initialized, the registration action is triggered, and the ServiceRegistry register method is called to register the service to the Nacos Server. + + + +### Service Discovery + +NacosServerList implements the com.netflix.loadbalancer.ServerList interface and auto-injects it under @ConditionOnMissingBean. The ribbon is integrated by default. + +If you need to be more customizable, you can use @Autowired to inject a NacosRegistration bean and call the Nacos API directly through the contents of the NamingService field it holds. + + +## Endpoint + +Nacos Discovery Starter also supports the implementation of Spring Boot actuator endpoints. + +**Prerequisite:** + +Add dependency spring-boot-starter-actuator to your pom.xml file, and configure your endpoint security strategy. + +Spring Boot 1.x: Add configuration management.security.enabled=false +Spring Boot 2.x: Add configuration management.endpoints.web.exposure.include=* +To view the endpoint information, visit the following URLS: + +Spring Boot1.x: Nacos Discovery Endpoint URL is http://127.0.0.1:18083/nacos_discovery. +Spring Boot2.x: Nacos Discovery Endpoint URL is http://127.0.0.1:18083/actuator/nacos-discovery. + +![actuator](https://cdn.nlark.com/lark/0/2018/png/54319/1536986319285-d542dc5f-5dff-462a-9f52-7254776bcd99.png) + +As shown in the figure above, NacosDiscoveryProperties is the configuration of Nacos Discovery itself, and also includes the contents registered by the application, subscribe is the service information that the application has subscribed to. + + +## More + +#### More configuration items +Configuration item|key|default value|Description +----|----|-----|----- +server address|spring.cloud.nacos.discovery.server-addr|| +service|spring.cloud.nacos.discovery.service|spring.application.name|service id to registry +weight|spring.cloud.nacos.discovery.weight|1|value from 1 to 100, The larger the value, the larger the weight +ip|spring.cloud.nacos.discovery.ip||ip address to registry, Highest priority +network interface|spring.cloud.nacos.discovery.network-interface||When the IP is not configured, the registered IP address is the IP address corresponding to the network-interface. If this item is not configured, the address of the first network-interface is taken by default. +port|spring.cloud.nacos.discovery.port|-1|port to registry, Automatically detect without configuration +namesapce|spring.cloud.nacos.discovery.namespace||One of the common scenarios is the separation of the configuration of different environments, such as the development of the test environment and the resource isolation of the production environment. +AccessKey|spring.cloud.nacos.discovery.access-key|| +SecretKey|spring.cloud.nacos.discovery.secret-key|| +Metadata|spring.cloud.nacos.discovery.metadata||Extended data, Configure using Map format +log name|spring.cloud.nacos.discovery.log-name|| +endpoint|spring.cloud.nacos.discovery.enpoint||The domain name of a service, through which the server address can be dynamically obtained. +Integration Ribbon|ribbon.nacos.enabled|true| + + + +#### More introduction + +[Nacos ](https://github.com/alibaba/Nacos) is committed to help you discover, configure, and manage your microservices. It provides a set of simple and useful features enabling you to realize dynamic service discovery, service configuration, service metadata and traffic management. + +Nacos makes it easier and faster to construct, deliver and manage your microservices platform. It is the infrastructure that supports a service-centered modern application architecture with a microservices or cloud-native approach. + +If you have any ideas or suggestions for Nacos Discovery starter, please don't hesitate to tell us by submitting github issues. + diff --git a/spring-cloud-alibaba-examples/pom.xml b/spring-cloud-alibaba-examples/pom.xml index 0fc20f0a4..e4c9fa155 100644 --- a/spring-cloud-alibaba-examples/pom.xml +++ b/spring-cloud-alibaba-examples/pom.xml @@ -12,13 +12,16 @@ spring-cloud-alibaba-examples pom + Spring Cloud Alibaba Examples Example showing how to use features of Spring Cloud Alibaba - sentinel-example - sentinel-dubbo-provider-example - sentinel-dubbo-consumer-example - sentinel-dubbo-api + sentinel-example/sentinel-core-example + sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example + sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example + sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api + nacos-example/nacos-discovery-example + nacos-example/nacos-config-example storage-example diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/readme-zh.md b/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/readme-zh.md deleted file mode 100644 index 866885fd7..000000000 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/readme-zh.md +++ /dev/null @@ -1,101 +0,0 @@ -# Sentinel Dubbo Provider Example - -## 项目说明 - -本项目演示如何使用 Sentinel starter 完成 Dubbo 应用的限流管理。 - -[Sentinel](https://github.com/alibaba/Sentinel) 是阿里巴巴开源的分布式系统的流量防卫组件,Sentinel 把流量作为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。 - -[Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架,有对应的[SpringBoot工程](https://github.com/apache/incubator-dubbo-spring-boot-project)。 - -本项目需要配合`sentinel-dubbo-consumer-example`模块一起完成演示。 - -本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example)。 - -## 示例 - -### 如何接入 -在启动示例进行演示之前,我们先了解一下 Dubbo 如何接入 Sentinel。 -**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。** - -1. 首先,修改 pom.xml 文件,引入 Sentinel starter 和 Dubbo starter。 - - - org.springframework.cloud - spring-cloud-starter-sentinel - - - - com.alibaba.boot - dubbo-spring-boot-starter - - -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)); - - -### 服务定义及发布 - -在application.properties文件中定义dubbo相关的配置,比如协议,注册中心: - - spring.application.name = dubbo-provider-demo - - foo.service.version = 1.0.0 - - dubbo.scan.basePackages = org.springframework.cloud.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 org.springframework.cloud.alibaba.cloud.examples.FooService; - public interface FooService { - String hello(String name); - } - -定义具体的服务: - - @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; - } - } - - -### 应用启动 - - -支持 IDE 直接启动和编译打包后启动。 - -1. IDE直接启动:找到主类 `SentinelDubboProviderApp`,执行 main 方法启动应用。 -2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-dubbo-provider-example.jar`启动应用。 - - diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/readme.md b/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/readme.md deleted file mode 100644 index 885296f4c..000000000 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/readme.md +++ /dev/null @@ -1,97 +0,0 @@ -# Sentinel Dubbo Provider 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 work with 'sentinel-dubbo-consumer-example' module and `sentinel-dubbo-provider-example` module should startup firstly. - -This example focus on the integration of Sentinel and Dubbo. You can see more features on [sentinel-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-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-sentinel and dubbo-spring-boot-starter in the pom.xml file in your Spring Cloud project. - - - org.springframework.cloud - spring-cloud-starter-sentinel - - - - com.alibaba.boot - dubbo-spring-boot-starter - - -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`, like protocol, config registry: - - spring.application.name = dubbo-provider-demo - - foo.service.version = 1.0.0 - - dubbo.scan.basePackages = org.springframework.cloud.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 org.springframework.cloud.alibaba.cloud.examples.FooService; - 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; - } - } - -### Start Application - -Start the application in IDE or by building a fatjar. - -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. - - diff --git a/spring-cloud-alibaba-examples/sentinel-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml similarity index 90% rename from spring-cloud-alibaba-examples/sentinel-example/pom.xml rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml index 6da7873c5..ec35b244d 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/pom.xml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/pom.xml @@ -6,30 +6,30 @@ org.springframework.cloud spring-cloud-alibaba-examples 0.2.0.BUILD-SNAPSHOT + ../../pom.xml 4.0.0 - sentinel-example + sentinel-core-example jar Example demonstrating how to use sentinel - - org.springframework.boot - spring-boot-starter-web - org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-actuator - diff --git a/spring-cloud-alibaba-examples/sentinel-example/readme-zh.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md similarity index 58% rename from spring-cloud-alibaba-examples/sentinel-example/readme-zh.md rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md index 4ae6cfaad..49d1e8989 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/readme-zh.md +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme-zh.md @@ -10,45 +10,55 @@ ## 示例 ### 如何接入 + 在启动示例进行演示之前,我们先了解一下如何接入 Sentinel。 -**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。** -1. 首先,修改 pom.xml 文件,引入 Sentinel starter。 +> **注意:本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。** + +1. 首先,修改 `pom.xml` 文件,引入 Sentinel starter。 + +```xml + + org.springframework.cloud + spring-cloud-starter-alibaba-sentinel + +``` - - org.springframework.cloud - spring-cloud-starter-sentinel - - 2. 接入限流埋点 + - HTTP 埋点 - 1. HTTP埋点 Sentinel starter 默认为所有的 HTTP 服务提供了限流埋点,如果只想对 HTTP 服务进行限流,那么只需要引入依赖,无需修改代码。 + - 自定义埋点 + + 如果需要对某个特定的方法进行限流或降级,可以通过 `@SentinelResource` 注解来完成限流的埋点,示例代码如下: + + ```java + @SentinelResource("resource") + public String hello() { + return "Hello"; + } + ``` - 2. 自定义埋点 - 如果需要对某个特定的方法进行限流或降级,可以通过 @SentinelResource 来完成限流的埋点,示例代码如下 + 当然也可以通过原始的 `SphU.entry(xxx)` 方法进行埋点,可以参见 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%B5%84%E6%BA%90)。 - @SentinelResource("resource") - public String hello() { - return "Hello"; - } - 3. 配置限流规则 - Sentinel提供了两种配置限流规则的方式,代码配置 和 控制台配置,本示例使用的方式为通过控制台配置。 + Sentinel 提供了两种配置限流规则的方式:代码配置 和 控制台配置。本示例使用的方式为通过控制台配置。 1. 通过代码来实现限流规则的配置。一个简单的限流规则配置示例代码如下,更多限流规则配置详情请参考 [Sentinel 文档](https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E5%AE%9A%E4%B9%89%E8%A7%84%E5%88%99)。 - List rules = new ArrayList(); - FlowRule rule = new FlowRule(); - rule.setResource(str); - // set limit qps to 10 - rule.setCount(10); - rule.setGrade(RuleConstant.FLOW_GRADE_QPS); - rule.setLimitApp("default"); - rules.add(rule); - FlowRuleManager.loadRules(rules); - + ```java + List rules = new ArrayList(); + FlowRule rule = new FlowRule(); + rule.setResource(str); + // set limit qps to 10 + rule.setCount(10); + rule.setGrade(RuleConstant.FLOW_GRADE_QPS); + rule.setLimitApp("default"); + rules.add(rule); + FlowRuleManager.loadRules(rules); + ``` + 2. 通过控制台进行限流规则配置请参考文章后面的图文说明。 ### 启动 Sentinel 控制台 @@ -65,14 +75,16 @@ 1. 增加配置,在应用的 /src/main/resources/application.properties 中添加基本配置信息 - spring.application.name=sentinel-example - server.port=18083 - spring.cloud.sentinel.dashboard=localhost:8080 - + ``` + spring.application.name=sentinel-example + server.port=18083 + spring.cloud.sentinel.dashboard=localhost:8080 + ``` + 2. 启动应用,支持 IDE 直接启动和编译打包后启动。 1. IDE直接启动:找到主类 `ServiceApplication`,执行 main 方法启动应用。 - 2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-example.jar`启动应用。 + 2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-core-example.jar`启动应用。 ### 调用服务 @@ -84,7 +96,8 @@ ### 配置限流规则并验证 1. 访问 http://localhost:8080 页面,可以在左侧看到 Sentinel-Example 应用已经注册到了控制台,单击 **流控规则** ,可以看到目前的流控规则为空。 -**注意 如果您在控制台没有找到应用,请调用一下进行了 Sentinel 埋点的 URL 或方法,因为 Sentinel 使用了 lazy load 策略** + +> **注意:如果您在控制台没有找到应用,请调用一下进行了 Sentinel 埋点的 URL 或方法,因为 Sentinel 使用了 lazy load 策略。详细的排查过程请参见 [Sentinel FAQ](https://github.com/alibaba/Sentinel/wiki/FAQ)。**

@@ -94,7 +107,7 @@

-3. 配置自定义限流规则:点击新增流控规则,资源名填写 @SentinelResource 注解 value 字段的值,单机阈值选择需要限流的阈值,点击新增进行确认。(为了便于演示效果,这里将值设置成了 1)。 +3. 配置自定义限流规则:点击新增流控规则,资源名填写 `@SentinelResource` 注解 `value` 字段的值,单机阈值选择需要限流的阈值,点击新增进行确认。(为了便于演示效果,这里将值设置成了 1)。

@@ -110,61 +123,82 @@ ## 自定义限流处理逻辑 1. URL 限流触发后默认处理逻辑是,直接返回 "Blocked by Sentinel (flow limiting)"。 - 如果需要自定义处理逻辑,实现的方式如下 - - public class CustomUrlBlockHandler implements UrlBlockHandler { - @Override - public void blocked(HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse) throws IOException { - // todo add your logic - } - } - - WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler()); + 如果需要自定义处理逻辑,实现的方式如下: + ```java + public class CustomUrlBlockHandler implements UrlBlockHandler { + @Override + public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException { + // todo add your logic + } + } + WebCallbackManager.setUrlBlockHandler(new CustomUrlBlockHandler()); + ``` 2. 自定义限流触发后,默认的处理逻辑是抛出异常。 - 如果需要自定义处理逻辑,填写@SentinelResource注解的blockHandler和blockHandlerClass属性,指定后会去blockHandlerClass类里找对应的blockHandler静态方法。示例实现如下 - - @SentinelResource(value = "resource", blockHandler = "", blockHandlerClass = ExceptionUtil.class) - public String hello() { - return "Hello"; - } - - // ExceptionUtil.java - public class ExceptionUtil { - public static void handleException(BlockException ex) { - System.out.println("Oops: " + ex.getClass().getCanonicalName()); - } - } - + +如果需要自定义处理逻辑,填写 `@SentinelResource` 注解的 `blockHandler` 属性(针对所有类型的 `BlockException`,需自行判断)或 `fallback` 属性(针对熔断降级异常),注意**对应方法的签名和位置有限制**,详情见 [Sentinel 注解支持文档](https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81#sentinelresource-%E6%B3%A8%E8%A7%A3)。示例实现如下: + +```java +public class TestService { + + // blockHandler 是位于 ExceptionUtil 类下的 handleException 静态方法,需符合对应的类型限制. + @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class}) + public void test() { + System.out.println("Test"); + } + + // blockHandler 是位于当前类下的 exceptionHandler 方法,需符合对应的类型限制. + @SentinelResource(value = "hello", blockHandler = "exceptionHandler") + public String hello(long s) { + return String.format("Hello at %d", s); + } + + public String exceptionHandler(long s, BlockException ex) { + // Do some log here. + ex.printStackTrace(); + return "Oops, error occurred at " + s; + } +} +``` + +```java +public final class ExceptionUtil { + + public static void handleException(BlockException ex) { + System.out.println("Oops: " + ex.getClass().getCanonicalName()); + } +} +``` + +一个简单的示例可以见 [sentinel-demo-annotation-spring-aop](https://github.com/alibaba/Sentinel/tree/master/sentinel-demo/sentinel-demo-annotation-spring-aop)。 ## Endpoint 信息查看 Spring Boot 应用支持通过 Endpoint 来暴露相关信息,Sentinel Starter 也支持这一点。 -在使用之前需要在 maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。 -* Spring Boot1.x 中添加配置 management.security.enabled=false -* Spring Boot2.x 中添加配置 management.endpoints.web.exposure.include=* +在使用之前需要在 Maven 中添加 `spring-boot-starter-actuator`依赖,并在配置中允许 Endpoints 的访问。 +* Spring Boot 1.x 中添加配置 `management.security.enabled=false` +* Spring Boot 2.x 中添加配置 `management.endpoints.web.exposure.include=*` -Spring Boot1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot2.x 可以通过访问 http://127.0.0.1:18083/acutator/sentinel 来访问。 +Spring Boot 1.x 可以通过访问 http://127.0.0.1:18083/sentinel 来查看 Sentinel Endpoint 的信息。Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/acutator/sentinel 来访问。

## 查看实时监控 Sentinel 控制台支持实时监控查看,您可以通过 Sentinel 控制台查看各链路的请求的通过数和被限流数等信息。 -其中 p_qps 为通过(pass) 流控的 QPS,b_qps 为被限流 (block) 的 QPS。 +其中 `p_qps` 为通过(pass) 流控的 QPS,`b_qps` 为被限流 (block) 的 QPS。

-## DataSource支持 +## DataSource 支持 -Sentinel内部提供了[动态规则的扩展实现DataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。 +Sentinel 内部提供了[动态规则的扩展实现 DataSource](https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95#datasource-%E6%89%A9%E5%B1%95)。 -Sentinel starter整合了目前存在的4类DataSource。只需要在配置文件中进行相关配置,即可在Spring容器中自动注册DataSource。 +Sentinel starter 整合了目前存在的几类 DataSource。只需要在配置文件中进行相关配置,即可在 Spring 容器中自动注册 DataSource。 -比如要定义一个FileRefreshableDataSource,配置如下: +比如要定义一个 `FileRefreshableDataSource`,配置如下: spring.cloud.sentinel.datasource.type=file spring.cloud.sentinel.datasource.recommendRefreshMs=2000 @@ -172,40 +206,40 @@ Sentinel starter整合了目前存在的4类DataSource。只需要在配置文 spring.cloud.sentinel.datasource.charset=utf-8 spring.cloud.sentinel.datasource.configParser=myParser spring.cloud.sentinel.datasource.file=/Users/you/rule.json - -然后使用`@SentinelDataSource`注解修饰DataSource即可注入: - + +然后使用`@SentinelDataSource` 注解修饰 DataSource 即可注入: + @SentinelDataSource("spring.cloud.sentinel.datasource") private DataSource dataSource; - -`@SentinelDataSource`注解的value属性可以不填。默认值就是spring.cloud.sentinel.datasource。 -value属性代表配置前缀。示例中会去找spring.cloud.sentinel.datasource.xxx相关的配置。 +`@SentinelDataSource` 注解的 value 属性可以不填。默认值就是 `spring.cloud.sentinel.datasource`。 -spring.cloud.sentinel.datasource.type就是对应的DataSource类型。 +`value` 属性代表配置前缀。示例中会去找 `spring.cloud.sentinel.datasource.xxx` 相关的配置。 -spring.cloud.sentinel.datasource.recommendRefreshMs里的recommendRefreshMs对应相关DataSource的属性。 +`spring.cloud.sentinel.datasource.type` 就是对应的 DataSource 类型。 -spring.cloud.sentinel.datasource.configParser代表ConfigParser在Spring容器里的name。如果没找到,会抛出异常。 +`spring.cloud.sentinel.datasource.recommendRefreshMs` 里的 `recommendRefreshMs` 对应相关 DataSource 的属性。 + +`spring.cloud.sentinel.datasource.configParser`代表 `ConfigParser` 在 Spring 容器里的 name。如果没找到,会抛出异常。 type目前支持file, nacos, zk, apollo。 ### 自定义DataSource -自定义DataSource只需要两部。 +自定义DataSource只需要两步。 1. 定义DataSource - + public class CustomDataSource implements DataSource { private String fieldA; private String fieldB; ... } - + 2. 装配DataSource。有两种方式处理。 * 直接构造DataSource - + @Bean public CustomDataSource customDataSource() { CustomDataSource customDataSource = @@ -219,13 +253,13 @@ type目前支持file, nacos, zk, apollo。 * 在classpath:/META-INF/sentinel-datasource.properties中管理DataSource信息 custom = yourpackage.CustomDataSource - + 在application.properties中定义DataSource - + spring.cloud.sentinel.datasource.type = custom spring.cloud.sentinel.datasource.fieldA = valueA spring.cloud.sentinel.datasource.fieldB = valueB - + 注意:由于目前Sentinel的AbstractDataSource需要有个ConfigParser作为构造函数中的参数,并且它的子类的构造都是通过多个参数的构造函数构造的。 所以目前所有的Sentinel starter中的DataSource都是基于FactoryBean并且通过设置属性构造的。如果有这方面的需求,需要再多加一个registerFactoryBean过程。 diff --git a/spring-cloud-alibaba-examples/sentinel-example/readme.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md similarity index 97% rename from spring-cloud-alibaba-examples/sentinel-example/readme.md rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md index 85a44863e..86156b53a 100644 --- a/spring-cloud-alibaba-examples/sentinel-example/readme.md +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/readme.md @@ -12,11 +12,11 @@ This example illustrates how to use Sentinel starter to implement flow control f Before we start the demo, let's learn how to connect Sentinel 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-sentinel in the pom.xml file in your Spring Cloud project. +1. Add dependency spring-cloud-starter-alibaba-sentinel in the pom.xml file in your Spring Cloud project. org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel 2. Define Resources @@ -71,7 +71,7 @@ Before we start the demo, let's learn how to connect Sentinel to a Spring Cloud 2. Start the application in IDE or by building a fatjar. 1. Start in IDE: Find main class `ServiceApplication`, and execute the main method. - 2. Build a fatjar:Execute command `mvn clean package` to build a fatjar,and run command `java -jar sentinel-example.jar` to start the application. + 2. Build a fatjar:Execute command `mvn clean package` to build a fatjar,and run command `java -jar sentinel-core-example.jar` to start the application. ### Invoke Service diff --git a/spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ExceptionUtil.java diff --git a/spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/JsonFlowRuleListParser.java diff --git a/spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ServiceApplication.java diff --git a/spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestController.java diff --git a/spring-cloud-alibaba-examples/sentinel-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-example/src/main/resources/application.properties rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/readme-zh.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/readme-zh.md similarity index 61% rename from spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/readme-zh.md rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/readme-zh.md index b2a27e83c..0a26836bf 100644 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/readme-zh.md +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/readme-zh.md @@ -1,4 +1,4 @@ -# Sentinel Dubbo Consumer Example +# Sentinel Dubbo Example ## 项目说明 @@ -8,9 +8,7 @@ [Dubbo](http://dubbo.apache.org/)是一款高性能Java RPC框架,有对应的[SpringBoot工程](https://github.com/apache/incubator-dubbo-spring-boot-project)。 -本项目需要配合`sentinel-dubbo-provider-example`模块一起完成演示,并且需要先启动sentinel-dubbo-provider-example。 - -本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example)。 +本项目专注于Sentinel与Dubbo的整合,关于Sentinel的更多特性可以查看[sentinel-core-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example)。 ## 示例 @@ -22,7 +20,7 @@ org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel @@ -37,14 +35,61 @@ sentinel-dubbo-adapter内部的Dubbo Filter会根据资源名进行限流降级处理。只需要配置规则即可: FlowRule flowRule = new FlowRule(); - flowRule.setResource( - "org.springframework.cloud.alibaba.cloud.examples.FooService:hello(java.lang.String)"); + 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 = org.springframework.cloud.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 org.springframework.cloud.alibaba.cloud.examples.FooService; + public interface FooService { + String hello(String name); + } + +定义具体的服务: + + @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; + } + } + +### 服务调用 + +Consumer端在服务调用之前,先定义限流规则。 `sentinel-dubbo-api`模块中定义了FooService服务,内容如下: @@ -58,15 +103,13 @@ 定义该资源名对应的限流规则: FlowRule flowRule = new FlowRule(); - flowRule.setResource("dubboResource"); + flowRule.setResource("org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)"); flowRule.setCount(10); flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); flowRule.setLimitApp("default"); FlowRuleManager.loadRules(Collections.singletonList(flowRule)); -### 服务调用 - -根据`sentinel-dubbo-provider-example`中发布的定义,使用Dubbo的@Reference注解注入服务对应的Bean。 +根据Provider端中发布的定义,使用Dubbo的@Reference注解注入服务对应的Bean: @Reference(version = "${foo.service.version}", application = "${dubbo.application.id}", url = "dubbo://localhost:12345", timeout = 30000) @@ -91,9 +134,15 @@ ### 应用启动 + 支持 IDE 直接启动和编译打包后启动。 -1. IDE直接启动:找到主类 `SentinelDubboConsumerApp`,执行 main 方法启动应用。 -2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-dubbo-consumer-example.jar`启动应用。 +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`启动应用。 diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/readme.md b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/readme.md similarity index 58% rename from spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/readme.md rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/readme.md index 42bd4561c..2bfcaec9e 100644 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/readme.md +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/readme.md @@ -1,4 +1,4 @@ -# Sentinel Dubbo Consumer Example +# Sentinel Dubbo Example ## Project Instruction This example illustrates how to use Sentinel starter to implement flow control for Spring Cloud applications. @@ -7,9 +7,7 @@ This example illustrates how to use Sentinel starter to implement flow control f [Dubbo](http://dubbo.apache.org/) is a high-performance, java based open source RPC framework. -This example work with 'sentinel-dubbo-provider-example' module and `sentinel-dubbo-provider-example` module should startup firstly. - -This example focus on the integration of Sentinel and Dubbo. You can see more features on [sentinel-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example). +This example focus on the integration of Sentinel and Dubbo. You can see more features on [sentinel-core-example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example). ## Demo @@ -17,11 +15,11 @@ This example focus on the integration of Sentinel and Dubbo. You can see more fe 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-sentinel and dubbo-spring-boot-starter in the pom.xml file in your Spring Cloud project. +1. Add dependency spring-cloud-starter-alibaba-sentinel and dubbo-spring-boot-starter in the pom.xml file in your Spring Cloud project. org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel @@ -42,7 +40,54 @@ Before we start the demo, let's learn how to connect Sentinel with Dubbo to a Sp flowRule.setLimitApp("default"); FlowRuleManager.loadRules(Collections.singletonList(flowRule)); -### Configure Rules +### 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 = org.springframework.cloud.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 org.springframework.cloud.alibaba.cloud.examples.FooService; + 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: @@ -53,17 +98,15 @@ Before we start the demo, let's learn how to connect Sentinel with Dubbo to a Sp The resource name of this service's `hello` method is `org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)` . -Configure rules: +Configure rules: FlowRule flowRule = new FlowRule(); - flowRule.setResource("dubboResource"); + flowRule.setResource("org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)"); flowRule.setCount(10); flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); flowRule.setLimitApp("default"); FlowRuleManager.loadRules(Collections.singletonList(flowRule)); -### Service Invocation - Using the `@Reference` annotation to inject service: @Reference(version = "${foo.service.version}", application = "${dubbo.application.id}", @@ -91,7 +134,12 @@ Because QPS is 10, we can see that flow control takes effect in this invocation: Start the application in IDE or by building a fatjar. -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. +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. diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-api/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api/pom.xml similarity index 95% rename from spring-cloud-alibaba-examples/sentinel-dubbo-api/pom.xml rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api/pom.xml index 376f2a96a..24cde890d 100644 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-api/pom.xml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api/pom.xml @@ -6,6 +6,7 @@ org.springframework.cloud spring-cloud-alibaba-examples 0.2.0.BUILD-SNAPSHOT + ../../../pom.xml 4.0.0 diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-api/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooService.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooService.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-api/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooService.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooService.java diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml similarity index 93% rename from spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/pom.xml rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml index 2757c1237..890656ea8 100644 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/pom.xml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml @@ -6,6 +6,7 @@ org.springframework.cloud spring-cloud-alibaba-examples 0.2.0.BUILD-SNAPSHOT + ../../../pom.xml 4.0.0 @@ -18,7 +19,7 @@ org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceConsumer.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceConsumer.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceConsumer.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceConsumer.java diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboConsumerApp.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboConsumerApp.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboConsumerApp.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboConsumerApp.java diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/resources/application.properties similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-consumer-example/src/main/resources/application.properties rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/src/main/resources/application.properties diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml similarity index 93% rename from spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/pom.xml rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml index 1ffda73c3..87adbbaf7 100644 --- a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/pom.xml +++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/pom.xml @@ -6,6 +6,7 @@ org.springframework.cloud spring-cloud-alibaba-examples 0.2.0.BUILD-SNAPSHOT + ../../../pom.xml 4.0.0 @@ -18,9 +19,8 @@ org.springframework.cloud - spring-cloud-starter-sentinel + spring-cloud-starter-alibaba-sentinel - org.springframework.cloud sentinel-dubbo-api @@ -31,7 +31,6 @@ dubbo-spring-boot-starter 0.2.0 - diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceImpl.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceImpl.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceImpl.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/FooServiceImpl.java diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboProviderApp.java b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboProviderApp.java similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboProviderApp.java rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SentinelDubboProviderApp.java diff --git a/spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/src/main/resources/application.properties similarity index 100% rename from spring-cloud-alibaba-examples/sentinel-dubbo-provider-example/src/main/resources/application.properties rename to spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example/src/main/resources/application.properties diff --git a/spring-cloud-alibaba-examples/storage-example/pom.xml b/spring-cloud-alibaba-examples/storage-example/pom.xml index aa80b7e07..98065cf4a 100644 --- a/spring-cloud-alibaba-examples/storage-example/pom.xml +++ b/spring-cloud-alibaba-examples/storage-example/pom.xml @@ -22,7 +22,7 @@ org.springframework.cloud - spring-cloud-starter-storage + spring-cloud-starter-alibaba-storage diff --git a/spring-cloud-alibaba-examples/storage-example/readme-zh.md b/spring-cloud-alibaba-examples/storage-example/readme-zh.md index ed6d7e20a..40652e795 100644 --- a/spring-cloud-alibaba-examples/storage-example/readme-zh.md +++ b/spring-cloud-alibaba-examples/storage-example/readme-zh.md @@ -13,11 +13,11 @@ **注意:本节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您只需修改 accessKeyId、secretAccessKey、region 即可。** -1. 修改 pom.xml 文件,引入 OSS starter。 +1. 修改 pom.xml 文件,引入 alibaba-storage starter。 org.springframework.cloud - spring-cloud-starter-oss + spring-cloud-starter-alibaba-storage 2. 在配置文件中配置 OSS 服务对应的 accessKeyId、secretAccessKey 和 region。 diff --git a/spring-cloud-alibaba-examples/storage-example/readme.md b/spring-cloud-alibaba-examples/storage-example/readme.md index 3beae3239..45fa51b97 100644 --- a/spring-cloud-alibaba-examples/storage-example/readme.md +++ b/spring-cloud-alibaba-examples/storage-example/readme.md @@ -13,11 +13,11 @@ If your applications are Spring Cloud applications and you need to use Alibaba C Before we start the demo, let's learn how to connect OSS to a Spring Cloud application. **Note: This section is to show you how to connect to oss. The actual configurations have been completed in the following example, and you only need to specify your accessKeyId, secretAccessKey and region.** -1. Add dependency spring-cloud-starter-oss in the pom.xml file in your Spring Cloud project. +1. Add dependency spring-cloud-starter-alibaba-storage in the pom.xml file in your Spring Cloud project. org.springframework.cloud - spring-cloud-starter-oss + spring-cloud-starter-alibaba-storage 2. Configure accessKeyId, secretAccessKey and region in application.properties. diff --git a/spring-cloud-alibaba-nacos-config/pom.xml b/spring-cloud-alibaba-nacos-config/pom.xml new file mode 100644 index 000000000..12ff873c1 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/pom.xml @@ -0,0 +1,81 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + org.springframework.cloud + spring-cloud-alibaba-nacos-config + Spring Cloud Alibaba Nacos Config + + + + + com.alibaba.nacos + nacos-client + + + + + org.springframework.cloud + spring-cloud-commons + + + org.springframework.cloud + spring-cloud-context + + + + + + org.springframework.boot + spring-boot-actuator + provided + true + + + + org.springframework.boot + spring-boot-actuator-autoconfigure + provided + true + + + org.springframework.boot + spring-boot-configuration-processor + provided + true + + + org.springframework.boot + spring-boot + provided + true + + + + org.springframework.boot + spring-boot-autoconfigure + provided + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.cloud + spring-cloud-test-support + test + + + + + diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java new file mode 100644 index 000000000..f08969121 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfiguration.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.nacos.refresh.NacosContextRefresher; +import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory; +import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshProperties; +import org.springframework.cloud.context.refresh.ContextRefresher; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author juven.xuxb + */ +@Configuration +public class NacosConfigAutoConfiguration implements ApplicationContextAware { + + private ApplicationContext applicationContext; + + @Autowired + private NacosConfigProperties nacosConfigProperties; + + @Autowired + private NacosRefreshProperties nacosRefreshProperties; + + @Autowired + private ConfigService configService; + + @Bean + public NacosConfigProperties nacosConfigProperties() { + return new NacosConfigProperties(); + } + + @Bean + public NacosPropertySourceRepository nacosPropertySourceRepository() { + return new NacosPropertySourceRepository(applicationContext); + } + + @Bean + public NacosRefreshProperties nacosRefreshProperties() { + return new NacosRefreshProperties(); + } + + @Bean + public NacosRefreshHistory nacosRefreshHistory() { + return new NacosRefreshHistory(); + } + + @Bean + public NacosContextRefresher nacosContextRefresher(ContextRefresher contextRefresher, + NacosRefreshHistory refreshHistory, + NacosPropertySourceRepository propertySourceRepository, + ConfigService configService) { + return new NacosContextRefresher(contextRefresher, nacosConfigProperties, + nacosRefreshProperties, refreshHistory, propertySourceRepository,configService); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java new file mode 100644 index 000000000..d5e3bd3b8 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author xiaojing + */ +@Configuration +public class NacosConfigBootstrapConfiguration { + + @Bean + public NacosPropertySourceLocator nacosPropertySourceLocator() { + return new NacosPropertySourceLocator(); + } + + @Bean + public NacosConfigProperties nacosConfigProperties() { + return new NacosConfigProperties(); + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java new file mode 100644 index 000000000..f445ffe7a --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosConfigProperties.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +/** + * nacos properties + * + * @author leijuan + * @author xiaojing + */ +@ConfigurationProperties("spring.cloud.nacos.config") +public class NacosConfigProperties { + + /** + * nacos config server address + */ + private String serverAddr; + + /** + * encode for nacos config content. + */ + private String encode; + + /** + * nacos config group, group is config data meta info. + */ + private String group = "DEFAULT_GROUP"; + + /** + * nacos config dataId prefix + */ + private String prefix; + /** + * the content type of nacos config content. + */ + private String contentType = "properties"; + + /** + * timeout for get config from nacos. + */ + private int timeout = 3000; + + /** + * endpoint for Nacos, the domain name of a service, through which the server address can be dynamically obtained. + */ + private String endpoint; + + /** + * namespace, separation configuration of different environments. + */ + private String namespace; + + /** + * access key for namespace. + */ + private String accessKey; + + /** + * secret key for namespace. + */ + private String secretKey; + + /** + * context path for nacos config server. + */ + private String contextPath; + + /** + * nacos config cluster name + */ + private String clusterName; + + //todo sts support + + public String getServerAddr() { + return serverAddr; + } + + public void setServerAddr(String serverAddr) { + this.serverAddr = serverAddr; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getEncode() { + return encode; + } + + public void setEncode(String encode) { + this.encode = encode; + } + + public String getContextPath() { + return contextPath; + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + @Override + public String toString() { + return "NacosConfigProperties{" + + "serverAddr='" + serverAddr + '\'' + + ", encode='" + encode + '\'' + + ", group='" + group + '\'' + + ", prefix='" + prefix + '\'' + + ", contentType='" + contentType + '\'' + + ", timeout=" + timeout + + ", endpoint='" + endpoint + '\'' + + ", namespace='" + namespace + '\'' + + ", accessKey='" + accessKey + '\'' + + ", secretKey='" + secretKey + '\'' + + ", contextPath='" + contextPath + '\'' + + ", clusterName='" + clusterName + '\'' + + '}'; + } + + public void overrideFromEnv(Environment env){ + + if(StringUtils.isEmpty(this.getServerAddr())) { + this.setServerAddr(env.resolvePlaceholders("${spring.cloud.nacos.config.server-addr:}")); + } + if(StringUtils.isEmpty(this.getEncode())) { + this.setEncode(env.resolvePlaceholders("${spring.cloud.nacos.config.encode:}")); + } + if(StringUtils.isEmpty(this.getNamespace())) { + this.setNamespace(env.resolvePlaceholders("${spring.cloud.nacos.config.namespace:}")); + } + if(StringUtils.isEmpty(this.getAccessKey())) { + this.setAccessKey(env.resolvePlaceholders("${spring.cloud.nacos.config.access-key:}")); + } + if(StringUtils.isEmpty(this.getSecretKey())) { + this.setSecretKey(env.resolvePlaceholders("${spring.cloud.nacos.config.secret-key:}")); + } + if(StringUtils.isEmpty(this.getContextPath())) { + this.setContextPath(env.resolvePlaceholders("${spring.cloud.nacos.config.context-path:}")); + } + if(StringUtils.isEmpty(this.getClusterName())) { + this.setClusterName(env.resolvePlaceholders("${spring.cloud.nacos.config.cluster-name:}")); + } + if(StringUtils.isEmpty(this.getEndpoint())) { + this.setEndpoint(env.resolvePlaceholders("${spring.cloud.nacos.config.endpoint:}")); + } + if(StringUtils.isEmpty(this.getPrefix())) { + this.setPrefix(env.resolvePlaceholders("${spring.cloud.nacos.config.prefix:}")); + } + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosPropertySourceRepository.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosPropertySourceRepository.java new file mode 100644 index 000000000..fab891b57 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/NacosPropertySourceRepository.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.PropertySource; + +/** + * @author xiaojing + */ +public class NacosPropertySourceRepository { + + private final ApplicationContext applicationContext; + + public NacosPropertySourceRepository(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + /** + * @return all nacos properties from application context + */ + public List getAll() { + List result = new ArrayList<>(); + ConfigurableApplicationContext ctx = (ConfigurableApplicationContext) applicationContext; + for (PropertySource p : ctx.getEnvironment().getPropertySources()) { + if (p instanceof NacosPropertySource) { + result.add((NacosPropertySource) p); + } + else if (p instanceof CompositePropertySource) { + collectNacosPropertySources((CompositePropertySource) p, result); + } + } + return result; + } + + private void collectNacosPropertySources(CompositePropertySource composite, + List result) { + for (PropertySource p : composite.getPropertySources()) { + if (p instanceof NacosPropertySource) { + result.add((NacosPropertySource) p); + } + else if (p instanceof CompositePropertySource) { + collectNacosPropertySources((CompositePropertySource) p, result); + } + } + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySource.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySource.java new file mode 100644 index 000000000..7d9d9a0d2 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySource.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.client; + +import java.util.Date; +import java.util.Map; + +import org.springframework.core.env.MapPropertySource; + +/** + * @author xiaojing + */ +public class NacosPropertySource extends MapPropertySource { + + /** + * Nacos dataID + */ + private final String dataId; + + /** + * timestamp the property get + */ + private final Date timestamp; + + + NacosPropertySource(String dataId, Map source, Date timestamp) { + super(dataId, source); + this.dataId = dataId; + this.timestamp = timestamp; + } + + public String getDataId() { + return dataId; + } + + public Date getTimestamp() { + return timestamp; + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java new file mode 100644 index 000000000..7a721dd21 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceBuilder.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.client; + +import java.io.StringReader; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.exception.NacosException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +/** + * @author xiaojing + */ +public class NacosPropertySourceBuilder { + + private static final Logger logger = LoggerFactory + .getLogger(NacosPropertySourceBuilder.class); + + private ConfigService configService; + private long timeout; + + public NacosPropertySourceBuilder() { + } + + public NacosPropertySourceBuilder(ConfigService configService, long timeout) { + this.configService = configService; + this.timeout = timeout; + } + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public ConfigService getConfigService() { + return configService; + } + + public void setConfigService(ConfigService configService) { + this.configService = configService; + } + + /** + * @param dataId Nacos dataId + * @param group Nacos group + */ + NacosPropertySource build(String dataId, String group, String contentType) { + Properties p = loadNacosData(dataId, group, contentType); + if (p == null) { + return null; + } + return new NacosPropertySource(dataId, propertiesToMap(p), new Date()); + } + + private Properties loadNacosData(String dataId, String group, String contentType) { + String data = null; + try { + data = configService.getConfig(dataId, group, timeout); + // todo add content type yaml support + if (!StringUtils.isEmpty(data)) { + Properties properties = new Properties(); + logger.info(String.format("Loading nacos data, dataId: '%s', group: '%s'", + dataId, group)); + properties.load(new StringReader(data)); + return properties; + } + } + catch (NacosException e) { + logger.error("get data from Nacos error,dataId:{}, ", dataId, e); + } + catch (Exception e) { + logger.error("parse data from Nacos error,dataId:{},data:{},", dataId, data, + e); + } + return null; + } + + @SuppressWarnings("unchecked") + private Map propertiesToMap(Properties properties) { + Map result = new HashMap<>(16); + Enumeration keys = (Enumeration) properties.propertyNames(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + Object value = properties.getProperty(key); + if (value != null) { + result.put(key, ((String) value).trim()); + } + else { + result.put(key, null); + } + } + return result; + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java new file mode 100644 index 000000000..9f356a291 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/client/NacosPropertySourceLocator.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.client; + + +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.bootstrap.config.PropertySourceLocator; +import org.springframework.core.annotation.Order; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; +import org.springframework.util.StringUtils; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.exception.NacosException; + +import static com.alibaba.nacos.api.PropertyKeyConst.*; + +/** + * @author xiaojing + */ +@Order(0) +public class NacosPropertySourceLocator implements PropertySourceLocator { + + private static final Logger logger = LoggerFactory + .getLogger(NacosPropertySourceLocator.class); + private static final String NACOS_PROPERTY_SOURCE_NAME = "NACOS"; + private static final String SEP1 = "-"; + private static final String DOT = "."; + + @Autowired + private ConfigurableListableBeanFactory beanFactory; + + @Autowired + private NacosConfigProperties nacosConfigProperties; + + private ConfigService configService; + + private NacosPropertySourceBuilder nacosPropertySourceBuilder; + + private Properties getPropertiesFromEnv(Environment env) { + + nacosConfigProperties.overrideFromEnv(env); + + Properties properties = new Properties(); + properties.put(SERVER_ADDR, nacosConfigProperties.getServerAddr()); + properties.put(ENCODE, nacosConfigProperties.getEncode()); + properties.put(NAMESPACE, nacosConfigProperties.getNamespace()); + properties.put(ACCESS_KEY, nacosConfigProperties.getAccessKey()); + properties.put(SECRET_KEY, nacosConfigProperties.getSecretKey()); + properties.put(CONTEXT_PATH, nacosConfigProperties.getContextPath()); + properties.put(CLUSTER_NAME, nacosConfigProperties.getClusterName()); + properties.put(ENDPOINT, nacosConfigProperties.getEndpoint()); + return properties; + } + + @Override + public PropertySource locate(Environment env) { + + Properties properties = getPropertiesFromEnv(env); + + try { + configService = NacosFactory.createConfigService(properties); + } + catch (NacosException e) { + // todo 为什么这里是 checkException,什么时候会抛出,什么时候需要关心 + logger.error("create config service error, nacosConfigProperties:{}, ", properties, e); + return null; + } + + beanFactory.registerSingleton("configService", configService); + + if (null == configService) { + logger.warn( + "no instance of config service found, can't load config from nacos"); + return null; + } + long timeout = nacosConfigProperties.getTimeout(); + nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService, timeout); + + String applicationName = env.getProperty("spring.application.name"); + logger.info("Initialize spring.application.name '" + applicationName + "'."); + + String nacosGroup = nacosConfigProperties.getGroup(); + String dataIdPrefix = nacosConfigProperties.getPrefix(); + if (StringUtils.isEmpty(dataIdPrefix)) { + dataIdPrefix = applicationName; + } + + String contentType = nacosConfigProperties.getContentType(); + + CompositePropertySource composite = new CompositePropertySource( + NACOS_PROPERTY_SOURCE_NAME); + + loadApplicationConfiguration(composite, env, nacosGroup, dataIdPrefix, contentType); + + return composite; + } + + private void loadApplicationConfiguration( + CompositePropertySource compositePropertySource, Environment environment, + String nacosGroup, String dataIdPrefix, String contentType) { + loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + DOT + contentType, + nacosGroup, contentType); + for (String profile : environment.getActiveProfiles()) { + String dataId = dataIdPrefix + SEP1 + profile + DOT + contentType; + loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, + contentType); + } + // todo multi profile active order and priority + } + + private void loadNacosDataIfPresent(final CompositePropertySource composite, + final String dataId, final String group,String contentType) { + NacosPropertySource ps = nacosPropertySourceBuilder.build(dataId, group, contentType); + if (ps != null) { + composite.addFirstPropertySource(ps); + } + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/diagnostics/analyzer/NacosConnectionFailureAnalyzer.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/diagnostics/analyzer/NacosConnectionFailureAnalyzer.java new file mode 100644 index 000000000..1bbbe940c --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/diagnostics/analyzer/NacosConnectionFailureAnalyzer.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.diagnostics.analyzer; + +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; + +/** + * A {@code FailureAnalyzer} that performs analysis of failures caused by a + * {@code NacosConnectionFailureException}. + * + * @author juven.xuxb + */ +public class NacosConnectionFailureAnalyzer + extends AbstractFailureAnalyzer { + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, + NacosConnectionFailureException cause) { + return new FailureAnalysis("Application failed to connect to Nacos server", + "check your nacos server config", cause); + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/diagnostics/analyzer/NacosConnectionFailureException.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/diagnostics/analyzer/NacosConnectionFailureException.java new file mode 100644 index 000000000..2ca75d05a --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/diagnostics/analyzer/NacosConnectionFailureException.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.diagnostics.analyzer; + +/** + * A {@code NacosConnectionFailureException} is thrown when the application fails to connect + * to Nacos Server. + * + * @author juven.xuxb + */ +public class NacosConnectionFailureException extends RuntimeException { + + private final String domain; + + private final String port; + + public NacosConnectionFailureException(String domain, String port, String message) { + super(message); + this.domain = domain; + this.port = port; + } + + public NacosConnectionFailureException(String domain, String port, String message, + Throwable cause) { + super(message, cause); + this.domain = domain; + this.port = port; + } + + String getDomain() { + return domain; + } + + String getPort() { + return port; + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java new file mode 100644 index 000000000..02db85afd --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpoint.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.endpoint; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; +import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory; + +/** + * Endpoint for Nacos, contains config data and refresh history + * @author xiaojing + */ +@Endpoint(id = "nacos-config") +public class NacosConfigEndpoint { + + private final NacosConfigProperties properties; + + private final NacosRefreshHistory refreshHistory; + + private final NacosPropertySourceRepository propertySourceRepository; + + private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public NacosConfigEndpoint(NacosConfigProperties properties, NacosRefreshHistory refreshHistory, + NacosPropertySourceRepository propertySourceRepository) { + this.properties = properties; + this.refreshHistory = refreshHistory; + this.propertySourceRepository = propertySourceRepository; + } + + @ReadOperation + public Map invoke() { + Map result = new HashMap<>(16); + result.put("NacosConfigProperties", properties); + + List all = propertySourceRepository.getAll(); + + List> sources = new ArrayList<>(); + for (NacosPropertySource ps : all) { + Map source = new HashMap<>(16); + source.put("dataId", ps.getDataId()); + source.put("lastSynced", dateFormat.format(ps.getTimestamp())); + sources.add(source); + } + result.put("Sources", sources); + result.put("RefreshHistory", refreshHistory.getRecords()); + + return result; + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpointAutoConfiguration.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpointAutoConfiguration.java new file mode 100644 index 000000000..d6d8464bb --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigEndpointAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.endpoint; + +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; +import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory; +import org.springframework.context.annotation.Bean; + +/** + * @author xiaojing + */ +@ConditionalOnWebApplication +@ConditionalOnClass(value = Endpoint.class) +public class NacosConfigEndpointAutoConfiguration { + + @Autowired + private NacosConfigProperties nacosConfigProperties; + + @Autowired + private NacosRefreshHistory nacosRefreshHistory; + + @Autowired + private NacosPropertySourceRepository nacosPropertySourceRepository; + + @Autowired + private ConfigService configService; + + @Bean + @ConditionalOnBean + public NacosConfigProperties nacosConfigProperties() { + return new NacosConfigProperties(); + } + + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + @Bean + public NacosConfigEndpoint nacosConfigEndpoint() { + return new NacosConfigEndpoint(nacosConfigProperties, nacosRefreshHistory, + nacosPropertySourceRepository); + } + + @Bean + public NacosConfigHealthIndicator nacosConfigHealthIndicator( + NacosPropertySourceRepository nacosPropertySourceRepository) { + return new NacosConfigHealthIndicator(nacosConfigProperties, + nacosPropertySourceRepository, configService); + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigHealthIndicator.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigHealthIndicator.java new file mode 100644 index 000000000..417961577 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosConfigHealthIndicator.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.endpoint; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.nacos.api.config.ConfigService; + +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; +import org.springframework.util.StringUtils; + +/** + * @author xiaojing + */ +public class NacosConfigHealthIndicator extends AbstractHealthIndicator { + + private final NacosConfigProperties nacosConfigProperties; + + private final NacosPropertySourceRepository nacosPropertySourceRepository; + + private final List dataIds; + + private final ConfigService configService; + + public NacosConfigHealthIndicator(NacosConfigProperties nacosConfigProperties, + NacosPropertySourceRepository nacosPropertySourceRepository, + ConfigService configService) { + this.nacosConfigProperties = nacosConfigProperties; + this.nacosPropertySourceRepository = nacosPropertySourceRepository; + this.configService = configService; + + this.dataIds = new ArrayList<>(); + for (NacosPropertySource nacosPropertySource : this.nacosPropertySourceRepository + .getAll()) { + this.dataIds.add(nacosPropertySource.getDataId()); + } + } + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + for (String dataId : dataIds) { + try { + String config = configService.getConfig(dataId, + nacosConfigProperties.getGroup(), + nacosConfigProperties.getTimeout()); + if (StringUtils.isEmpty(config)) { + builder.down().withDetail(String.format("dataId: '%s', group: '%s'", + dataId, nacosConfigProperties.getGroup()), "config is empty"); + } + } + catch (Exception e) { + builder.down().withDetail(String.format("dataId: '%s', group: '%s'", + dataId, nacosConfigProperties.getGroup()), e.getMessage()); + } + } + builder.up().withDetail("dataIds", dataIds); + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java new file mode 100644 index 000000000..88d237a0b --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosContextRefresher.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.refresh; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.cloud.alibaba.nacos.NacosConfigProperties; +import org.springframework.cloud.alibaba.nacos.NacosPropertySourceRepository; +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySource; +import org.springframework.cloud.context.refresh.ContextRefresher; +import org.springframework.context.ApplicationListener; +import org.springframework.util.StringUtils; + +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.listener.Listener; +import com.alibaba.nacos.api.exception.NacosException; + +/** + * On application start up, NacosContextRefresher add nacos listeners to all application + * level dataIds, when there is a change in the data, listeners will refresh + * configurations. + * + * @author juven.xuxb + */ +public class NacosContextRefresher implements ApplicationListener { + + private Logger logger = LoggerFactory.getLogger(NacosContextRefresher.class); + + private final ContextRefresher contextRefresher; + + private final NacosConfigProperties properties; + + private final NacosRefreshProperties refreshProperties; + + private final NacosRefreshHistory refreshHistory; + + private final NacosPropertySourceRepository nacosPropertySourceRepository; + + private final ConfigService configService; + + private Map listenerMap = new ConcurrentHashMap<>(16); + + public NacosContextRefresher(ContextRefresher contextRefresher, + NacosConfigProperties properties, NacosRefreshProperties refreshProperties, + NacosRefreshHistory refreshHistory, + NacosPropertySourceRepository nacosPropertySourceRepository, + ConfigService configService) { + this.contextRefresher = contextRefresher; + this.properties = properties; + this.refreshProperties = refreshProperties; + this.refreshHistory = refreshHistory; + this.nacosPropertySourceRepository = nacosPropertySourceRepository; + this.configService = configService; + } + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + this.registerNacosListenersForApplications(); + } + + private void registerNacosListenersForApplications() { + if (refreshProperties.isEnabled()) { + for (NacosPropertySource nacosPropertySource : nacosPropertySourceRepository + .getAll()) { + String dataId = nacosPropertySource.getDataId(); + registerNacosListener(dataId); + } + } + } + + private void registerNacosListener(final String dataId) { + + Listener listener = listenerMap.computeIfAbsent(dataId, i -> new Listener() { + @Override + public void receiveConfigInfo(String configInfo) { + String md5 = ""; + if (!StringUtils.isEmpty(configInfo)) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md5 = new BigInteger(1, md.digest(configInfo.getBytes("UTF-8"))) + .toString(16); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + logger.warn("unable to get md5 for dataId: " + dataId, e); + } + } + refreshHistory.add(dataId, md5); + contextRefresher.refresh(); + } + + @Override + public Executor getExecutor() { + return null; + } + }); + + try { + configService.addListener(dataId, properties.getGroup(), listener); + } catch (NacosException e) { + e.printStackTrace(); + } + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java new file mode 100644 index 000000000..ec5a83ca6 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshHistory.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.refresh; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; + +public class NacosRefreshHistory { + + private static final int MAX_SIZE = 20; + + private LinkedList records = new LinkedList<>(); + + private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public void add(String dataId, String md5) { + records.addFirst(new Record(dateFormat.format(new Date()), dataId, md5)); + if (records.size() > MAX_SIZE) { + records.removeLast(); + } + } + + public LinkedList getRecords() { + return records; + } +} + +class Record { + + private final String timestamp; + + private final String dataId; + + private final String md5; + + public Record(String timestamp, String dataId, String md5) { + this.timestamp = timestamp; + this.dataId = dataId; + this.md5 = md5; + } + + public String getTimestamp() { + return timestamp; + } + + public String getDataId() { + return dataId; + } + + public String getMd5() { + return md5; + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshProperties.java b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshProperties.java new file mode 100644 index 000000000..acf34ed17 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/java/org/springframework/cloud/alibaba/nacos/refresh/NacosRefreshProperties.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.refresh; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * @author xiaojing + */ +@Component +public class NacosRefreshProperties { + + @Value("${spring.cloud.nacos.config.refresh.enabled:true}") + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} diff --git a/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..189ae565e --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,20 @@ +{"properties": [ + { + "name": "spring.cloud.nacos.config.encode", + "type": "java.lang.String", + "defaultValue": "UTF-8", + "description": "default encode for nacos config content." + }, + { + "name": "spring.cloud.nacos.config.prefix", + "type": "java.lang.String", + "defaultValue": "${spring.application.name}", + "description": "the prefix of dataId, nacos config data meta info. dataId = prefix + '-' + ${spring.active.profile} + `-` + ${spring.cloud.nacos.config.content-type}." + }, + { + "name": "spring.cloud.nacos.config.content-type", + "type": "java.lang.String", + "defaultValue": "properties", + "description": "the content type of nacos config content, only support properties now." + } +]} \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..3d6be0498 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/main/resources/META-INF/spring.factories @@ -0,0 +1,7 @@ +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.alibaba.nacos.NacosConfigBootstrapConfiguration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.cloud.alibaba.nacos.NacosConfigAutoConfiguration,\ +org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration +org.springframework.boot.diagnostics.FailureAnalyzer=\ +org.springframework.cloud.alibaba.nacos..analyzer.NacosConnectionFailureAnalyzerdiagnostics \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-config/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfigurationTests.java b/spring-cloud-alibaba-nacos-config/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfigurationTests.java new file mode 100644 index 000000000..b5191e2d4 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigAutoConfigurationTests.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator; +import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshProperties; +import org.springframework.cloud.context.refresh.ContextRefresher; +import org.springframework.cloud.context.scope.refresh.RefreshScope; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author xiaojing + */ +public class NacosConfigAutoConfigurationTests { + + private ConfigurableApplicationContext context; + + @Before + public void setUp() throws Exception { + this.context = new SpringApplicationBuilder( + NacosConfigBootstrapConfiguration.class, + NacosConfigAutoConfiguration.class, + TestConfiguration.class) + .web(WebApplicationType.NONE).run( + "--spring.cloud.config.enabled=true", + "--spring.cloud.nacos.config.server-addr=127.0.0.1:8080", + "--spring.cloud.nacos.config.prefix=myapp"); + } + + @After + public void tearDown() throws Exception { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testNacosConfigProperties() { + + NacosPropertySourceLocator nacosPropertySourceLocator = this.context.getBean(NacosPropertySourceLocator.class); + Environment environment = this.context.getEnvironment(); + try{ + nacosPropertySourceLocator.locate(environment); + }catch (Exception e){ + + } + + NacosConfigProperties nacosConfigProperties = this.context.getBean(NacosConfigProperties.class); + assertThat(nacosConfigProperties.getContentType()).isEqualTo("properties"); + assertThat(nacosConfigProperties.getPrefix()).isEqualTo("myapp"); + + } + + + @Test + public void testNacosRefreshProperties() { + + NacosRefreshProperties nacosRefreshProperties = this.context.getBean(NacosRefreshProperties.class); + assertThat(nacosRefreshProperties.isEnabled()).isEqualTo(true); + + } + + @Configuration + @AutoConfigureBefore(NacosConfigAutoConfiguration.class) + static class TestConfiguration{ + + + @Autowired + ConfigurableApplicationContext context; + + @Bean + ContextRefresher contextRefresher(){ + return new ContextRefresher(context, new RefreshScope()); + } + + } + +} diff --git a/spring-cloud-alibaba-nacos-config/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfigurationTests.java b/spring-cloud-alibaba-nacos-config/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfigurationTests.java new file mode 100644 index 000000000..ae43f03f7 --- /dev/null +++ b/spring-cloud-alibaba-nacos-config/src/test/java/org/springframework/cloud/alibaba/nacos/NacosConfigBootstrapConfigurationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import java.lang.reflect.Field; + +import com.alibaba.nacos.api.config.ConfigService; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.util.ReflectionUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author xiaojing + */ +public class NacosConfigBootstrapConfigurationTests { + + private ConfigurableApplicationContext context; + + @Before + public void setUp() throws Exception { + this.context = new SpringApplicationBuilder( + NacosConfigBootstrapConfiguration.class).web(WebApplicationType.NONE).run( + "--spring.cloud.config.enabled=true", + "--spring.cloud.nacos.config.server-addr=127.0.0.1:8080", + "--spring.cloud.nacos.config.prefix=myapp"); + } + + @After + public void tearDown() throws Exception { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testNacosPropertySourceLocator() { + + NacosPropertySourceLocator locator = this.context + .getBean(NacosPropertySourceLocator.class); + Environment environment = this.context.getEnvironment(); + try { + locator.locate(environment); + } + catch (Exception e) { + + } + + Field configServiceField = ReflectionUtils + .findField(NacosPropertySourceLocator.class, "configService"); + configServiceField.setAccessible(true); + + ConfigService configService = (ConfigService) ReflectionUtils + .getField(configServiceField, locator); + + assertThat(configService).isNotNull(); + } + + +} diff --git a/spring-cloud-alibaba-nacos-discovery/pom.xml b/spring-cloud-alibaba-nacos-discovery/pom.xml new file mode 100644 index 000000000..3b5717302 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/pom.xml @@ -0,0 +1,91 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + org.springframework.cloud + spring-cloud-alibaba-nacos-discovery + Spring Cloud Alibaba Nacos Discovery + + + + + com.alibaba.nacos + nacos-client + + + + org.springframework + spring-context + + + org.springframework.cloud + spring-cloud-commons + + + + org.springframework.cloud + spring-cloud-starter-netflix-ribbon + + + + org.springframework.boot + spring-boot-actuator + true + + + org.springframework.boot + spring-boot-actuator-autoconfigure + provided + true + + + org.springframework.boot + spring-boot-configuration-processor + provided + true + + + org.springframework.boot + spring-boot + provided + true + + + com.fasterxml.jackson.core + jackson-annotations + provided + true + + + org.springframework.boot + spring-boot-autoconfigure + provided + true + + + + org.springframework.boot + spring-boot-starter-web + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.cloud + spring-cloud-test-support + test + + + + + diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ConditionalOnNacosDiscoveryEnabled.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ConditionalOnNacosDiscoveryEnabled.java new file mode 100644 index 000000000..71b9656c3 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ConditionalOnNacosDiscoveryEnabled.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.enabled", matchIfMissing = true) +public @interface ConditionalOnNacosDiscoveryEnabled { + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java new file mode 100644 index 000000000..b61801448 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfiguration.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration; +import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; +import org.springframework.cloud.alibaba.nacos.registry.NacosServiceRegistry; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author xiaojing + */ + +@Configuration +@EnableConfigurationProperties +@ConditionalOnNacosDiscoveryEnabled +@ConditionalOnClass(name = "org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent") +@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) +@AutoConfigureBefore({ AutoServiceRegistrationAutoConfiguration.class, + NacosDiscoveryClientAutoConfiguration.class }) +public class NacosDiscoveryAutoConfiguration { + + @Bean + public NacosServiceRegistry nacosServiceRegistry() { + return new NacosServiceRegistry(); + } + + @Bean + @ConditionalOnMissingBean + public NacosDiscoveryProperties nacosProperties() { + return new NacosDiscoveryProperties(); + } + + @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + public NacosRegistration nacosRegistration() { + return new NacosRegistration(); + } + + @Bean + @ConditionalOnBean(AutoServiceRegistrationProperties.class) + public NacosAutoServiceRegistration nacosAutoServiceRegistration( + NacosServiceRegistry registry, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + NacosRegistration registration) { + return new NacosAutoServiceRegistration(registry, + autoServiceRegistrationProperties, registration); + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClient.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClient.java new file mode 100644 index 000000000..48f40a17e --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClient.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; + +import java.util.*; + +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.naming.pojo.ListView; + +/** + * @author xiaojing + */ +public class NacosDiscoveryClient implements DiscoveryClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(NacosDiscoveryClient.class); + public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client"; + + @Autowired + private NacosRegistration nacosRegistration; + + @Override + public String description() { + return DESCRIPTION; + } + + @Override + public List getInstances(String serviceId) { + try { + NamingService namingService = nacosRegistration.getNacosNamingService(); + List instances = namingService.selectInstances(serviceId,true); + return hostToServiceInstanceList(instances, serviceId); + } + catch (Exception e) { + throw new RuntimeException( + "Can not get hosts from nacos server. serviceId: " + serviceId, e); + } + } + + private static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) { + NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); + nacosServiceInstance.setHost(instance.getIp()); + nacosServiceInstance.setPort(instance.getPort()); + nacosServiceInstance.setServiceId(serviceId); + Map metadata = new HashMap(); + metadata.put("instanceId", instance.getInstanceId()); + metadata.put("weight", instance.getWeight()+""); + metadata.put("healthy", instance.isHealthy()+""); + metadata.put("cluster", instance.getCluster()+""); + metadata.putAll(instance.getMetadata()); + nacosServiceInstance.setMetadata(metadata); + return nacosServiceInstance; + } + + private static List hostToServiceInstanceList(List instances, + String serviceId) { + List result = new ArrayList(instances.size()); + for (Instance instance: instances) { + result.add(hostToServiceInstance(instance, serviceId)); + } + return result; + } + + @Override + public List getServices() { + + try { + NamingService namingService = nacosRegistration.getNacosNamingService(); + ListView services = namingService.getServicesOfServer(1, Integer.MAX_VALUE); + return services.getData(); + }catch( Exception e){ + LOGGER.error("get service name from nacos server fail,", e); + return Collections.emptyList(); + } + } + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java new file mode 100644 index 000000000..2563cbe6d --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryClientAutoConfiguration.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author xiaojing + */ +@Configuration +@ConditionalOnMissingBean(DiscoveryClient.class) +@ConditionalOnNacosDiscoveryEnabled +@EnableConfigurationProperties +public class NacosDiscoveryClientAutoConfiguration { + + @Bean + public DiscoveryClient nacosDiscoveryClient() { + return new NacosDiscoveryClient(); + } + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java new file mode 100644 index 000000000..f042e4bcc --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryProperties.java @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * @author dungu.zpf + * @author xiaojing + */ + +@ConfigurationProperties("spring.cloud.nacos.discovery") +public class NacosDiscoveryProperties { + + /** + * nacos discovery server address + */ + private String serverAddr; + + /** + * the domain name of a service, through which the server address can be dynamically obtained. + */ + private String endpoint; + + /** + * namespace, separation registry of different environments. + */ + private String namespace; + + /** + * nacos naming log file name + */ + private String logName; + + /** + * service name to registry + */ + @Value("${spring.cloud.nacos.discovery.service:${spring.application.name:}}") + private String service; + + /** + * weight for service instance, the larger the value, the larger the weight. + */ + private float weight = 1; + + /** + * cluster name for nacos server. + */ + private String clusterName = "DEFAULT"; + + /** + * extra metadata to register. + */ + private Map metadata = new HashMap<>(); + + /** + * if you just want to subscribe, but don't want to register your service, set it to + * false. + */ + private boolean registerEnabled = true; + + /** + * The ip address your want to register for your service instance, needn't to set it if + * the auto detect ip works well + */ + private String ip; + + /** + * which network interface's ip you want to register + */ + private String networkInterface = ""; + + /** + * The port your want to register for your service instance, needn't to set it if the + * auto detect port works well + */ + private int port = -1; + + /** + * whether your service is a https service + */ + private boolean secure = false; + + /** + * access key for namespace. + */ + private String accessKey; + + /** + * secret key for namespace. + */ + private String secretKey; + + @Autowired + @JsonIgnore + private InetUtils inetUtils; + + @PostConstruct + public void init() throws SocketException { + + serverAddr = Objects.toString(serverAddr, ""); + endpoint = Objects.toString(endpoint, ""); + namespace = Objects.toString(namespace, ""); + logName = Objects.toString(logName, ""); + + if (StringUtils.isEmpty(ip)) { + // traversing network interfaces if didn't specify a interface + if (StringUtils.isEmpty(networkInterface)) { + ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + } + else { + NetworkInterface netInterface = NetworkInterface + .getByName(networkInterface); + if (null == networkInterface) { + throw new IllegalArgumentException( + "no such interface " + networkInterface); + } + + Enumeration inetAddress = netInterface.getInetAddresses(); + while (inetAddress.hasMoreElements()) { + InetAddress currentAddress = inetAddress.nextElement(); + if (currentAddress instanceof Inet4Address + && !currentAddress.isLoopbackAddress()) { + ip = currentAddress.getHostAddress(); + break; + } + } + + if (StringUtils.isEmpty(ip)) { + throw new RuntimeException("cannot find available ip from" + + " network interface " + networkInterface); + } + + } + } + } + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getNamespace() { + return namespace; + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + public String getLogName() { + return logName; + } + + public void setLogName(String logName) { + this.logName = logName; + } + + public InetUtils getInetUtils() { + return inetUtils; + } + + public void setInetUtils(InetUtils inetUtils) { + this.inetUtils = inetUtils; + } + + public float getWeight() { + return weight; + } + + public void setWeight(float weight) { + this.weight = weight; + } + + public String getClusterName() { + return clusterName; + } + + public void setClusterName(String clusterName) { + this.clusterName = clusterName; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public boolean isRegisterEnabled() { + return registerEnabled; + } + + public void setRegisterEnabled(boolean registerEnabled) { + this.registerEnabled = registerEnabled; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getNetworkInterface() { + return networkInterface; + } + + public void setNetworkInterface(String networkInterface) { + this.networkInterface = networkInterface; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getServerAddr() { + return serverAddr; + } + + public void setServerAddr(String serverAddr) { + this.serverAddr = serverAddr; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + @Override + public String toString() { + return "NacosDiscoveryProperties{" + + "serverAddr='" + serverAddr + '\'' + + ", endpoint='" + endpoint + '\'' + + ", namespace='" + namespace + '\'' + + ", logName='" + logName + '\'' + + ", service='" + service + '\'' + + ", weight=" + weight + + ", clusterName='" + clusterName + '\'' + + ", metadata=" + metadata + + ", registerEnabled=" + registerEnabled + + ", ip='" + ip + '\'' + + ", networkInterface='" + networkInterface + '\'' + + ", port=" + port + + ", secure=" + secure + + ", accessKey='" + accessKey + '\'' + + ", secretKey='" + secretKey + '\'' + + '}'; + } + + public void overrideFromEnv(Environment env){ + + if(StringUtils.isEmpty(this.getServerAddr())) { + this.setServerAddr(env.resolvePlaceholders("${spring.cloud.nacos.discovery.server-addr:}")); + } + if(StringUtils.isEmpty(this.getNamespace())) { + this.setNamespace(env.resolvePlaceholders("${spring.cloud.nacos.discovery.namespace:}")); + } + if(StringUtils.isEmpty(this.getAccessKey())) { + this.setAccessKey(env.resolvePlaceholders("${spring.cloud.nacos.discovery.access-key:}")); + } + if(StringUtils.isEmpty(this.getSecretKey())) { + this.setSecretKey(env.resolvePlaceholders("${spring.cloud.nacos.discovery.secret-key:}")); + } + if(StringUtils.isEmpty(this.getLogName())) { + this.setLogName(env.resolvePlaceholders("${spring.cloud.nacos.discovery.log-name:}")); + } + if(StringUtils.isEmpty(this.getClusterName())) { + this.setClusterName(env.resolvePlaceholders("${spring.cloud.nacos.discovery.clusterName-name:}")); + } + if(StringUtils.isEmpty(this.getEndpoint())) { + this.setEndpoint(env.resolvePlaceholders("${spring.cloud.nacos.discovery.endpoint:}")); + } + } + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosServiceInstance.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosServiceInstance.java new file mode 100644 index 000000000..4059ba2e4 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/NacosServiceInstance.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; + +import java.net.URI; +import java.util.Map; + +/** + * @author xiaojing + */ +public class NacosServiceInstance implements ServiceInstance { + private String serviceId; + private String host; + private int port; + private boolean secure; + private Map metadata; + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getHost() { + return host; + } + + @Override + public int getPort() { + return port; + } + + @Override + public boolean isSecure() { + return secure; + } + + @Override + public URI getUri() { + return DefaultServiceInstance.getUri(this); + } + + @Override + public Map getMetadata() { + return metadata; + } + + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + public void setHost(String host) { + this.host = host; + } + + public void setPort(int port) { + this.port = port; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpoint.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpoint.java new file mode 100644 index 000000000..d2cf66e03 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpoint.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.endpoint; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.ServiceInfo; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; +import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; + +/** + * Endpoint for nacos discovery, get nacos properties and subscribed services + * @author xiaojing + */ +@Endpoint(id = "nacos-discovery") +public class NacosDiscoveryEndpoint { + + private static final Logger LOGGER = LoggerFactory.getLogger(NacosDiscoveryEndpoint.class); + + @Autowired + private NacosDiscoveryProperties nacosDiscoveryProperties; + + @Autowired + private NacosRegistration nacosRegistration; + + /** + * @return nacos discovery endpoint + */ + @ReadOperation + public Map nacosDiscovery() { + Map result = new HashMap<>(); + result.put("NacosDiscoveryProperties", nacosDiscoveryProperties); + + NamingService namingService = nacosRegistration.getNacosNamingService(); + List subscribe = Collections.emptyList() ; + + try{ + subscribe = namingService.getSubscribeServices(); + } catch (Exception e){ + LOGGER.error("get subscribe services from nacos fail,", e); + } + result.put("subscribe",subscribe); + return result; + } +} \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java new file mode 100644 index 000000000..c5b7993fd --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/endpoint/NacosDiscoveryEndpointAutoConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.endpoint; + +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.endpoint.annotation.Endpoint; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; + +/** + * @author xiaojing + */ +@ConditionalOnWebApplication +@ConditionalOnClass(Endpoint.class) +public class NacosDiscoveryEndpointAutoConfiguration { + + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + @Bean + public NacosDiscoveryEndpoint nacosDiscoveryEndpoint() { + return new NacosDiscoveryEndpoint(); + } + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java new file mode 100644 index 000000000..c56388542 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosAutoServiceRegistration.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.registry; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * @author xiaojing + */ +public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration { + private static final Logger LOGGER = LoggerFactory.getLogger(NacosAutoServiceRegistration.class); + + @Autowired + private NacosRegistration registration; + + + public NacosAutoServiceRegistration(ServiceRegistry serviceRegistry, + AutoServiceRegistrationProperties autoServiceRegistrationProperties, + NacosRegistration registration) { + super(serviceRegistry, autoServiceRegistrationProperties); + this.registration = registration; + } + + @Deprecated + public void setPort(int port) { + getPort().set(port); + } + + @Override + protected NacosRegistration getRegistration() { + if (this.registration.getPort() < 0 && this.getPort().get() > 0) { + this.registration.setPort(this.getPort().get()); + } + Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set"); + return this.registration; + } + + @Override + protected NacosRegistration getManagementRegistration() { + return null; + } + + @Override + protected void register() { + if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) { + LOGGER.debug("Registration disabled."); + return; + } + if (this.registration.getPort() < 0) { + this.registration.setPort(getPort().get()); + } + super.register(); + } + + @Override + protected void registerManagement() { + if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) { + return; + } + super.registerManagement(); + + } + + + @Override + protected Object getConfiguration() { + return this.registration.getNacosDiscoveryProperties(); + } + + @Override + protected boolean isEnabled() { + return this.registration.getNacosDiscoveryProperties().isRegisterEnabled(); + } + + @Override + @SuppressWarnings("deprecation") + protected String getAppName() { + String appName = registration.getNacosDiscoveryProperties().getService(); + return StringUtils.isEmpty(appName) ? super.getAppName() : appName; + } + +} + diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosRegistration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosRegistration.java new file mode 100644 index 000000000..fe895cb23 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosRegistration.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.registry; + +import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.Registration; +import org.springframework.core.env.Environment; + +import java.net.URI; +import java.util.Map; +import java.util.Properties; + +import javax.annotation.PostConstruct; + +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.client.naming.utils.UtilAndComs; + +import static com.alibaba.nacos.api.PropertyKeyConst.*; +/** + * @author xiaojing + */ +public class NacosRegistration implements Registration, ServiceInstance { + + @Autowired + private NacosDiscoveryProperties nacosDiscoveryProperties; + + private NamingService nacosNamingService; + + @Autowired + private Environment environment; + + @PostConstruct + public void init() { + nacosDiscoveryProperties.overrideFromEnv(environment); + + Properties properties = new Properties(); + properties.put(SERVER_ADDR, nacosDiscoveryProperties.getServerAddr()); + properties.put(NAMESPACE, nacosDiscoveryProperties.getNamespace()); + properties.put(UtilAndComs.NACOS_NAMING_LOG_NAME, nacosDiscoveryProperties.getLogName()); + properties.put(ENDPOINT, nacosDiscoveryProperties.getEndpoint()); + properties.put(ACCESS_KEY,nacosDiscoveryProperties.getAccessKey()); + properties.put(SECRET_KEY,nacosDiscoveryProperties.getSecretKey()); + properties.put(CLUSTER_NAME,nacosDiscoveryProperties.getClusterName()); + try { + nacosNamingService = NacosFactory.createNamingService(properties); + } + catch (Exception e) { + + } + } + + @Override + public String getServiceId() { + return nacosDiscoveryProperties.getService(); + } + + @Override + public String getHost() { + return nacosDiscoveryProperties.getIp(); + } + + @Override + public int getPort() { + return nacosDiscoveryProperties.getPort(); + } + + public void setPort(int port) { + if (nacosDiscoveryProperties.getPort() < 0) { + this.nacosDiscoveryProperties.setPort(port); + } + } + + @Override + public boolean isSecure() { + return nacosDiscoveryProperties.isSecure(); + } + + @Override + public URI getUri() { + return DefaultServiceInstance.getUri(this); + } + + @Override + public Map getMetadata() { + return nacosDiscoveryProperties.getMetadata(); + } + + public boolean isRegisterEnabled() { + return nacosDiscoveryProperties.isRegisterEnabled(); + } + + public String getCluster() { + return nacosDiscoveryProperties.getClusterName(); + } + + public float getRegisterWeight() { + return nacosDiscoveryProperties.getWeight(); + } + + public NacosDiscoveryProperties getNacosDiscoveryProperties() { + return nacosDiscoveryProperties; + } + + public NamingService getNacosNamingService() { + return nacosNamingService; + } + + public void setNacosNamingService(NamingService nacosNamingService) { + this.nacosNamingService = nacosNamingService; + } + + public void setNacosDiscoveryProperties( + NacosDiscoveryProperties nacosDiscoveryProperties) { + this.nacosDiscoveryProperties = nacosDiscoveryProperties; + } + + @Override + public String toString() { + return "NacosRegistration{" + + "nacosDiscoveryProperties=" + nacosDiscoveryProperties + + ", nacosNamingService=" + nacosNamingService + + '}'; + } +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java new file mode 100644 index 000000000..88243cb3a --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/registry/NacosServiceRegistry.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.registry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import org.springframework.util.StringUtils; + +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Cluster; +import com.alibaba.nacos.api.naming.pojo.Instance; + +/** + * @author xiaojing + */ +public class NacosServiceRegistry implements ServiceRegistry { + + private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); + + @Override + public void register(NacosRegistration registration) { + + if (!registration.isRegisterEnabled()) { + logger.info("Nacos Registration is disabled..."); + return; + } + if (StringUtils.isEmpty(registration.getServiceId())) { + logger.info("No service to register for nacos client..."); + return; + } + + NamingService namingService = registration.getNacosNamingService(); + String serviceId = registration.getServiceId(); + + Instance instance = new Instance(); + instance.setIp(registration.getHost()); + instance.setPort(registration.getPort()); + instance.setWeight(registration.getRegisterWeight()); + instance.setCluster(new Cluster(registration.getCluster())); + instance.setMetadata(registration.getMetadata()); + + try { + namingService.registerInstance(serviceId, instance); + logger.info("nacos registry, {} {}:{} register finished", serviceId, + instance.getIp(), instance.getPort()); + } + catch (Exception e) { + logger.error("nacos registry, {} register failed...{},", serviceId, + registration.toString(), e); + } + } + + @Override + public void deregister(NacosRegistration registration) { + + logger.info("De-registering from Nacos Server now..."); + + if (StringUtils.isEmpty(registration.getServiceId())) { + logger.info("No dom to de-register for nacos client..."); + return; + } + + NamingService namingService = registration.getNacosNamingService(); + String serviceId = registration.getServiceId(); + + try { + namingService.deregisterInstance(serviceId, registration.getHost(), + registration.getPort(), registration.getCluster()); + } + catch (Exception e) { + logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},", + registration.toString(), e); + } + + logger.info("De-registration finished."); + } + + @Override + public void close() { + + } + + @Override + public void setStatus(NacosRegistration registration, String status) { + // nacos doesn't support set status of a particular registration. + } + + @Override + public T getStatus(NacosRegistration registration) { + // nacos doesn't support query status of a particular registration. + return null; + } + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/ConditionalOnRibbonNacos.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/ConditionalOnRibbonNacos.java new file mode 100644 index 000000000..1e223ab07 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/ConditionalOnRibbonNacos.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.ribbon; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@ConditionalOnProperty(value = "ribbon.nacos.enabled", matchIfMissing = true) +public @interface ConditionalOnRibbonNacos { + +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRibbonClientConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRibbonClientConfiguration.java new file mode 100644 index 000000000..e3d1f7322 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRibbonClientConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.ribbon; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.ServerList; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * integrated Ribbon by default + * @author xiaojing + */ +@Configuration +@ConditionalOnRibbonNacos +public class NacosRibbonClientConfiguration { + + @Bean + @ConditionalOnMissingBean + public ServerList ribbonServerList(IClientConfig config) { + NacosServerList serverList = new NacosServerList(); + serverList.initWithNiwsConfig(config); + return serverList; + } +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosServer.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosServer.java new file mode 100644 index 000000000..4618bd9d9 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosServer.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.ribbon; + +import java.util.Map; + +import com.alibaba.nacos.api.naming.pojo.Instance; + +import com.netflix.loadbalancer.Server; + +/** + * @author xiaojing + */ +public class NacosServer extends Server { + + private final MetaInfo metaInfo; + private final Instance instance; + private final Map metadata; + + public NacosServer(Instance instance) { + super(instance.getIp(), instance.getPort()); + this.instance = instance; + this.metaInfo = new MetaInfo() { + @Override + public String getAppName() { + return instance.getService().getName(); + } + + @Override + public String getServerGroup() { + return null; + } + + @Override + public String getServiceIdForDiscovery() { + return null; + } + + @Override + public String getInstanceId() { + return instance.getInstanceId(); + } + }; + this.metadata = instance.getMetadata(); + } + + @Override + public MetaInfo getMetaInfo() { + return metaInfo; + } + + public Instance getInstance() { + return instance; + } + + public Map getMetadata() { + return metadata; + } +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosServerList.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosServerList.java new file mode 100644 index 000000000..0d4fdbb89 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosServerList.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.ribbon; + +import com.netflix.client.config.IClientConfig; +import com.netflix.loadbalancer.AbstractServerList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.nacos.api.naming.pojo.Instance; + +/** + * @author xiaojing + */ +public class NacosServerList extends AbstractServerList { + + @Autowired + private NacosRegistration registration; + + private String serviceId; + + public NacosServerList(){} + + public NacosServerList(String serviceId) { + this.serviceId = serviceId; + } + + @Override + public List getInitialListOfServers() { + return getServers(); + } + + @Override + public List getUpdatedListOfServers() { + return getServers(); + } + + private List getServers() { + try { + List instances = registration.getNacosNamingService().selectInstances(serviceId, true); + return instancesToServerList(instances); + } + catch (Exception e) { + throw new IllegalStateException("Can not get service instances from nacos, serviceId=" + serviceId, e); + } + } + + private List instancesToServerList(List instances) { + List result = new ArrayList<>(instances.size()); + for (Instance instance : instances) { + if (instance.isHealthy()) { + result.add(new NacosServer(instance)); + } + } + + return result; + } + + public String getServiceId() { + return serviceId; + } + + @Override + public void initWithNiwsConfig(IClientConfig iClientConfig) { + this.serviceId = iClientConfig.getClientName(); + } +} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/RibbonNacosAutoConfiguration.java b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/RibbonNacosAutoConfiguration.java new file mode 100644 index 000000000..8180a700e --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/java/org/springframework/cloud/alibaba/nacos/ribbon/RibbonNacosAutoConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos.ribbon; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonClients; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Configuration; + +/** + * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration + * Auto-configuration} that sets up Ribbon for Nacos. + */ +@Configuration +@EnableConfigurationProperties +@ConditionalOnBean(SpringClientFactory.class) +@ConditionalOnRibbonNacos +@AutoConfigureAfter(RibbonAutoConfiguration.class) +@RibbonClients(defaultConfiguration = NacosRibbonClientConfiguration.class) +public class RibbonNacosAutoConfiguration { +} \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..2ea041b08 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,8 @@ +{"properties": [ + { + "name": "spring.cloud.nacos.discovery.service", + "type": "java.lang.String", + "defaultValue": "${spring.application.name}", + "description": "the service name to register, default value is ${spring.application.name}." + } +]} diff --git a/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..723407fe5 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + org.springframework.cloud.alibaba.nacos.NacosDiscoveryAutoConfiguration,\ + org.springframework.cloud.alibaba.nacos.ribbon.RibbonNacosAutoConfiguration,\ + org.springframework.cloud.alibaba.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration +org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ +org.springframework.cloud.alibaba.nacos.NacosDiscoveryClientAutoConfiguration diff --git a/spring-cloud-alibaba-nacos-discovery/src/test/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfigurationTests.java b/spring-cloud-alibaba-nacos-discovery/src/test/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfigurationTests.java new file mode 100644 index 000000000..b7e5d8016 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/test/java/org/springframework/cloud/alibaba/nacos/NacosDiscoveryAutoConfigurationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.alibaba.nacos; + +import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.cloud.alibaba.nacos.registry.NacosRegistration; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author xiaojing + */ +public class NacosDiscoveryAutoConfigurationTests { + + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(NacosDiscoveryTestConfiguration.class, + NacosDiscoveryAutoConfiguration.class)) + .withPropertyValues("spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080") + .withPropertyValues("spring.cloud.nacos.discovery.port=18080") + .withPropertyValues("spring.cloud.nacos.discovery.service=myapp"); + + @Test + public void testProperties() { + this.contextRunner.run(context -> { + NacosDiscoveryProperties properties = context + .getBean(NacosDiscoveryProperties.class); + assertThat(properties.getPort()).isEqualTo(18080); + assertThat(properties.getServerAddr()).isEqualTo("127.0.0.1:8080"); + assertThat(properties.getService()).isEqualTo("myapp"); + }); + } + + @Test + public void nacosRegistration() { + this.contextRunner.run(context -> { + NacosRegistration nacosRegistration = context + .getBean(NacosRegistration.class); + assertThat(nacosRegistration.getPort()).isEqualTo(18080); + assertThat(nacosRegistration.getServiceId()).isEqualTo("myapp"); + assertThat(nacosRegistration.getRegisterWeight()).isEqualTo(1F); + }); + } + + @Configuration + @AutoConfigureBefore(NacosDiscoveryAutoConfiguration.class) + static class NacosDiscoveryTestConfiguration { + + @Bean + AutoServiceRegistrationProperties autoServiceRegistrationProperties() { + return new AutoServiceRegistrationProperties(); + } + + @Bean + InetUtils inetUtils() { + return new InetUtils(new InetUtilsProperties()); + } + } + +} \ No newline at end of file diff --git a/spring-cloud-alibaba-nacos-discovery/src/test/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRibbonClientConfigurationTests.java b/spring-cloud-alibaba-nacos-discovery/src/test/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRibbonClientConfigurationTests.java new file mode 100644 index 000000000..8c6da4290 --- /dev/null +++ b/spring-cloud-alibaba-nacos-discovery/src/test/java/org/springframework/cloud/alibaba/nacos/ribbon/NacosRibbonClientConfigurationTests.java @@ -0,0 +1,67 @@ +package org.springframework.cloud.alibaba.nacos.ribbon; + +import com.netflix.client.config.DefaultClientConfigImpl; +import com.netflix.client.config.IClientConfig; +import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author xiaojing + */ +public class NacosRibbonClientConfigurationTests { + + + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(NacosRibbonTestConfiguration.class, + NacosRibbonClientConfiguration.class, + RibbonNacosAutoConfiguration.class)) + .withPropertyValues("spring.cloud.nacos.discovery.server-addr=127.0.0.1:8080") + .withPropertyValues("spring.cloud.nacos.discovery.port=18080") + .withPropertyValues("spring.cloud.nacos.discovery.service=myapp"); + + + + @Test + public void testProperties() { + + this.contextRunner.run(context -> { + NacosServerList serverList = context.getBean(NacosServerList.class); + assertThat(serverList.getServiceId()).isEqualTo("myapp"); + }); + } + + + @Configuration + @EnableAutoConfiguration + @EnableDiscoveryClient + static class NacosRibbonTestConfiguration { + + + @Bean + IClientConfig iClientConfig(){ + //return new IClientConfig.Builder().s.build(); + DefaultClientConfigImpl config = new DefaultClientConfigImpl(); + config.setClientName("myapp"); + return config; + } + + + @Bean + @LoadBalanced + RestTemplate restTemplate(){ + return new RestTemplate(); + } + + } + +} diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/pom.xml b/spring-cloud-alibaba-sentinel/pom.xml similarity index 96% rename from spring-cloud-alibaba-sentinel-autoconfigure/pom.xml rename to spring-cloud-alibaba-sentinel/pom.xml index 486d320e6..1ac5ef319 100644 --- a/spring-cloud-alibaba-sentinel-autoconfigure/pom.xml +++ b/spring-cloud-alibaba-sentinel/pom.xml @@ -10,8 +10,8 @@ 4.0.0 org.springframework.cloud - spring-cloud-alibaba-sentinel-autoconfigure - Spring Cloud Alibaba Sentinel Autoconfigure + spring-cloud-alibaba-sentinel + Spring Cloud Alibaba Sentinel diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelConstants.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelConstants.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelConstants.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelConstants.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelProperties.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/SentinelWebAutoConfiguration.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelDataSource.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelDataSource.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelDataSource.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelDataSource.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/annotation/SentinelProtect.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/BlockClassRegistry.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java similarity index 65% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java index 623422926..d8ae30d9a 100644 --- a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java +++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelAutoConfiguration.java @@ -16,9 +16,16 @@ package org.springframework.cloud.alibaba.sentinel.custom; +import java.util.Optional; + +import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler; +import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner; +import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager; +import com.alibaba.csp.sentinel.init.InitExecutor; import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.util.AppNameUtil; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -43,24 +50,35 @@ import javax.annotation.PostConstruct; @EnableConfigurationProperties(SentinelProperties.class) public class SentinelAutoConfiguration { - @Value("${project.name:${spring.application.name:}}") - private String projectName; - - @Autowired - private SentinelProperties properties; - - @PostConstruct - private void init() { - if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME))) { - System.setProperty(AppNameUtil.APP_NAME, projectName); - } - if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))) { - System.setProperty(TransportConfig.SERVER_PORT, properties.getPort()); - } - if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))) { - System.setProperty(TransportConfig.CONSOLE_SERVER, properties.getDashboard()); - } - } + @Value("${project.name:${spring.application.name:}}") + private String projectName; + + @Autowired + private SentinelProperties properties; + + @Autowired + private Optional urlBlockHandlerOptional; + + @Autowired + private Optional urlCleanerOptional; + + @PostConstruct + private void init() { + if (StringUtils.isEmpty(System.getProperty(AppNameUtil.APP_NAME))) { + System.setProperty(AppNameUtil.APP_NAME, projectName); + } + if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))) { + System.setProperty(TransportConfig.SERVER_PORT, properties.getPort()); + } + if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))) { + System.setProperty(TransportConfig.CONSOLE_SERVER, properties.getDashboard()); + } + + urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler); + urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner); + + InitExecutor.doInit(); + } @Bean @ConditionalOnMissingBean diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelBeanPostProcessor.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/custom/SentinelProtectInterceptor.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/DataSourceLoader.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourcePostProcessor.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourcePostProcessor.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourcePostProcessor.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourcePostProcessor.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceRegistry.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceRegistry.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceRegistry.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/SentinelDataSourceRegistry.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ApolloDataSourceFactoryBean.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ApolloDataSourceFactoryBean.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ApolloDataSourceFactoryBean.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ApolloDataSourceFactoryBean.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/FileRefreshableDataSourceFactoryBean.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/FileRefreshableDataSourceFactoryBean.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/FileRefreshableDataSourceFactoryBean.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/FileRefreshableDataSourceFactoryBean.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/NacosDataSourceFactoryBean.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ZookeeperDataSourceFactoryBean.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ZookeeperDataSourceFactoryBean.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ZookeeperDataSourceFactoryBean.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/datasource/factorybean/ZookeeperDataSourceFactoryBean.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpoint.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/util/PropertySourcesUtils.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/util/PropertySourcesUtils.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/java/org/springframework/cloud/alibaba/sentinel/util/PropertySourcesUtils.java rename to spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/util/PropertySourcesUtils.java diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json rename to spring-cloud-alibaba-sentinel/src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/sentinel-datasource.properties b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/sentinel-datasource.properties similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/sentinel-datasource.properties rename to spring-cloud-alibaba-sentinel/src/main/resources/META-INF/sentinel-datasource.properties diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-sentinel/src/main/resources/META-INF/spring.factories similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/main/resources/META-INF/spring.factories rename to spring-cloud-alibaba-sentinel/src/main/resources/META-INF/spring.factories diff --git a/spring-cloud-alibaba-sentinel-autoconfigure/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java similarity index 100% rename from spring-cloud-alibaba-sentinel-autoconfigure/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java rename to spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/SentinelAutoConfigurationTests.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/pom.xml b/spring-cloud-alibaba-storage/pom.xml similarity index 96% rename from spring-cloud-alibaba-storage-autoconfigure/pom.xml rename to spring-cloud-alibaba-storage/pom.xml index b40e4286d..29bb54ae5 100644 --- a/spring-cloud-alibaba-storage-autoconfigure/pom.xml +++ b/spring-cloud-alibaba-storage/pom.xml @@ -10,7 +10,7 @@ 4.0.0 org.springframework.cloud - spring-cloud-alibaba-storage-autoconfigure + spring-cloud-alibaba-storage Spring Cloud Alibaba Storage Autoconfigure diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSApplicationListener.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSApplicationListener.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSApplicationListener.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSApplicationListener.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSAutoConfiguration.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSAutoConfiguration.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSAutoConfiguration.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSAutoConfiguration.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSConstants.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSConstants.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSConstants.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSConstants.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSProperties.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSProperties.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/OSSProperties.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/OSSProperties.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpoint.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpoint.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpoint.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpoint.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpointAutoConfiguration.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpointAutoConfiguration.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpointAutoConfiguration.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/endpoint/OSSEndpointAutoConfiguration.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageProtocolResolver.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageProtocolResolver.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageProtocolResolver.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageProtocolResolver.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageResource.java b/spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageResource.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageResource.java rename to spring-cloud-alibaba-storage/src/main/java/org/springframework/cloud/alibaba/storage/resource/OSSStorageResource.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-storage/src/main/resources/META-INF/spring.factories similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/main/resources/META-INF/spring.factories rename to spring-cloud-alibaba-storage/src/main/resources/META-INF/spring.factories diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSAutoConfigurationTests.java b/spring-cloud-alibaba-storage/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSAutoConfigurationTests.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSAutoConfigurationTests.java rename to spring-cloud-alibaba-storage/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSAutoConfigurationTests.java diff --git a/spring-cloud-alibaba-storage-autoconfigure/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSMultiClientAutoConfigurationTests.java b/spring-cloud-alibaba-storage/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSMultiClientAutoConfigurationTests.java similarity index 100% rename from spring-cloud-alibaba-storage-autoconfigure/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSMultiClientAutoConfigurationTests.java rename to spring-cloud-alibaba-storage/src/test/java/org/springframework/cloud/alibaba/storage/test/OSSMultiClientAutoConfigurationTests.java diff --git a/spring-cloud-alibaba-test/core-support/pom.xml b/spring-cloud-alibaba-test/core-support/pom.xml new file mode 100644 index 000000000..26712634f --- /dev/null +++ b/spring-cloud-alibaba-test/core-support/pom.xml @@ -0,0 +1,33 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba-test + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + + core-support + test core support + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + diff --git a/spring-cloud-alibaba-test/pom.xml b/spring-cloud-alibaba-test/pom.xml new file mode 100644 index 000000000..289cc1bb2 --- /dev/null +++ b/spring-cloud-alibaba-test/pom.xml @@ -0,0 +1,36 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + + spring-cloud-alibaba-test + pom + spring cloud alibaba test support + + + core-support + sentinel-test-support + + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + + diff --git a/spring-cloud-alibaba-test/sentinel-test-support/pom.xml b/spring-cloud-alibaba-test/sentinel-test-support/pom.xml new file mode 100644 index 000000000..3a7b21dc7 --- /dev/null +++ b/spring-cloud-alibaba-test/sentinel-test-support/pom.xml @@ -0,0 +1,32 @@ + + + + + org.springframework.cloud + spring-cloud-alibaba-test + 0.2.0.BUILD-SNAPSHOT + + 4.0.0 + + + sentinel-test-support + sentinel test support + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + diff --git a/spring-cloud-starter-alibaba/pom.xml b/spring-cloud-starter-alibaba/pom.xml new file mode 100644 index 000000000..a5d8e35fc --- /dev/null +++ b/spring-cloud-starter-alibaba/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + + org.springframework.cloud + spring-cloud-alibaba + 0.2.0.BUILD-SNAPSHOT + + spring-cloud-starter-alibaba + pom + Spring Cloud Alibaba Starters + Spring Cloud Alibaba Starters + + spring-cloud-starter-alibaba-nacos-config + spring-cloud-starter-alibaba-nacos-discovery + spring-cloud-starter-alibaba-sentinel + spring-cloud-starter-alibaba-storage + + \ No newline at end of file diff --git a/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-nacos-config/pom.xml b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-nacos-config/pom.xml new file mode 100644 index 000000000..2befd40c8 --- /dev/null +++ b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-nacos-config/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.springframework.cloud + spring-cloud-starter-alibaba + 0.2.0.BUILD-SNAPSHOT + + spring-cloud-starter-alibaba-nacos-config + Spring Cloud Starter Alibaba Nacos Config + + + + org.springframework.cloud + spring-cloud-alibaba-nacos-config + + + + diff --git a/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-nacos-discovery/pom.xml b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-nacos-discovery/pom.xml new file mode 100644 index 000000000..2ce41a2fd --- /dev/null +++ b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-nacos-discovery/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.springframework.cloud + spring-cloud-starter-alibaba + 0.2.0.BUILD-SNAPSHOT + + spring-cloud-starter-alibaba-nacos-discovery + Spring Cloud Starter Alibaba Nacos Discovery + + + + org.springframework.cloud + spring-cloud-alibaba-nacos-discovery + + + + diff --git a/spring-cloud-starter-sentinel/pom.xml b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-sentinel/pom.xml similarity index 79% rename from spring-cloud-starter-sentinel/pom.xml rename to spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-sentinel/pom.xml index 5399ff130..70300f790 100644 --- a/spring-cloud-starter-sentinel/pom.xml +++ b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-sentinel/pom.xml @@ -4,16 +4,16 @@ org.springframework.cloud - spring-cloud-alibaba + spring-cloud-starter-alibaba 0.2.0.BUILD-SNAPSHOT - spring-cloud-starter-sentinel - Spring Cloud Starter Sentinel + spring-cloud-starter-alibaba-sentinel + Spring Cloud Starter Alibaba Sentinel org.springframework.cloud - spring-cloud-alibaba-sentinel-autoconfigure + spring-cloud-alibaba-sentinel com.alibaba.csp diff --git a/spring-cloud-starter-storage/pom.xml b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-storage/pom.xml similarity index 73% rename from spring-cloud-starter-storage/pom.xml rename to spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-storage/pom.xml index 5d17ae4c2..bea93264a 100644 --- a/spring-cloud-starter-storage/pom.xml +++ b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-storage/pom.xml @@ -4,16 +4,16 @@ org.springframework.cloud - spring-cloud-alibaba + spring-cloud-starter-alibaba 0.2.0.BUILD-SNAPSHOT - spring-cloud-starter-storage - Spring Cloud Starter Storage + spring-cloud-starter-alibaba-storage + Spring Cloud Starter Alibaba Storage org.springframework.cloud - spring-cloud-alibaba-storage-autoconfigure + spring-cloud-alibaba-storage com.aliyun.oss