Merge pull request #2 from spring-cloud-incubator/master

merge
pull/581/head
Kai 6 years ago committed by GitHub
commit 199b4f10d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -122,7 +122,7 @@ Examples
[Alibaba Cloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme.md) [Alibaba Cloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme.md)
## Version control guidelines ## Version control guidelines
The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the first version number is fixed to 0, that is, the version number is 0.x.x. The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the version number is 0.x.x.
As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been changed significantly in the Actuator module, and spring-cloud-commons is also changed quite a lot from 1.x.x to 2.0.0, we maintain two different branches to support Spring Boot 1 and Spring Boot 2: As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been changed significantly in the Actuator module, and spring-cloud-commons is also changed quite a lot from 1.x.x to 2.0.0, we maintain two different branches to support Spring Boot 1 and Spring Boot 2:
* 0.1.x for Spring Boot 1 * 0.1.x for Spring Boot 1

@ -74,6 +74,7 @@
<spring-cloud-netflix.version>2.1.0.RELEASE</spring-cloud-netflix.version> <spring-cloud-netflix.version>2.1.0.RELEASE</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>2.1.0.RELEASE</spring-cloud-openfeign.version> <spring-cloud-openfeign.version>2.1.0.RELEASE</spring-cloud-openfeign.version>
<spring-cloud-bus.version>2.1.0.RELEASE</spring-cloud-bus.version> <spring-cloud-bus.version>2.1.0.RELEASE</spring-cloud-bus.version>
<spring-cloud-gateway.version>2.1.0.RELEASE</spring-cloud-gateway.version>
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<javax-servlet-api>3.0</javax-servlet-api> <javax-servlet-api>3.0</javax-servlet-api>
@ -171,6 +172,14 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-dependencies</artifactId>
<version>${spring-cloud-gateway.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

@ -58,25 +58,14 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-oss</artifactId> <artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-schedulerx</artifactId>
<version>${spring.cloud.alibaba.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alicloud-sms</artifactId>
<version>${spring.cloud.alibaba.version}</version> <version>${spring.cloud.alibaba.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId> <artifactId>spring-cloud-alibaba-fescar</artifactId>
<version>${spring.cloud.alibaba.version}</version> <version>${spring.cloud.alibaba.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

@ -19,8 +19,8 @@
<properties> <properties>
<sentinel.version>1.4.2</sentinel.version> <sentinel.version>1.4.2</sentinel.version>
<oss.version>3.1.0</oss.version> <oss.version>3.1.0</oss.version>
<fescar.version>0.1.3</fescar.version> <fescar.version>0.2.3</fescar.version>
<nacos.client.version>0.8.2</nacos.client.version> <nacos.client.version>0.9.1</nacos.client.version>
<nacos.config.version>0.8.0</nacos.config.version> <nacos.config.version>0.8.0</nacos.config.version>
<acm.version>1.0.8</acm.version> <acm.version>1.0.8</acm.version>
<ans.version>1.0.1</ans.version> <ans.version>1.0.1</ans.version>

@ -6,24 +6,7 @@ Spring Cloud AliCloud ACM 是 Config Server 和 Client 的替代方案,客户
=== 如何引入 Spring Cloud AliCloud ACM === 如何引入 Spring Cloud AliCloud ACM
Spring Cloud Alibaba 已经发布了 0.2.2.BUILD-SNAPSHOT 版本,需要首先导入依赖管理 POM。 如果要在您的项目中引入 ACM使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alicloud-acm` 的 starter。
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
并引入 Spring Cloud AliCloud ACM Starter 依赖。
[source,xml] [source,xml]
---- ----

@ -4,24 +4,7 @@ ANSApplication Naming Service 是隶属于阿里云 EDAS 产品的组件
=== 如何引入 Spring Cloud AliCloud ANS === 如何引入 Spring Cloud AliCloud ANS
Spring Cloud Alibaba 已经发布了 0.2.2.BUILD-SNAPSHOT 版本,需要首先导入依赖管理 POM。 如果要在您的项目中引入 ANS使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alicloud-ans` 的 starter。
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
接下来引入 Spring Cloud AliCloud ANS Starter 即可。
[source,xml] [source,xml]
---- ----

@ -2,3 +2,41 @@
Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。 Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。
### Spring Cloud Alibaba Bill of Materials (BOM)
如果您是 Maven Central 用户,请将我们的 BOM 添加到您的 pom.xml 中的 <dependencyManagement> 部分。 这将允许您省略任何Maven依赖项的版本而是将版本控制委派给BOM。
```xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
```
### Spring Snapshots Maven Repository
如果要使用最新的 BUILD-SNAPSHOT 版本,请在 pom.xml 中添加 Spring Snapshot Repository注意BUILD-SNAPSHOT随时可能更新:
```xml
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring SnapShots</name>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
```
举个例子, 0.2.0.BUILD-SNAPSHOT 版本就在这个仓库中可用。

@ -28,55 +28,14 @@ NOTE: 注意dataid是以 properties(默认的文件扩展名方式)为扩展名
===== 客户端使用方式 ===== 客户端使用方式
为了能够在应用程序中使用 Nacos 来实现应用的外部化配置在构建应用的同时添加一个Spring Boot Starter org.springframework.cloud:spring-cloud-starter-alibaba-nacos-config。以下是一个基本的 maven 依赖配置: 如果要在您的项目中使用 Nacos 来实现应用的外部化配置,使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alibaba-nacos-config` 的 starter。
[source,xml] [source,xml]
---- ----
<parent> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.0.5.RELEASE</version> </dependency>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
---- ----
现在就可以创建一个标准的 Spring Boot 应用。 现在就可以创建一个标准的 Spring Boot 应用。

@ -11,39 +11,18 @@ Discovery Starter 也将服务实例自身的一些元数据信息-例如 host
==== 如何引入 Nacos Discovery Starter ==== 如何引入 Nacos Discovery Starter
为了能够在你的工程下引入 Nacos Discovey Starter使用group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alibaba-nacos-discovery`。 如果要在您的项目中使用 Nacos 来实现服务发现,使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alibaba-nacos-discovery` 的 starter。
pom.xml 示例如下所示:
[source,xml,indent=0] [source,xml,indent=0]
---- ----
<!-- dependency management--> <dependency>
<dependencyManagement> <groupId>org.springframework.cloud</groupId>
<dependencies> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<dependency> </dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- dependencies -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
---- ----
==== 启动一个 Provider 应用 ==== 启动一个 Provider 应用
如果您使用的 Spring Cloud 版本是 Finchley.SR1 版本,那么这个时候您的Spring Boot版本的选择可需要额外的小心了因为版本的不匹对可能会导致许多意外的效果。
Spring Cloud 的 Finchley.SR1 版本最佳实践的 Spring Boot 版本是 2.0.6.RELEASE。在启动您的一个 Provider 应用时请检查依赖的 Spring Boot 版本是否是
1.X.Y.RELEASE 或者 2.1.0.RELEASE 的版本。如果不是,请更正到 2.0.6.RELEASE 版本。
以下步骤向您展示了如何将一个服务注册到 Nacos。 以下步骤向您展示了如何将一个服务注册到 Nacos。
1. pom.xml的配置。一个完整的 pom.xml 配置如下所示: 1. pom.xml的配置。一个完整的 pom.xml 配置如下所示:
@ -62,7 +41,7 @@ Spring Cloud 的 Finchley.SR1 版本最佳实践的 Spring Boot 版本是 2.0.6.
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version> <version>${spring.boot.version}</version>
<relativePath/> <relativePath/>
</parent> </parent>
@ -77,14 +56,14 @@ Spring Cloud 的 Finchley.SR1 版本最佳实践的 Spring Boot 版本是 2.0.6.
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId> <artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version> <version>${spring.cloud.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId> <artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version> <version>${spring.cloud.alibaba.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

@ -4,24 +4,7 @@ OSSObject Storage Service是阿里云的一款对象存储服务产品
=== 如何引入 Spring Cloud AliCloud OSS === 如何引入 Spring Cloud AliCloud OSS
Spring Cloud Alibaba 已经发布了0.2.0版本需要首先导入依赖管理POM。 如果要在您的项目中引入 OSS使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alicloud-oss` 的 starter。
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
接下来引入 Spring Cloud AliCloud OSS Starter 即可。
[source,xml] [source,xml]
---- ----

@ -4,24 +4,7 @@ SchedulerX分布式任务调度 是隶属于阿里云EDAS产品的组件
=== 如何引入 Spring Cloud AliCloud SchedulerX === 如何引入 Spring Cloud AliCloud SchedulerX
Spring Cloud Alibaba 已经发布了0.2.1版本需要首先导入依赖管理POM。 如果要在您的项目中引入 SchedulerX使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alicloud-schedulerX` 的 starter。
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
接下来引入 Spring Cloud AliCloud SchedulerX Starter 即可。
[source,xml] [source,xml]
---- ----

@ -266,12 +266,13 @@ Sentinel Endpoint 里暴露的信息非常有用。包括当前应用的所有
^|配置项 ^|含义 ^|默认值 ^|配置项 ^|含义 ^|默认值
|`spring.cloud.sentinel.enabled`|Sentinel自动化配置是否生效|true |`spring.cloud.sentinel.enabled`|Sentinel自动化配置是否生效|true
|`spring.cloud.sentinel.eager`|取消Sentinel控制台懒加载|false |`spring.cloud.sentinel.eager`|取消Sentinel控制台懒加载|false
|`spring.cloud.sentinel.transport.port`|应用与Sentinel控制台交互的端口应用本地会起一个该端口占用的HttpServer|8721 |`spring.cloud.sentinel.transport.port`|应用与Sentinel控制台交互的端口应用本地会起一个该端口占用的HttpServer|8719
|`spring.cloud.sentinel.transport.dashboard`|Sentinel 控制台地址| |`spring.cloud.sentinel.transport.dashboard`|Sentinel 控制台地址|
|`spring.cloud.sentinel.transport.heartbeat-interval-ms`|应用与Sentinel控制台的心跳间隔时间| |`spring.cloud.sentinel.transport.heartbeat-interval-ms`|应用与Sentinel控制台的心跳间隔时间|
|`spring.cloud.sentinel.transport.client-ip`|客户端IP| |`spring.cloud.sentinel.transport.client-ip`|客户端IP|
|`spring.cloud.sentinel.filter.order`|Servlet Filter的加载顺序。Starter内部会构造这个filter|Integer.MIN_VALUE |`spring.cloud.sentinel.filter.order`|Servlet Filter的加载顺序。Starter内部会构造这个filter|Integer.MIN_VALUE
|`spring.cloud.sentinel.filter.url-patterns`|数据类型是数组。表示Servlet Filter的url pattern集合|/* |`spring.cloud.sentinel.filter.url-patterns`|数据类型是数组。表示Servlet Filter的url pattern集合|/*
|`spring.cloud.sentinel.filter.enabled`|Enable to instance CommonFilter|true
|`spring.cloud.sentinel.metric.charset`|metric文件字符集|UTF-8 |`spring.cloud.sentinel.metric.charset`|metric文件字符集|UTF-8
|`spring.cloud.sentinel.metric.file-single-size`|Sentinel metric 单个文件的大小| |`spring.cloud.sentinel.metric.file-single-size`|Sentinel metric 单个文件的大小|
|`spring.cloud.sentinel.metric.file-total-count`|Sentinel metric 总文件数量| |`spring.cloud.sentinel.metric.file-total-count`|Sentinel metric 总文件数量|

@ -4,31 +4,7 @@
=== 如何引入 Spring Cloud AliCloud SMS === 如何引入 Spring Cloud AliCloud SMS
Spring Cloud Alibaba 已经发布了 0.2.2.BUILD-SNAPSHOT 版本,需要首先导入依赖管理 POM。 如果要在您的项目中引入 SMS使用 group ID 为 `org.springframework.cloud` 和 artifact ID 为 `spring-cloud-starter-alicloud-sms` 的 starter。
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
接下来引入 Spring Cloud AliCloud SMS Starter 即可。
[source,xml] [source,xml]
---- ----
@ -55,7 +31,7 @@ access-key 和 secret-key 是阿里云账号的 AK/SK需要首先注册阿里
==== 引入 SMS API ==== 引入 SMS API
Spring Cloud Alicloud SMS 中的 SMS API 基于阿里云官方 SMS SDK 提供,具备单个短信发送、多个短信批量发送、短信查询、短信消息(`短信回执消息``上行短信消息`) 类行操作API。 Spring Cloud Alicloud SMS 中的 SMS API 基于阿里云官方 SMS SDK 提供,具备单个短信发送、多个短信批量发送、短信查询、短信消息(短信回执消息 和 上行短信消息) 类行操作API。
一个简单的使用 SMS API 发送短信的应用如下。 一个简单的使用 SMS API 发送短信的应用如下。
@ -67,13 +43,7 @@ public class SmsApplication {
@Autowired @Autowired
private ISmsService smsService; private ISmsService smsService;
/**
* 短信发送 Example
* @param code
* @return
*/
@RequestMapping("/batch-sms-send.do") @RequestMapping("/batch-sms-send.do")
public SendBatchSmsResponse batchsendCheckCode( public SendBatchSmsResponse batchsendCheckCode(
@RequestParam(name = "code") String code) { @RequestParam(name = "code") String code) {
@ -99,7 +69,6 @@ public class SmsApplication {
} }
public static void main(String[] args) throws URISyntaxException { public static void main(String[] args) throws URISyntaxException {
SpringApplication.run(SmsApplication.class, args); SpringApplication.run(SmsApplication.class, args);
} }
@ -119,15 +88,10 @@ Spring Cloud Alicloud SMS 封装的 API 接口为了降低学习的成本,尽
* 批量短信发送 * 批量短信发送
参考以下的 Example ,来快速开发一个具有批量短信发送的功能。在 Controller 中或者新建一个 Controler 新增如下代码: 参考以下的 Example ,来快速开发一个具有批量短信发送的功能。在 Controller 中或者新建一个 Controller 新增如下代码:
[source,java] [source,java]
---- ----
/**
* 批量短信发送 Example
* @param code
* @return
*/
@RequestMapping("/batch-sms-send.do") @RequestMapping("/batch-sms-send.do")
public SendBatchSmsResponse batchsendCheckCode( public SendBatchSmsResponse batchsendCheckCode(
@RequestParam(name = "code") String code) { @RequestParam(name = "code") String code) {
@ -165,16 +129,10 @@ NOTE: 这里设置请求的 MethodType 为 GET和官网给出的例子还有
* 短信查询 * 短信查询
参考以下的 Example ,可以快速开发根据某个指定的号码查询短信历史发送状态。在 Controller 中或者新建一个 Controler 新增如下代码: 参考以下的 Example ,可以快速开发根据某个指定的号码查询短信历史发送状态。在 Controller 中或者新建一个 Controller 新增如下代码:
[source,java] [source,java]
---- ----
/**
*
* 短信查询 Example
* @param telephone
* @return
*/
@RequestMapping("/query.do") @RequestMapping("/query.do")
public QuerySendDetailsResponse querySendDetailsResponse( public QuerySendDetailsResponse querySendDetailsResponse(
@RequestParam(name = "tel") String telephone) { @RequestParam(name = "tel") String telephone) {
@ -241,7 +199,7 @@ public class SmsReportMessageListener
* 上行短信消息 * 上行短信消息
通过订阅SmsUp上行短信消息可以获知终端用户回复短信的内容。这些工作也已经被 Spring Cloud AliCloud SMS 封装好了。你只需要完成以下两步即可。 通过订阅 SmsUp 上行短信消息,可以获知终端用户回复短信的内容。这些工作也已经被 Spring Cloud AliCloud SMS 封装好了。你只需要完成以下两步即可。
1、 在 `application.properties` 配置文件中(也可以是 application.yaml)配置 SmsReport 的队列名称。 1、 在 `application.properties` 配置文件中(也可以是 application.yaml)配置 SmsReport 的队列名称。

@ -6,24 +6,7 @@ Spring Cloud Alibaba Cloud ACM is an alternative solution for Config Server and
=== How to Introduce Spring Cloud Alibaba Cloud ACM === How to Introduce Spring Cloud Alibaba Cloud ACM
Weve released Spring Cloud Alibaba version 0.2.2.BUILD-SNAPSHOT. You will need to add dependency management POM first. If you want to use ACM in your project, please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alicloud-acm`.
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
Next we need to introduce Spring Cloud Alibaba Cloud ACM Starter.
[source,xml] [source,xml]
---- ----

@ -4,24 +4,7 @@ ANS(Application Naming Service) is a component of EDAS. Spring Cloud Alibaba Cl
=== How to Introduce Spring Cloud Alibaba Cloud ANS === How to Introduce Spring Cloud Alibaba Cloud ANS
Weve released Spring Cloud Alibaba version 0.2.1. You will need to add dependency management POM first. If you want to use ANS in your project, please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alicloud-ans`.
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
Next we need to introduce Spring Cloud AliCloud ANS Starter.
[source,xml] [source,xml]
---- ----

@ -1,38 +1,38 @@
== Dependency Management == Dependency Management
The Spring Cloud Alibaba Bill of Materials (BOM) contains the versions of all the dependencies it uses. ### Spring Cloud Alibaba Bill of Materials (BOM)
Version 0.2.2.BUILD-SNAPSHOT is compatible with the Spring Cloud Finchley. Version 0.1.1.RELEASE is compatible with the Spring Cloud Edgware. If youre a Maven Central user, add our BOM to your pom.xml <dependencyManagement> section. This will allow you to omit versions for any of the Maven dependencies and instead delegate versioning to the BOM.
These artifacts are available from Maven Central and Spring Release repository via BOM: ```xml
[source,xml]
----
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId> <artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version> <version>2.1.0.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
---- ```
### Spring Snapshots Maven Repository
If you want to use the latest BUILD-SNAPSHOT version, add Spring Snapshot Repository in pom.xml , Attention: BUILD-SNAPSHOT may be updated in any time If you want to use the latest BUILD-SNAPSHOT version, add Spring Snapshot Repository in pom.xml , Attention: BUILD-SNAPSHOT may be updated in any time:
[source,xml] ```xml
----
<repositories> <repositories>
<repository> <repository>
<id>spring-snapshot</id> <id>spring-snapshots</id>
<name>Spring Snapshot Repository</name> <name>Spring SnapShots</name>
<path>https://repo.spring.io/snapshot</path> <url>https://repo.spring.io/libs-snapshot</url>
<snapshots> <snapshots>
<enabled>true</enabled> <enabled>true</enabled>
</snapshots> </snapshots>
</repository> </repository>
</repositories> </repositories>
---- ```
For example, the 0.2.0.BUILD-SNAPSHOT is available from this repository.

@ -28,55 +28,14 @@ NOTE: The default file extension of dataid is properties.
===== Usage on the Client ===== Usage on the Client
To use Nacos to manage externalized configurations for your applications, you need to add a Spring Boot Starter while building your application: org.springframework.cloud:spring-cloud-starter-alibaba-nacos-config The following is a basic configuration of maven dependency: If you want to use Nacos to manage externalized configurations for your applications, please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alibaba-nacos-config`.
[source,xml] [source,xml]
---- ----
<parent> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.0.5.RELEASE</version> </dependency>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
---- ----
Now we can create a standard Spring Boot application. Now we can create a standard Spring Boot application.

@ -11,39 +11,18 @@ Discovery Starter registers some of the metadata of the service instance, such a
==== How to Introduce Nacos Discovery Starter ==== How to Introduce Nacos Discovery Starter
To introduce Nacos Discovey Starter into your project, use the group ID of `org.springframework.cloud` and the artifact ID of `spring-cloud-starter-alibaba-nacos-discovery`. please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alibaba-nacos-discovery`.
pom.xml sample
[source,xml,indent=0] [source,xml,indent=0]
---- ----
<! -- dependency management--> <dependency>
<dependencyManagement> <groupId>org.springframework.cloud</groupId>
<dependencies> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<dependency> </dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<! -- dependencies -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
---- ----
==== Start a Provider Application ==== Start a Provider Application
If you use the Finchley.SR1 version of Spring Cloud , then you will need to be very cautious when selecting the Spring Boot version, because the version incompatibility might lead to many unexpected results.
The best practice for Spring Cloud Finchley.SR1 is to use the 2.0.6 release of Spring Boot. When starting a provider application, please also check if your Spring Boot version is
1.X.Y.RELEASE or 2.1.0.RELEASE. If not, please change it to 2.0.6.RELEASE.
The following sample illustrates how to register a service to Nacos. The following sample illustrates how to register a service to Nacos.
1. Configuration of pom.xml The following is a complete example of pom.xml: 1. Configuration of pom.xml The following is a complete example of pom.xml:
@ -62,7 +41,7 @@ The following sample illustrates how to register a service to Nacos.
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version> <version>${spring.boot.version}</version>
<relativePath/> <relativePath/>
</parent> </parent>
@ -77,14 +56,14 @@ The following sample illustrates how to register a service to Nacos.
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId> <artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version> <version>${spring.cloud.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId> <artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version> <version>${spring.cloud.alibaba.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

@ -4,24 +4,7 @@ SchedulerXDistributed job scheduling is a component of EDAS, an Alibaba Cl
=== How to Introduce Spring Cloud Alibaba Cloud SchedulerX === How to Introduce Spring Cloud Alibaba Cloud SchedulerX
Weve released Spring Cloud Alibaba version 0.2.1. You will need to add dependency management POM first. If you want to use SchedulerX in your project, please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alicloud-schedulerX`.
[source,xml]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----
Next we need to introduce Spring Cloud AliCloud SchedulerX Starter.
[source,xml] [source,xml]
---- ----

@ -265,12 +265,13 @@ The following table shows all the configurations of Spring Cloud Alibaba Sentine
^|Configuration ^|Description ^|Default Value ^|Configuration ^|Description ^|Default Value
|`spring.cloud.sentinel.enabled`|Whether Sentinel automatic configuration takes effect|true |`spring.cloud.sentinel.enabled`|Whether Sentinel automatic configuration takes effect|true
|`spring.cloud.sentinel.eager`|Cancel Sentinel dashboard lazy load|false |`spring.cloud.sentinel.eager`|Cancel Sentinel dashboard lazy load|false
|`spring.cloud.sentinel.transport.port`|Port for the application to interact with Sentinel dashboard. An HTTP Server which uses this port will be started in the application|8721 |`spring.cloud.sentinel.transport.port`|Port for the application to interact with Sentinel dashboard. An HTTP Server which uses this port will be started in the application|8719
|`spring.cloud.sentinel.transport.dashboard`|Sentinel dashboard address| |`spring.cloud.sentinel.transport.dashboard`|Sentinel dashboard address|
|`spring.cloud.sentinel.transport.heartbeatIntervalMs`|Hearbeat interval between the application and Sentinel dashboard| |`spring.cloud.sentinel.transport.heartbeatIntervalMs`|Hearbeat interval between the application and Sentinel dashboard|
|`spring.cloud.sentinel.transport.client-ip`|Client IP| |`spring.cloud.sentinel.transport.client-ip`|Client IP|
|`spring.cloud.sentinel.filter.order`|Loading order of Servlet Filter. The filter will be constructed in the Starter|Integer.MIN_VALUE |`spring.cloud.sentinel.filter.order`|Loading order of Servlet Filter. The filter will be constructed in the Starter|Integer.MIN_VALUE
|`spring.cloud.sentinel.filter.url-patterns`|Data type is array. Refers to the collection of Servlet Filter ULR patterns|/* |`spring.cloud.sentinel.filter.url-patterns`|Data type is array. Refers to the collection of Servlet Filter ULR patterns|/*
|`spring.cloud.sentinel.filter.enabled`|Enable to instance CommonFilter|true
|`spring.cloud.sentinel.metric.charset`|metric file character set|UTF-8 |`spring.cloud.sentinel.metric.charset`|metric file character set|UTF-8
|`spring.cloud.sentinel.metric.fileSingleSize`|Sentinel metric single file size| |`spring.cloud.sentinel.metric.fileSingleSize`|Sentinel metric single file size|
|`spring.cloud.sentinel.metric.fileTotalCount`|Sentinel metric total file number| |`spring.cloud.sentinel.metric.fileTotalCount`|Sentinel metric total file number|

@ -0,0 +1,209 @@
== Spring Cloud Alibaba Cloud SMS
SMSShort Message Serviceis a messaging service that covers the globe, Alibaba SMS provides convenient, efficient, and intelligent communication capabilities that help businesses quickly contact their customers.
Spring Cloud AliCloud SMS provide an easier-to-use API for quick access to Alibaba Cloud's SMS service based on Spring Cloud Alibaba SMS.
=== 如何引入 Spring Cloud AliCloud SMS
If you want to use SMS in your project, please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alicloud-sms`.
[source,xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-sms</artifactId>
</dependency>
----
=== How to use SMS API
==== Configure SMS
Before you start to use Spring Cloud Alibaba Cloud SMS, please add the following configurations in application.properties.
[source,properties]
----
spring.cloud.alicloud.access-key=AK
spring.cloud.alicloud.secret-key=SK
----
access-key and secret-key is the AK/SK of your Alibaba Cloud account. If you dont have one, please register an account first, and log on to https://usercenter.console.aliyun.com/#/manage/ak[Alibaba Cloud AK/SK Management] to get your AccessKey ID and Access Key Secret . If you havent create the AccessKeys, click “Create AccessKey” to create one.
==== Introduce SMS API
The SMS API in Spring Cloud Alicloud SMS is based on Alibaba Cloud SMS SDK. It has a single SMS sending, multiple SMS bulk sending, SMS query, SMS message (SMS receipt message and Upstream SMS message) class operation API.
The following is a simple example of how to use SMS api to send short message:
[source,java]
----
@SpringBootApplication
public class SmsApplication {
@Autowired
private ISmsService smsService;
@RequestMapping("/batch-sms-send.do")
public SendBatchSmsResponse batchsendCheckCode(
@RequestParam(name = "code") String code) {
SendSmsRequest request = new SendSmsRequest();
// Required:the mobile number
request.setPhoneNumbers("152******");
// Required:SMS-SignName-could be found in sms console
request.setSignName("******");
// Required:Template-could be found in sms console
request.setTemplateCode("******");
// Required:The param of sms template.For exmaple, if the template is "Hello,your verification code is ${code}". The param should be like following value
request.setTemplateParam("{\"code\":\"" + code + "\"}");
SendSmsResponse sendSmsResponse ;
try {
sendSmsResponse = smsService.sendSmsRequest(request);
}
catch (ClientException e) {
e.printStackTrace();
sendSmsResponse = new SendSmsResponse();
}
return sendSmsResponse ;
}
public static void main(String[] args) throws URISyntaxException {
SpringApplication.run(SmsApplication.class, args);
}
}
----
Before you send your messages, please https://account.aliyun.com/register/register.htm?spm=5176.8142029.388261.26.e9396d3eaYK2sG&oauth_callback=https%3A%2F%2Fwww.aliyun.com%2F[Register an Alibaba Cloud Account]. If you already have one, please https://dysms.console.aliyun.com/dysms.htm?spm=5176.8195934.1283918..18924183bHPct2&accounttraceid=c8cb4243-3080-4eb1-96b0-1f2316584269#/[Turn on SMS Service].
For more information about SMS , please refer to the SMS official https://help.aliyun.com/document_detail/55284.html?spm=a2c4g.11186623.6.568.715e4f30ZiVkbI[SMS] (SendSms)---JAVA] docs .
NOTE: Due to an issue with the earlier SMS sdk version, if the text message fails to be sent, please delete the line of code that contains the explicit MethodType as POST. If you still have problems, please contact us as soon as possible.
=== The Advanced Features of SMS Api
In order to reduce the cost of learning, the API interface of the Spring Cloud Alicloud SMS package is kept as consistent as the API and Example provided by the official website.
* Batch SMS sending
Refer to the following example to quickly develop a feature with bulk SMS sending. Add the following code in the Controller or create a new Controller:
[source,java]
----
@RequestMapping("/batch-sms-send.do")
public SendBatchSmsResponse batchsendCheckCode(
@RequestParam(name = "code") String code) {
SendBatchSmsRequest request = new SendBatchSmsRequest();
request.setMethod(MethodType.GET);
request.setPhoneNumberJson("[\"177********\",\"130********\"]");
request.setSignNameJson("[\"*******\",\"*******\"]");
request.setTemplateCode("******");
request.setTemplateParamJson(
"[{\"code\":\"" + code + "\"},{\"code\":\"" + code + "\"}]");
SendBatchSmsResponse sendSmsResponse ;
try {
sendSmsResponse = smsService
.sendSmsBatchRequest(request);
return sendSmsResponse;
}
catch (ClientException e) {
e.printStackTrace();
sendSmsResponse = new SendBatchSmsResponse();
}
return sendSmsResponse ;
}
----
NOTE: The MethodType of the request is set to GET, which is somewhat different from the example given by the official website. This is because the inconsistent version of the dependent Alibaba Cloud POP API version causes incompatibility issues, set to GET.
More parameter descriptions can be https://help.aliyun.com/document_detail/66041.html?spm=a2c4g.11186623.6.571.631315e8AauJhP[reference here]
* SMS Query
Refer to the following example to quickly develop a history of sending SMS messages based on a specified number. Add the following code in the Controller or create a new Controller:
[source,java]
----
@RequestMapping("/query.do")
public QuerySendDetailsResponse querySendDetailsResponse(
@RequestParam(name = "tel") String telephone) {
QuerySendDetailsRequest request = new QuerySendDetailsRequest();
request.setPhoneNumber(telephone);
request.setSendDate("20190103");
request.setPageSize(10L);
request.setCurrentPage(1L);
try {
QuerySendDetailsResponse response = smsService.querySendDetails(request);
return response;
}
catch (ClientException e) {
e.printStackTrace();
}
return new QuerySendDetailsResponse();
}
----
More parameter descriptions can be found at https://help.aliyun.com/document_detail/55289.html?spm=a2c4g.11186623.6.569.4f852c78mugEfx[reference here]
* SMS receipt message
By subscribing to the SmsReport SMS status report, you can know the status of each SMS message and whether it knows the status and related information of the terminal user. These efforts have been encapsulated internally by Spring Cloud AliCloud SMS. You only need to complete the following two steps.
1、Configure the queue name for SmsReport in the `application.properties` configuration file (which can also be application.yaml).
.application.properties
----
spring.cloud.alicloud.sms.report-queue-name=Alicom-Queue-********-SmsReport
----
2、Implement the SmsReportMessageListener interface and initialize a Spring Bean.
[source,java]
----
@Component
public class SmsReportMessageListener
implements org.springframework.cloud.alicloud.sms.SmsReportMessageListener {
@Override
public boolean dealMessage(Message message) {
//do something
System.err.println(this.getClass().getName() + "; " + message.toString());
return true;
}
}
----
More message body format for Message can be https://help.aliyun.com/document_detail/55496.html?spm=a2c4g.11186623.6.570.7f792c78rOiWXO[reference here].
* Upstream SMS message
By subscribing to the SmsUp upstream SMS message, you can know the content of the end user replying to the SMS. These efforts have also been packaged by Spring Cloud AliCloud SMS. You only need to complete the following two steps.
1、Configure the queue name for SmsReport in the `application.properties` configuration file (which can also be application.yaml).
.application.properties
----
spring.cloud.alicloud.sms.up-queue-name=Alicom-Queue-********-SmsUp
----
2、Implement the SmsUpMessageListener interface and initialize a Spring Bean.
[source,java]
----
@Component
public class SmsUpMessageListener
implements org.springframework.cloud.alicloud.sms.SmsUpMessageListener {
@Override
public boolean dealMessage(Message message) {
//do something
System.err.println(this.getClass().getName() + "; " + message.toString());
return true;
}
}
----
More message body format for Message can be https://help.aliyun.com/document_detail/55496.html?spm=a2c4g.11186623.6.570.7f792c78rOiWXO[reference here].

@ -14,9 +14,7 @@
<name>Spring Cloud Alibaba Dubbo</name> <name>Spring Cloud Alibaba Dubbo</name>
<properties> <properties>
<dubbo.version>2.6.5</dubbo.version> <dubbo.version>2.7.0</dubbo.version>
<dubbo-spring-boot.version>0.2.1.RELEASE</dubbo-spring-boot.version>
<dubbo-registry-nacos.version>0.0.2</dubbo-registry-nacos.version>
<spring-cloud-zookeeper.version>2.1.0.RELEASE</spring-cloud-zookeeper.version> <spring-cloud-zookeeper.version>2.1.0.RELEASE</spring-cloud-zookeeper.version>
<spring-cloud-consul.version>2.1.0.RELEASE</spring-cloud-consul.version> <spring-cloud-consul.version>2.1.0.RELEASE</spring-cloud-consul.version>
<curator.version>4.0.1</curator.version> <curator.version>4.0.1</curator.version>
@ -36,7 +34,7 @@
<!-- Apache Dubbo dependencies--> <!-- Apache Dubbo dependencies-->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId> <artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version> <version>${dubbo.version}</version>
<type>pom</type> <type>pom</type>
@ -157,15 +155,32 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- Dubbo Spring Boot Starter --> <!-- Dubbo -->
<dependency> <dependency>
<groupId>com.alibaba.boot</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId> <artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId> <artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency> </dependency>
<!-- Netty --> <!-- Netty -->

@ -16,13 +16,16 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.autoconfigure; package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import com.alibaba.dubbo.config.ProtocolConfig; import feign.Contract;
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan; import org.apache.dubbo.config.ProtocolConfig;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy; import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigServiceProxy;
import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@ -38,12 +41,17 @@ import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
@Configuration @Configuration
@Import(DubboServiceMetadataRepository.class) @Import({DubboServiceMetadataRepository.class, PublishingDubboMetadataConfigService.class})
@DubboComponentScan(basePackages = "org.springframework.cloud.alibaba.dubbo.service")
public class DubboMetadataAutoConfiguration { public class DubboMetadataAutoConfiguration {
public static final String METADATA_PROTOCOL_BEAN_NAME = "metadata"; public static final String METADATA_PROTOCOL_BEAN_NAME = "metadata";
@Bean
@ConditionalOnMissingBean
public MetadataResolver metadataJsonResolver(ObjectProvider<Contract> contract) {
return new DubboServiceBeanMetadataResolver(contract);
}
/** /**
* Build an alias Bean for {@link ProtocolConfig} * Build an alias Bean for {@link ProtocolConfig}
* *

@ -0,0 +1,138 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* 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.dubbo.autoconfigure;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.AutoConfigureAfter;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataConfigService;
import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration.METADATA_PROTOCOL_BEAN_NAME;
/**
* The Auto-Configuration class for Dubbo metadata {@link EventListener event handling}.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@AutoConfigureAfter(value = {DubboMetadataAutoConfiguration.class})
@Configuration
public class DubboMetadataEventHandlingAutoConfiguration {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MetadataResolver metadataResolver;
@Autowired
private PublishingDubboMetadataConfigService dubboMetadataConfigService;
@Autowired
private ApplicationConfig applicationConfig;
@Autowired
@Qualifier(METADATA_PROTOCOL_BEAN_NAME)
private ProtocolConfig metadataProtocolConfig;
@Value("${spring.application.name:application}")
private String currentApplicationName;
/**
* The ServiceConfig of DubboMetadataConfigService to be exported, can be nullable.
*/
private ServiceConfig<DubboMetadataConfigService> serviceConfig;
@EventListener(ServiceBeanExportedEvent.class)
public void recordRestMetadata(ServiceBeanExportedEvent event) {
ServiceBean serviceBean = event.getServiceBean();
dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
}
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
exportDubboMetadataConfigService();
}
@EventListener(ApplicationFailedEvent.class)
public void onApplicationFailed() {
unexportDubboMetadataConfigService();
}
@EventListener(ContextClosedEvent.class)
public void onContextClosed() {
unexportDubboMetadataConfigService();
}
private void exportDubboMetadataConfigService() {
if (serviceConfig != null && serviceConfig.isExported()) {
return;
}
if (StringUtils.isEmpty(dubboMetadataConfigService.getServiceRestMetadata())) {
// If there is no REST metadata, DubboMetadataConfigService will not be exported.
if (logger.isInfoEnabled()) {
logger.info("There is no REST metadata, the Dubbo service[{}] will not be exported.",
dubboMetadataConfigService.getClass().getName());
}
return;
}
serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(DubboMetadataConfigService.class);
// Use current Spring application name as the Dubbo Service version
serviceConfig.setVersion(currentApplicationName);
serviceConfig.setRef(dubboMetadataConfigService);
serviceConfig.setApplication(applicationConfig);
serviceConfig.setProtocol(metadataProtocolConfig);
serviceConfig.export();
if (logger.isInfoEnabled()) {
logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString());
}
}
private void unexportDubboMetadataConfigService() {
if (serviceConfig == null || serviceConfig.isUnexported()) {
return;
}
serviceConfig.unexport();
if (logger.isInfoEnabled()) {
logger.info("The Dubbo service[{}] has been unexported.", serviceConfig.toString());
}
}
}

@ -16,14 +16,9 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.autoconfigure; package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import feign.Contract;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository; import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor; import org.springframework.cloud.alibaba.dubbo.openfeign.TargeterBeanPostProcessor;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
@ -31,22 +26,20 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.TARGETER_CLASS_NAME;
/** /**
* Dubbo Feign Auto-{@link Configuration Configuration} * Dubbo Feign Auto-{@link Configuration Configuration}
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
@ConditionalOnClass(name = {"feign.Feign"}) @ConditionalOnClass(name = {"feign.Feign", TARGETER_CLASS_NAME})
@AutoConfigureAfter(name = {"org.springframework.cloud.openfeign.FeignAutoConfiguration"}) @AutoConfigureAfter(name = {"org.springframework.cloud.openfeign.FeignAutoConfiguration"})
@Configuration @Configuration
public class DubboOpenFeignAutoConfiguration { public class DubboOpenFeignAutoConfiguration {
@Bean public static final String TARGETER_CLASS_NAME = "org.springframework.cloud.openfeign.Targeter";
@ConditionalOnMissingBean
public MetadataResolver metadataJsonResolver(ObjectProvider<Contract> contract) {
return new DubboServiceBeanMetadataResolver(contract);
}
@Bean @Bean
public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment, public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment,

@ -1,62 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* 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.dubbo.autoconfigure;
import com.alibaba.dubbo.config.spring.ServiceBean;
import com.alibaba.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolver;
import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataConfigService;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
/**
* The Auto-Configuration class for Dubbo REST metadata registration,
* REST metadata that is a part of {@link Registration#getMetadata() Spring Cloud service instances' metadata}
* will be registered Spring Cloud registry.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@ConditionalOnBean(value = {
MetadataResolver.class
})
@AutoConfigureAfter(value = {DubboMetadataAutoConfiguration.class})
@Configuration
public class DubboRestMetadataRegistrationAutoConfiguration {
@Autowired
private MetadataResolver metadataResolver;
@Autowired
private PublishingDubboMetadataConfigService dubboMetadataConfigService;
@Value("${spring.application.name:application}")
private String currentApplicationName;
@EventListener(ServiceBeanExportedEvent.class)
public void recordRestMetadata(ServiceBeanExportedEvent event) {
ServiceBean serviceBean = event.getServiceBean();
dubboMetadataConfigService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
}
}

@ -16,16 +16,34 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.autoconfigure; package org.springframework.cloud.alibaba.dubbo.autoconfigure;
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.config.spring.util.PropertySourcesUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler;
import org.springframework.cloud.alibaba.dubbo.registry.handler.StandardDubboRegistryServiceIdHandler;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
import org.springframework.cloud.alibaba.dubbo.service.parameter.PathVariableServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.PathVariableServiceParameterResolver;
import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestBodyServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestBodyServiceParameterResolver;
import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestHeaderServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestHeaderServiceParameterResolver;
import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestParamServiceParameterResolver; import org.springframework.cloud.alibaba.dubbo.service.parameter.RequestParamServiceParameterResolver;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertyResolver;
import org.springframework.lang.Nullable;
import java.util.Map;
import static org.apache.dubbo.spring.boot.util.DubboUtils.BASE_PACKAGES_PROPERTY_RESOLVER_BEAN_NAME;
import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_SCAN_PREFIX;
/** /**
* Spring Boot Auto-Configuration class for Dubbo Service * Spring Boot Auto-Configuration class for Dubbo Service
@ -51,4 +69,87 @@ public class DubboServiceAutoConfiguration {
}) })
static class ParameterResolversConfiguration { static class ParameterResolversConfiguration {
} }
@Bean
@ConditionalOnMissingBean
public DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler(ConfigurableApplicationContext context) {
return new StandardDubboRegistryServiceIdHandler(context);
}
/**
* Bugfix code for an issue : https://github.com/apache/incubator-dubbo-spring-boot-project/issues/459
*
* @param environment {@link ConfigurableEnvironment}
* @return a Bean of {@link PropertyResolver}
*/
@Primary
@Bean(name = BASE_PACKAGES_PROPERTY_RESOLVER_BEAN_NAME)
public PropertyResolver dubboScanBasePackagesPropertyResolver(ConfigurableEnvironment environment) {
ConfigurableEnvironment propertyResolver = new AbstractEnvironment() {
protected void customizePropertySources(MutablePropertySources propertySources) {
Map<String, Object> dubboScanProperties = PropertySourcesUtils.getSubProperties(environment, DUBBO_SCAN_PREFIX);
propertySources.addLast(new MapPropertySource("dubboScanProperties", dubboScanProperties));
}
};
ConfigurationPropertySources.attach(propertyResolver);
return new DelegatingPropertyResolver(propertyResolver);
}
private static class DelegatingPropertyResolver implements PropertyResolver {
private final PropertyResolver delegate;
DelegatingPropertyResolver(PropertyResolver delegate) {
Assert.notNull(delegate, "The delegate of PropertyResolver must not be null");
this.delegate = delegate;
}
@Override
public boolean containsProperty(String key) {
return delegate.containsProperty(key);
}
@Override
@Nullable
public String getProperty(String key) {
return delegate.getProperty(key);
}
@Override
public String getProperty(String key, String defaultValue) {
return delegate.getProperty(key, defaultValue);
}
@Override
@Nullable
public <T> T getProperty(String key, Class<T> targetType) {
return delegate.getProperty(key, targetType);
}
@Override
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
return delegate.getProperty(key, targetType, defaultValue);
}
@Override
public String getRequiredProperty(String key) throws IllegalStateException {
return delegate.getRequiredProperty(key);
}
@Override
public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {
return delegate.getRequiredProperty(key, targetType);
}
@Override
public String resolvePlaceholders(String text) {
return delegate.resolvePlaceholders(text);
}
@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return delegate.resolveRequiredPlaceholders(text);
}
}
} }

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.client.loadbalancer; package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
import com.alibaba.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericException;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.client.loadbalancer; package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
import com.alibaba.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericException;
import org.springframework.cloud.alibaba.dubbo.http.converter.HttpMessageConverterHolder; import org.springframework.cloud.alibaba.dubbo.http.converter.HttpMessageConverterHolder;
import org.springframework.cloud.alibaba.dubbo.http.util.HttpMessageConverterResolver; import org.springframework.cloud.alibaba.dubbo.http.util.HttpMessageConverterResolver;
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;

@ -16,9 +16,8 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.client.loadbalancer; package org.springframework.cloud.alibaba.dubbo.client.loadbalancer;
import com.alibaba.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericException;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest; import org.springframework.cloud.alibaba.dubbo.http.MutableHttpServerRequest;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.DubboTransportedMetadata;

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.http; package org.springframework.cloud.alibaba.dubbo.http;
import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream; import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;

@ -30,16 +30,16 @@ import java.util.Set;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class ServiceRestMetadata { public class ServiceRestMetadata {
private String name; private String url;
private Set<RestMethodMetadata> meta; private Set<RestMethodMetadata> meta;
public String getName() { public String getUrl() {
return name; return url;
} }
public void setName(String name) { public void setUrl(String url) {
this.name = name; this.url = url;
} }
public Set<RestMethodMetadata> getMeta() { public Set<RestMethodMetadata> getMeta() {
@ -55,12 +55,12 @@ public class ServiceRestMetadata {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof ServiceRestMetadata)) return false; if (!(o instanceof ServiceRestMetadata)) return false;
ServiceRestMetadata that = (ServiceRestMetadata) o; ServiceRestMetadata that = (ServiceRestMetadata) o;
return Objects.equals(name, that.name) && return Objects.equals(url, that.url) &&
Objects.equals(meta, that.meta); Objects.equals(meta, that.meta);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(name, meta); return Objects.hash(url, meta);
} }
} }

@ -16,20 +16,18 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.metadata.resolver; package org.springframework.cloud.alibaba.dubbo.metadata.resolver;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.config.spring.ServiceBean;
import feign.Contract; import feign.Contract;
import feign.Feign; import feign.Feign;
import feign.MethodMetadata; import feign.MethodMetadata;
import feign.Util; import feign.Util;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.spring.ServiceBean;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -116,10 +114,10 @@ public class DubboServiceBeanMetadataResolver implements BeanClassLoaderAware, S
List<URL> urls = serviceBean.getExportedUrls(); List<URL> urls = serviceBean.getExportedUrls();
urls.stream() urls.stream()
.map(SpringCloudRegistry::getServiceName) .map(URL::toString)
.forEach(serviceName -> { .forEach(url -> {
ServiceRestMetadata metadata = new ServiceRestMetadata(); ServiceRestMetadata metadata = new ServiceRestMetadata();
metadata.setName(serviceName); metadata.setUrl(url);
metadata.setMeta(methodRestMetadata); metadata.setMeta(methodRestMetadata);
serviceRestMetadata.add(metadata); serviceRestMetadata.add(metadata);
}); });

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.metadata.resolver; package org.springframework.cloud.alibaba.dubbo.metadata.resolver;
import com.alibaba.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.ServiceBean;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.openfeign; package org.springframework.cloud.alibaba.dubbo.openfeign;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContext;
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory; import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceExecutionContextFactory;

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.openfeign; package org.springframework.cloud.alibaba.dubbo.openfeign;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
import java.lang.reflect.Method; import java.lang.reflect.Method;

@ -25,6 +25,7 @@ import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactor
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import static java.lang.reflect.Proxy.newProxyInstance; import static java.lang.reflect.Proxy.newProxyInstance;
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.TARGETER_CLASS_NAME;
import static org.springframework.util.ClassUtils.getUserClass; import static org.springframework.util.ClassUtils.getUserClass;
import static org.springframework.util.ClassUtils.isPresent; import static org.springframework.util.ClassUtils.isPresent;
import static org.springframework.util.ClassUtils.resolveClassName; import static org.springframework.util.ClassUtils.resolveClassName;
@ -36,8 +37,6 @@ import static org.springframework.util.ClassUtils.resolveClassName;
*/ */
public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLoaderAware { public class TargeterBeanPostProcessor implements BeanPostProcessor, BeanClassLoaderAware {
private static final String TARGETER_CLASS_NAME = "org.springframework.cloud.openfeign.Targeter";
private final Environment environment; private final Environment environment;
private final DubboServiceMetadataRepository dubboServiceMetadataRepository; private final DubboServiceMetadataRepository dubboServiceMetadataRepository;

@ -17,10 +17,9 @@
package org.springframework.cloud.alibaba.dubbo.openfeign; package org.springframework.cloud.alibaba.dubbo.openfeign;
import com.alibaba.dubbo.rpc.service.GenericService;
import feign.Contract; import feign.Contract;
import feign.Target; import feign.Target;
import org.apache.dubbo.rpc.service.GenericService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported; import org.springframework.cloud.alibaba.dubbo.annotation.DubboTransported;

@ -16,13 +16,13 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry; package org.springframework.cloud.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.Constants; import org.apache.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL; import org.apache.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.NetUtils; import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -30,20 +30,49 @@ import java.util.LinkedHashMap;
* Abstract {@link RegistrationFactory} implementation * Abstract {@link RegistrationFactory} implementation
* <p> * <p>
* *
* @param <T> The subclass of {@link Registration} * @param <R> The subclass of {@link Registration}
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
public abstract class AbstractRegistrationFactory<T extends Registration> implements RegistrationFactory<T> { public abstract class AbstractRegistrationFactory<R extends Registration> implements RegistrationFactory<R> {
public final R create(URL url, ConfigurableApplicationContext applicationContext) {
ServiceInstance serviceInstance = createServiceInstance(url, applicationContext);
return create(url, applicationContext, serviceInstance);
}
/**
* Sub-class should override this method to create an instance of {@link R}
*
* @param url The Dubbo's {@link URL}
* @param applicationContext {@link ConfigurableApplicationContext}
* @param serviceInstance {@link ServiceInstance}
* @return nullable
*/
protected abstract R create(URL url, ConfigurableApplicationContext applicationContext, ServiceInstance serviceInstance);
protected ServiceInstance createServiceInstance(String serviceName, URL url) { /**
* Create an instance {@link ServiceInstance}. This method maybe override by sub-class.
*
* @param url The Dubbo's {@link URL}
* @param applicationContext {@link ConfigurableApplicationContext}
* @return an instance {@link ServiceInstance}
*/
protected ServiceInstance createServiceInstance(URL url, ConfigurableApplicationContext applicationContext) {
String serviceId = createServiceId(url, applicationContext);
// Append default category if absent // Append default category if absent
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
URL newURL = url.addParameter(Constants.CATEGORY_KEY, category); URL newURL = url.addParameter(Constants.CATEGORY_KEY, category);
newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol()); newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol());
String ip = NetUtils.getLocalHost(); String ip = url.getIp();
int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort()); int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort());
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(url.toIdentityString(), serviceName, ip, port, false); DefaultServiceInstance serviceInstance = new DefaultServiceInstance(url.toIdentityString(), serviceId, ip, port, false);
serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters())); serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters()));
return serviceInstance; return serviceInstance;
} }
protected String createServiceId(URL url, ConfigurableApplicationContext applicationContext) {
DubboRegistryServiceIdHandler handler = applicationContext.getBean(DubboRegistryServiceIdHandler.class);
return handler.createServiceId(url);
}
} }

@ -16,10 +16,10 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry; package org.springframework.cloud.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
/** /**
* Default {@link RegistrationFactory} * Default {@link RegistrationFactory}
@ -29,7 +29,7 @@ import org.springframework.context.ApplicationContext;
public class DefaultRegistrationFactory extends AbstractRegistrationFactory<Registration> { public class DefaultRegistrationFactory extends AbstractRegistrationFactory<Registration> {
@Override @Override
public Registration create(String serviceName, URL url, ApplicationContext applicationContext) { protected Registration create(URL url, ConfigurableApplicationContext applicationContext, ServiceInstance serviceInstance) {
return new DelegatingRegistration(createServiceInstance(serviceName, url)); return new DelegatingRegistration(serviceInstance);
} }
} }

@ -16,27 +16,25 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry; package org.springframework.cloud.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
/** /**
* {@link Registration} Factory to createServiceInstance a instance of {@link Registration} * {@link Registration} Factory to createServiceInstance a instance of {@link Registration}
* *
* @param <T> The subclass of {@link Registration} * @param <R> The subclass of {@link Registration}
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
public interface RegistrationFactory<T extends Registration> { public interface RegistrationFactory<R extends Registration> {
/** /**
* Create a instance of {@link T} * Create a instance of {@link R}
* *
* @param serviceName The service name of Dubbo service interface * @param url The Dubbo's {@link URL}
* @param url The Dubbo's URL * @param applicationContext {@link ConfigurableApplicationContext}
* @param applicationContext {@link ApplicationContext} * @return a instance of {@link R}, if null, it indicates the registration will not be executed.
* @return a instance of {@link T}
*/ */
T create(String serviceName, URL url, ApplicationContext applicationContext); R create(URL url, ConfigurableApplicationContext applicationContext);
} }

@ -16,47 +16,37 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry; package org.springframework.cloud.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.Constants; import org.apache.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL; import org.apache.dubbo.common.URL;
import com.alibaba.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.UrlUtils;
import com.alibaba.dubbo.common.utils.UrlUtils; import org.apache.dubbo.registry.NotifyListener;
import com.alibaba.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.RegistryFactory;
import com.alibaba.dubbo.registry.RegistryFactory; import org.apache.dubbo.registry.support.FailbackRegistry;
import com.alibaba.dubbo.registry.support.FailbackRegistry;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.dubbo.registry.handler.DubboRegistryServiceIdHandler;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Map;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY; import static java.util.Collections.singletonList;
import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY; import static org.apache.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY; import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY;
import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY; import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY;
import static java.lang.Long.getLong; import static org.apache.dubbo.common.Constants.PROVIDER_SIDE;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; import static org.apache.dubbo.common.Constants.ROUTERS_CATEGORY;
import static org.springframework.beans.BeanUtils.instantiateClass; import static org.apache.dubbo.common.Constants.SIDE_KEY;
import static org.springframework.core.ResolvableType.forInstance;
import static org.springframework.core.ResolvableType.forType;
import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames;
import static org.springframework.util.ClassUtils.isPresent;
import static org.springframework.util.ClassUtils.resolveClassName;
/** /**
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
@ -66,305 +56,130 @@ import static org.springframework.util.ClassUtils.resolveClassName;
public class SpringCloudRegistry extends FailbackRegistry { public class SpringCloudRegistry extends FailbackRegistry {
/** /**
* All supported categories * The parameter name of {@link #allServicesLookupInterval}
*/ */
private static final String[] ALL_SUPPORTED_CATEGORIES = of( public static final String ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.all.services.lookup.interval";
PROVIDERS_CATEGORY,
CONSUMERS_CATEGORY,
ROUTERS_CATEGORY,
CONFIGURATORS_CATEGORY
);
private static final int CATEGORY_INDEX = 0;
private static final int SERVICE_INTERFACE_INDEX = CATEGORY_INDEX + 1;
private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1;
private static final String WILDCARD = "*";
/** /**
* The interval in second of lookup service names(only for Dubbo-OPS) * The parameter name of {@link #registeredServicesLookupInterval}
*/ */
private static final long ALL_SERVICES_LOOKUP_INTERVAL = getLong("dubbo.all.services.lookup.interval", 30); public static final String REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.registered.services.lookup.interval";
/** /**
* The interval in second of lookup regigered service instances * All supported categories
*/
private static final long REGISTERED_SERVICES_LOOKUP_INTERVAL = getLong("dubbo.registered.services.lookup.interval", 300);
/**
* The {@link ScheduledExecutorService Scheduler} to lookup the registered services
*/
private static final ScheduledExecutorService registeredServicesLookupScheduler = newSingleThreadScheduledExecutor(new NamedThreadFactory("dubbo-registered-services-lookup-"));
/**
* The {@link ScheduledExecutorService Scheduler} to lookup all services (only for Dubbo-OPS)
*/ */
private static volatile ScheduledExecutorService allServicesLookupScheduler; public static final String[] ALL_SUPPORTED_CATEGORIES = of(
PROVIDERS_CATEGORY,
CONSUMERS_CATEGORY,
ROUTERS_CATEGORY,
CONFIGURATORS_CATEGORY
);
private final Logger logger = LoggerFactory.getLogger(getClass()); private final Logger logger = LoggerFactory.getLogger(getClass());
/** /**
* The separator for service name * The interval in second of lookup service names(only for Dubbo-OPS)
*/ */
private static final String SERVICE_NAME_SEPARATOR = ":"; private final long allServicesLookupInterval;
private final ApplicationContext applicationContext; private final long registeredServicesLookupInterval;
private final ServiceRegistry<Registration> serviceRegistry; private final ServiceRegistry<Registration> serviceRegistry;
private final DiscoveryClient discoveryClient;
private final RegistrationFactory registrationFactory; private final RegistrationFactory registrationFactory;
public SpringCloudRegistry(URL url, ApplicationContext applicationContext) { private final DiscoveryClient discoveryClient;
super(url);
this.applicationContext = applicationContext;
this.serviceRegistry = applicationContext.getBean(ServiceRegistry.class);
this.registrationFactory = buildRegistrationFactory(serviceRegistry, applicationContext.getClassLoader());
this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
applicationContext.getClassLoader();
}
private RegistrationFactory buildRegistrationFactory(ServiceRegistry<Registration> serviceRegistry,
ClassLoader classLoader) {
RegistrationFactory registrationFactory = null;
List<String> factoryClassNames = loadFactoryNames(RegistrationFactory.class, classLoader);
ResolvableType serviceRegistryType = forInstance(serviceRegistry);
// Get first generic Class
Class<?> registrationClass = resolveGenericClass(serviceRegistryType, ServiceRegistry.class, 0);
for (String factoryClassName : factoryClassNames) {
if (isPresent(factoryClassName, classLoader)) { // ignore compilation issue
Class<?> factoryClass = resolveClassName(factoryClassName, classLoader);
ResolvableType registrationFactoryType = forType(factoryClass);
Class<?> actualRegistrationClass = resolveGenericClass(registrationFactoryType, RegistrationFactory.class, 0);
if (registrationClass.equals(actualRegistrationClass)) {
registrationFactory = (RegistrationFactory) instantiateClass(registrationFactoryType.getRawClass());
break;
}
}
}
if (registrationFactory == null) { private final DubboRegistryServiceIdHandler dubboRegistryServiceIdHandler;
if (logger.isWarnEnabled()) { private final ScheduledExecutorService servicesLookupScheduler;
logger.warn("{} implementation can't be resolved by ServiceRegistry[{}]",
registrationClass.getSimpleName(), serviceRegistry.getClass().getName());
}
registrationFactory = new DefaultRegistrationFactory(); private final ConfigurableApplicationContext applicationContext;
} else {
if (logger.isInfoEnabled()) {
logger.info("{} has been resolved by ServiceRegistry[{}]",
registrationFactory.getClass().getName(), serviceRegistry.getClass().getName());
}
}
return registrationFactory; public SpringCloudRegistry(URL url,
ServiceRegistry<Registration> serviceRegistry,
RegistrationFactory registrationFactory,
DiscoveryClient discoveryClient,
ScheduledExecutorService servicesLookupScheduler,
ConfigurableApplicationContext applicationContext) {
super(url);
this.allServicesLookupInterval = url.getParameter(ALL_SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 30L);
this.registeredServicesLookupInterval = url.getParameter(REGISTERED_SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 300L);
this.serviceRegistry = serviceRegistry;
this.registrationFactory = registrationFactory;
this.discoveryClient = discoveryClient;
this.dubboRegistryServiceIdHandler = applicationContext.getBean(DubboRegistryServiceIdHandler.class);
this.applicationContext = applicationContext;
this.servicesLookupScheduler = servicesLookupScheduler;
} }
private Class<?> resolveGenericClass(ResolvableType implementedType, Class<?> interfaceClass, int index) { protected boolean shouldRegister(Registration registration) {
Map<String, String> metadata = registration.getMetadata();
ResolvableType resolvableType = implementedType; String side = metadata.get(SIDE_KEY);
return PROVIDER_SIDE.equals(side); // Only register the Provider.
try {
OUTER:
while (true) {
ResolvableType[] interfaceTypes = resolvableType.getInterfaces();
for (ResolvableType interfaceType : interfaceTypes) {
if (interfaceType.resolve().equals(interfaceClass)) {
resolvableType = interfaceType;
break OUTER;
}
}
ResolvableType superType = resolvableType.getSuperType();
Class<?> superClass = superType.resolve();
if (Object.class.equals(superClass)) {
break;
}
resolvableType = superType;
}
} catch (Throwable e) {
resolvableType = ResolvableType.forType(void.class);
}
return resolvableType.resolveGeneric(index);
} }
@Override @Override
protected void doRegister(URL url) { public void doRegister(URL url) {
final String serviceName = getServiceName(url); final Registration registration = createRegistration(url);
final Registration registration = createRegistration(serviceName, url); if (shouldRegister(registration)) {
serviceRegistry.register(registration); serviceRegistry.register(registration);
}
} }
@Override @Override
protected void doUnregister(URL url) { public void doUnregister(URL url) {
final String serviceName = getServiceName(url); final Registration registration = createRegistration(url);
final Registration registration = createRegistration(serviceName, url); if (shouldRegister(registration)) {
this.serviceRegistry.deregister(registration); this.serviceRegistry.deregister(registration);
}
} }
@Override @Override
protected void doSubscribe(URL url, NotifyListener listener) { public void doSubscribe(URL url, NotifyListener listener) {
List<String> serviceNames = getServiceNames(url, listener); List<String> serviceNames = getServiceNames(url, listener);
doSubscribe(url, listener, serviceNames); doSubscribe(url, listener, serviceNames);
this.registeredServicesLookupScheduler.scheduleAtFixedRate(new Runnable() { this.servicesLookupScheduler.scheduleAtFixedRate(new Runnable() {
@Override @Override
public void run() { public void run() {
doSubscribe(url, listener, serviceNames); doSubscribe(url, listener, serviceNames);
} }
}, REGISTERED_SERVICES_LOOKUP_INTERVAL, REGISTERED_SERVICES_LOOKUP_INTERVAL, TimeUnit.SECONDS); }, registeredServicesLookupInterval, registeredServicesLookupInterval, TimeUnit.SECONDS);
} }
@Override @Override
protected void doUnsubscribe(URL url, NotifyListener listener) { public void doUnsubscribe(URL url, NotifyListener listener) {
if (isAdminProtocol(url)) { if (isAdminProtocol(url)) {
shutdownServiceNamesLookup(); shutdownServiceNamesLookup();
} }
// if (registeredServicesLookupScheduler != null) {
// registeredServicesLookupScheduler.shutdown();
// }
} }
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return false; return !discoveryClient.getServices().isEmpty();
} }
private void shutdownServiceNamesLookup() { private void shutdownServiceNamesLookup() {
if (allServicesLookupScheduler != null) { if (servicesLookupScheduler != null) {
allServicesLookupScheduler.shutdown(); servicesLookupScheduler.shutdown();
} }
} }
private Registration createRegistration(String serviceName, URL url) { private Registration createRegistration(URL url) {
return registrationFactory.create(serviceName, url, applicationContext); return registrationFactory.create(url, applicationContext);
}
public static String getServiceName(URL url) {
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
return getServiceName(url, category);
} }
private static String getServiceName(URL url, String category) { private void filterServiceNames(List<String> serviceNames) {
StringBuilder serviceNameBuilder = new StringBuilder(category);
appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
return serviceNameBuilder.toString();
}
private static void appendIfPresent(StringBuilder target, URL url, String parameterName) {
String parameterValue = url.getParameter(parameterName);
appendIfPresent(target, parameterValue);
}
private static void appendIfPresent(StringBuilder target, String parameterValue) {
if (StringUtils.hasText(parameterValue)) {
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
}
}
private void filterServiceNames(List<String> serviceNames, URL url) {
final String[] categories = getCategories(url);
final String targetServiceInterface = url.getServiceInterface();
final String targetVersion = url.getParameter(Constants.VERSION_KEY);
final String targetGroup = url.getParameter(Constants.GROUP_KEY);
filter(serviceNames, new Filter<String>() { filter(serviceNames, new Filter<String>() {
@Override @Override
public boolean accept(String serviceName) { public boolean accept(String serviceName) {
// split service name to segments return dubboRegistryServiceIdHandler.supports(serviceName);
// (required) segments[0] = category
// (required) segments[1] = serviceInterface
// (required) segments[2] = version
// (optional) segments[3] = group
String[] segments = getServiceSegments(serviceName);
int length = segments.length;
if (length < SERVICE_GROUP_INDEX) { // must present 4 segments or more
return false;
}
String category = getCategory(segments);
if (Arrays.binarySearch(categories, category) > -1) { // no match category
return false;
}
String serviceInterface = getServiceInterface(segments);
if (!WILDCARD.equals(targetServiceInterface) &&
!Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface
return false;
}
String version = getServiceVersion(segments);
if (!WILDCARD.equals(targetVersion) &&
!Objects.equals(targetVersion, version)) { // no match service version
return false;
}
String group = getServiceGroup(segments);
if (group != null && !WILDCARD.equals(targetGroup)
&& !Objects.equals(targetGroup, group)) { // no match service group
return false;
}
return true;
} }
}); });
} }
public static String[] getServiceSegments(String serviceName) {
return StringUtils.delimitedListToStringArray(serviceName, SERVICE_NAME_SEPARATOR);
}
public static String getCategory(String[] segments) {
return segments[CATEGORY_INDEX];
}
public static String getServiceInterface(String[] segments) {
return segments[SERVICE_INTERFACE_INDEX];
}
public static String getServiceVersion(String[] segments) {
return segments[SERVICE_VERSION_INDEX];
}
public static String getServiceGroup(String[] segments) {
return segments.length > SERVICE_GROUP_INDEX ? segments[SERVICE_GROUP_INDEX] : null;
}
/**
* Get the categories from {@link URL}
*
* @param url {@link URL}
* @return non-null array
*/
private String[] getCategories(URL url) {
return Constants.ANY_VALUE.equals(url.getServiceInterface()) ?
ALL_SUPPORTED_CATEGORIES : of(Constants.DEFAULT_CATEGORY);
}
private List<String> getAllServiceNames() { private List<String> getAllServiceNames() {
return discoveryClient.getServices(); return new LinkedList<>(discoveryClient.getServices());
} }
/** /**
@ -379,7 +194,7 @@ public class SpringCloudRegistry extends FailbackRegistry {
initAllServicesLookupScheduler(url, listener); initAllServicesLookupScheduler(url, listener);
return getServiceNamesForOps(url); return getServiceNamesForOps(url);
} else { } else {
return doGetServiceNames(url); return singletonList(dubboRegistryServiceIdHandler.createServiceId(url));
} }
} }
@ -389,30 +204,14 @@ public class SpringCloudRegistry extends FailbackRegistry {
} }
private void initAllServicesLookupScheduler(final URL url, final NotifyListener listener) { private void initAllServicesLookupScheduler(final URL url, final NotifyListener listener) {
if (allServicesLookupScheduler == null) { servicesLookupScheduler.scheduleAtFixedRate(new Runnable() {
allServicesLookupScheduler = newSingleThreadScheduledExecutor(new NamedThreadFactory("dubbo-all-services-lookup-")); @Override
allServicesLookupScheduler.scheduleAtFixedRate(new Runnable() { public void run() {
@Override List<String> serviceNames = getAllServiceNames();
public void run() { filterServiceNames(serviceNames);
List<String> serviceNames = getAllServiceNames(); doSubscribe(url, listener, serviceNames);
filter(serviceNames, new Filter<String>() { }
@Override }, allServicesLookupInterval, allServicesLookupInterval, TimeUnit.SECONDS);
public boolean accept(String serviceName) {
boolean accepted = false;
for (String category : ALL_SUPPORTED_CATEGORIES) {
String prefix = category + SERVICE_NAME_SEPARATOR;
if (StringUtils.startsWithIgnoreCase(serviceName, prefix)) {
accepted = true;
break;
}
}
return accepted;
}
});
doSubscribe(url, listener, serviceNames);
}
}, ALL_SERVICES_LOOKUP_INTERVAL, ALL_SERVICES_LOOKUP_INTERVAL, TimeUnit.SECONDS);
}
} }
private void doSubscribe(final URL url, final NotifyListener listener, final List<String> serviceNames) { private void doSubscribe(final URL url, final NotifyListener listener, final List<String> serviceNames) {
@ -422,16 +221,6 @@ public class SpringCloudRegistry extends FailbackRegistry {
} }
} }
private List<String> doGetServiceNames(URL url) {
String[] categories = getCategories(url);
List<String> serviceNames = new ArrayList<String>(categories.length);
for (String category : categories) {
final String serviceName = getServiceName(url, category);
serviceNames.add(serviceName);
}
return serviceNames;
}
/** /**
* Notify the Healthy {@link ServiceInstance service instance} to subscriber. * Notify the Healthy {@link ServiceInstance service instance} to subscriber.
* *
@ -488,7 +277,7 @@ public class SpringCloudRegistry extends FailbackRegistry {
*/ */
private List<String> getServiceNamesForOps(URL url) { private List<String> getServiceNamesForOps(URL url) {
List<String> serviceNames = getAllServiceNames(); List<String> serviceNames = getAllServiceNames();
filterServiceNames(serviceNames, url); filterServiceNames(serviceNames);
return serviceNames; return serviceNames;
} }
@ -509,7 +298,7 @@ public class SpringCloudRegistry extends FailbackRegistry {
/** /**
* A filter * A filter
*/ */
private interface Filter<T> { public interface Filter<T> {
/** /**
* Tests whether or not the specified data should be accepted. * Tests whether or not the specified data should be accepted.

@ -16,11 +16,29 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry; package org.springframework.cloud.alibaba.dubbo.registry;
import com.alibaba.dubbo.common.URL; import org.apache.dubbo.common.URL;
import com.alibaba.dubbo.registry.Registry; import org.apache.dubbo.common.utils.NamedThreadFactory;
import com.alibaba.dubbo.registry.RegistryFactory; import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.context.ApplicationContext; import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import static java.lang.System.getProperty;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.springframework.beans.BeanUtils.instantiateClass;
import static org.springframework.core.ResolvableType.forInstance;
import static org.springframework.core.ResolvableType.forType;
import static org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames;
import static org.springframework.util.ClassUtils.isPresent;
import static org.springframework.util.ClassUtils.resolveClassName;
/** /**
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud" * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
@ -31,14 +49,122 @@ import org.springframework.context.ApplicationContext;
*/ */
public class SpringCloudRegistryFactory implements RegistryFactory { public class SpringCloudRegistryFactory implements RegistryFactory {
private static ApplicationContext applicationContext; private static String SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX =
getProperty("dubbo.services.lookup.scheduler.thread.name.prefix ", "dubbo-services-lookup-");
private static ConfigurableApplicationContext applicationContext;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final ScheduledExecutorService servicesLookupScheduler;
private ServiceRegistry<Registration> serviceRegistry;
private RegistrationFactory registrationFactory;
private DiscoveryClient discoveryClient;
private volatile boolean initialized = false;
public SpringCloudRegistryFactory() {
servicesLookupScheduler = newSingleThreadScheduledExecutor(
new NamedThreadFactory(SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX));
}
protected void init() {
if (initialized || applicationContext == null) {
return;
}
this.serviceRegistry = applicationContext.getBean(ServiceRegistry.class);
this.registrationFactory = buildRegistrationFactory(serviceRegistry, applicationContext.getClassLoader());
this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
}
@Override @Override
public Registry getRegistry(URL url) { public Registry getRegistry(URL url) {
return new SpringCloudRegistry(url, applicationContext); init();
return new SpringCloudRegistry(url, serviceRegistry, registrationFactory, discoveryClient,
servicesLookupScheduler, applicationContext);
} }
public static void setApplicationContext(ApplicationContext applicationContext) { public static void setApplicationContext(ConfigurableApplicationContext applicationContext) {
SpringCloudRegistryFactory.applicationContext = applicationContext; SpringCloudRegistryFactory.applicationContext = applicationContext;
} }
private RegistrationFactory buildRegistrationFactory(ServiceRegistry<Registration> serviceRegistry,
ClassLoader classLoader) {
RegistrationFactory registrationFactory = null;
List<String> factoryClassNames = loadFactoryNames(RegistrationFactory.class, classLoader);
ResolvableType serviceRegistryType = forInstance(serviceRegistry);
// Get first generic Class
Class<?> registrationClass = resolveGenericClass(serviceRegistryType, ServiceRegistry.class, 0);
for (String factoryClassName : factoryClassNames) {
if (isPresent(factoryClassName, classLoader)) { // ignore compilation issue
Class<?> factoryClass = resolveClassName(factoryClassName, classLoader);
ResolvableType registrationFactoryType = forType(factoryClass);
Class<?> actualRegistrationClass = resolveGenericClass(registrationFactoryType, RegistrationFactory.class, 0);
if (registrationClass.equals(actualRegistrationClass)) {
registrationFactory = (RegistrationFactory) instantiateClass(registrationFactoryType.getRawClass());
break;
}
}
}
if (registrationFactory == null) {
if (logger.isWarnEnabled()) {
logger.warn("{} implementation can't be resolved by ServiceRegistry[{}]",
registrationClass.getSimpleName(), serviceRegistry.getClass().getName());
}
registrationFactory = new DefaultRegistrationFactory();
} else {
if (logger.isInfoEnabled()) {
logger.info("{} has been resolved by ServiceRegistry[{}]",
registrationFactory.getClass().getName(), serviceRegistry.getClass().getName());
}
}
return registrationFactory;
}
private Class<?> resolveGenericClass(ResolvableType implementedType, Class<?> interfaceClass, int index) {
ResolvableType resolvableType = implementedType;
try {
OUTER:
while (true) {
ResolvableType[] interfaceTypes = resolvableType.getInterfaces();
for (ResolvableType interfaceType : interfaceTypes) {
if (interfaceType.resolve().equals(interfaceClass)) {
resolvableType = interfaceType;
break OUTER;
}
}
ResolvableType superType = resolvableType.getSuperType();
Class<?> superClass = superType.resolve();
if (Object.class.equals(superClass)) {
break;
}
resolvableType = superType;
}
} catch (Throwable e) {
resolvableType = ResolvableType.forType(void.class);
}
return resolvableType.resolveGeneric(index);
}
} }

@ -16,15 +16,14 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper; package org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper;
import com.alibaba.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory; import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory;
import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory; import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.zookeeper.discovery.ZookeeperInstance; import org.springframework.cloud.zookeeper.discovery.ZookeeperInstance;
import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegistration; import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegistration;
import org.springframework.cloud.zookeeper.serviceregistry.ZookeeperRegistration; import org.springframework.cloud.zookeeper.serviceregistry.ZookeeperRegistration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
/** /**
* Zookeeper {@link RegistrationFactory} * Zookeeper {@link RegistrationFactory}
@ -34,10 +33,7 @@ import org.springframework.context.ApplicationContext;
public class ZookeeperRegistrationFactory extends AbstractRegistrationFactory<ZookeeperRegistration> { public class ZookeeperRegistrationFactory extends AbstractRegistrationFactory<ZookeeperRegistration> {
@Override @Override
public ZookeeperRegistration create(String serviceName, URL url, ApplicationContext applicationContext) { protected ZookeeperRegistration create(URL url, ConfigurableApplicationContext applicationContext, ServiceInstance serviceInstance) {
ServiceInstance serviceInstance = createServiceInstance(serviceName, url);
ZookeeperInstance zookeeperInstance = new ZookeeperInstance(serviceInstance.getInstanceId(), ZookeeperInstance zookeeperInstance = new ZookeeperInstance(serviceInstance.getInstanceId(),
serviceInstance.getServiceId(), serviceInstance.getMetadata()); serviceInstance.getServiceId(), serviceInstance.getMetadata());

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* 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.dubbo.registry.handler;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.registry.Registry;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Dubbo {@link Registry} Spring Cloud Service Id Builder
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public interface DubboRegistryServiceIdHandler {
/**
* Supports the specified id of Spring Cloud Service or not
*
* @param serviceId the specified id of Spring Cloud Service
* @return if supports, return <code>true</code>, or <code>false</code>
*/
boolean supports(String serviceId);
/**
* Creates the id of Spring Cloud Service
*
* @param url The Dubbo's {@link URL}
* @return non-null
*/
String createServiceId(URL url);
/**
* The instance if {@link ConfigurableApplicationContext} .
*
* @return non-null
*/
ConfigurableApplicationContext getContext();
}

@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* 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.dubbo.registry.handler;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
import java.util.Objects;
import static java.lang.System.getProperty;
import static org.apache.dubbo.common.Constants.CONSUMERS_CATEGORY;
import static org.apache.dubbo.common.Constants.PROVIDERS_CATEGORY;
import static org.springframework.util.StringUtils.startsWithIgnoreCase;
/**
* The Standard {@link DubboRegistryServiceIdHandler}
* <p>
* The service ID pattern is "${category}:${interface}:${version}:${group}"
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/
public class StandardDubboRegistryServiceIdHandler implements DubboRegistryServiceIdHandler {
/**
* The separator for service name that could be changed by the Java Property "dubbo.service.name.separator".
*/
protected static final String SERVICE_NAME_SEPARATOR = getProperty("dubbo.service.name.separator", ":");
private final ConfigurableApplicationContext context;
public StandardDubboRegistryServiceIdHandler(ConfigurableApplicationContext context) {
this.context = context;
}
@Override
public boolean supports(String serviceId) {
return startsWithIgnoreCase(serviceId, PROVIDERS_CATEGORY) ||
startsWithIgnoreCase(serviceId, CONSUMERS_CATEGORY);
}
@Override
public String createServiceId(URL url) {
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
if (!Objects.equals(category, PROVIDERS_CATEGORY) && !Objects.equals(category, CONSUMERS_CATEGORY)) {
category = PROVIDERS_CATEGORY;
}
return createServiceId(url, category);
}
@Override
public ConfigurableApplicationContext getContext() {
return context;
}
/**
* This method maybe override by sub-class.
*
* @param url The Dubbo's {@link URL}
* @param category The category
* @return
*/
protected String createServiceId(URL url, String category) {
StringBuilder serviceNameBuilder = new StringBuilder(category);
appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
return serviceNameBuilder.toString();
}
private static void appendIfPresent(StringBuilder target, URL url, String parameterName) {
String parameterValue = url.getParameter(parameterName);
appendIfPresent(target, parameterValue);
}
private static void appendIfPresent(StringBuilder target, String parameterValue) {
if (StringUtils.hasText(parameterValue)) {
target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
}
}
}

@ -16,16 +16,15 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul; package org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul;
import com.alibaba.dubbo.common.URL;
import com.ecwid.consul.v1.agent.model.NewService; import com.ecwid.consul.v1.agent.model.NewService;
import org.apache.dubbo.common.URL;
import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory; import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory;
import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory; import org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties; import org.springframework.cloud.consul.discovery.ConsulDiscoveryProperties;
import org.springframework.cloud.consul.discovery.ConsulServerUtils; import org.springframework.cloud.consul.discovery.ConsulServerUtils;
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration; import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.LinkedList; import java.util.LinkedList;
@ -41,9 +40,7 @@ import java.util.Set;
public class ConsulRegistrationFactory extends AbstractRegistrationFactory<ConsulRegistration> { public class ConsulRegistrationFactory extends AbstractRegistrationFactory<ConsulRegistration> {
@Override @Override
public ConsulRegistration create(String serviceName, URL url, ApplicationContext applicationContext) { protected ConsulRegistration create(URL url, ConfigurableApplicationContext applicationContext, ServiceInstance serviceInstance) {
ServiceInstance serviceInstance = createServiceInstance(serviceName, url);
Map<String, String> metadata = getMetadata(serviceInstance); Map<String, String> metadata = getMetadata(serviceInstance);
List<String> tags = createTags(metadata); List<String> tags = createTags(metadata);

@ -16,10 +16,9 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka; package org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka;
import com.alibaba.dubbo.common.URL;
import com.netflix.appinfo.HealthCheckHandler; import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.discovery.EurekaClientConfig; import com.netflix.discovery.EurekaClientConfig;
import org.apache.dubbo.common.URL;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory; import org.springframework.cloud.alibaba.dubbo.registry.AbstractRegistrationFactory;
@ -28,7 +27,7 @@ import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig; import org.springframework.cloud.netflix.eureka.CloudEurekaInstanceConfig;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
/** /**
* {@link EurekaRegistration} Factory * {@link EurekaRegistration} Factory
@ -38,8 +37,7 @@ import org.springframework.context.ApplicationContext;
public class EurekaRegistrationFactory extends AbstractRegistrationFactory<EurekaRegistration> { public class EurekaRegistrationFactory extends AbstractRegistrationFactory<EurekaRegistration> {
@Override @Override
public EurekaRegistration create(String serviceName, URL url, ApplicationContext applicationContext) { protected EurekaRegistration create(URL url, ConfigurableApplicationContext applicationContext, ServiceInstance serviceInstance) {
ServiceInstance serviceInstance = createServiceInstance(serviceName, url);
CloudEurekaInstanceConfig cloudEurekaInstanceConfig = applicationContext.getBean(CloudEurekaInstanceConfig.class); CloudEurekaInstanceConfig cloudEurekaInstanceConfig = applicationContext.getBean(CloudEurekaInstanceConfig.class);
ObjectProvider<HealthCheckHandler> healthCheckHandler = applicationContext.getBeanProvider(HealthCheckHandler.class); ObjectProvider<HealthCheckHandler> healthCheckHandler = applicationContext.getBeanProvider(HealthCheckHandler.class);
EurekaClientConfig eurekaClientConfig = applicationContext.getBean(EurekaClientConfig.class); EurekaClientConfig eurekaClientConfig = applicationContext.getBean(EurekaClientConfig.class);

@ -16,7 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.service; package org.springframework.cloud.alibaba.dubbo.service;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.service.GenericService;
/** /**
* Dubbo {@link GenericService} execution context * Dubbo {@link GenericService} execution context

@ -16,9 +16,9 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.service; package org.springframework.cloud.alibaba.dubbo.service;
import com.alibaba.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.common.URL;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.rpc.service.GenericService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.DubboServiceMetadata;
@ -31,12 +31,10 @@ import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import static com.alibaba.dubbo.common.Constants.DEFAULT_CLUSTER; import static org.apache.dubbo.common.Constants.DEFAULT_CLUSTER;
import static com.alibaba.dubbo.common.Constants.DEFAULT_PROTOCOL; import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceGroup; import static org.apache.dubbo.common.Constants.GROUP_KEY;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceInterface; import static org.apache.dubbo.common.Constants.VERSION_KEY;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceSegments;
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceVersion;
/** /**
* Dubbo {@link GenericService} Factory * Dubbo {@link GenericService} Factory
@ -67,11 +65,11 @@ public class DubboGenericServiceFactory {
private ReferenceBean<GenericService> build(ServiceRestMetadata serviceRestMetadata, private ReferenceBean<GenericService> build(ServiceRestMetadata serviceRestMetadata,
DubboTransportedMetadata dubboTransportedMetadata) { DubboTransportedMetadata dubboTransportedMetadata) {
String dubboServiceName = serviceRestMetadata.getName(); String urlValue = serviceRestMetadata.getUrl();
String[] segments = getServiceSegments(dubboServiceName); URL url = URL.valueOf(urlValue);
String interfaceName = getServiceInterface(segments); String interfaceName = url.getServiceInterface();
String version = getServiceVersion(segments); String version = url.getParameter(VERSION_KEY);
String group = getServiceGroup(segments); String group = url.getParameter(GROUP_KEY);
String protocol = dubboTransportedMetadata.getProtocol(); String protocol = dubboTransportedMetadata.getProtocol();
String cluster = dubboTransportedMetadata.getCluster(); String cluster = dubboTransportedMetadata.getCluster();

@ -16,7 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.service; package org.springframework.cloud.alibaba.dubbo.service;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.service.GenericService;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;

@ -16,8 +16,6 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.service; package org.springframework.cloud.alibaba.dubbo.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializationFeature;
@ -28,15 +26,13 @@ import javax.annotation.PostConstruct;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration.METADATA_PROTOCOL_BEAN_NAME; import static org.springframework.util.ObjectUtils.isEmpty;
/** /**
* Publishing {@link DubboMetadataConfigService} implementation * Publishing {@link DubboMetadataConfigService} implementation
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
@Service(version = "${spring.application.name}", protocol = METADATA_PROTOCOL_BEAN_NAME)
// Use current Spring application name as the Dubbo Service version
public class PublishingDubboMetadataConfigService implements DubboMetadataConfigService { public class PublishingDubboMetadataConfigService implements DubboMetadataConfigService {
/** /**
@ -69,7 +65,9 @@ public class PublishingDubboMetadataConfigService implements DubboMetadataConfig
public String getServiceRestMetadata() { public String getServiceRestMetadata() {
String serviceRestMetadataJsonConfig = null; String serviceRestMetadataJsonConfig = null;
try { try {
serviceRestMetadataJsonConfig = objectMapper.writeValueAsString(serviceRestMetadata); if (!isEmpty(serviceRestMetadata)) {
serviceRestMetadataJsonConfig = objectMapper.writeValueAsString(serviceRestMetadata);
}
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.service.parameter; package org.springframework.cloud.alibaba.dubbo.service.parameter;
import com.alibaba.dubbo.rpc.service.GenericService; import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.cloud.alibaba.dubbo.http.HttpServerRequest; import org.springframework.cloud.alibaba.dubbo.http.HttpServerRequest;
import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata;
import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata; import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;

@ -1,7 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataEventHandlingAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration,\
org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceAutoConfiguration
@ -9,7 +9,6 @@ org.springframework.context.ApplicationContextInitializer=\
org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory=\ org.springframework.cloud.alibaba.dubbo.registry.RegistrationFactory=\
org.springframework.cloud.alibaba.dubbo.registry.DefaultRegistrationFactory,\
org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka.EurekaRegistrationFactory,\ org.springframework.cloud.alibaba.dubbo.registry.netflix.eureka.EurekaRegistrationFactory,\
org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper.ZookeeperRegistrationFactory,\ org.springframework.cloud.alibaba.dubbo.registry.apache.zookeeper.ZookeeperRegistrationFactory,\
org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul.ConsulRegistrationFactory org.springframework.cloud.alibaba.dubbo.registry.hashicorp.consul.ConsulRegistrationFactory

@ -5,5 +5,5 @@ mysql.server.ip=127.0.0.1
mysql.server.port=3306 mysql.server.port=3306
mysql.db.name=demo mysql.db.name=demo
mysql.user.name=xxxxx mysql.user.name=root
mysql.user.password=xxxxx mysql.user.password=123456

@ -16,11 +16,6 @@
package org.springframework.cloud.alibaba.cloud.examples; package org.springframework.cloud.alibaba.cloud.examples;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
import com.alibaba.fescar.core.context.RootContext; import com.alibaba.fescar.core.context.RootContext;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -40,92 +35,97 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
/** /**
* @author xiaojing * @author xiaojing
*/ */
@RestController @RestController
public class OrderController { public class OrderController {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class); private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class);
private static final String SUCCESS = "SUCCESS"; private static final String SUCCESS = "SUCCESS";
private static final String FAIL = "FAIL"; private static final String FAIL = "FAIL";
private static final String USER_ID = "U100001"; private static final String USER_ID = "U100001";
private static final String COMMODITY_CODE = "C00321"; private static final String COMMODITY_CODE = "C00321";
private final JdbcTemplate jdbcTemplate; private final JdbcTemplate jdbcTemplate;
private final RestTemplate restTemplate; private final RestTemplate restTemplate;
private Random random; private Random random;
public OrderController(JdbcTemplate jdbcTemplate, RestTemplate restTemplate) { public OrderController(JdbcTemplate jdbcTemplate, RestTemplate restTemplate) {
this.jdbcTemplate = jdbcTemplate; this.jdbcTemplate = jdbcTemplate;
this.restTemplate = restTemplate; this.restTemplate = restTemplate;
this.random = new Random(); this.random = new Random();
} }
@RequestMapping(value = "/order", method = RequestMethod.POST, produces = "application/json") @RequestMapping(value = "/order", method = RequestMethod.POST, produces = "application/json")
public String order(String userId, String commodityCode, int orderCount) { public String order(String userId, String commodityCode, int orderCount) {
LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID()); LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
int orderMoney = calculate(commodityCode, orderCount); int orderMoney = calculate(commodityCode, orderCount);
invokerAccountService(orderMoney); invokerAccountService(orderMoney);
final Order order = new Order(); final Order order = new Order();
order.userId = userId; order.userId = userId;
order.commodityCode = commodityCode; order.commodityCode = commodityCode;
order.count = orderCount; order.count = orderCount;
order.money = orderMoney; order.money = orderMoney;
KeyHolder keyHolder = new GeneratedKeyHolder(); KeyHolder keyHolder = new GeneratedKeyHolder();
int result = jdbcTemplate.update(new PreparedStatementCreator() { int result = jdbcTemplate.update(new PreparedStatementCreator() {
@Override @Override
public PreparedStatement createPreparedStatement(Connection con) public PreparedStatement createPreparedStatement(Connection con)
throws SQLException { throws SQLException {
PreparedStatement pst = con.prepareStatement( PreparedStatement pst = con.prepareStatement(
"insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)", "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
PreparedStatement.RETURN_GENERATED_KEYS); PreparedStatement.RETURN_GENERATED_KEYS);
pst.setObject(1, order.userId); pst.setObject(1, order.userId);
pst.setObject(2, order.commodityCode); pst.setObject(2, order.commodityCode);
pst.setObject(3, order.count); pst.setObject(3, order.count);
pst.setObject(4, order.money); pst.setObject(4, order.money);
return pst; return pst;
} }
}, keyHolder); }, keyHolder);
order.id = (long) keyHolder.getKey(); order.id = keyHolder.getKey().longValue();
if (random.nextBoolean()) { // if (random.nextBoolean()) {
throw new RuntimeException("this is a mock Exception"); // throw new RuntimeException("this is a mock Exception");
} // }
LOGGER.info("Order Service End ... Created " + order); LOGGER.info("Order Service End ... Created " + order);
if (result == 1) { if (result == 1) {
return SUCCESS; return SUCCESS;
} }
return FAIL; return FAIL;
} }
private int calculate(String commodityId, int orderCount) { private int calculate(String commodityId, int orderCount) {
return 2 * orderCount; return 2 * orderCount;
} }
private void invokerAccountService(int orderMoney) { private void invokerAccountService(int orderMoney) {
String url = "http://127.0.0.1:18084/account"; String url = "http://127.0.0.1:18084/account";
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>(); MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("userId", USER_ID); map.add("userId", USER_ID);
map.add("money", orderMoney + ""); map.add("money", orderMoney + "");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>( HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(
map, headers); map, headers);
ResponseEntity<String> response = restTemplate.postForEntity(url, request, ResponseEntity<String> response = restTemplate.postForEntity(url, request,
String.class); String.class);
} }
} }

@ -5,5 +5,5 @@ mysql.server.ip=127.0.0.1
mysql.server.port=3306 mysql.server.port=3306
mysql.db.name=demo mysql.db.name=demo
mysql.user.name=xxxxx mysql.user.name=root
mysql.user.password=xxxxx mysql.user.password=123456

@ -5,5 +5,5 @@ mysql.server.ip=127.0.0.1
mysql.server.port=3306 mysql.server.port=3306
mysql.db.name=demo mysql.db.name=demo
mysql.user.name=xxxxx mysql.user.name=root
mysql.user.password=xxxxx mysql.user.password=123456

@ -19,7 +19,6 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId> <artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.0.2.RELEASE</version>
</dependency> </dependency>
<dependency> <dependency>

@ -3,47 +3,22 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>alibaba.com</groupId>
<artifactId>sms-example</artifactId> <artifactId>sms-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>Example demonstrating how to use alicloud sms</description>
<name>sms-example</name>
<description>Demo project for Spring Boot</description>
<parent> <parent>
<groupId>org.springframework.boot</groupId> <artifactId>spring-cloud-alibaba-examples</artifactId>
<artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.cloud</groupId>
<version>2.0.6.RELEASE</version> <version>0.2.2.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
<spring-cloud-alibaba-alicloud.version>0.2.2.BUILD-SNAPSHOT</spring-cloud-alibaba-alicloud.version>
</properties> </properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-alicloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies> <dependencies>
<!--Spring Boot --> <!--Spring Boot -->
@ -59,11 +34,6 @@
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-sms</artifactId> <artifactId>spring-cloud-starter-alicloud-sms</artifactId>
</dependency> </dependency>
<dependency>
<groupId>alibaba.com</groupId>
<artifactId>env-extension</artifactId>
<version>0.2.2.BUILD-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -72,6 +42,14 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>

@ -15,7 +15,6 @@
*/ */
package org.springframework.cloud.alibaba.cloud.example; package org.springframework.cloud.alibaba.cloud.example;
import org.springframework.alicloud.env.extension.ImportExtraConfig;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -23,7 +22,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* *
*/ */
@SpringBootApplication @SpringBootApplication
@ImportExtraConfig(name = "/Users/toava/sms.properties")
public class SmsApplication { public class SmsApplication {
public static void main(String[] args) throws Exception{ public static void main(String[] args) throws Exception{

@ -1,4 +1,9 @@
spring.application.name=sca-sms-example spring.application.name=sca-sms-example
server.port=9051 server.port=9051
# config management # config sms
spring.cloud.alicloud.access-key=*****
spring.cloud.alicloud.secret-key=******
spring.cloud.alicloud.sms.report-queue-name=*****
spring.cloud.alicloud.sms.up-queue-name=*****
#config endpoint
management.endpoints.web.exposure.include=* management.endpoints.web.exposure.include=*

@ -22,9 +22,7 @@
</modules> </modules>
<properties> <properties>
<dubbo.version>2.6.5</dubbo.version> <dubbo.version>2.7.0</dubbo.version>
<dubbo-spring-boot.version>0.2.1.RELEASE</dubbo-spring-boot.version>
<dubbo-registry-nacos.version>0.0.2</dubbo-registry-nacos.version>
<spring-cloud-zookeeper.version>2.1.0.RELEASE</spring-cloud-zookeeper.version> <spring-cloud-zookeeper.version>2.1.0.RELEASE</spring-cloud-zookeeper.version>
<spring-cloud-consul.version>2.1.0.RELEASE</spring-cloud-consul.version> <spring-cloud-consul.version>2.1.0.RELEASE</spring-cloud-consul.version>
<curator.version>4.0.1</curator.version> <curator.version>4.0.1</curator.version>
@ -44,7 +42,7 @@
<!-- Apache Dubbo dependencies--> <!-- Apache Dubbo dependencies-->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId> <artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version> <version>${dubbo.version}</version>
<type>pom</type> <type>pom</type>

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.bootstrap; package org.springframework.cloud.alibaba.dubbo.bootstrap;
import com.alibaba.dubbo.config.annotation.Reference; import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationRunner; import org.springframework.boot.ApplicationRunner;
@ -95,7 +94,7 @@ public class DubboSpringCloudConsumerBootstrap {
} }
@FeignClient("${provider.application.name}") @FeignClient("${provider.application.name}")
@DubboTransported @DubboTransported()
public interface DubboFeignRestService { public interface DubboFeignRestService {
@GetMapping(value = "/param") @GetMapping(value = "/param")

@ -1,5 +1,8 @@
dubbo: dubbo:
registry: registry:
address: spring-cloud://nacos # The Spring Cloud Dubbo's registry extension
address: spring-cloud://localhost
# The traditional Dubbo's registry
# address: zookeeper://127.0.0.1:2181
server: server:
port: 7070 port: 7070

@ -16,8 +16,7 @@
*/ */
package org.springframework.cloud.alibaba.dubbo.service; package org.springframework.cloud.alibaba.dubbo.service;
import com.alibaba.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -48,7 +47,7 @@ import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
*/ */
@com.alibaba.dubbo.config.annotation.Service(version = "1.0.0", protocol = {"dubbo", "rest"}) @org.apache.dubbo.config.annotation.Service(version = "1.0.0", protocol = {"dubbo", "rest"})
@RestController @RestController
@Path("/") @Path("/")
public class StandardRestService implements RestService { public class StandardRestService implements RestService {

@ -10,7 +10,10 @@ dubbo:
port: 8081 port: 8081
server: netty server: netty
registry: registry:
address: spring-cloud://nacos # The Spring Cloud Dubbo's registry extension
address: spring-cloud://localhost
# The traditional Dubbo's registry
# address: zookeeper://127.0.0.1:2181
feign: feign:
hystrix: hystrix:

@ -4,6 +4,7 @@ spring:
main: main:
allow-bean-definition-overriding: true allow-bean-definition-overriding: true
# default disable all # default disable all
cloud: cloud:
nacos: nacos:

@ -31,18 +31,17 @@
package org.springframework.cloud.alibaba.fescar.rest; package org.springframework.cloud.alibaba.fescar.rest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** /**
* @author xiaojing * @author xiaojing
*/ */

@ -122,8 +122,6 @@ public class NacosConfigProperties {
private String name; private String name;
private String[] activeProfiles;
/** /**
* the dataids for configurable multiple shared configurations , multiple separated by * the dataids for configurable multiple shared configurations , multiple separated by
* commas . * commas .
@ -145,11 +143,6 @@ public class NacosConfigProperties {
@Autowired @Autowired
private Environment environment; private Environment environment;
@PostConstruct
public void init() {
this.activeProfiles = environment.getActiveProfiles();
}
// todo sts support // todo sts support
public boolean isEnabled() { public boolean isEnabled() {
@ -260,10 +253,6 @@ public class NacosConfigProperties {
return name; return name;
} }
public String[] getActiveProfiles() {
return activeProfiles;
}
public String getSharedDataids() { public String getSharedDataids() {
return sharedDataids; return sharedDataids;
} }
@ -292,10 +281,6 @@ public class NacosConfigProperties {
this.name = name; this.name = name;
} }
public void setActiveProfiles(String[] activeProfiles) {
this.activeProfiles = activeProfiles;
}
public static class Config { public static class Config {
/** /**
* the data id of extended configuration * the data id of extended configuration
@ -344,8 +329,7 @@ public class NacosConfigProperties {
+ endpoint + '\'' + ", namespace='" + namespace + '\'' + ", accessKey='" + endpoint + '\'' + ", namespace='" + namespace + '\'' + ", accessKey='"
+ accessKey + '\'' + ", secretKey='" + secretKey + '\'' + accessKey + '\'' + ", secretKey='" + secretKey + '\''
+ ", contextPath='" + contextPath + '\'' + ", clusterName='" + clusterName + ", contextPath='" + contextPath + '\'' + ", clusterName='" + clusterName
+ '\'' + ", name='" + name + '\'' + ", activeProfiles=" + '\'' + ", name='" + name + '\'' + ", sharedDataids='" + sharedDataids
+ Arrays.toString(activeProfiles) + ", sharedDataids='" + sharedDataids
+ '\'' + ", refreshableDataids='" + refreshableDataids + '\'' + '\'' + ", refreshableDataids='" + refreshableDataids + '\''
+ ", extConfig=" + extConfig + '}'; + ", extConfig=" + extConfig + '}';
} }

@ -71,7 +71,6 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
timeout); timeout);
String name = nacosConfigProperties.getName(); String name = nacosConfigProperties.getName();
String nacosGroup = nacosConfigProperties.getGroup();
String dataIdPrefix = nacosConfigProperties.getPrefix(); String dataIdPrefix = nacosConfigProperties.getPrefix();
if (StringUtils.isEmpty(dataIdPrefix)) { if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = name; dataIdPrefix = name;
@ -81,17 +80,12 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
dataIdPrefix = env.getProperty("spring.application.name"); dataIdPrefix = env.getProperty("spring.application.name");
} }
List<String> profiles = Arrays.asList(env.getActiveProfiles());
nacosConfigProperties.setActiveProfiles(profiles.toArray(new String[0]));
String fileExtension = nacosConfigProperties.getFileExtension();
CompositePropertySource composite = new CompositePropertySource( CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME); NACOS_PROPERTY_SOURCE_NAME);
loadSharedConfiguration(composite); loadSharedConfiguration(composite);
loadExtConfiguration(composite); loadExtConfiguration(composite);
loadApplicationConfiguration(composite, nacosGroup, dataIdPrefix, fileExtension); loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
return composite; return composite;
} }
@ -152,11 +146,15 @@ public class NacosPropertySourceLocator implements PropertySourceLocator {
} }
private void loadApplicationConfiguration( private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, String nacosGroup, CompositePropertySource compositePropertySource, String dataIdPrefix,
String dataIdPrefix, String fileExtension) { NacosConfigProperties properties, Environment environment) {
String fileExtension = properties.getFileExtension();
String nacosGroup = properties.getGroup();
loadNacosDataIfPresent(compositePropertySource, loadNacosDataIfPresent(compositePropertySource,
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true); dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
for (String profile : nacosConfigProperties.getActiveProfiles()) { for (String profile : environment.getActiveProfiles()) {
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension; String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension, true); fileExtension, true);

@ -16,15 +16,12 @@
package org.springframework.cloud.alibaba.nacos; package org.springframework.cloud.alibaba.nacos;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map;
import com.alibaba.nacos.client.config.NacosConfigService; import com.alibaba.nacos.client.config.NacosConfigService;
import org.junit.Assert; import org.junit.Assert;
@ -42,7 +39,6 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator; import org.springframework.cloud.alibaba.nacos.client.NacosPropertySourceLocator;
import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration; import org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration;
import org.springframework.cloud.alibaba.nacos.refresh.NacosRefreshHistory;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;

@ -163,13 +163,10 @@ public class NacosConfigurationTests {
checkoutNacosConfigFileExtension(); checkoutNacosConfigFileExtension();
checkoutNacosConfigTimeout(); checkoutNacosConfigTimeout();
checkoutNacosConfigEncode(); checkoutNacosConfigEncode();
checkoutNacosConfigProfiles();
checkoutNacosConfigExtConfig();
checkoutEndpoint(); checkoutEndpoint();
checkoutDataLoad();
Assert.assertEquals(environment.getProperty("user.name"), "dev");
Assert.assertEquals(environment.getProperty("user.age"), "12");
} }
private void checkoutNacosConfigServerAddr() { private void checkoutNacosConfigServerAddr() {
@ -235,20 +232,10 @@ public class NacosConfigurationTests {
properties.getEncode()); properties.getEncode());
} }
private void checkoutNacosConfigExtConfig() { private void checkoutDataLoad() {
assertEquals("NacosConfigProperties' ext config is wrong",
"ext-config-common01.properties",
properties.getExtConfig().get(0).getDataId());
assertEquals("NacosConfigProperties' ext config is wrong",
"ext-config-common02.properties",
properties.getExtConfig().get(1).getDataId());
assertEquals("NacosConfigProperties' ext config is wrong", "GLOBAL_GROUP",
properties.getExtConfig().get(1).getGroup());
}
private void checkoutNacosConfigProfiles() { Assert.assertEquals(environment.getProperty("user.name"), "dev");
assertEquals("NacosConfigProperties' profiles is wrong", Assert.assertEquals(environment.getProperty("user.age"), "12");
new String[] { "dev", "test" }, properties.getActiveProfiles());
} }
private void checkoutEndpoint() throws Exception { private void checkoutEndpoint() throws Exception {

@ -18,6 +18,7 @@ package org.springframework.cloud.alibaba.nacos.discovery;
import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView; import com.alibaba.nacos.api.naming.pojo.ListView;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties; import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
@ -25,7 +26,11 @@ import org.springframework.cloud.alibaba.nacos.NacosServiceInstance;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.DiscoveryClient;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author xiaojing * @author xiaojing
@ -33,75 +38,74 @@ import java.util.*;
*/ */
public class NacosDiscoveryClient implements DiscoveryClient { public class NacosDiscoveryClient implements DiscoveryClient {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(NacosDiscoveryClient.class); .getLogger(NacosDiscoveryClient.class);
public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client"; public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";
private NacosDiscoveryProperties discoveryProperties; private NacosDiscoveryProperties discoveryProperties;
public NacosDiscoveryClient(NacosDiscoveryProperties discoveryProperties) { public NacosDiscoveryClient(NacosDiscoveryProperties discoveryProperties) {
this.discoveryProperties = discoveryProperties; this.discoveryProperties = discoveryProperties;
} }
@Override @Override
public String description() { public String description() {
return DESCRIPTION; return DESCRIPTION;
} }
@Override @Override
public List<ServiceInstance> getInstances(String serviceId) { public List<ServiceInstance> getInstances(String serviceId) {
try { try {
List<Instance> instances = discoveryProperties.namingServiceInstance() List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, true); .selectInstances(serviceId, true);
return hostToServiceInstanceList(instances, serviceId); return hostToServiceInstanceList(instances, serviceId);
} } catch (Exception e) {
catch (Exception e) { throw new RuntimeException(
throw new RuntimeException( "Can not get hosts from nacos server. serviceId: " + serviceId, e);
"Can not get hosts from nacos server. serviceId: " + serviceId, e); }
} }
}
private static ServiceInstance hostToServiceInstance(Instance instance,
private static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) {
String serviceId) { NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance(); nacosServiceInstance.setHost(instance.getIp());
nacosServiceInstance.setHost(instance.getIp()); nacosServiceInstance.setPort(instance.getPort());
nacosServiceInstance.setPort(instance.getPort()); nacosServiceInstance.setServiceId(serviceId);
nacosServiceInstance.setServiceId(serviceId);
Map<String, String> metadata = new HashMap<>(); Map<String, String> metadata = new HashMap<>();
metadata.put("instanceId", instance.getInstanceId()); metadata.put("nacos.instanceId", instance.getInstanceId());
metadata.put("weight", instance.getWeight() + ""); metadata.put("nacos.weight", instance.getWeight() + "");
metadata.put("healthy", instance.isHealthy() + ""); metadata.put("nacos.healthy", instance.isHealthy() + "");
metadata.put("cluster", instance.getClusterName() + ""); metadata.put("nacos.cluster", instance.getClusterName() + "");
metadata.putAll(instance.getMetadata()); metadata.putAll(instance.getMetadata());
nacosServiceInstance.setMetadata(metadata); nacosServiceInstance.setMetadata(metadata);
if (metadata.containsKey("secure")) { if (metadata.containsKey("secure")) {
boolean secure = Boolean.parseBoolean(metadata.get("secure")); boolean secure = Boolean.parseBoolean(metadata.get("secure"));
nacosServiceInstance.setSecure(secure); nacosServiceInstance.setSecure(secure);
} }
return nacosServiceInstance; return nacosServiceInstance;
} }
private static List<ServiceInstance> hostToServiceInstanceList( private static List<ServiceInstance> hostToServiceInstanceList(
List<Instance> instances, String serviceId) { List<Instance> instances, String serviceId) {
List<ServiceInstance> result = new ArrayList<>(instances.size()); List<ServiceInstance> result = new ArrayList<>(instances.size());
for (Instance instance : instances) { for (Instance instance : instances) {
result.add(hostToServiceInstance(instance, serviceId)); result.add(hostToServiceInstance(instance, serviceId));
} }
return result; return result;
} }
@Override @Override
public List<String> getServices() { public List<String> getServices() {
try { try {
ListView<String> services = discoveryProperties.namingServiceInstance() ListView<String> services = discoveryProperties.namingServiceInstance()
.getServicesOfServer(1, Integer.MAX_VALUE); .getServicesOfServer(1, Integer.MAX_VALUE);
return services.getData(); return services.getData();
} } catch (Exception e) {
catch (Exception e) { log.error("get service name from nacos server fail,", e);
log.error("get service name from nacos server fail,", e); return Collections.emptyList();
return Collections.emptyList(); }
} }
}
} }

@ -16,6 +16,17 @@
package org.springframework.cloud.alibaba.sentinel.zuul; package org.springframework.cloud.alibaba.sentinel.zuul;
import static org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration.PREFIX;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.alibaba.sentinel.zuul.handler.FallBackProviderHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultRequestOriginParser; import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultRequestOriginParser;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultUrlCleaner; import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultUrlCleaner;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.RequestOriginParser; import com.alibaba.csp.sentinel.adapter.zuul.fallback.RequestOriginParser;
@ -25,17 +36,8 @@ import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPostFilter;
import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPreFilter; import com.alibaba.csp.sentinel.adapter.zuul.filters.SentinelPreFilter;
import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties; import com.alibaba.csp.sentinel.adapter.zuul.properties.SentinelZuulProperties;
import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.util.StringUtil;
import com.netflix.zuul.ZuulFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.alibaba.sentinel.zuul.listener.FallBackProviderListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import static org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoConfiguration.PREFIX; import com.netflix.zuul.ZuulFilter;
/** /**
* Sentinel Spring Cloud Zuul AutoConfiguration * Sentinel Spring Cloud Zuul AutoConfiguration
@ -43,68 +45,70 @@ import static org.springframework.cloud.alibaba.sentinel.zuul.SentinelZuulAutoCo
* @author tiger * @author tiger
*/ */
@Configuration @Configuration
@ConditionalOnProperty(prefix = PREFIX, name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class SentinelZuulAutoConfiguration { public class SentinelZuulAutoConfiguration {
@Autowired @Autowired
private Environment environment; private Environment environment;
public static final String PREFIX = "spring.cloud.alibaba.sentinel.zuul"; public static final String PREFIX = "spring.cloud.sentinel.zuul";
@Bean @Bean
public SentinelZuulProperties sentinelZuulProperties() { public SentinelZuulProperties sentinelZuulProperties() {
SentinelZuulProperties properties = new SentinelZuulProperties(); SentinelZuulProperties properties = new SentinelZuulProperties();
String enabledStr = environment.getProperty(PREFIX + "." + "enabled"); String enabledStr = environment.getProperty(PREFIX + "." + "enabled");
String preOrderStr = environment.getProperty(PREFIX + "." + "order.pre"); String preOrderStr = environment.getProperty(PREFIX + "." + "order.pre");
String postOrderStr = environment.getProperty(PREFIX + "." + "order.post"); String postOrderStr = environment.getProperty(PREFIX + "." + "order.post");
String errorOrderStr = environment.getProperty(PREFIX + "." + "order.error"); String errorOrderStr = environment.getProperty(PREFIX + "." + "order.error");
if (StringUtil.isNotEmpty(enabledStr)) { if (StringUtil.isNotEmpty(enabledStr)) {
Boolean enabled = Boolean.valueOf(enabledStr); Boolean enabled = Boolean.valueOf(enabledStr);
properties.setEnabled(enabled); properties.setEnabled(enabled);
} }
if (StringUtil.isNotEmpty(preOrderStr)) { if (StringUtil.isNotEmpty(preOrderStr)) {
properties.getOrder().setPre(Integer.parseInt(preOrderStr)); properties.getOrder().setPre(Integer.parseInt(preOrderStr));
} }
if (StringUtil.isNotEmpty(postOrderStr)) { if (StringUtil.isNotEmpty(postOrderStr)) {
properties.getOrder().setPost(Integer.parseInt(postOrderStr)); properties.getOrder().setPost(Integer.parseInt(postOrderStr));
} }
if (StringUtil.isNotEmpty(errorOrderStr)) { if (StringUtil.isNotEmpty(errorOrderStr)) {
properties.getOrder().setError(Integer.parseInt(errorOrderStr)); properties.getOrder().setError(Integer.parseInt(errorOrderStr));
} }
return properties; return properties;
} }
@Bean @Bean
@ConditionalOnMissingBean(UrlCleaner.class) @ConditionalOnMissingBean(UrlCleaner.class)
public UrlCleaner urlCleaner(){ public UrlCleaner urlCleaner() {
return new DefaultUrlCleaner(); return new DefaultUrlCleaner();
} }
@Bean @Bean
@ConditionalOnMissingBean(RequestOriginParser.class) @ConditionalOnMissingBean(RequestOriginParser.class)
public RequestOriginParser requestOriginParser(){ public RequestOriginParser requestOriginParser() {
return new DefaultRequestOriginParser(); return new DefaultRequestOriginParser();
} }
@Bean @Bean
public ZuulFilter preFilter(SentinelZuulProperties sentinelZuulProperties,UrlCleaner urlCleaner, public ZuulFilter preFilter(SentinelZuulProperties sentinelZuulProperties,
RequestOriginParser requestOriginParser) { UrlCleaner urlCleaner, RequestOriginParser requestOriginParser) {
return new SentinelPreFilter(sentinelZuulProperties,urlCleaner,requestOriginParser); return new SentinelPreFilter(sentinelZuulProperties, urlCleaner,
} requestOriginParser);
}
@Bean
public ZuulFilter postFilter(SentinelZuulProperties sentinelZuulProperties) { @Bean
return new SentinelPostFilter(sentinelZuulProperties); public ZuulFilter postFilter(SentinelZuulProperties sentinelZuulProperties) {
} return new SentinelPostFilter(sentinelZuulProperties);
}
@Bean
public ZuulFilter errorFilter(SentinelZuulProperties sentinelZuulProperties) { @Bean
return new SentinelErrorFilter(sentinelZuulProperties); public ZuulFilter errorFilter(SentinelZuulProperties sentinelZuulProperties) {
} return new SentinelErrorFilter(sentinelZuulProperties);
}
@Bean
public FallBackProviderListener fallBackProviderListener(DefaultListableBeanFactory beanFactory) { @Bean
return new FallBackProviderListener(beanFactory); public FallBackProviderHandler fallBackProviderListener(
} DefaultListableBeanFactory beanFactory) {
return new FallBackProviderHandler(beanFactory);
}
} }

@ -0,0 +1,45 @@
package org.springframework.cloud.alibaba.sentinel.zuul.handler;
import java.util.Map;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultBlockFallbackProvider;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackManager;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider;
/**
* @author tiger
*/
public class FallBackProviderHandler implements SmartInitializingSingleton {
private static final Logger logger = LoggerFactory
.getLogger(FallBackProviderHandler.class);
private final DefaultListableBeanFactory beanFactory;
public FallBackProviderHandler(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterSingletonsInstantiated() {
Map<String, ZuulBlockFallbackProvider> providerMap = beanFactory
.getBeansOfType(ZuulBlockFallbackProvider.class);
if (MapUtils.isNotEmpty(providerMap)) {
providerMap.forEach((k, v) -> {
logger.info("[Sentinel Zuul] Register provider name:{}, instance: {}", k,
v);
ZuulBlockFallbackManager.registerProvider(v);
});
}
else {
logger.info("[Sentinel Zuul] Register default fallback provider. ");
ZuulBlockFallbackManager.registerProvider(new DefaultBlockFallbackProvider());
}
}
}

@ -1,43 +0,0 @@
package org.springframework.cloud.alibaba.sentinel.zuul.listener;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.DefaultBlockFallbackProvider;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackManager;
import com.alibaba.csp.sentinel.adapter.zuul.fallback.ZuulBlockFallbackProvider;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import java.util.Map;
/**
* @author tiger
*/
public class FallBackProviderListener implements SmartInitializingSingleton {
private static final Logger logger = LoggerFactory.getLogger(FallBackProviderListener.class);
private final DefaultListableBeanFactory beanFactory;
public FallBackProviderListener(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterSingletonsInstantiated() {
Map<String, ZuulBlockFallbackProvider> providerMap = beanFactory.getBeansOfType(ZuulBlockFallbackProvider.class);
if (MapUtils.isNotEmpty(providerMap)) {
providerMap.forEach((k, v) -> {
logger.info("[Sentinel] Register provider name:{}, instance: {}", k, v);
ZuulBlockFallbackManager.registerProvider(v);
});
} else {
logger.info("[Sentinel] Register default fallback provider. ");
ZuulBlockFallbackManager.registerProvider(new DefaultBlockFallbackProvider());
}
}
}

@ -16,17 +16,18 @@
package org.springframework.cloud.alibaba.sentinel; package org.springframework.cloud.alibaba.sentinel;
import com.alibaba.csp.sentinel.config.SentinelConfig; import java.util.List;
import com.alibaba.csp.sentinel.log.LogBase; import java.util.Map;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import java.util.TreeMap;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration; import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePropertiesConfiguration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.util.List; import com.alibaba.csp.sentinel.config.SentinelConfig;
import java.util.Map; import com.alibaba.csp.sentinel.log.LogBase;
import java.util.TreeMap; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
/** /**
* {@link ConfigurationProperties} for Sentinel. * {@link ConfigurationProperties} for Sentinel.
@ -306,6 +307,12 @@ public class SentinelProperties {
*/ */
private List<String> urlPatterns; private List<String> urlPatterns;
/**
* Enable to instance
* {@link com.alibaba.csp.sentinel.adapter.servlet.CommonFilter}.
*/
private boolean enabled = true;
public int getOrder() { public int getOrder() {
return this.order; return this.order;
} }
@ -321,6 +328,14 @@ public class SentinelProperties {
public void setUrlPatterns(List<String> urlPatterns) { public void setUrlPatterns(List<String> urlPatterns) {
this.urlPatterns = urlPatterns; this.urlPatterns = urlPatterns;
} }
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
} }
public static class Log { public static class Log {

@ -16,7 +16,10 @@
package org.springframework.cloud.alibaba.sentinel; package org.springframework.cloud.alibaba.sentinel;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter; import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -28,9 +31,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter; import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import java.util.ArrayList;
import java.util.List;
/** /**
* @author xiaojing * @author xiaojing
@ -48,7 +49,8 @@ public class SentinelWebAutoConfiguration {
private SentinelProperties properties; private SentinelProperties properties;
@Bean @Bean
public FilterRegistrationBean servletRequestListener() { @ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled", matchIfMissing = true)
public FilterRegistrationBean sentinelFilter() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
SentinelProperties.Filter filterConfig = properties.getFilter(); SentinelProperties.Filter filterConfig = properties.getFilter();

@ -16,6 +16,13 @@
package org.springframework.cloud.alibaba.sentinel.endpoint; package org.springframework.cloud.alibaba.sentinel.endpoint;
import java.util.HashMap;
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.sentinel.SentinelProperties;
import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig; import com.alibaba.csp.sentinel.adapter.servlet.config.WebServletConfig;
import com.alibaba.csp.sentinel.config.SentinelConfig; import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.log.LogBase; import com.alibaba.csp.sentinel.log.LogBase;
@ -25,12 +32,7 @@ import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager; import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import com.alibaba.csp.sentinel.util.AppNameUtil;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
import java.util.HashMap;
import java.util.Map;
/** /**
* Endpoint for Sentinel, contains ans properties and rules * Endpoint for Sentinel, contains ans properties and rules
@ -50,6 +52,7 @@ public class SentinelEndpoint {
final Map<String, Object> result = new HashMap<>(); final Map<String, Object> result = new HashMap<>();
if (sentinelProperties.isEnabled()) { if (sentinelProperties.isEnabled()) {
result.put("appName", AppNameUtil.getAppName());
result.put("logDir", LogBase.getLogBaseDir()); result.put("logDir", LogBase.getLogBaseDir());
result.put("logUsePid", LogBase.isLogNameUsePid()); result.put("logUsePid", LogBase.isLogNameUsePid());
result.put("blockPage", WebServletConfig.getBlockPage()); result.put("blockPage", WebServletConfig.getBlockPage());

@ -39,6 +39,12 @@
"defaultValue": "Integer.MIN_VALUE", "defaultValue": "Integer.MIN_VALUE",
"description": "sentinel filter chain order, will be set to FilterRegistrationBean." "description": "sentinel filter chain order, will be set to FilterRegistrationBean."
}, },
{
"name": "spring.cloud.sentinel.filter.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "Enable to instance com.alibaba.csp.sentinel.adapter.servlet.CommonFilter."
},
{ {
"name": "spring.cloud.sentinel.metric.charset", "name": "spring.cloud.sentinel.metric.charset",
"type": "java.lang.String", "type": "java.lang.String",

@ -17,15 +17,20 @@ package org.springframework.cloud.alicloud.sms;
import java.text.ParseException; import java.text.ParseException;
import org.apache.commons.logging.Log; import org.slf4j.Logger;
import org.apache.commons.logging.LogFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.alicloud.context.AliCloudProperties; import org.springframework.cloud.alicloud.context.AliCloudProperties;
import org.springframework.cloud.alicloud.context.sms.SmsProperties; import org.springframework.cloud.alicloud.context.sms.SmsProperties;
import org.springframework.cloud.alicloud.sms.base.DefaultAlicomMessagePuller; import org.springframework.cloud.alicloud.sms.base.DefaultAlicomMessagePuller;
import org.springframework.cloud.alicloud.sms.endpoint.EndpointManager; import org.springframework.cloud.alicloud.sms.endpoint.EndpointManager;
import org.springframework.cloud.alicloud.sms.endpoint.ReceiveMessageEntity; import org.springframework.cloud.alicloud.sms.endpoint.ReceiveMessageEntity;
import com.aliyuncs.dysmsapi.model.v20170525.*; import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendBatchSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendBatchSmsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException; import com.aliyuncs.exceptions.ServerException;
@ -34,7 +39,7 @@ import com.aliyuncs.exceptions.ServerException;
*/ */
public final class SmsServiceImpl extends AbstractSmsService { public final class SmsServiceImpl extends AbstractSmsService {
private static final Log log = LogFactory.getLog(SmsServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(SmsServiceImpl.class);
/** /**
* will expose user to call this method send sms message * will expose user to call this method send sms message
* @param sendSmsRequest * @param sendSmsRequest

@ -15,14 +15,6 @@
*/ */
package org.springframework.cloud.alicloud.sms.base; package org.springframework.cloud.alicloud.sms.base;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.common.ClientException;
import com.aliyun.mns.common.ServiceException;
import com.aliyun.mns.model.Message;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@ -33,12 +25,22 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.common.ClientException;
import com.aliyun.mns.common.ServiceException;
import com.aliyun.mns.model.Message;
/** /**
* *
*/ */
public class DefaultAlicomMessagePuller { public class DefaultAlicomMessagePuller {
private Log logger = LogFactory.getLog(DefaultAlicomMessagePuller.class); private static final Logger log = LoggerFactory
.getLogger(DefaultAlicomMessagePuller.class);
private String mnsAccountEndpoint = "https://1943695596114318.mns.cn-hangzhou.aliyuncs.com/";// 阿里通信消息的endpoint,固定。 private String mnsAccountEndpoint = "https://1943695596114318.mns.cn-hangzhou.aliyuncs.com/";// 阿里通信消息的endpoint,固定。
private String endpointNameForPop = "cn-hangzhou"; private String endpointNameForPop = "cn-hangzhou";
@ -103,7 +105,7 @@ public class DefaultAlicomMessagePuller {
sPollingMap.put(queueName, false); sPollingMap.put(queueName, false);
lockObj.notifyAll(); lockObj.notifyAll();
if (debugLogOpen) { if (debugLogOpen) {
logger.info("PullMessageTask_WakeUp:Everyone WakeUp and Work!"); log.info("PullMessageTask_WakeUp:Everyone WakeUp and Work!");
} }
} }
} }
@ -131,7 +133,7 @@ public class DefaultAlicomMessagePuller {
if (p != null && p) { if (p != null && p) {
try { try {
if (debugLogOpen) { if (debugLogOpen) {
logger.info("PullMessageTask_sleep:" log.info("PullMessageTask_sleep:"
+ Thread.currentThread().getName() + Thread.currentThread().getName()
+ " Have a nice sleep!"); + " Have a nice sleep!");
} }
@ -140,7 +142,7 @@ public class DefaultAlicomMessagePuller {
} }
catch (InterruptedException e) { catch (InterruptedException e) {
if (debugLogOpen) { if (debugLogOpen) {
logger.info("PullMessageTask_Interrupted!" log.info("PullMessageTask_Interrupted!"
+ Thread.currentThread().getName() + Thread.currentThread().getName()
+ " QueueName is " + queueName); + " QueueName is " + queueName);
} }
@ -158,7 +160,7 @@ public class DefaultAlicomMessagePuller {
if (debugLogOpen) { if (debugLogOpen) {
SimpleDateFormat format = new SimpleDateFormat( SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"); "yyyy-MM-dd HH:mm:ss");
logger.info("PullMessageTask_popMessage:" log.info("PullMessageTask_popMessage:"
+ Thread.currentThread().getName() + "-popDone at " + Thread.currentThread().getName() + "-popDone at "
+ "," + format.format(new Date()) + " msgSize=" + "," + format.format(new Date()) + " msgSize="
+ (popMsg == null ? 0 : popMsg.getMessageId())); + (popMsg == null ? 0 : popMsg.getMessageId()));
@ -171,7 +173,7 @@ public class DefaultAlicomMessagePuller {
else { else {
if (setPolling(queueName)) { if (setPolling(queueName)) {
if (debugLogOpen) { if (debugLogOpen) {
logger.info("PullMessageTask_setPolling:" log.info("PullMessageTask_setPolling:"
+ Thread.currentThread().getName() + " Polling!"); + Thread.currentThread().getName() + " Polling!");
} }
} }
@ -180,7 +182,7 @@ public class DefaultAlicomMessagePuller {
} }
do { do {
if (debugLogOpen) { if (debugLogOpen) {
logger.info("PullMessageTask_Keep_Polling" log.info("PullMessageTask_Keep_Polling"
+ Thread.currentThread().getName() + Thread.currentThread().getName()
+ "KEEP Polling!"); + "KEEP Polling!");
} }
@ -189,7 +191,7 @@ public class DefaultAlicomMessagePuller {
} }
catch (ClientException e) { catch (ClientException e) {
if (debugLogOpen) { if (debugLogOpen) {
logger.info( log.info(
"PullMessageTask_Pop_Message:ClientException Refresh accessKey" "PullMessageTask_Pop_Message:ClientException Refresh accessKey"
+ e); + e);
} }
@ -200,7 +202,7 @@ public class DefaultAlicomMessagePuller {
} }
catch (ServiceException e) { catch (ServiceException e) {
if (debugLogOpen) { if (debugLogOpen) {
logger.info( log.info(
"PullMessageTask_Pop_Message:ServiceException Refresh accessKey" "PullMessageTask_Pop_Message:ServiceException Refresh accessKey"
+ e); + e);
} }
@ -211,7 +213,7 @@ public class DefaultAlicomMessagePuller {
} }
catch (Exception e) { catch (Exception e) {
if (debugLogOpen) { if (debugLogOpen) {
logger.info( log.info(
"PullMessageTask_Pop_Message:Exception Happened when polling popMessage: " "PullMessageTask_Pop_Message:Exception Happened when polling popMessage: "
+ e); + e);
} }
@ -224,7 +226,7 @@ public class DefaultAlicomMessagePuller {
if (dealResult) { if (dealResult) {
// remember to delete message when consume message successfully. // remember to delete message when consume message successfully.
if (debugLogOpen) { if (debugLogOpen) {
logger.info("PullMessageTask_Deal_Message:" log.info("PullMessageTask_Deal_Message:"
+ Thread.currentThread().getName() + "deleteMessage " + Thread.currentThread().getName() + "deleteMessage "
+ popMsg.getMessageId()); + popMsg.getMessageId());
} }
@ -232,19 +234,19 @@ public class DefaultAlicomMessagePuller {
} }
} }
catch (ClientException e) { catch (ClientException e) {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:" + messageType
+ messageType + ",queueName:" + queueName, e); + ",queueName:" + queueName, e);
break; break;
} }
catch (ServiceException e) { catch (ServiceException e) {
if (e.getErrorCode().equals("AccessDenied")) { if (e.getErrorCode().equals("AccessDenied")) {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:"
+ messageType + ",queueName:" + queueName + messageType + ",queueName:" + queueName
+ ",please check messageType and queueName", e); + ",please check messageType and queueName", e);
} }
else { else {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:"
+ messageType + ",queueName:" + queueName, e); + messageType + ",queueName:" + queueName, e);
} }
break; break;
@ -252,30 +254,30 @@ public class DefaultAlicomMessagePuller {
} }
catch (com.aliyuncs.exceptions.ClientException e) { catch (com.aliyuncs.exceptions.ClientException e) {
if (e.getErrCode().equals("InvalidAccessKeyId.NotFound")) { if (e.getErrCode().equals("InvalidAccessKeyId.NotFound")) {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:"
+ messageType + ",queueName:" + queueName + messageType + ",queueName:" + queueName
+ ",please check AccessKeyId", e); + ",please check AccessKeyId", e);
} }
if (e.getErrCode().equals("SignatureDoesNotMatch")) { if (e.getErrCode().equals("SignatureDoesNotMatch")) {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:"
+ messageType + ",queueName:" + queueName + messageType + ",queueName:" + queueName
+ ",please check AccessKeySecret", e); + ",please check AccessKeySecret", e);
} }
else { else {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:"
+ messageType + ",queueName:" + queueName, e); + messageType + ",queueName:" + queueName, e);
} }
break; break;
} }
catch (Exception e) { catch (Exception e) {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:" + messageType
+ messageType + ",queueName:" + queueName, e); + ",queueName:" + queueName, e);
try { try {
Thread.sleep(sleepSecondWhenNoData); Thread.sleep(sleepSecondWhenNoData);
} }
catch (InterruptedException e1) { catch (InterruptedException e1) {
logger.error("PullMessageTask_execute_error,messageType:" log.error("PullMessageTask_execute_error,messageType:"
+ messageType + ",queueName:" + queueName, e); + messageType + ",queueName:" + queueName, e);
} }
} }

@ -15,6 +15,15 @@
*/ */
package org.springframework.cloud.alicloud.sms.base; package org.springframework.cloud.alicloud.sms.base;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.aliyun.mns.client.CloudAccount; import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue; import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient; import com.aliyun.mns.client.MNSClient;
@ -27,21 +36,13 @@ import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType; import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile; import com.aliyuncs.profile.IClientProfile;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/** /**
* token * token
* *
*/ */
public class TokenGetterForAlicom { public class TokenGetterForAlicom {
private Log logger = LogFactory.getLog(TokenGetterForAlicom.class); private static final Logger log = LoggerFactory.getLogger(TokenGetterForAlicom.class);
private String accessKeyId; private String accessKeyId;
private String accessKeySecret; private String accessKeySecret;
private String endpointNameForPop; private String endpointNameForPop;
@ -100,7 +101,7 @@ public class TokenGetterForAlicom {
return token; return token;
} }
else { else {
logger.error("getTokenFromRemote_error,messageType:" + messageType + ",code:" log.error("getTokenFromRemote_error,messageType:" + messageType + ",code:"
+ response.getCode() + ",message:" + response.getMessage()); + response.getCode() + ",message:" + response.getMessage());
throw new ServerException(response.getCode(), response.getMessage()); throw new ServerException(response.getCode(), response.getMessage());
} }
@ -124,8 +125,6 @@ public class TokenGetterForAlicom {
CloudAccount account = new CloudAccount(token.getTempAccessKeyId(), CloudAccount account = new CloudAccount(token.getTempAccessKeyId(),
token.getTempAccessKeySecret(), mnsAccountEndpoint, token.getTempAccessKeySecret(), mnsAccountEndpoint,
token.getToken()); token.getToken());
// logger.warn("ak:"+token.getTempAccessKey());
// logger.warn("token:"+token.getToken());
MNSClient client = account.getMNSClient(); MNSClient client = account.getMNSClient();
CloudQueue queue = client.getQueueRef(queueName); CloudQueue queue = client.getQueueRef(queueName);
token.setClient(client); token.setClient(client);

@ -15,12 +15,12 @@
*/ */
package org.springframework.cloud.alicloud.sms.endpoint; package org.springframework.cloud.alicloud.sms.endpoint;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import java.util.Map; @Endpoint(id = "sms")
@Endpoint(id = "sms-info")
public class SmsEndpoint { public class SmsEndpoint {
@ReadOperation @ReadOperation

Loading…
Cancel
Save