1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

Compare commits

..

No commits in common. "master" and "2.2.5.RELEASE" have entirely different histories.

52 changed files with 572 additions and 1817 deletions

View File

@ -48,16 +48,15 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。 更多组件请参考 [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap-zh.md)。
## 如何构建 ## 如何构建
* 2020.0 分支对应的是 Spring Cloud 2020最低支持 JDK 1.8。
* master 分支对应的是 Spring Cloud Hoxton最低支持 JDK 1.8。 * master 分支对应的是 Spring Cloud Greenwich最低支持 JDK 1.8。
* greenwich 分支对应的是 Spring Cloud Greenwich最低支持 JDK 1.8。
* finchley 分支对应的是 Spring Cloud Finchley最低支持 JDK 1.8。 * finchley 分支对应的是 Spring Cloud Finchley最低支持 JDK 1.8。
* 1.x 分支对应的是 Spring Cloud Edgware最低支持 JDK 1.7。 * 1.x 分支对应的是 Spring Cloud Edgware最低支持 JDK 1.7。
Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone 到本地,然后执行以下命令: Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone 到本地,然后执行以下命令:
```bash
./mvnw install ./mvnw install
```
执行完毕后,项目将被安装到本地 Maven 仓库。 执行完毕后,项目将被安装到本地 Maven 仓库。
## 如何使用 ## 如何使用
@ -65,19 +64,19 @@ Spring Cloud 使用 Maven 来构建,最快的使用方式是将本项目 clone
### 如何引入依赖 ### 如何引入依赖
如果需要使用已发布的版本,在 `dependencyManagement` 中添加如下配置。 如果需要使用已发布的版本,在 `dependencyManagement` 中添加如下配置。
```xml
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId> <artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version> <version>2.2.4.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
```
然后在 `dependencies` 中添加自己所需使用的依赖即可使用。 然后在 `dependencies` 中添加自己所需使用的依赖即可使用。
## 演示 Demo ## 演示 Demo
@ -112,7 +111,7 @@ Example 列表:
* 2.0.x 版本适用于 Spring Boot 2.0.x * 2.0.x 版本适用于 Spring Boot 2.0.x
* 2.1.x 版本适用于 Spring Boot 2.1.x * 2.1.x 版本适用于 Spring Boot 2.1.x
* 2.2.x 版本适用于 Spring Boot 2.2.x * 2.2.x 版本适用于 Spring Boot 2.2.x
* 2021.x 版本适用于 Spring Boot 2.4.x
## 社区交流 ## 社区交流

View File

@ -27,7 +27,6 @@ With Spring Cloud Alibaba, you only need to add some annotations and a small amo
For more features, please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md). For more features, please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md).
## Components ## Components
**[Sentinel](https://github.com/alibaba/Sentinel)**: Sentinel takes "traffic flow" as the breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability. **[Sentinel](https://github.com/alibaba/Sentinel)**: Sentinel takes "traffic flow" as the breakthrough point, and provides solutions in areas such as flow control, concurrency, circuit breaking, and load protection to protect service stability.
@ -51,35 +50,34 @@ For more features, please refer to [Roadmap](https://github.com/alibaba/spring-c
For more features please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md). For more features please refer to [Roadmap](https://github.com/alibaba/spring-cloud-alibaba/blob/master/Roadmap.md).
## How to build ## How to build
* **2020.0 branch**: Corresponds to Spring Cloud 2020 & Spring Boot 2.4.x. JDK 1.8 or later versions are supported.
* **master branch**: Corresponds to Spring Cloud Hoxton & Spring Boot 2.2.x. JDK 1.8 or later versions are supported. * **master branch**: Corresponds to Spring Cloud Greenwich & Spring Boot 2.x. JDK 1.8 or later versions are supported.
* **greenwich branch**: Corresponds to Spring Cloud Greenwich & Spring Boot 2.1.x. JDK 1.8 or later versions are supported. * **finchley branch**: Corresponds to Spring Cloud Finchley & Spring Boot 2.x. JDK 1.8 or later versions are supported.
* **finchley branch**: Corresponds to Spring Cloud Finchley & Spring Boot 2.0.x. JDK 1.8 or later versions are supported.
* **1.x branch**: Corresponds to Spring Cloud Edgware & Spring Boot 1.x, JDK 1.7 or later versions are supported. * **1.x branch**: Corresponds to Spring Cloud Edgware & Spring Boot 1.x, JDK 1.7 or later versions are supported.
Spring Cloud uses Maven for most build-related activities, and you should be able to get off the ground quite quickly by cloning the project you are interested in and typing: Spring Cloud uses Maven for most build-related activities, and you should be able to get off the ground quite quickly by cloning the project you are interested in and typing:
```bash
./mvnw install ./mvnw install
```
## How to Use ## How to Use
### Add maven dependency ### Add maven dependency
These artifacts are available from Maven Central and Spring Release repository via BOM: These artifacts are available from Maven Central and Spring Release repository via BOM:
```xml
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId> <artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version> <version>2.2.4.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
```
add the module in `dependencies`. add the module in `dependencies`.
@ -119,7 +117,6 @@ As the interfaces and annotations of Spring Boot 1 and Spring Boot 2 have been c
* 2.0.x for Spring Boot 2.0.x * 2.0.x for Spring Boot 2.0.x
* 2.1.x for Spring Boot 2.1.x * 2.1.x for Spring Boot 2.1.x
* 2.2.x for Spring Boot 2.2.x * 2.2.x for Spring Boot 2.2.x
* 2020.x for Spring Boot 2.4.x
## Code of Conduct ## Code of Conduct
This project is a sub-project of Spring Cloud, it adheres to the Contributor Covenant [code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io. This project is a sub-project of Spring Cloud, it adheres to the Contributor Covenant [code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.

97
pom.xml
View File

@ -80,10 +80,18 @@
<properties> <properties>
<!-- Project revision --> <!-- Project revision -->
<revision>2.2.6-SNAPSHOT</revision> <revision>2.2.5.RC2</revision>
<!-- Spring Cloud --> <!-- Dependency Versions -->
<spring.cloud.version>Hoxton.SR9</spring.cloud.version> <spring-cloud-commons.version>2.2.5.RELEASE</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.2.5.RELEASE</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>2.2.5.RELEASE</spring-cloud-openfeign.version>
<spring-cloud-bus.version>2.2.3.RELEASE</spring-cloud-bus.version>
<spring-cloud-gateway.version>2.2.5.RELEASE</spring-cloud-gateway.version>
<spring-cloud-stream.version>Horsham.SR3</spring-cloud-stream.version>
<spring-cloud-consul.version>2.2.4.RELEASE</spring-cloud-consul.version>
<spring-cloud-config.version>2.2.5.RELEASE</spring-cloud-config.version>
<spring-cloud-zookeeper.version>2.2.3.RELEASE</spring-cloud-zookeeper.version>
<!-- Apache Dubbo --> <!-- Apache Dubbo -->
<dubbo.version>2.7.8</dubbo.version> <dubbo.version>2.7.8</dubbo.version>
@ -125,17 +133,88 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId> <artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.version}</version> <version>${project.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId> <artifactId>spring-cloud-commons-dependencies</artifactId>
<version>${project.version}</version> <version>${spring-cloud-commons.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
<version>${spring-cloud-commons.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-dependencies</artifactId>
<version>${spring-cloud-netflix.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>${spring-cloud-openfeign.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-dependencies</artifactId>
<version>${spring-cloud-config.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus-dependencies</artifactId>
<version>${spring-cloud-bus.version}</version>
<type>pom</type>
<scope>import</scope>
</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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-dependencies</artifactId>
<version>${spring-cloud-stream.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-dependencies</artifactId>
<version>${spring-cloud-consul.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-zookeeper-dependencies</artifactId>
<version>${spring-cloud-zookeeper.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

View File

@ -18,10 +18,10 @@
<description>Spring Cloud Alibaba Dependencies</description> <description>Spring Cloud Alibaba Dependencies</description>
<properties> <properties>
<revision>2.2.6-SNAPSHOT</revision> <revision>2.2.5.RC2</revision>
<sentinel.version>1.8.1</sentinel.version> <sentinel.version>1.8.0</sentinel.version>
<seata.version>1.3.0</seata.version> <seata.version>1.3.0</seata.version>
<nacos.client.version>1.4.2</nacos.client.version> <nacos.client.version>1.4.1</nacos.client.version>
<nacos.config.version>0.8.0</nacos.config.version> <nacos.config.version>0.8.0</nacos.config.version>
<spring.context.support.version>1.0.10</spring.context.support.version> <spring.context.support.version>1.0.10</spring.context.support.version>

View File

@ -260,7 +260,7 @@ Nacos 内部有 https://nacos.io/zh-cn/docs/concepts.html[Namespace 的概念]:
[quote] [quote]
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
在没有明确指定 `${spring.cloud.nacos.config.namespace}` 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespace。如果需要使用自定义的命名空间可以通过以下配置来实现 在没有明确指定 `${spring.cloud.nacos.config.namespace}` 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。如果需要使用自定义的命名空间可以通过以下配置来实现
[source,properties] [source,properties]
---- ----
spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7 spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7
@ -348,13 +348,7 @@ Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置
* B: 通过 `spring.cloud.nacos.config.ext-config[n].data-id` 的方式支持多个扩展 Data Id 的配置 * B: 通过 `spring.cloud.nacos.config.ext-config[n].data-id` 的方式支持多个扩展 Data Id 的配置
* C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置 * C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置
当三种方式共同使用时,他们的一个优先级关系是: 当三种方式共同使用时,他们的一个优先级关系是:A < B < C
->A为优先级最高的
->B的优先级低于A
->C的优先级是最低的
=== Nacos Config 对外暴露的 Endpoint === Nacos Config 对外暴露的 Endpoint

View File

@ -57,7 +57,7 @@ Send messages:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
``` ```
Output when the message is successfully sent: `SendResult [sendStatus=SEND_OK, msgId= ...` Output when the message is successfuly sent: `SendResult [sendStatus=SEND_OK, msgId= ...`
Receive messages: Receive messages:

View File

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

View File

@ -18,18 +18,18 @@ spring.cloud.nacos.password=nacos
#spring.cloud.nacos.config.shared-data-ids=common.properties,base-common.properties #spring.cloud.nacos.config.shared-data-ids=common.properties,base-common.properties
## recommended. ## recommended.
spring.cloud.nacos.config.shared-configs[0].data-id=test2.yaml spring.cloud.nacos.config.shared-configs[0].data-id= test2.yaml
spring.cloud.nacos.config.shared-configs[0].refresh=true spring.cloud.nacos.config.shared-configs[0].refresh=true
## the default value is 'DEFAULT_GROUP' , if not specified. ## the default value is 'DEFAULT_GROUP' , if not specified.
spring.cloud.nacos.config.shared-configs[0].group=GROUP_APP1 spring.cloud.nacos.config.shared-configs[0].group= GROUP_APP1
## not recommended. ## not recommended.
#spring.cloud.nacos.config.ext-config[0]=ext.properties #spring.cloud.nacos.config.ext-config[0]=ext.properties
## recommended. ## recommended.
spring.cloud.nacos.config.extension-configs[0].data-id=extension1.properties spring.cloud.nacos.config.extension-configs[0].data-id= extension1.properties
spring.cloud.nacos.config.extension-configs[0].refresh=true spring.cloud.nacos.config.extension-configs[0].refresh=true
spring.cloud.nacos.config.extension-configs[1].data-id=test1.yml spring.cloud.nacos.config.extension-configs[1].data-id= test1.yml
spring.cloud.nacos.config.extension-configs[1].refresh=true spring.cloud.nacos.config.extension-configs[1].refresh= true

View File

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

View File

@ -72,7 +72,7 @@ Before we start the demo, let's learn how to connect Nacos Config to a Spring Cl
#### Query Service #### Query Service
Enter `http://127.0.0.1:8848/nacos/#/serviceDetail?name=service-provider&groupName=DEFAULT_GROUP` in the browser address bar and click Go to, we can see that the service node has been successfully registered to Nacos Server. Enter `http://127.0.0.1:8848/nacos/v1/ns/instances?serviceName=service-provider` in the browser address bar and click Go to, we can see that the service node has been successfully registered to Nacos Server.
![查询服务](https://cdn.nlark.com/lark/0/2018/png/54319/1536986288092-5cf96af9-9a26-466b-85f6-39ad1d92dfdc.png) ![查询服务](https://cdn.nlark.com/lark/0/2018/png/54319/1536986288092-5cf96af9-9a26-466b-85f6-39ad1d92dfdc.png)

View File

@ -73,7 +73,7 @@ spring.cloud.stream.bindings.input.group=test-group
You should startup Name Server and Broker before using RocketMQ Binder. You should startup Name Server and Broker before using RocketMQ Binder.
1. Download [RocketMQ](https://archive.apache.org/dist/rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip) and unzip it. 1. Download [RocketMQ](https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip) and unzip it.
2. Startup Name Server 2. Startup Name Server

View File

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

View File

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

View File

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

View File

@ -114,8 +114,6 @@ public class EchoController {
- 启动nacos 注册中心 - 启动nacos 注册中心
- 启动sentinel
- 启动服务提供方: - 启动服务提供方:
1. IDE直接启动找到主类 `ProviderApplication`,执行 main 方法启动应用。 1. IDE直接启动找到主类 `ProviderApplication`,执行 main 方法启动应用。
@ -125,5 +123,3 @@ public class EchoController {
1. IDE直接启动找到主类 `ConsumerApplication`,执行 main 方法启动应用。 1. IDE直接启动找到主类 `ConsumerApplication`,执行 main 方法启动应用。
2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-feign-consumer-example.jar`启动应用。 2. 打包编译后启动:首先执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar sentinel-feign-consumer-example.jar`启动应用。
- 启动之后Sentinel Dashboard可能看不见service-consumer服务的详细信息多请求几次接口即可。

View File

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

View File

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

View File

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

View File

@ -99,6 +99,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId> <artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -90,6 +90,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId> <artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency> </dependency>
<!-- REST support dependencies --> <!-- REST support dependencies -->

View File

@ -89,6 +89,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId> <artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

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

View File

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

View File

@ -86,8 +86,9 @@ public abstract class SentinelConverter<T extends Object>
}); });
for (Object obj : sourceArray) { for (Object obj : sourceArray) {
String item = null;
try { try {
String item = objectMapper.writeValueAsString(obj); item = objectMapper.writeValueAsString(obj);
Optional.ofNullable(convertRule(item)) Optional.ofNullable(convertRule(item))
.ifPresent(convertRule -> ruleCollection.add(convertRule)); .ifPresent(convertRule -> ruleCollection.add(convertRule));
} }

View File

@ -51,6 +51,12 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId> <artifactId>spring-boot-starter</artifactId>

View File

@ -85,6 +85,12 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.powermock.modules.test.powermockito/powermock-modules-test-powermockito --> <!-- https://mvnrepository.com/artifact/org.powermock.modules.test.powermockito/powermock-modules-test-powermockito -->
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>

View File

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

View File

@ -1,54 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.logging;
import com.alibaba.nacos.client.logging.NacosLogging;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
/**
* Reload nacos log configuration file, after
* {@link org.springframework.boot.context.logging.LoggingApplicationListener}.
*
* @author mai.jh
*/
public class NacosLoggingListener implements GenericApplicationListener {
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
Class<?> type = resolvableType.getRawClass();
if (type != null) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type);
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
NacosLogging.getInstance().loadConfiguration();
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 21;
}
}

View File

@ -8,5 +8,3 @@ com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertySourceLoader=\
com.alibaba.cloud.nacos.parser.NacosJsonPropertySourceLoader,\ com.alibaba.cloud.nacos.parser.NacosJsonPropertySourceLoader,\
com.alibaba.cloud.nacos.parser.NacosXmlPropertySourceLoader com.alibaba.cloud.nacos.parser.NacosXmlPropertySourceLoader
org.springframework.context.ApplicationListener=\
com.alibaba.cloud.nacos.logging.NacosLoggingListener

View File

@ -111,6 +111,12 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>io.projectreactor</groupId> <groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId> <artifactId>reactor-test</artifactId>

View File

@ -207,12 +207,6 @@ public class NacosDiscoveryProperties {
*/ */
private boolean ephemeral = true; private boolean ephemeral = true;
/**
* Throw exceptions during service registration if true, otherwise, log error
* (defaults to true).
*/
private boolean failFast = true;
@Autowired @Autowired
private InetUtils inetUtils; private InetUtils inetUtils;
@ -492,14 +486,6 @@ public class NacosDiscoveryProperties {
this.ephemeral = ephemeral; this.ephemeral = ephemeral;
} }
public boolean isFailFast() {
return failFast;
}
public void setFailFast(boolean failFast) {
this.failFast = failFast;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@ -524,7 +510,6 @@ public class NacosDiscoveryProperties {
&& Objects.equals(secretKey, that.secretKey) && Objects.equals(secretKey, that.secretKey)
&& Objects.equals(heartBeatInterval, that.heartBeatInterval) && Objects.equals(heartBeatInterval, that.heartBeatInterval)
&& Objects.equals(heartBeatTimeout, that.heartBeatTimeout) && Objects.equals(heartBeatTimeout, that.heartBeatTimeout)
&& Objects.equals(failFast, that.failFast)
&& Objects.equals(ipDeleteTimeout, that.ipDeleteTimeout); && Objects.equals(ipDeleteTimeout, that.ipDeleteTimeout);
} }
@ -534,7 +519,7 @@ public class NacosDiscoveryProperties {
watchDelay, logName, service, weight, clusterName, group, watchDelay, logName, service, weight, clusterName, group,
namingLoadCacheAtStart, registerEnabled, ip, networkInterface, port, namingLoadCacheAtStart, registerEnabled, ip, networkInterface, port,
secure, accessKey, secretKey, heartBeatInterval, heartBeatTimeout, secure, accessKey, secretKey, heartBeatInterval, heartBeatTimeout,
ipDeleteTimeout, instanceEnabled, ephemeral, failFast); ipDeleteTimeout, instanceEnabled, ephemeral);
} }
@Override @Override
@ -550,7 +535,7 @@ public class NacosDiscoveryProperties {
+ ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey + ", port=" + port + ", secure=" + secure + ", accessKey='" + accessKey
+ '\'' + ", secretKey='" + secretKey + '\'' + ", heartBeatInterval=" + '\'' + ", secretKey='" + secretKey + '\'' + ", heartBeatInterval="
+ heartBeatInterval + ", heartBeatTimeout=" + heartBeatTimeout + heartBeatInterval + ", heartBeatTimeout=" + heartBeatTimeout
+ ", ipDeleteTimeout=" + ipDeleteTimeout + ", failFast=" + failFast + '}'; + ", ipDeleteTimeout=" + ipDeleteTimeout + '}';
} }
public void overrideFromEnv(Environment env) { public void overrideFromEnv(Environment env) {

View File

@ -31,16 +31,6 @@ import org.springframework.boot.actuate.health.HealthIndicator;
*/ */
public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator { public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator {
/**
* status up.
*/
private static final String STATUS_UP = "UP";
/**
* status down.
*/
private static final String STATUS_DOWN = "DOWN";
private final NamingService namingService; private final NamingService namingService;
public NacosDiscoveryHealthIndicator(NamingService namingService) { public NacosDiscoveryHealthIndicator(NamingService namingService) {
@ -54,10 +44,10 @@ public class NacosDiscoveryHealthIndicator extends AbstractHealthIndicator {
// Set the status to Builder // Set the status to Builder
builder.status(status); builder.status(status);
switch (status) { switch (status) {
case STATUS_UP: case "UP":
builder.up(); builder.up();
break; break;
case STATUS_DOWN: case "DOWN":
builder.down(); builder.down();
break; break;
default: default:

View File

@ -1,54 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.nacos.discovery.logging;
import com.alibaba.nacos.client.logging.NacosLogging;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
/**
* Reload nacos log configuration file, after
* {@link org.springframework.boot.context.logging.LoggingApplicationListener}.
*
* @author mai.jh
*/
public class NacosLoggingListener implements GenericApplicationListener {
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
Class<?> type = resolvableType.getRawClass();
if (type != null) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type);
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
NacosLogging.getInstance().loadConfiguration();
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 21;
}
}

View File

@ -76,16 +76,12 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
instance.getIp(), instance.getPort()); instance.getIp(), instance.getPort());
} }
catch (Exception e) { catch (Exception e) {
if (nacosDiscoveryProperties.isFailFast()) {
log.error("nacos registry, {} register failed...{},", serviceId, log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e); registration.toString(), e);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
rethrowRuntimeException(e); rethrowRuntimeException(e);
} }
else {
log.warn("Failfast is false. {} register failed...{},", serviceId,
registration.toString(), e);
}
}
} }
@Override @Override
@ -159,9 +155,8 @@ public class NacosServiceRegistry implements ServiceRegistry<Registration> {
public Object getStatus(Registration registration) { public Object getStatus(Registration registration) {
String serviceName = registration.getServiceId(); String serviceName = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
try { try {
List<Instance> instances = namingService().getAllInstances(serviceName, group); List<Instance> instances = namingService().getAllInstances(serviceName);
for (Instance instance : instances) { for (Instance instance : instances) {
if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp()) if (instance.getIp().equalsIgnoreCase(nacosDiscoveryProperties.getIp())
&& instance.getPort() == nacosDiscoveryProperties.getPort()) { && instance.getPort() == nacosDiscoveryProperties.getPort()) {

View File

@ -9,5 +9,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.NacosServiceAutoConfiguration com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.context.ApplicationListener=\
com.alibaba.cloud.nacos.discovery.logging.NacosLoggingListener

View File

@ -25,7 +25,7 @@ import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider; import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
import com.alibaba.csp.sentinel.transport.HeartbeatSender; import com.alibaba.csp.sentinel.transport.HeartbeatSender;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.transport.endpoint.Endpoint; import com.alibaba.csp.sentinel.util.function.Tuple2;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.AbstractHealthIndicator;
@ -84,7 +84,8 @@ public class SentinelHealthIndicator extends AbstractHealthIndicator {
// Check health of Dashboard // Check health of Dashboard
boolean dashboardUp = true; boolean dashboardUp = true;
List<Endpoint> consoleServerList = TransportConfig.getConsoleServerList(); List<Tuple2<String, Integer>> consoleServerList = TransportConfig
.getConsoleServerList();
if (CollectionUtils.isEmpty(consoleServerList)) { if (CollectionUtils.isEmpty(consoleServerList)) {
// If Dashboard isn't configured, it's OK and mark the status of Dashboard // If Dashboard isn't configured, it's OK and mark the status of Dashboard
// with UNKNOWN. // with UNKNOWN.

View File

@ -31,8 +31,7 @@ import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.transport.config.TransportConfig; import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.transport.endpoint.Endpoint; import com.alibaba.csp.sentinel.util.function.Tuple2;
import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -135,10 +134,8 @@ public class SentinelAutoConfigurationTests {
Map<String, Object> map = sentinelEndpoint.invoke(); Map<String, Object> map = sentinelEndpoint.invoke();
assertThat(map.get("logUsePid")).isEqualTo(Boolean.TRUE); assertThat(map.get("logUsePid")).isEqualTo(Boolean.TRUE);
assertThat(map.get("consoleServer").toString()) assertThat(map.get("consoleServer").toString()).isEqualTo(
.isEqualTo(Arrays Arrays.asList(Tuple2.of("localhost", 8080), Tuple2.of("localhost", 8081))
.asList(new Endpoint(Protocol.HTTP, "localhost", 8080),
new Endpoint(Protocol.HTTP, "localhost", 8081))
.toString()); .toString());
assertThat(map.get("clientPort")).isEqualTo("9999"); assertThat(map.get("clientPort")).isEqualTo("9999");
assertThat(map.get("heartbeatIntervalMs")).isEqualTo(20000L); assertThat(map.get("heartbeatIntervalMs")).isEqualTo(20000L);
@ -188,10 +185,8 @@ public class SentinelAutoConfigurationTests {
@Test @Test
public void testSentinelSystemProperties() { public void testSentinelSystemProperties() {
assertThat(LogBase.isLogNameUsePid()).isEqualTo(true); assertThat(LogBase.isLogNameUsePid()).isEqualTo(true);
assertThat(TransportConfig.getConsoleServerList().toString()) assertThat(TransportConfig.getConsoleServerList().toString()).isEqualTo(
.isEqualTo(Arrays Arrays.asList(Tuple2.of("localhost", 8080), Tuple2.of("localhost", 8081))
.asList(new Endpoint(Protocol.HTTP, "localhost", 8080),
new Endpoint(Protocol.HTTP, "localhost", 8081))
.toString()); .toString());
assertThat(TransportConfig.getPort()).isEqualTo("9999"); assertThat(TransportConfig.getPort()).isEqualTo("9999");
assertThat(TransportConfig.getHeartbeatIntervalMs().longValue()) assertThat(TransportConfig.getHeartbeatIntervalMs().longValue())

View File

@ -78,6 +78,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<version>${spring-cloud-zookeeper.version}</version>
<optional>true</optional> <optional>true</optional>
<exclusions> <exclusions>
<exclusion> <exclusion>
@ -111,6 +112,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId> <artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>${spring-cloud-consul.version}</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>

View File

@ -51,10 +51,6 @@ public class DubboCloudProperties {
private String registryType = DUBBO_CLOUD_REGISTRY_PROPERTY_VALUE; private String registryType = DUBBO_CLOUD_REGISTRY_PROPERTY_VALUE;
private int maxReSubscribeMetadataTimes = 1000;
private int reSubscribeMetadataIntervial = 5;
public String getSubscribedServices() { public String getSubscribedServices() {
return subscribedServices; return subscribedServices;
} }
@ -95,20 +91,4 @@ public class DubboCloudProperties {
this.registryType = registryType; this.registryType = registryType;
} }
public int getMaxReSubscribeMetadataTimes() {
return maxReSubscribeMetadataTimes;
}
public void setMaxReSubscribeMetadataTimes(int maxReSubscribeMetadataTimes) {
this.maxReSubscribeMetadataTimes = maxReSubscribeMetadataTimes;
}
public int getReSubscribeMetadataIntervial() {
return reSubscribeMetadataIntervial;
}
public void setReSubscribeMetadataIntervial(int reSubscribeMetadataIntervial) {
this.reSubscribeMetadataIntervial = reSubscribeMetadataIntervial;
}
} }

View File

@ -1,55 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.metadata;
import org.apache.dubbo.common.extension.Activate;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.CODEC_KEY;
import static org.apache.dubbo.remoting.Constants.CONNECTIONS_KEY;
import static org.apache.dubbo.remoting.Constants.EXCHANGER_KEY;
import static org.apache.dubbo.remoting.Constants.SERIALIZATION_KEY;
import static org.apache.dubbo.rpc.Constants.DEPRECATED_KEY;
import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;
/**
* Copy from org.apache.dubbo.metadata.DefaultMetadataParamsFilter.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
@Activate
public class DefaultMetadataParamsFilter implements MetadataParamsFilter {
@Override
public String[] serviceParamsIncluded() {
return new String[] { CODEC_KEY, EXCHANGER_KEY, SERIALIZATION_KEY, CLUSTER_KEY,
CONNECTIONS_KEY, DEPRECATED_KEY, GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY,
PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY, WEIGHT_KEY,
DUBBO_VERSION_KEY, RELEASE_KEY };
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.metadata;
import org.apache.dubbo.common.extension.SPI;
/**
* Copy from org.apache.dubbo.metadata.MetadataParamsFilter.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
@SPI
public interface MetadataParamsFilter {
/**
* params that need to be sent to metadata center.
* @return arrays of keys
*/
String[] serviceParamsIncluded();
}

View File

@ -1,74 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.metadata;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Copy from org.apache.dubbo.metadata.RevisionResolver.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public final class RevisionResolver {
private static final Logger logger = LoggerFactory.getLogger(RevisionResolver.class);
private static final String EMPTY_REVISION = "0";
private static final char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F' };
private static MessageDigest mdInst;
static {
try {
mdInst = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e) {
logger.error("Failed to calculate metadata revision", e);
}
}
private RevisionResolver() {
}
public static String getEmptyRevision() {
return EMPTY_REVISION;
}
public static String calRevision(String metadata) {
mdInst.update(metadata.getBytes(UTF_8));
byte[] md5 = mdInst.digest();
int j = md5.length;
char[] str = new char[j * 2];
int k = 0;
for (byte byte0 : md5) {
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
}
}

View File

@ -1,351 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.metadata;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.compiler.support.ClassUtils;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.ArrayUtils;
import org.apache.dubbo.common.utils.StringUtils;
import static org.apache.dubbo.common.constants.CommonConstants.DOT_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
/**
* Copy from org.apache.dubbo.metadata.MetadataInfo.ServiceInfo.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public class ServiceInfo implements Serializable {
private static final long serialVersionUID = -258557978718735302L;
private static ExtensionLoader<MetadataParamsFilter> loader = ExtensionLoader
.getExtensionLoader(MetadataParamsFilter.class);
private String name;
private String group;
private String version;
private String protocol;
private String path; // most of the time, path is the same with the interface name.
private Map<String, String> params;
// params configured on consumer side,
private transient Map<String, String> consumerParams;
// cached method params
private transient Map<String, Map<String, String>> methodParams;
private transient Map<String, Map<String, String>> consumerMethodParams;
// cached numbers
private transient Map<String, Number> numbers;
private transient Map<String, Map<String, Number>> methodNumbers;
// service + group + version
private transient String serviceKey;
// service + group + version + protocol
private transient String matchKey;
private transient URL url;
public ServiceInfo() {
}
public ServiceInfo(URL url) {
this(url.getServiceInterface(), url.getParameter(GROUP_KEY),
url.getParameter(VERSION_KEY), url.getProtocol(), url.getPath(), null);
this.url = url;
Map<String, String> params = new HashMap<>();
List<MetadataParamsFilter> filters = loader.getActivateExtension(url,
"params-filter");
for (MetadataParamsFilter filter : filters) {
String[] paramsIncluded = filter.serviceParamsIncluded();
if (ArrayUtils.isNotEmpty(paramsIncluded)) {
for (String p : paramsIncluded) {
String value = url.getParameter(p);
if (StringUtils.isNotEmpty(value) && params.get(p) == null) {
params.put(p, value);
}
String[] methods = url.getParameter(METHODS_KEY, (String[]) null);
if (methods != null) {
for (String method : methods) {
String mValue = getMethodParameterStrict(url, method, p);
if (StringUtils.isNotEmpty(mValue)) {
params.put(method + DOT_SEPARATOR + p, mValue);
}
}
}
}
}
}
this.params = params;
}
public String getMethodParameterStrict(URL url, String method, String key) {
Map<String, String> keyMap = url.getMethodParameters().get(method);
String value = null;
if (keyMap != null) {
value = keyMap.get(key);
}
return value;
}
public ServiceInfo(String name, String group, String version, String protocol,
String path, Map<String, String> params) {
this.name = name;
this.group = group;
this.version = version;
this.protocol = protocol;
this.path = path;
this.params = params == null ? new HashMap<>() : params;
this.serviceKey = URL.buildKey(name, group, version);
this.matchKey = buildMatchKey();
}
public String getMatchKey() {
if (matchKey != null) {
return matchKey;
}
buildMatchKey();
return matchKey;
}
private String buildMatchKey() {
matchKey = getServiceKey();
if (StringUtils.isNotEmpty(protocol)) {
matchKey = getServiceKey() + GROUP_CHAR_SEPARATOR + protocol;
}
return matchKey;
}
public String getServiceKey() {
if (serviceKey != null) {
return serviceKey;
}
this.serviceKey = URL.buildKey(name, group, version);
return serviceKey;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Map<String, String> getParams() {
if (params == null) {
return Collections.emptyMap();
}
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
public Map<String, String> getAllParams() {
if (consumerParams != null) {
Map<String, String> allParams = new HashMap<>(
(int) ((params.size() + consumerParams.size()) / 0.75f + 1));
allParams.putAll(params);
allParams.putAll(consumerParams);
return allParams;
}
return params;
}
public String getParameter(String key) {
if (consumerParams != null) {
String value = consumerParams.get(key);
if (value != null) {
return value;
}
}
return params.get(key);
}
public String getMethodParameter(String method, String key, String defaultValue) {
if (methodParams == null) {
methodParams = URL.toMethodParameters(params);
consumerMethodParams = URL.toMethodParameters(consumerParams);
}
String value = getMethodParameter(method, key, consumerMethodParams);
if (value != null) {
return value;
}
value = getMethodParameter(method, key, methodParams);
return value == null ? defaultValue : value;
}
private String getMethodParameter(String method, String key,
Map<String, Map<String, String>> map) {
Map<String, String> keyMap = map.get(method);
String value = null;
if (keyMap != null) {
value = keyMap.get(key);
}
if (StringUtils.isEmpty(value)) {
value = getParameter(key);
}
return value;
}
public boolean hasMethodParameter(String method, String key) {
String value = this.getMethodParameter(method, key, (String) null);
return StringUtils.isNotEmpty(value);
}
public boolean hasMethodParameter(String method) {
if (methodParams == null) {
methodParams = URL.toMethodParameters(params);
consumerMethodParams = URL.toMethodParameters(consumerParams);
}
return consumerMethodParams.containsKey(method)
|| methodParams.containsKey(method);
}
public String toDescString() {
return this.getMatchKey() + getMethodSignaturesString() + getParams();
}
private String getMethodSignaturesString() {
SortedSet<String> methodStrings = new TreeSet();
Method[] methods = ClassUtils.forName(name).getMethods();
for (Method method : methods) {
methodStrings.add(method.toString());
}
return methodStrings.toString();
}
public void addParameter(String key, String value) {
if (consumerParams != null) {
this.consumerParams.put(key, value);
}
}
public void addParameterIfAbsent(String key, String value) {
if (consumerParams != null) {
this.consumerParams.putIfAbsent(key, value);
}
}
public void addConsumerParams(Map<String, String> params) {
// copy once for one service subscription
if (consumerParams == null) {
consumerParams = new HashMap<>(params);
}
}
public Map<String, Number> getNumbers() {
// concurrent initialization is tolerant
if (numbers == null) {
numbers = new ConcurrentHashMap<>();
}
return numbers;
}
public Map<String, Map<String, Number>> getMethodNumbers() {
if (methodNumbers == null) { // concurrent initialization is tolerant
methodNumbers = new ConcurrentHashMap<>();
}
return methodNumbers;
}
public URL getUrl() {
return url;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof ServiceInfo)) {
return false;
}
ServiceInfo serviceInfo = (ServiceInfo) obj;
return this.getMatchKey().equals(serviceInfo.getMatchKey())
&& this.getParams().equals(serviceInfo.getParams());
}
@Override
public int hashCode() {
return Objects.hash(getMatchKey(), getParams());
}
@Override
public String toString() {
return "service{" + "name='" + name + "'," + "group='" + group + "',"
+ "version='" + version + "'," + "protocol='" + protocol + "',"
+ "params=" + params + "," + "consumerParams=" + consumerParams + "}";
}
}

View File

@ -16,11 +16,9 @@
package com.alibaba.cloud.dubbo.metadata.repository; package com.alibaba.cloud.dubbo.metadata.repository;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -33,8 +31,6 @@ import com.alibaba.cloud.dubbo.env.DubboCloudProperties;
import com.alibaba.cloud.dubbo.http.matcher.RequestMetadataMatcher; import com.alibaba.cloud.dubbo.http.matcher.RequestMetadataMatcher;
import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata; import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata;
import com.alibaba.cloud.dubbo.metadata.RequestMetadata; import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
import com.alibaba.cloud.dubbo.metadata.RevisionResolver;
import com.alibaba.cloud.dubbo.metadata.ServiceInfo;
import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata; import com.alibaba.cloud.dubbo.metadata.ServiceRestMetadata;
import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent; import com.alibaba.cloud.dubbo.registry.event.SubscribedServicesChangedEvent;
import com.alibaba.cloud.dubbo.service.DubboMetadataService; import com.alibaba.cloud.dubbo.service.DubboMetadataService;
@ -45,8 +41,6 @@ import com.alibaba.cloud.dubbo.util.JSONUtils;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -100,12 +94,6 @@ public class DubboServiceMetadataRepository
@Deprecated @Deprecated
public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = METADATA_SERVICE_URLS_PROPERTY_NAME; public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = METADATA_SERVICE_URLS_PROPERTY_NAME;
/**
* The key of dubbo metadata revision. copyed from
* ServiceInstanceMetadataUtils.EXPORTED_SERVICES_REVISION_PROPERTY_NAME.
*/
public static String EXPORTED_SERVICES_REVISION_PROPERTY_NAME = "dubbo.metadata.revision";
/** /**
* The {@link String#format(String, Object...) pattern} of dubbo protocols port. * The {@link String#format(String, Object...) pattern} of dubbo protocols port.
*/ */
@ -127,11 +115,14 @@ public class DubboServiceMetadataRepository
*/ */
private final MultiValueMap<String, URL> allExportedURLs = new LinkedMultiValueMap<>(); private final MultiValueMap<String, URL> allExportedURLs = new LinkedMultiValueMap<>();
// ======================== Registration ======================== // // =================================== Registration
// =================================== //
// ============================================================== // // ====================================================================================
// //
// ======================== Subscription ======================== // // =================================== Subscription
// =================================== //
/** /**
* A Map to store REST metadata temporary, its' key is the special service name for a * A Map to store REST metadata temporary, its' key is the special service name for a
* Dubbo service, the value is a JSON content of JAX-RS or Spring MVC REST metadata * Dubbo service, the value is a JSON content of JAX-RS or Spring MVC REST metadata
@ -141,9 +132,11 @@ public class DubboServiceMetadataRepository
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
// =============================================================== // // ====================================================================================
// //
// ======================== REST Metadata ======================== // // =================================== REST Metadata
// ================================== //
private volatile Set<String> subscribedServices = emptySet(); private volatile Set<String> subscribedServices = emptySet();
/** /**
@ -152,9 +145,11 @@ public class DubboServiceMetadataRepository
*/ */
private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> dubboRestServiceMetadataRepository = newHashMap(); private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> dubboRestServiceMetadataRepository = newHashMap();
// =============================================================== // // ====================================================================================
// //
// ======================== Dependencies ========================= // // =================================== Dependencies
// =================================== //
@Autowired @Autowired
private DubboCloudProperties dubboCloudProperties; private DubboCloudProperties dubboCloudProperties;
@ -183,7 +178,8 @@ public class DubboServiceMetadataRepository
@Autowired @Autowired
private DubboMetadataServiceExporter dubboMetadataServiceExporter; private DubboMetadataServiceExporter dubboMetadataServiceExporter;
// =============================================================== // // ====================================================================================
// //
private static <K, V> Map<K, V> getMap(Map<String, Map<K, V>> repository, private static <K, V> Map<K, V> getMap(Map<String, Map<K, V>> repository,
String key) { String key) {
@ -191,7 +187,12 @@ public class DubboServiceMetadataRepository
} }
private static <K, V> V getOrDefault(Map<K, V> source, K key, V defaultValue) { private static <K, V> V getOrDefault(Map<K, V> source, K key, V defaultValue) {
return source.computeIfAbsent(key, k -> defaultValue); V value = source.get(key);
if (value == null) {
value = defaultValue;
source.put(key, value);
}
return value;
} }
private static <K, V> Map<K, V> newHashMap() { private static <K, V> Map<K, V> newHashMap() {
@ -236,6 +237,9 @@ public class DubboServiceMetadataRepository
dispatchEvent(new SubscribedServicesChangedEvent(this, oldSubscribedServices, dispatchEvent(new SubscribedServicesChangedEvent(this, oldSubscribedServices,
newSubscribedServices)); newSubscribedServices));
// clear old one, help GC
oldSubscribedServices.clear();
return newSubscribedServices.stream(); return newSubscribedServices.stream();
} }
@ -245,14 +249,13 @@ public class DubboServiceMetadataRepository
@Override @Override
public void afterSingletonsInstantiated() { public void afterSingletonsInstantiated() {
// inited by DubboCloudRegistry.preInit() @theonefx initializeMetadata();
// initializeMetadata();
} }
/** /**
* Initialize the metadata. * Initialize the metadata.
*/ */
public void initializeMetadata() { private void initializeMetadata() {
doGetSubscribedServices().forEach(this::initializeMetadata); doGetSubscribedServices().forEach(this::initializeMetadata);
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info("The metadata of Dubbo services has been initialized"); logger.info("The metadata of Dubbo services has been initialized");
@ -299,36 +302,12 @@ public class DubboServiceMetadataRepository
addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs); addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs);
addDubboProtocolsPortMetadata(metadata); addDubboProtocolsPortMetadata(metadata);
addRevision(metadata);
return Collections.unmodifiableMap(metadata); return Collections.unmodifiableMap(metadata);
} }
private void addRevision(Map<String, String> metadata) {
metadata.put(EXPORTED_SERVICES_REVISION_PROPERTY_NAME, calAndGetRevision());
}
public String calAndGetRevision() {
if (CollectionUtils.isEmptyMap(allExportedURLs)) {
return RevisionResolver.getEmptyRevision();
}
else {
List<String> descs = new ArrayList<>(allExportedURLs.size());
for (Map.Entry<String, List<URL>> entry : allExportedURLs.entrySet()) {
entry.getValue().stream().map(ServiceInfo::new)
.map(ServiceInfo::toDescString).forEach(descs::add);
}
descs.sort(String::compareTo);
return RevisionResolver.calRevision(descs.toString());
}
}
private void removeDubboMetadataServiceURLs(List<URL> dubboMetadataServiceURLs) { private void removeDubboMetadataServiceURLs(List<URL> dubboMetadataServiceURLs) {
dubboMetadataServiceURLs.stream().map(URL::getServiceKey).distinct() dubboMetadataServiceURLs.forEach(this::unexportURL);
.forEach(allExportedURLs::remove);
// dubboMetadataServiceURLs.forEach(this::unexportURL);
} }
private void addDubboMetadataServiceURLsMetadata(Map<String, String> metadata, private void addDubboMetadataServiceURLsMetadata(Map<String, String> metadata,
@ -428,35 +407,9 @@ public class DubboServiceMetadataRepository
public List<URL> getExportedURLs(String serviceInterface, String group, public List<URL> getExportedURLs(String serviceInterface, String group,
String version) { String version) {
if (group != null) {
List<URL> urls = new LinkedList<>();
if (CommonConstants.ANY_VALUE.equals(group)) {
String serviceKey = URL.buildKey(serviceInterface, group, version); String serviceKey = URL.buildKey(serviceInterface, group, version);
String expectKey = serviceKey.substring(2);
for (String key : allExportedURLs.keySet()) {
if (key.endsWith(expectKey)) {
urls.addAll(allExportedURLs.get(key));
}
}
}
else {
String[] groups = group.split(CommonConstants.COMMA_SEPARATOR);
for (String expectKey : groups) {
String serviceKey = URL.buildKey(serviceInterface, expectKey,
version);
List<URL> urlList = allExportedURLs.get(serviceKey);
if (urlList != null) {
urls.addAll(urlList);
}
}
}
return urls;
}
else {
String serviceKey = URL.buildKey(serviceInterface, null, version);
return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList()); return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList());
} }
}
/** /**
* Initialize the specified service's {@link ServiceRestMetadata}. * Initialize the specified service's {@link ServiceRestMetadata}.

View File

@ -1,90 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.registry;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.registry.NotifyListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.dubbo.common.URLBuilder.from;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
/**
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public abstract class AbstractServiceSubscribeHandler {
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected final URL url;
protected final NotifyListener listener;
protected final DubboCloudRegistry registry;
public AbstractServiceSubscribeHandler(URL url, NotifyListener listener,
DubboCloudRegistry registry) {
this.url = url;
this.listener = listener;
this.registry = registry;
}
protected void notifyAllSubscribedURLs(URL url, List<URL> subscribedURLs,
NotifyListener listener) {
if (isEmpty(subscribedURLs)) {
// Add the EMPTY_PROTOCOL URL
listener.notify(Collections.singletonList(emptyURL(url)));
// if (isDubboMetadataServiceURL(url)) {
// if meta service change, and serviceInstances is zero, will clean up
// information about this client
// String serviceName = url.getParameter(GROUP_KEY);
// repository.removeMetadataAndInitializedService(serviceName, url);
// }
}
else {
// Notify all
listener.notify(subscribedURLs);
}
}
private URL emptyURL(URL url) {
// issue : When the last service provider is closed, the client still periodically
// connects to the last provider.n
// fix https://github.com/alibaba/spring-cloud-alibaba/issues/1259
return from(url).setProtocol(EMPTY_PROTOCOL).removeParameter(CATEGORY_KEY)
.build();
}
private final AtomicBoolean inited = new AtomicBoolean(false);
public void init() {
if (inited.compareAndSet(false, true)) {
doInit();
}
}
protected abstract void doInit();
}

View File

@ -16,27 +16,25 @@
package com.alibaba.cloud.dubbo.registry; package com.alibaba.cloud.dubbo.registry;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.dubbo.metadata.RevisionResolver;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository; import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent; import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent;
import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
import com.alibaba.cloud.dubbo.service.DubboMetadataService; import com.alibaba.cloud.dubbo.service.DubboMetadataService;
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy; import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
import com.alibaba.cloud.dubbo.util.DubboMetadataUtils; import com.alibaba.cloud.dubbo.util.DubboMetadataUtils;
import com.alibaba.cloud.dubbo.util.JSONUtils; import com.alibaba.cloud.dubbo.util.JSONUtils;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.support.FailbackRegistry; import org.apache.dubbo.registry.support.FailbackRegistry;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -46,15 +44,25 @@ import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.CollectionUtils;
import static com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository.EXPORTED_SERVICES_REVISION_PROPERTY_NAME; import static java.lang.String.format;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static java.util.stream.StreamSupport.stream;
import static org.apache.dubbo.common.URLBuilder.from;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL; import static org.apache.dubbo.registry.Constants.ADMIN_PROTOCOL;
import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URLS_PROPERTY_NAME; import static org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.METADATA_SERVICE_URLS_PROPERTY_NAME;
import static org.springframework.util.StringUtils.hasText; import static org.springframework.util.StringUtils.hasText;
@ -63,14 +71,22 @@ import static org.springframework.util.StringUtils.hasText;
* Dubbo Cloud {@link FailbackRegistry} is based on Spring Cloud {@link DiscoveryClient}. * Dubbo Cloud {@link FailbackRegistry} is based on Spring Cloud {@link DiscoveryClient}.
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/ */
public class DubboCloudRegistry extends FailbackRegistry public class DubboCloudRegistry extends FailbackRegistry {
implements ApplicationListener<ServiceInstancesChangedEvent> {
/**
* The parameter name of {@link #servicesLookupInterval}.
*/
public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval";
protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class
.getName(); .getName();
/**
* Caches the IDs of {@link ApplicationListener}.
*/
private static final Set<String> REGISTER_LISTENERS = new HashSet<>();
protected final Logger logger = LoggerFactory.getLogger(getClass()); protected final Logger logger = LoggerFactory.getLogger(getClass());
private final DiscoveryClient discoveryClient; private final DiscoveryClient discoveryClient;
@ -81,373 +97,275 @@ public class DubboCloudRegistry extends FailbackRegistry
private final JSONUtils jsonUtils; private final JSONUtils jsonUtils;
private final DubboGenericServiceFactory dubboGenericServiceFactory;
private final DubboMetadataUtils dubboMetadataUtils; private final DubboMetadataUtils dubboMetadataUtils;
/**
* The interval in second of lookup service names(only for Dubbo-OPS).
*/
private final long servicesLookupInterval;
private final ConfigurableApplicationContext applicationContext; private final ConfigurableApplicationContext applicationContext;
private final ReSubscribeManager reSubscribeManager; private final String currentApplicationName;
private final AtomicBoolean inited = new AtomicBoolean(false);
/**
* {subscribedURL : ServiceSubscribeHandler}.
*/
private final Map<URL, GenearalServiceSubscribeHandler> urlSubscribeHandlerMap = new ConcurrentHashMap<>();
/**
* {appName: MetadataServiceSubscribeHandler}.
*/
private final Map<String, MetadataServiceSubscribeHandler> metadataSubscribeHandlerMap = new ConcurrentHashMap<>();
/**
* {appName : {revision: [instances]}}.
*/
private final Map<String, Map<String, List<ServiceInstance>>> serviceRevisionInstanceMap = new ConcurrentHashMap<>();
public DubboCloudRegistry(URL url, DiscoveryClient discoveryClient, public DubboCloudRegistry(URL url, DiscoveryClient discoveryClient,
DubboServiceMetadataRepository repository, DubboServiceMetadataRepository repository,
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy, DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
JSONUtils jsonUtils, ConfigurableApplicationContext applicationContext) { JSONUtils jsonUtils, DubboGenericServiceFactory dubboGenericServiceFactory,
ConfigurableApplicationContext applicationContext) {
super(url); super(url);
this.servicesLookupInterval = url
.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L);
this.discoveryClient = discoveryClient; this.discoveryClient = discoveryClient;
this.repository = repository; this.repository = repository;
this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy; this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy;
this.jsonUtils = jsonUtils; this.jsonUtils = jsonUtils;
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.dubboMetadataUtils = getBean(DubboMetadataUtils.class); this.dubboMetadataUtils = getBean(DubboMetadataUtils.class);
this.reSubscribeManager = new ReSubscribeManager(this); this.currentApplicationName = dubboMetadataUtils.getCurrentApplicationName();
} }
private void preInit() { private <T> T getBean(Class<T> beanClass) {
if (inited.compareAndSet(false, true)) {
Set<String> subscribeApps = getServices(null);
for (String appName : subscribeApps) {
List<ServiceInstance> instances = discoveryClient.getInstances(appName);
Map<String, List<ServiceInstance>> map = serviceRevisionInstanceMap
.computeIfAbsent(appName, k -> new HashMap<>());
for (ServiceInstance instance : instances) {
String revision = getRevision(instance);
List<ServiceInstance> list = map.computeIfAbsent(revision,
k -> new ArrayList<>());
list.add(instance);
}
if (map.size() == 0) {
logger.debug("APP {} preInited, instance siez is zero!!", appName);
}
else {
map.forEach((revision, list) -> logger.debug(
"APP {} revision {} preInited, instance size = {}", appName,
revision, list.size()));
}
}
metadataSubscribeHandlerMap.forEach((url, handler) -> handler.init());
urlSubscribeHandlerMap.forEach((url, handler) -> handler.init());
repository.initializeMetadata();
// meke sure everything prepared, then can listening
// ServiceInstanceChangeEvent
applicationContext.addApplicationListener(this);
logger.info("DubboCloudRegistry preInit Done.");
}
}
protected <T> T getBean(Class<T> beanClass) {
return this.applicationContext.getBean(beanClass); return this.applicationContext.getBean(beanClass);
} }
protected boolean shouldNotRegister(URL url) { protected boolean shouldRegister(URL url) {
String side = url.getParameter(SIDE_KEY); String side = url.getParameter(SIDE_KEY);
boolean should = PROVIDER_SIDE.equals(side); // Only register the Provider. boolean should = PROVIDER_SIDE.equals(side); // Only register the Provider.
if (logger.isDebugEnabled()) {
if (!should) { if (!should) {
logger.debug("The URL should NOT!! be registered & unregistered [{}] .", if (logger.isDebugEnabled()) {
url); logger.debug("The URL[{}] should not be registered.", url.toString());
}
else {
logger.debug("The URL should be registered & unregistered [{}] .", url);
} }
} }
return !should; return should;
} }
@Override @Override
public final void doRegister(URL url) { public final void doRegister(URL url) {
synchronized (this) { if (!shouldRegister(url)) {
preInit();
if (shouldNotRegister(url)) {
return; return;
} }
repository.exportURL(url); repository.exportURL(url);
} }
}
@Override @Override
public final void doUnregister(URL url) { public final void doUnregister(URL url) {
synchronized (this) { if (!shouldRegister(url)) {
preInit();
if (shouldNotRegister(url)) {
return; return;
} }
repository.unexportURL(url); repository.unexportURL(url);
} }
}
@Override @Override
public final void doSubscribe(URL url, NotifyListener listener) { public final void doSubscribe(URL url, NotifyListener listener) {
synchronized (this) {
preInit();
if (isAdminURL(url)) { if (isAdminURL(url)) {
// TODO in future // TODO in future
if (logger.isWarnEnabled()) {
logger.warn("This feature about admin will be supported in the future.");
}
}
else if (isDubboMetadataServiceURL(url)) { // for DubboMetadataService
subscribeDubboMetadataServiceURLs(url, listener);
}
else { // for general Dubbo Services
subscribeURLs(url, listener);
}
}
private void subscribeURLs(URL url, NotifyListener listener) {
// Sync subscription
subscribeURLs(url, getServices(url), listener);
// Async subscription
registerServiceInstancesChangedListener(url,
new ApplicationListener<ServiceInstancesChangedEvent>() {
private final URL url2subscribe = url;
@Override
@Order
public void onApplicationEvent(ServiceInstancesChangedEvent event) {
Set<String> serviceNames = getServices(url);
String serviceName = event.getServiceName();
if (serviceNames.contains(serviceName)) {
subscribeURLs(url, serviceNames, listener);
}
}
@Override
public String toString() {
return "ServiceInstancesChangedEventListener:"
+ url.getServiceKey();
}
});
}
private void subscribeURLs(URL url, Set<String> serviceNames,
NotifyListener listener) {
List<URL> subscribedURLs = new LinkedList<>();
serviceNames.forEach(serviceName -> {
subscribeURLs(url, subscribedURLs, serviceName,
() -> getServiceInstances(serviceName));
});
// Notify all
notifyAllSubscribedURLs(url, subscribedURLs, listener);
}
private void registerServiceInstancesChangedListener(URL url,
ApplicationListener<ServiceInstancesChangedEvent> listener) {
String listenerId = generateId(url);
if (REGISTER_LISTENERS.add(listenerId)) {
applicationContext.addApplicationListener(listener);
}
}
private void subscribeURLs(URL subscribedURL, List<URL> subscribedURLs,
String serviceName,
Supplier<List<ServiceInstance>> serviceInstancesSupplier) {
List<ServiceInstance> serviceInstances = serviceInstancesSupplier.get();
subscribeURLs(subscribedURL, subscribedURLs, serviceName, serviceInstances);
}
private void subscribeURLs(URL subscribedURL, List<URL> subscribedURLs,
String serviceName, List<ServiceInstance> serviceInstances) {
if (CollectionUtils.isEmpty(serviceInstances)) {
if (logger.isWarnEnabled()) {
logger.warn(format("There is no instance in service[name : %s]",
serviceName));
}
}
List<URL> exportedURLs = getExportedURLs(subscribedURL, serviceName,
serviceInstances);
/**
* Add the exported URLs from {@link MetadataService}
*/
subscribedURLs.addAll(exportedURLs);
}
private List<URL> getExportedURLs(URL subscribedURL, String serviceName,
List<ServiceInstance> serviceInstances) {
List<ServiceInstance> validServiceInstances = filter(serviceInstances);
// If there is no valid ServiceInstance, return empty result
if (isEmpty(validServiceInstances)) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn( logger.warn(
"This feature about admin will be supported in the future."); "There is no instance from service[name : {}], and then Dubbo Service[key : {}] will not be "
} + "available , please make sure the further impact",
} serviceName, subscribedURL.getServiceKey());
else if (isDubboMetadataServiceURL(url) && containsProviderCategory(url)) {
// for DubboMetadataService
String appName = getServiceName(url);
MetadataServiceSubscribeHandler handler = new MetadataServiceSubscribeHandler(
appName, url, listener, this, dubboMetadataUtils);
if (inited.get()) {
handler.init();
}
metadataSubscribeHandlerMap.put(appName, handler);
}
else if (isConsumerServiceURL(url)) {
// for general Dubbo Services
GenearalServiceSubscribeHandler handler = new GenearalServiceSubscribeHandler(
url, listener, this, repository, jsonUtils,
dubboMetadataConfigServiceProxy);
if (inited.get()) {
handler.init();
}
urlSubscribeHandlerMap.put(url, handler);
} }
return emptyList();
} }
List<URL> subscribedURLs = cloneExportedURLs(subscribedURL, serviceInstances);
// clear local service instances, help GC
validServiceInstances.clear();
return subscribedURLs;
} }
/** /**
* Process ServiceInstanceChangedEvent, refresh dubbo reference and metadata info. * Clone the subscribed URLs based on the template URLs.
* @param subscribedURL the URL to be subscribed
* @param serviceInstances the list of {@link ServiceInstance service instances}
* @return non-null
*/ */
@Override private List<URL> cloneExportedURLs(URL subscribedURL,
public void onApplicationEvent(ServiceInstancesChangedEvent event) {
String appName = event.getServiceName();
List<ServiceInstance> instances = filter(
event.getServiceInstances() != null ? event.getServiceInstances()
: Collections.emptyList());
Set<String> subscribedServiceNames = getServices(null);
if (!subscribedServiceNames.contains(appName)) {
return;
}
if (instances.size() == 0) {
logger.warn("APP {} instance changed, size changed zero!!!", appName);
}
else {
logger.info("APP {} instance changed, size changed to {}", appName,
instances.size());
}
// group by revision
Map<String, List<ServiceInstance>> newGroup = instances.stream()
.collect(Collectors.groupingBy(this::getRevision));
synchronized (this) {
Map<String, List<ServiceInstance>> oldGroup = serviceRevisionInstanceMap
.computeIfAbsent(appName, k -> new HashMap<>());
if (serviceInstanceNotChanged(oldGroup, newGroup)) {
logger.debug("APP {} instance changed, but nothing different", appName);
return;
}
try {
// ensure that the service metadata is correct
refreshServiceMetadataInfo(appName, instances);
// then , refresh general service associated with current application
refreshGeneralServiceInfo(appName, oldGroup, newGroup);
// mark process successful
reSubscribeManager.onRefreshSuccess(event);
}
catch (Exception e) {
logger.error(String.format(
"APP %s instance changed, handler faild, try resubscribe",
appName), e);
reSubscribeManager.onRefreshFail(event);
}
}
}
private void refreshGeneralServiceInfo(String appName,
Map<String, List<ServiceInstance>> oldGroup,
Map<String, List<ServiceInstance>> newGroup) {
Set<URL> urls2refresh = new HashSet<>();
// compare with local
for (String revision : oldGroup.keySet()) {
if (!newGroup.containsKey(revision)) {
// all instances of this list with revision has losted
urlSubscribeHandlerMap.forEach((url, handler) -> {
if (handler.relatedWith(appName, revision)) {
handler.removeAppNameWithRevision(appName, revision);
urls2refresh.add(url);
}
});
logger.debug("Subscription app {} revision {} has all losted", appName,
revision);
}
}
for (Map.Entry<String, List<ServiceInstance>> entry : newGroup.entrySet()) {
String revision = entry.getKey();
List<ServiceInstance> instanceList = entry.getValue();
if (!oldGroup.containsKey(revision)) {
// this instance list of revision not exists
// should acquire urls
urlSubscribeHandlerMap.forEach(
(url, handler) -> handler.init(appName, revision, instanceList));
}
urlSubscribeHandlerMap.forEach((url, handler) -> {
if (handler.relatedWith(appName, revision)) {
urls2refresh.add(url);
}
});
if (logger.isDebugEnabled()) {
logger.debug("Subscription app {} revision {} changed, instance list {}",
appName, revision,
instanceList.stream().map(
instance -> instance.getHost() + ":" + instance.getPort())
.collect(Collectors.toList()));
}
}
serviceRevisionInstanceMap.put(appName, newGroup);
if (urls2refresh.size() == 0) {
logger.debug("Subscription app {}, no urls will be refreshed", appName);
}
else {
logger.debug("Subscription app {}, the following url will be refresh:{}",
appName, urls2refresh.stream().map(URL::getServiceKey)
.collect(Collectors.toList()));
for (URL url : urls2refresh) {
GenearalServiceSubscribeHandler handler = urlSubscribeHandlerMap.get(url);
if (handler == null) {
logger.warn("Subscription app {}, can't find handler for service {}",
appName, url.getServiceKey());
continue;
}
handler.refresh();
}
}
}
private void refreshServiceMetadataInfo(String serviceName,
List<ServiceInstance> serviceInstances) { List<ServiceInstance> serviceInstances) {
MetadataServiceSubscribeHandler handler = metadataSubscribeHandlerMap
.get(serviceName);
if (handler == null) { List<URL> clonedExportedURLs = new LinkedList<>();
logger.warn("Subscription app {}, can't find metadata handler", serviceName);
return; serviceInstances.forEach(serviceInstance -> {
}
handler.refresh(serviceInstances); String host = serviceInstance.getHost();
getTemplateExportedURLs(subscribedURL, serviceInstances).stream()
.map(templateURL -> templateURL.removeParameter(TIMESTAMP_KEY))
.map(templateURL -> templateURL.removeParameter(PID_KEY))
.map(templateURL -> {
String protocol = templateURL.getProtocol();
Integer port = repository.getDubboProtocolPort(serviceInstance,
protocol);
if (Objects.equals(templateURL.getHost(), host)
&& Objects.equals(templateURL.getPort(), port)) { // use
// templateURL
// if
// equals
return templateURL;
} }
private boolean serviceInstanceNotChanged(Map<String, List<ServiceInstance>> oldGroup, if (port == null) {
Map<String, List<ServiceInstance>> newGroup) { if (logger.isWarnEnabled()) {
if (newGroup.size() != oldGroup.size()) { logger.warn(
return false; "The protocol[{}] port of Dubbo service instance[host : {}] "
+ "can't be resolved",
protocol, host);
}
return null;
}
else {
URLBuilder clonedURLBuilder = from(templateURL) // remove the
// parameters from
// the template
// URL
.setHost(host) // reset the host
.setPort(port); // reset the port
return clonedURLBuilder.build();
} }
for (Map.Entry<String, List<ServiceInstance>> entry : newGroup.entrySet()) { }).filter(Objects::nonNull).forEach(clonedExportedURLs::add);
String appName = entry.getKey();
List<ServiceInstance> newInstances = entry.getValue();
if (!oldGroup.containsKey(appName)) {
return false;
}
List<ServiceInstance> oldInstances = oldGroup.get(appName);
if (newInstances.size() != oldInstances.size()) {
return false;
}
boolean matched = newInstances.stream().allMatch(newInstance -> {
for (ServiceInstance oldInstance : oldInstances) {
if (instanceSame(newInstance, oldInstance)) {
return true;
}
}
return false;
}); });
if (!matched) { return clonedExportedURLs;
return false;
}
} }
return true; private List<URL> getTemplateExportedURLs(URL subscribedURL,
List<ServiceInstance> serviceInstances) {
DubboMetadataService dubboMetadataService = getProxy(serviceInstances);
List<URL> templateExportedURLs = emptyList();
if (dubboMetadataService != null) {
templateExportedURLs = getExportedURLs(dubboMetadataService, subscribedURL);
}
else {
if (logger.isWarnEnabled()) {
logger.warn(
"The metadata of Dubbo service[key : {}] still can't be found, it could effect the further "
+ "Dubbo service invocation",
subscribedURL.getServiceKey());
} }
private boolean instanceSame(ServiceInstance newInstance,
ServiceInstance oldInstance) {
if (!StringUtils.equals(newInstance.getInstanceId(),
oldInstance.getInstanceId())) {
return false;
}
if (!StringUtils.equals(newInstance.getHost(), oldInstance.getHost())) {
return false;
}
if (!StringUtils.equals(newInstance.getServiceId(), oldInstance.getServiceId())) {
return false;
}
if (!StringUtils.equals(newInstance.getScheme(), oldInstance.getScheme())) {
return false;
}
if (oldInstance.getPort() != newInstance.getPort()) {
return false;
} }
if (!oldInstance.getMetadata().equals(newInstance.getMetadata())) { return templateExportedURLs;
return false;
} }
return true; private DubboMetadataService getProxy(List<ServiceInstance> serviceInstances) {
} return dubboMetadataConfigServiceProxy.getProxy(serviceInstances);
String getRevision(ServiceInstance instance) {
Map<String, String> metadata = instance.getMetadata();
String revision = metadata.get(EXPORTED_SERVICES_REVISION_PROPERTY_NAME);
if (revision == null) {
revision = RevisionResolver.getEmptyRevision();
}
return revision;
} }
private List<ServiceInstance> filter(Collection<ServiceInstance> serviceInstances) { private List<ServiceInstance> filter(Collection<ServiceInstance> serviceInstances) {
@ -462,14 +380,40 @@ public class DubboCloudRegistry extends FailbackRegistry
private Set<String> getServices(URL url) { private Set<String> getServices(URL url) {
Set<String> subscribedServices = repository.getSubscribedServices(); Set<String> subscribedServices = repository.getSubscribedServices();
if (subscribedServices.contains("*")) {
subscribedServices = new HashSet<>(discoveryClient.getServices());
}
// TODO Add the filter feature // TODO Add the filter feature
return subscribedServices; return subscribedServices;
} }
List<ServiceInstance> getServiceInstances(String serviceName) { private void notifyAllSubscribedURLs(URL url, List<URL> subscribedURLs,
NotifyListener listener) {
if (isEmpty(subscribedURLs)) {
// Add the EMPTY_PROTOCOL URL
subscribedURLs.add(emptyURL(url));
// if (isDubboMetadataServiceURL(url)) {
// if meta service change, and serviceInstances is zero, will clean up
// information about this client
// String serviceName = url.getParameter(GROUP_KEY);
// repository.removeMetadataAndInitializedService(serviceName, url);
// }
}
if (logger.isDebugEnabled()) {
logger.debug("The subscribed URL[{}] will notify all URLs : {}", url,
subscribedURLs);
}
// Notify all
listener.notify(subscribedURLs);
}
private List<ServiceInstance> getServiceInstances(Iterable<String> serviceNames) {
return stream(serviceNames.spliterator(), false).map(this::getServiceInstances)
.flatMap(Collection::stream).collect(Collectors.toList());
}
private List<ServiceInstance> getServiceInstances(String serviceName) {
return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList(); return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList();
} }
@ -486,14 +430,106 @@ public class DubboCloudRegistry extends FailbackRegistry
return serviceInstances; return serviceInstances;
} }
// the group of DubboMetadataService is current application name private String generateId(URL url) {
return url.toString();
}
private URL emptyURL(URL url) {
// issue : When the last service provider is closed, the client still periodically
// connects to the last provider.n
// fix https://github.com/alibaba/spring-cloud-alibaba/issues/1259
return from(url).setProtocol(EMPTY_PROTOCOL).removeParameter(CATEGORY_KEY)
.build();
}
private List<URL> getExportedURLs(DubboMetadataService dubboMetadataService,
URL subscribedURL) {
String serviceInterface = subscribedURL.getServiceInterface();
String group = subscribedURL.getParameter(GROUP_KEY);
String version = subscribedURL.getParameter(VERSION_KEY);
// The subscribed protocol may be null
String subscribedProtocol = subscribedURL.getParameter(PROTOCOL_KEY);
String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface,
group, version);
return jsonUtils.toURLs(exportedURLsJSON).stream()
.filter(exportedURL -> subscribedProtocol == null
|| subscribedProtocol.equalsIgnoreCase(exportedURL.getProtocol()))
.collect(Collectors.toList());
}
private void subscribeDubboMetadataServiceURLs(URL subscribedURL,
NotifyListener listener) {
// Sync subscription
subscribeDubboMetadataServiceURLs(subscribedURL, listener,
getServiceName(subscribedURL));
// Sync subscription
if (containsProviderCategory(subscribedURL)) {
registerServiceInstancesChangedListener(subscribedURL,
new ApplicationListener<ServiceInstancesChangedEvent>() {
private final URL url2subscribe = subscribedURL;
@Override
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public void onApplicationEvent(
ServiceInstancesChangedEvent event) {
String sourceServiceName = event.getServiceName();
String serviceName = getServiceName(subscribedURL);
if (Objects.equals(sourceServiceName, serviceName)) {
subscribeDubboMetadataServiceURLs(subscribedURL, listener,
sourceServiceName);
}
}
@Override
public String toString() {
return "ServiceInstancesChangedEventListener:"
+ subscribedURL.getServiceKey();
}
});
}
}
private String getServiceName(URL subscribedURL) { private String getServiceName(URL subscribedURL) {
return subscribedURL.getParameter(GROUP_KEY); return subscribedURL.getParameter(GROUP_KEY);
} }
private void subscribeDubboMetadataServiceURLs(URL subscribedURL,
NotifyListener listener, String serviceName) {
String serviceInterface = subscribedURL.getServiceInterface();
String version = subscribedURL.getParameter(VERSION_KEY);
String protocol = subscribedURL.getParameter(PROTOCOL_KEY);
List<ServiceInstance> serviceInstances = getServiceInstances(serviceName);
List<URL> urls = dubboMetadataUtils.getDubboMetadataServiceURLs(serviceInstances,
serviceInterface, version, protocol);
notifyAllSubscribedURLs(subscribedURL, urls, listener);
}
// private void subscribeDubboMetadataServiceURLs(URL subscribedURL,
// NotifyListener listener, Set<String> serviceNames) {
//
// String serviceInterface = subscribedURL.getServiceInterface();
// String version = subscribedURL.getParameter(VERSION_KEY);
// String protocol = subscribedURL.getParameter(PROTOCOL_KEY);
//
// List<ServiceInstance> serviceInstances = getServiceInstances(serviceNames);
//
// List<URL> urls = dubboMetadataUtils.getDubboMetadataServiceURLs(serviceInstances,
// serviceInterface, version, protocol);
//
// notifyAllSubscribedURLs(subscribedURL, urls, listener);
// }
private boolean containsProviderCategory(URL subscribedURL) { private boolean containsProviderCategory(URL subscribedURL) {
String category = subscribedURL.getParameter(CATEGORY_KEY); String category = subscribedURL.getParameter(CATEGORY_KEY);
return category != null && category.contains(PROVIDER); return category == null ? false : category.contains(PROVIDER);
} }
@Override @Override
@ -514,32 +550,4 @@ public class DubboCloudRegistry extends FailbackRegistry
return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface()); return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface());
} }
protected boolean isConsumerServiceURL(URL url) {
return CONSUMER.equals(url.getProtocol());
}
public List<ServiceInstance> getServiceInstances(Map<String, Set<String>> providers) {
List<ServiceInstance> instances = new ArrayList<>();
providers.forEach((appName, revisions) -> {
Map<String, List<ServiceInstance>> revisionMap = serviceRevisionInstanceMap
.get(appName);
if (revisionMap == null) {
return;
}
for (String revision : revisions) {
List<ServiceInstance> list = revisionMap.get(revision);
if (list != null) {
instances.addAll(list);
}
}
});
return instances;
}
public Map<String, Map<String, List<ServiceInstance>>> getServiceRevisionInstanceMap() {
return serviceRevisionInstanceMap;
}
} }

View File

@ -1,270 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.registry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
import com.alibaba.cloud.dubbo.service.DubboMetadataService;
import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
import com.alibaba.cloud.dubbo.util.JSONUtils;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.registry.NotifyListener;
import org.springframework.cloud.client.ServiceInstance;
import static java.util.Collections.emptyList;
import static org.apache.dubbo.common.URLBuilder.from;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
/**
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public class GenearalServiceSubscribeHandler extends AbstractServiceSubscribeHandler {
private final Map<String, Set<String>> providers = new HashMap<>();
private final Map<String, URL> urlTemplateMap = new HashMap<>();
private final JSONUtils jsonUtils;
private final DubboServiceMetadataRepository repository;
private final DubboMetadataServiceProxy dubboMetadataConfigServiceProxy;
public GenearalServiceSubscribeHandler(URL url, NotifyListener listener,
DubboCloudRegistry registry, DubboServiceMetadataRepository repository,
JSONUtils jsonUtils,
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy) {
super(url, listener, registry);
this.repository = repository;
this.jsonUtils = jsonUtils;
this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy;
}
public boolean relatedWith(String appName, String revision) {
Set<String> list = providers.get(appName);
if (list != null && list.size() > 0) {
if (list.contains(revision)) {
return true;
}
}
return false;
}
public void removeAppNameWithRevision(String appName, String revision) {
Set<String> list = providers.get(appName);
if (list != null) {
list.remove(revision);
if (list.size() == 0) {
providers.remove(appName);
}
}
}
public void addAppNameWithRevision(String appName, String revision) {
Set<String> set = providers.computeIfAbsent(appName, k -> new HashSet<>());
set.add(revision);
}
public synchronized void doInit() {
logger.debug("Subscription interface {}, GenearalServiceSubscribeHandler init",
url.getServiceKey());
Map<String, Map<String, List<ServiceInstance>>> map = registry
.getServiceRevisionInstanceMap();
for (Map.Entry<String, Map<String, List<ServiceInstance>>> entry : map
.entrySet()) {
String appName = entry.getKey();
Map<String, List<ServiceInstance>> revisionMap = entry.getValue();
for (Map.Entry<String, List<ServiceInstance>> revisionEntity : revisionMap
.entrySet()) {
String revision = revisionEntity.getKey();
List<ServiceInstance> instances = revisionEntity.getValue();
init(appName, revision, instances);
}
}
refresh();
}
public void init(String appName, String revision,
List<ServiceInstance> instanceList) {
List<URL> urls = getTemplateExportedURLs(url, instanceList);
if (urls != null && urls.size() > 0) {
addAppNameWithRevision(appName, revision);
setUrlTemplate(appName, revision, urls);
}
}
public synchronized void refresh() {
List<URL> urls = getProviderURLs();
notifyAllSubscribedURLs(url, urls, listener);
}
private List<URL> getProviderURLs() {
List<ServiceInstance> instances = registry.getServiceInstances(providers);
logger.debug("Subscription interfece {}, providers {}, total {}",
url.getServiceKey(), providers, instances.size());
if (instances.size() == 0) {
return Collections.emptyList();
}
return cloneExportedURLs(instances);
}
void setUrlTemplate(String appName, String revision, List<URL> urls) {
if (urls == null || urls.size() == 0) {
return;
}
String key = getAppRevisionKey(appName, revision);
if (urlTemplateMap.containsKey(key)) {
return;
}
urlTemplateMap.put(key, urls.get(0));
}
private String getAppRevisionKey(String appName, String revision) {
return appName + "@" + revision;
}
/**
* Clone the subscribed URLs based on the template URLs.
* @param serviceInstances the list of
* {@link org.springframework.cloud.client.ServiceInstance service instances}
* @return
*/
List<URL> cloneExportedURLs(List<ServiceInstance> serviceInstances) {
List<URL> urlsCloneTo = new ArrayList<>();
serviceInstances.forEach(serviceInstance -> {
String host = serviceInstance.getHost();
String appName = serviceInstance.getServiceId();
String revision = registry.getRevision(serviceInstance);
URL template = urlTemplateMap.get(getAppRevisionKey(appName, revision));
Stream.of(template)
.map(templateURL -> templateURL.removeParameter(TIMESTAMP_KEY))
.map(templateURL -> templateURL.removeParameter(PID_KEY))
.map(templateURL -> {
String protocol = templateURL.getProtocol();
Integer port = repository.getDubboProtocolPort(serviceInstance,
protocol);
// reserve tag
String tag = null;
List<URL> urls = jsonUtils.toURLs(serviceInstance.getMetadata()
.get("dubbo.metadata-service.urls"));
if (urls != null && urls.size() > 0) {
Map<String, String> parameters = urls.get(0).getParameters();
tag = parameters.get("dubbo.tag");
}
if (Objects.equals(templateURL.getHost(), host)
&& Objects.equals(templateURL.getPort(), port)) { // use
// templateURL
// if
// equals
return templateURL;
}
if (port == null) {
if (logger.isWarnEnabled()) {
logger.warn(
"The protocol[{}] port of Dubbo service instance[host : {}] "
+ "can't be resolved",
protocol, host);
}
return null;
}
else {
URLBuilder clonedURLBuilder = from(templateURL) // remove the
// parameters from
// the template
// URL
.setHost(host) // reset the host
.setPort(port) // reset the port
.addParameter("dubbo.tag", tag); // reset the tag
return clonedURLBuilder.build();
}
}).filter(Objects::nonNull).forEach(urlsCloneTo::add);
});
return urlsCloneTo;
}
private List<URL> getTemplateExportedURLs(URL subscribedURL,
List<ServiceInstance> serviceInstances) {
DubboMetadataService dubboMetadataService = getProxy(serviceInstances);
List<URL> templateExportedURLs = emptyList();
if (dubboMetadataService != null) {
templateExportedURLs = getExportedURLs(dubboMetadataService, subscribedURL);
}
else {
if (logger.isWarnEnabled()) {
logger.warn(
"The metadata of Dubbo service[key : {}] still can't be found, it could effect the further "
+ "Dubbo service invocation",
subscribedURL.getServiceKey());
}
}
return templateExportedURLs;
}
private DubboMetadataService getProxy(List<ServiceInstance> serviceInstances) {
return dubboMetadataConfigServiceProxy.getProxy(serviceInstances);
}
private List<URL> getExportedURLs(DubboMetadataService dubboMetadataService,
URL subscribedURL) {
String serviceInterface = subscribedURL.getServiceInterface();
String group = subscribedURL.getParameter(GROUP_KEY);
String version = subscribedURL.getParameter(VERSION_KEY);
// The subscribed protocol may be null
String subscribedProtocol = subscribedURL.getParameter(PROTOCOL_KEY);
String exportedURLsJSON = dubboMetadataService.getExportedURLs(serviceInterface,
group, version);
return jsonUtils.toURLs(exportedURLsJSON).stream()
.filter(exportedURL -> subscribedProtocol == null
|| subscribedProtocol.equalsIgnoreCase(exportedURL.getProtocol()))
.collect(Collectors.toList());
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.registry;
import java.util.List;
import com.alibaba.cloud.dubbo.util.DubboMetadataUtils;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.registry.NotifyListener;
import org.springframework.cloud.client.ServiceInstance;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
/**
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public class MetadataServiceSubscribeHandler extends AbstractServiceSubscribeHandler {
private final String appName;
private final DubboMetadataUtils dubboMetadataUtils;
public MetadataServiceSubscribeHandler(String appName, URL url,
NotifyListener listener, DubboCloudRegistry registry,
DubboMetadataUtils dubboMetadataUtils) {
super(url, listener, registry);
this.appName = appName;
this.dubboMetadataUtils = dubboMetadataUtils;
}
public void doInit() {
logger.debug("Subscription app {} MetadataService handler init", appName);
List<ServiceInstance> serviceInstances = registry.getServiceInstances(appName);
subscribeDubboMetadataServiceURLs(url, listener, serviceInstances);
}
public void refresh(List<ServiceInstance> serviceInstances) {
logger.debug("Subscription app {}, instance changed, new size = {}", appName,
serviceInstances.size());
subscribeDubboMetadataServiceURLs(url, listener, serviceInstances);
}
private void subscribeDubboMetadataServiceURLs(URL subscribedURL,
NotifyListener listener, List<ServiceInstance> serviceInstances) {
logger.debug("Subscription app {}, service instance changed to size {}", appName,
serviceInstances.size());
String serviceInterface = subscribedURL.getServiceInterface();
String version = subscribedURL.getParameter(VERSION_KEY);
String protocol = subscribedURL.getParameter(PROTOCOL_KEY);
List<URL> urls = dubboMetadataUtils.getDubboMetadataServiceURLs(serviceInstances,
serviceInterface, version, protocol);
notifyAllSubscribedURLs(subscribedURL, urls, listener);
}
}

View File

@ -1,125 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.registry;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.alibaba.cloud.dubbo.env.DubboCloudProperties;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
/**
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
*/
public class ReSubscribeManager {
private final Logger logger = LoggerFactory.getLogger(ReSubscribeManager.class);
private final Map<String, ReSubscribeMetadataJob> reConnectJobMap = new ConcurrentHashMap<>();
private final ScheduledThreadPoolExecutor reConnectPool = new ScheduledThreadPoolExecutor(
5);
private final DubboCloudRegistry registry;
private final DubboCloudProperties properties;
public ReSubscribeManager(DubboCloudRegistry registry) {
this.registry = registry;
this.properties = registry.getBean(DubboCloudProperties.class);
reConnectPool.setKeepAliveTime(10, TimeUnit.MINUTES);
reConnectPool.allowCoreThreadTimeOut(true);
}
public void onRefreshSuccess(ServiceInstancesChangedEvent event) {
reConnectJobMap.remove(event.getServiceName());
}
public void onRefreshFail(ServiceInstancesChangedEvent event) {
String serviceName = event.getServiceName();
int count = 1;
if (event instanceof FakeServiceInstancesChangedEvent) {
count = ((FakeServiceInstancesChangedEvent) event).getCount() + 1;
}
if (count >= properties.getMaxReSubscribeMetadataTimes()) {
logger.error(
"reSubscribe failed too many times, serviceName = {}, count = {}",
serviceName, count);
return;
}
ReSubscribeMetadataJob job = new ReSubscribeMetadataJob(serviceName, count);
reConnectPool.schedule(job, properties.getReSubscribeMetadataIntervial(),
TimeUnit.SECONDS);
}
private final class ReSubscribeMetadataJob implements Runnable {
private final String serviceName;
private final int errorCounts;
private ReSubscribeMetadataJob(String serviceName, int errorCounts) {
this.errorCounts = errorCounts;
this.serviceName = serviceName;
}
@Override
public void run() {
if (!reConnectJobMap.containsKey(serviceName)
|| reConnectJobMap.get(serviceName) != this) {
return;
}
List<ServiceInstance> list = registry.getServiceInstances(serviceName);
FakeServiceInstancesChangedEvent event = new FakeServiceInstancesChangedEvent(
serviceName, list, errorCounts);
registry.onApplicationEvent(event);
}
}
private static final class FakeServiceInstancesChangedEvent
extends ServiceInstancesChangedEvent {
private static final long serialVersionUID = -2832478604601472915L;
private final int count;
private FakeServiceInstancesChangedEvent(String serviceName,
List<ServiceInstance> serviceInstances, int count) {
super(serviceName, serviceInstances);
this.count = count;
}
public int getCount() {
return count;
}
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.dubbo.registry;
import com.alibaba.cloud.dubbo.registry.event.ServiceInstancesChangedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.Ordered;
/**
* The interface of ServiceInstanceChange event Listener.
*
* @author <a href="mailto:chenxilzx1@gmail.com">theonefx</a>
* @see ServiceInstancesChangedEvent
* @see Ordered
* @see ApplicationListener
*/
public interface ServiceInstanceChangeListener
extends ApplicationListener<ServiceInstancesChangedEvent>, Ordered {
}

View File

@ -89,7 +89,7 @@ public class SpringCloudRegistryFactory extends AbstractRegistryFactory {
DubboCloudProperties dubboCloudProperties = applicationContext DubboCloudProperties dubboCloudProperties = applicationContext
.getBean(DubboCloudProperties.class); .getBean(DubboCloudProperties.class);
Registry registry; Registry registry = null;
switch (dubboCloudProperties.getRegistryType()) { switch (dubboCloudProperties.getRegistryType()) {
case SPRING_CLOUD_REGISTRY_PROPERTY_VALUE: case SPRING_CLOUD_REGISTRY_PROPERTY_VALUE:
@ -100,7 +100,7 @@ public class SpringCloudRegistryFactory extends AbstractRegistryFactory {
default: default:
registry = new DubboCloudRegistry(url, discoveryClient, registry = new DubboCloudRegistry(url, discoveryClient,
dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy,
jsonUtils, applicationContext); jsonUtils, dubboGenericServiceFactory, applicationContext);
break; break;
} }

View File

@ -1 +0,0 @@
default=com.alibaba.cloud.dubbo.metadata.DefaultMetadataParamsFilter