mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
bc2b835d62
@ -37,7 +37,7 @@ Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。
|
||||
|
||||
**[Dubbo](https://github.com/apache/incubator-dubbo)**:Apache Dubbo™ (incubating) 是一款高性能 Java RPC 框架。
|
||||
|
||||
**[Fescar](https://github.com/alibaba/fescar)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
|
||||
**[Seata](https://github.com/seata/seata)**:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
|
||||
|
||||
**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产品。
|
||||
|
||||
|
@ -37,7 +37,7 @@ For more features, please refer to [Roadmap](https://github.com/spring-cloud-inc
|
||||
|
||||
**[Dubbo](https://github.com/apache/incubator-dubbo)**:A high-performance, Java based open source RPC framework.
|
||||
|
||||
**[Fescar](https://github.com/alibaba/fescar)**:A distributed transaction solution with high performance and ease of use for microservices architecture.
|
||||
**[Seata](https://github.com/seata/seata)**:A distributed transaction solution with high performance and ease of use for microservices architecture.
|
||||
|
||||
**[Alibaba Cloud ACM](https://www.aliyun.com/product/acm)**:An application configuration center that enables you to centralize the management of application configurations, and accomplish real-time configuration push in a distributed environment.
|
||||
|
||||
@ -121,6 +121,8 @@ Examples:
|
||||
|
||||
[Alibaba Cloud OSS Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/oss-example/readme.md)
|
||||
|
||||
[Duboo Spring Cloud Example](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/spring-cloud-alibaba-dubbo-examples/README_CN.md)
|
||||
|
||||
## Version control guidelines
|
||||
The version number of the project is in the form of x.x.x, where x is a number, starting from 0, and is not limited to the range 0~9. When the project is in the incubator phase, the version number is 0.x.x.
|
||||
|
||||
|
8
pom.xml
8
pom.xml
@ -14,7 +14,7 @@
|
||||
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Alibaba</name>
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
<organization>Alibaba</organization>
|
||||
<url>https://github.com/mercyblitz</url>
|
||||
</developer>
|
||||
<developer>
|
||||
<developer>
|
||||
<name>yunzheng</name>
|
||||
<email>yunzheng1228@gmail.com</email>
|
||||
</developer>
|
||||
@ -93,10 +93,10 @@
|
||||
<module>spring-cloud-alibaba-dependencies</module>
|
||||
<module>spring-cloud-alibaba-sentinel</module>
|
||||
<module>spring-cloud-alibaba-sentinel-datasource</module>
|
||||
<module>spring-cloud-alibaba-sentinel-zuul</module>
|
||||
<module>spring-cloud-alibaba-sentinel-gateway</module>
|
||||
<module>spring-cloud-alibaba-nacos-config</module>
|
||||
<module>spring-cloud-alibaba-nacos-discovery</module>
|
||||
<module>spring-cloud-alibaba-fescar</module>
|
||||
<module>spring-cloud-alibaba-seata</module>
|
||||
<module>spring-cloud-stream-binder-rocketmq</module>
|
||||
<module>spring-cloud-alibaba-nacos-config-server</module>
|
||||
<module>spring-cloud-alibaba-dubbo</module>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<name>Spring Cloud Alibaba Coverage</name>
|
||||
|
||||
<properties>
|
||||
<spring.cloud.alibaba.version>2.1.0.BUILD-SNAPSHOT</spring.cloud.alibaba.version>
|
||||
<spring.cloud.alibaba.version>0.9.1.BUILD-SNAPSHOT</spring.cloud.alibaba.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@ -63,7 +63,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-alibaba-seata</artifactId>
|
||||
<version>${spring.cloud.alibaba.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@ -98,4 +98,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
@ -11,29 +11,29 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Alibaba Dependencies</name>
|
||||
<description>Spring Cloud Alibaba Dependencies</description>
|
||||
|
||||
<properties>
|
||||
<sentinel.version>1.4.2</sentinel.version>
|
||||
<sentinel.version>1.6.0</sentinel.version>
|
||||
<oss.version>3.1.0</oss.version>
|
||||
<fescar.version>0.4.0</fescar.version>
|
||||
<nacos.client.version>1.0.0-RC4-SNAPSHOT</nacos.client.version>
|
||||
<seata.version>0.5.1</seata.version>
|
||||
<nacos.client.version>1.0.0</nacos.client.version>
|
||||
<nacos.config.version>0.8.0</nacos.config.version>
|
||||
<acm.version>1.0.8</acm.version>
|
||||
<acm.version>1.0.9</acm.version>
|
||||
<ans.version>1.0.1</ans.version>
|
||||
<aliyun.sdk.version>4.0.1</aliyun.sdk.version>
|
||||
<aliyun.sdk.version>4.4.1</aliyun.sdk.version>
|
||||
<alicloud.context.version>1.0.5</alicloud.context.version>
|
||||
<aliyun.sdk.edas.version>2.16.0</aliyun.sdk.edas.version>
|
||||
<aliyun.sdk.edas.version>2.44.0</aliyun.sdk.edas.version>
|
||||
<rocketmq.starter.version>2.0.2</rocketmq.starter.version>
|
||||
<schedulerX.client.version>2.1.6</schedulerX.client.version>
|
||||
<dubbo.version>2.6.5</dubbo.version>
|
||||
<dubbo-spring-boot.version>0.2.1.RELEASE</dubbo-spring-boot.version>
|
||||
<dubbo.version>2.7.1</dubbo.version>
|
||||
<dubbo-spring-boot.version>2.7.1</dubbo-spring-boot.version>
|
||||
<dubbo-registry-nacos.version>0.0.2</dubbo-registry-nacos.version>
|
||||
<aliyun.java.sdk.dysmsapi>1.1.0</aliyun.java.sdk.dysmsapi>
|
||||
<aliyun.sdk.mns>1.1.8</aliyun.sdk.mns>
|
||||
<aliyun.sdk.mns>1.1.8.6</aliyun.sdk.mns>
|
||||
<aliyun.java.sdk.dyvmsapi>1.1.1</aliyun.java.sdk.dyvmsapi>
|
||||
</properties>
|
||||
|
||||
@ -152,6 +152,11 @@
|
||||
<artifactId>sentinel-zuul-adapter</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
@ -167,6 +172,11 @@
|
||||
<artifactId>sentinel-dubbo-adapter</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>sentinel-dubbo-api</artifactId>
|
||||
@ -182,19 +192,30 @@
|
||||
<artifactId>sentinel-cluster-client-default</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-spring-webflux-adapter</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-api-gateway-adapter-common</artifactId>
|
||||
<version>${sentinel.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!--Alibaba Fescar-->
|
||||
|
||||
<!--Alibaba Seata-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fescar</groupId>
|
||||
<artifactId>fescar-spring</artifactId>
|
||||
<version>${fescar.version}</version>
|
||||
<groupId>io.seata</groupId>
|
||||
<artifactId>seata-spring</artifactId>
|
||||
<version>${seata.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dubbo -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<version>${dubbo.version}</version>
|
||||
<exclusions>
|
||||
@ -215,7 +236,7 @@
|
||||
|
||||
<!-- Dubbo Spring Boot Starter -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.boot</groupId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
<version>${dubbo-spring-boot.version}</version>
|
||||
</dependency>
|
||||
@ -247,7 +268,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-sentinel-zuul</artifactId>
|
||||
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -272,7 +293,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-alibaba-seata</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -325,7 +346,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -318,4 +318,14 @@ NOTE: 通过 `spring.cloud.nacos.config.shared-dataids` 来支持多个共享配
|
||||
NOTE: 通过 `spring.cloud.nacos.config.shared-dataids` 来配置时,Data Id 必须带文件扩展名,文件扩展名既可支持 properties,也可以支持 yaml/yml。
|
||||
此时 `spring.cloud.nacos.config.file-extension` 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。
|
||||
|
||||
NOTE: `spring.cloud.nacos.config.refreshable-dataids` 给出哪些需要支持动态刷新时,Data Id 的值也必须明确给出文件扩展名。
|
||||
NOTE: `spring.cloud.nacos.config.refreshable-dataids` 给出哪些需要支持动态刷新时,Data Id 的值也必须明确给出文件扩展名。
|
||||
|
||||
=== 配置的优先级
|
||||
|
||||
Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置。
|
||||
|
||||
* A: 通过 `spring.cloud.nacos.config.shared-dataids` 支持多个共享 Data Id 的配置
|
||||
* B: 通过 `spring.cloud.nacos.config.ext-config[n].data-id` 的方式支持多个扩展 Data Id 的配置
|
||||
* C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置
|
||||
|
||||
当三种方式共同使用时,他们的一个优先级关系是:A < B < C
|
@ -134,7 +134,7 @@ public class NacosProviderDemoApplication {
|
||||
|
||||
这个时候你就可以在 Nacos的控制台上看到注册上来的服务信息了。
|
||||
|
||||
NOTE: 再启动 Provider 应用之前 请先将 Nacos 服务启动。具体启动方式可参考 https://nacos.io/zh-cn/docs/quick-start.html[Naco 官网]。
|
||||
NOTE: 再启动 Provider 应用之前 请先将 Nacos 服务启动。具体启动方式可参考 https://nacos.io/zh-cn/docs/quick-start.html[Nacos 官网]。
|
||||
|
||||
=== 服务的 EndPoint
|
||||
|
||||
@ -240,9 +240,9 @@ public class NacosConsumerApp {
|
||||
public String echoAppName(){
|
||||
//使用 LoadBalanceClient 和 RestTemolate 结合的方式来访问
|
||||
ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
|
||||
String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
|
||||
System.out.println("request path:"+path);
|
||||
return restTemplate.getForObject(path,String.class);
|
||||
String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
|
||||
System.out.println("request url:"+url);
|
||||
return restTemplate.getForObject(url,String.class);
|
||||
}
|
||||
|
||||
}
|
||||
@ -290,6 +290,7 @@ NOTE: 在启动 Consumer 应用之前请先将 Nacos 服务启动好。具体启
|
||||
|`SecretKey`|`spring.cloud.nacos.discovery.secret-key`|`无`|`当要上阿里云时,阿里云上面的一个云账号密码`
|
||||
|`Metadata`|`spring.cloud.nacos.discovery.metadata`|`无`|`使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息`
|
||||
|`日志文件名`|`spring.cloud.nacos.discovery.log-name`|`无`|
|
||||
|`集群`|`spring.cloud.nacos.discovery.cluster-name`|`DEFAULT`|`配置成Nacos集群名称`
|
||||
|`接入点`|`spring.cloud.nacos.discovery.enpoint`|`UTF-8`|`地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址`
|
||||
|`是否集成Ribbon`|`ribbon.nacos.enabled`|`true`|`一般都设置成true即可`
|
||||
|====
|
||||
|
6
spring-cloud-alibaba-dubbo/README.md
Normal file
6
spring-cloud-alibaba-dubbo/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
## Info
|
||||
|
||||
|
||||
|
||||
## Features
|
||||
|
49
spring-cloud-alibaba-dubbo/README_CN.md
Normal file
49
spring-cloud-alibaba-dubbo/README_CN.md
Normal file
@ -0,0 +1,49 @@
|
||||
## 简介
|
||||
|
||||
Dubbo Spring Cloud 基于 Dubbo Spring Boot 2.7.1[1] 和 Spring Cloud 2.x 开发,无论开发人员是 Dubbo 用户还是 Spring Cloud 用户,
|
||||
都能轻松地驾驭,并以接近“零”成本的代价使应用向上迁移。Dubbo Spring Cloud 致力于简化 Cloud Native 开发成本,提高研发效能以及提升应用性能等目的。
|
||||
|
||||
Dubbo Spring Cloud 首个 Preview Release,随同 Spring Cloud Alibaba `0.2.2.RELEASE` 和 `0.9.0.RELEASE` 一同发布[2],
|
||||
分别对应 Spring Cloud Finchley[3] 与 Greenwich[4] (下文分别简称为 “F” 版 和 “G” 版) 。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 功能
|
||||
|
||||
由于 Dubbo Spring Cloud 构建在原生的 Spring Cloud 之上,其服务治理方面的能力可认为是 Spring Cloud Plus,
|
||||
不仅完全覆盖 Spring Cloud 原生特性[5],而且提供更为稳定和成熟的实现,特性比对如下表所示:
|
||||
|
||||
| 功能组件 | Spring Cloud | Dubbo Spring Cloud |
|
||||
| ---------------------------------------------------- | -------------------------------------- | ------------------------------------------------------ |
|
||||
| 分布式配置(Distributed configuration) | Git、Zookeeper、Consul、JDBC | Spring Cloud 分布式配置 + Dubbo 配置中心[6] |
|
||||
| 服务注册与发现(Service registration and discovery) | Eureka、Zookeeper、Consul | Spring Cloud 原生注册中心[7] + Dubbo 原生注册中[8] |
|
||||
| 负载均衡(Load balancing) | Ribbon(随机、轮询等算法) | Dubbo 内建实现(随机、轮询等算法 + 权重等特性) |
|
||||
| 服务熔断(Circuit Breakers) | Spring Cloud Hystrix | Spring Cloud Hystrix + Alibaba Sentinel[9] 等 |
|
||||
| 服务调用(Service-to-service calls) | Open Feign、`RestTemplate` | Spring Cloud 服务调用 + Dubbo `@Reference` |
|
||||
| 链路跟踪(Tracing) | Spring Cloud Sleuth[10] + Zipkin[11] | Zipkin、opentracing 等 |
|
||||
|
||||
|
||||
|
||||
[1]: 从 2.7.0 开始,Dubbo Spring Boot 与 Dubbo 在版本上保持一致
|
||||
|
||||
[2]: Preview releases of Spring Cloud Alibaba are available: 0.9.0, 0.2.2, and 0.1.2 - <https://spring.io/blog/2011/04/11/preview-releases-of-spring-cloud-alibaba-are-available-0-9-0-0-2-2-and-0-1-2>
|
||||
|
||||
[3]: 目前最新的 Spring Cloud “F” 版的版本为:`Finchley.SR2` - <https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html>
|
||||
|
||||
[4]: 当前Spring Cloud “G” 版为 `Greenwich.RELEASE`
|
||||
|
||||
[5]: Spring Cloud 特性列表 - <https://cloud.spring.io/spring-cloud-static/Greenwich.RELEASE/single/spring-cloud.html#_features>
|
||||
|
||||
[6]: Dubbo 2.7 开始支持配置中心,可自定义适配 - <http://dubbo.apache.org/zh-cn/docs/user/configuration/config-center.html>
|
||||
|
||||
[7]: Spring Cloud 原生注册中心,除 Eureka、Zookeeper、Consul 之外,还包括 Spring Cloud Alibaba 中的 Nacos
|
||||
|
||||
[8]: Dubbo 原生注册中心 - <http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html>
|
||||
|
||||
[9]: Alibaba Sentinel:Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性 - <https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D>,目前 Sentinel 已被 Spring Cloud 项目纳为 Circuit Breaker 的候选实现 - <https://spring.io/blog/2011/04/8/introducing-spring-cloud-circuit-breaker>
|
||||
|
||||
[10]:Spring Cloud Sleuth - <https://spring.io/projects/spring-cloud-sleuth>
|
||||
|
||||
[11]: Zipkin - <https://github.com/apache/incubator-zipkin>
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -32,7 +32,7 @@ import org.springframework.cloud.alibaba.dubbo.metadata.resolver.MetadataResolve
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboGenericServiceFactory;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceExporter;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.PublishingDubboMetadataService;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.IntrospectiveDubboMetadataService;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -50,13 +50,13 @@ import java.util.function.Supplier;
|
||||
*/
|
||||
@Configuration
|
||||
@Import({DubboServiceMetadataRepository.class,
|
||||
PublishingDubboMetadataService.class,
|
||||
IntrospectiveDubboMetadataService.class,
|
||||
DubboMetadataServiceExporter.class,
|
||||
JSONUtils.class})
|
||||
public class DubboMetadataAutoConfiguration {
|
||||
|
||||
@Autowired
|
||||
private PublishingDubboMetadataService dubboMetadataService;
|
||||
private ObjectProvider<DubboServiceMetadataRepository> dubboServiceMetadataRepository;
|
||||
|
||||
@Autowired
|
||||
private MetadataResolver metadataResolver;
|
||||
@ -87,7 +87,6 @@ public class DubboMetadataAutoConfiguration {
|
||||
public void onServiceBeanExported(ServiceBeanExportedEvent event) {
|
||||
ServiceBean serviceBean = event.getServiceBean();
|
||||
publishServiceRestMetadata(serviceBean);
|
||||
exportDubboMetadataConfigService();
|
||||
}
|
||||
|
||||
@EventListener(ApplicationFailedEvent.class)
|
||||
@ -97,15 +96,11 @@ public class DubboMetadataAutoConfiguration {
|
||||
|
||||
@EventListener(ContextClosedEvent.class)
|
||||
public void onContextClosed() {
|
||||
dubboMetadataConfigServiceExporter.unexport();
|
||||
unExportDubboMetadataConfigService();
|
||||
}
|
||||
|
||||
private void publishServiceRestMetadata(ServiceBean serviceBean) {
|
||||
dubboMetadataService.publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
|
||||
}
|
||||
|
||||
private void exportDubboMetadataConfigService() {
|
||||
dubboMetadataConfigServiceExporter.export();
|
||||
dubboServiceMetadataRepository.getIfAvailable().publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
|
||||
}
|
||||
|
||||
private void unExportDubboMetadataConfigService() {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.spring.ServiceBean;
|
||||
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
@ -32,10 +32,10 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.alibaba.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import org.springframework.cloud.alibaba.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
|
||||
import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
|
||||
@ -43,20 +43,20 @@ import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServic
|
||||
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
|
||||
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME;
|
||||
import static org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME;
|
||||
import static org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository.DUBBO_URLS_METADATA_PROPERTY_NAME;
|
||||
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
|
||||
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
|
||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
||||
|
||||
/**
|
||||
@ -93,13 +93,18 @@ public class DubboServiceRegistrationAutoConfiguration {
|
||||
@Autowired
|
||||
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||
|
||||
@Autowired
|
||||
private JSONUtils jsonUtils;
|
||||
@Bean
|
||||
@Conditional(value = {
|
||||
MissingSpringCloudRegistryConfigPropertyCondition.class
|
||||
})
|
||||
public RegistryConfig defaultSpringCloudRegistryConfig() {
|
||||
return new RegistryConfig(ADDRESS, PROTOCOL);
|
||||
}
|
||||
|
||||
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
||||
public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
|
||||
Registration registration = event.getSource();
|
||||
attachURLsIntoMetadata(registration);
|
||||
attachDubboMetadataServiceMetadata(registration);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ -115,7 +120,7 @@ public class DubboServiceRegistrationAutoConfiguration {
|
||||
Registration registration = event.getSource();
|
||||
EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration);
|
||||
InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo();
|
||||
attachURLsIntoMetadata(instanceInfo.getMetadata());
|
||||
attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,39 +160,30 @@ public class DubboServiceRegistrationAutoConfiguration {
|
||||
|
||||
private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
|
||||
NewService newService = consulRegistration.getService();
|
||||
String dubboURLsJson = getDubboURLsJSON();
|
||||
if (StringUtils.hasText(dubboURLsJson)) {
|
||||
Map<String, String> serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
|
||||
if (!isEmpty(serviceMetadata)) {
|
||||
List<String> tags = newService.getTags();
|
||||
tags.add(DUBBO_URLS_METADATA_PROPERTY_NAME + "=" + dubboURLsJson);
|
||||
for (Map.Entry<String, String> entry : serviceMetadata.entrySet()) {
|
||||
tags.add(entry.getKey() + "=" + entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void attachURLsIntoMetadata(Registration registration) {
|
||||
private void attachDubboMetadataServiceMetadata(Registration registration) {
|
||||
if (registration == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (registration) {
|
||||
Map<String, String> metadata = registration.getMetadata();
|
||||
attachURLsIntoMetadata(metadata);
|
||||
attachDubboMetadataServiceMetadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private void attachURLsIntoMetadata(Map<String, String> metadata) {
|
||||
String dubboURLsJson = getDubboURLsJSON();
|
||||
if (StringUtils.hasText(dubboURLsJson)) {
|
||||
metadata.put(DUBBO_URLS_METADATA_PROPERTY_NAME, dubboURLsJson);
|
||||
private void attachDubboMetadataServiceMetadata(Map<String, String> metadata) {
|
||||
Map<String, String> serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
|
||||
if (!isEmpty(serviceMetadata)) {
|
||||
metadata.putAll(serviceMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
private String getDubboURLsJSON() {
|
||||
Collection<URL> urls = dubboServiceMetadataRepository.getRegisteredUrls();
|
||||
if (CollectionUtils.isEmpty(urls)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("There is no registered URL to attach into metadata.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return jsonUtils.toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
@ -18,7 +18,6 @@ package org.springframework.cloud.alibaba.dubbo.autoconfigure;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.config.spring.ServiceBean;
|
||||
import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
|
||||
|
||||
import com.ecwid.consul.v1.agent.model.NewService;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
@ -30,6 +29,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import org.springframework.cloud.alibaba.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.serviceregistry.Registration;
|
||||
@ -65,18 +66,21 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
|
||||
@Autowired
|
||||
private Registration registration;
|
||||
|
||||
private volatile Integer webPort = null;
|
||||
private volatile Integer serverPort = null;
|
||||
|
||||
private volatile boolean registered = false;
|
||||
|
||||
@Autowired
|
||||
private DubboServiceMetadataRepository repository;
|
||||
|
||||
@Around("execution(* org.springframework.cloud.client.serviceregistry.Registration.getPort())")
|
||||
public Object getPort(ProceedingJoinPoint pjp) throws Throwable {
|
||||
return webPort != null ? webPort : pjp.proceed();
|
||||
return serverPort != null ? serverPort : pjp.proceed();
|
||||
}
|
||||
|
||||
@EventListener(ServiceBeanExportedEvent.class)
|
||||
public void onServiceBeanExported(ServiceBeanExportedEvent event) {
|
||||
setWebPort(event.getServiceBean());
|
||||
@EventListener(ApplicationStartedEvent.class)
|
||||
public void onApplicationStarted() {
|
||||
setServerPort();
|
||||
register();
|
||||
}
|
||||
|
||||
@ -90,18 +94,25 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Set web port from {@link ServiceBean#getExportedUrls() exported URLs} if "rest" protocol is present.
|
||||
*
|
||||
* @param serviceBean {@link ServiceBean}
|
||||
*/
|
||||
private void setWebPort(ServiceBean serviceBean) {
|
||||
if (webPort == null) {
|
||||
List<URL> urls = serviceBean.getExportedUrls();
|
||||
urls.stream()
|
||||
.filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol()))
|
||||
.findFirst()
|
||||
.ifPresent(url -> {
|
||||
webPort = url.getPort();
|
||||
private void setServerPort() {
|
||||
if (serverPort == null) {
|
||||
for (List<URL> urls : repository.getAllExportedUrls().values()) {
|
||||
urls.stream()
|
||||
.filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol()))
|
||||
.findFirst()
|
||||
.ifPresent(url -> {
|
||||
serverPort = url.getPort();
|
||||
});
|
||||
|
||||
// If REST protocol is not present, use any applied port.
|
||||
if (serverPort == null) {
|
||||
urls.stream()
|
||||
.findAny().ifPresent(url -> {
|
||||
serverPort = url.getPort();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +125,7 @@ public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
|
||||
|
||||
@EventListener(ServiceInstancePreRegisteredEvent.class)
|
||||
public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
|
||||
registration.setPort(webPort);
|
||||
registration.setPort(serverPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.autoconfigure.condition;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties;
|
||||
import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
|
||||
|
||||
/**
|
||||
* Missing {@link SpringCloudRegistry} Property {@link Condition}
|
||||
*
|
||||
* @see SpringCloudRegistry
|
||||
* @see Condition
|
||||
*/
|
||||
public class MissingSpringCloudRegistryConfigPropertyCondition extends SpringBootCondition {
|
||||
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();
|
||||
|
||||
String protocol = environment.getProperty("dubbo.registry.protocol");
|
||||
|
||||
if (PROTOCOL.equals(protocol)) {
|
||||
return ConditionOutcome.noMatch("'spring-cloud' protocol was found from 'dubbo.registry.protocol'");
|
||||
}
|
||||
|
||||
String address = environment.getProperty("dubbo.registry.address");
|
||||
|
||||
if (StringUtils.startsWithIgnoreCase(address, PROTOCOL)) {
|
||||
return ConditionOutcome.noMatch("'spring-cloud' protocol was found from 'dubbo.registry.address'");
|
||||
}
|
||||
|
||||
Map<String, Object> properties = getSubProperties(environment, "dubbo.registries.");
|
||||
|
||||
boolean found = properties.entrySet().stream().anyMatch(entry -> {
|
||||
String key = entry.getKey();
|
||||
String value = String.valueOf(entry.getValue());
|
||||
return (key.endsWith(".address") && value.startsWith(PROTOCOL)) ||
|
||||
(key.endsWith(".protocol") && PROTOCOL.equals(value));
|
||||
|
||||
});
|
||||
|
||||
return found ? ConditionOutcome.noMatch("'spring-cloud' protocol was found in 'dubbo.registries.*'") : ConditionOutcome.match();
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import java.util.Iterator;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
/**
|
||||
* Dubbo's {@link ProtocolConfig} {@link Supplier}
|
||||
@ -43,23 +44,26 @@ public class DubboProtocolConfigSupplier implements Supplier<ProtocolConfig> {
|
||||
public ProtocolConfig get() {
|
||||
ProtocolConfig protocolConfig = null;
|
||||
Collection<ProtocolConfig> protocols = this.protocols.getIfAvailable();
|
||||
for (ProtocolConfig protocol : protocols) {
|
||||
String protocolName = protocol.getName();
|
||||
if (DEFAULT_PROTOCOL.equals(protocolName)) {
|
||||
protocolConfig = protocol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them
|
||||
Iterator<ProtocolConfig> iterator = protocols.iterator();
|
||||
protocolConfig = iterator.hasNext() ? iterator.next() : null;
|
||||
if (!isEmpty(protocols)) {
|
||||
for (ProtocolConfig protocol : protocols) {
|
||||
String protocolName = protocol.getName();
|
||||
if (DEFAULT_PROTOCOL.equals(protocolName)) {
|
||||
protocolConfig = protocol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (protocolConfig == null) { // If The ProtocolConfig bean named "dubbo" is absent, take first one of them
|
||||
Iterator<ProtocolConfig> iterator = protocols.iterator();
|
||||
protocolConfig = iterator.hasNext() ? iterator.next() : null;
|
||||
}
|
||||
}
|
||||
|
||||
if (protocolConfig == null) {
|
||||
protocolConfig = new ProtocolConfig();
|
||||
protocolConfig.setName(DEFAULT_PROTOCOL);
|
||||
protocolConfig.setPort(20880);
|
||||
protocolConfig.setPort(-1);
|
||||
}
|
||||
|
||||
return protocolConfig;
|
||||
|
@ -30,30 +30,43 @@ import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataService;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceExporter;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.String.valueOf;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
|
||||
import static org.apache.dubbo.common.Constants.VERSION_KEY;
|
||||
import static org.springframework.cloud.alibaba.dubbo.env.DubboCloudProperties.ALL_DUBBO_SERVICES;
|
||||
import static org.springframework.cloud.alibaba.dubbo.http.DefaultHttpRequest.builder;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* Dubbo Service Metadata {@link Repository}
|
||||
@ -64,17 +77,56 @@ import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
public class DubboServiceMetadataRepository {
|
||||
|
||||
/**
|
||||
* The property name of Dubbo {@link URL URLs} metadata
|
||||
* The prefix of {@link DubboMetadataService} : "dubbo.metadata-service."
|
||||
*/
|
||||
public static final String DUBBO_URLS_METADATA_PROPERTY_NAME = "dubbo.urls";
|
||||
public static final String DUBBO_METADATA_SERVICE_PREFIX = "dubbo.metadata-service.";
|
||||
|
||||
/**
|
||||
* The {@link URL URLs} property name of {@link DubboMetadataService} : "dubbo.metadata-service.urls"
|
||||
*/
|
||||
public static final String DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME = DUBBO_METADATA_SERVICE_PREFIX + "urls";
|
||||
|
||||
/**
|
||||
* The {@link String#format(String, Object...) pattern} of dubbo protocols port
|
||||
*/
|
||||
public static final String DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN = "dubbo.protocols.%s.port";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private final Set<URL> registeredURLs = new LinkedHashSet<>();
|
||||
// =================================== Registration =================================== //
|
||||
|
||||
private final Map<String, String> dubboServiceKeysRepository = new HashMap<>();
|
||||
/**
|
||||
* All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method
|
||||
* and value is the {@link List} of {@link URL URLs}
|
||||
*/
|
||||
private final MultiValueMap<String, URL> allExportedURLs = new LinkedMultiValueMap<>();
|
||||
|
||||
// ==================================================================================== //
|
||||
|
||||
|
||||
// =================================== Subscription =================================== //
|
||||
|
||||
private Set<String> subscribedServices;
|
||||
|
||||
/**
|
||||
* The subscribed {@link URL urls} {@link Map} of {@link DubboMetadataService},
|
||||
* whose key is the return value of {@link URL#getServiceKey()} method and value is the {@link List} of
|
||||
* {@link URL URLs}
|
||||
*/
|
||||
private final MultiValueMap<String, URL> subscribedDubboMetadataServiceURLs = new LinkedMultiValueMap<>();
|
||||
|
||||
// ==================================================================================== //
|
||||
|
||||
|
||||
// =================================== REST Metadata ================================== //
|
||||
|
||||
/**
|
||||
* 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 from the annotated methods.
|
||||
*/
|
||||
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||
|
||||
/**
|
||||
* Key is application name
|
||||
@ -82,7 +134,10 @@ public class DubboServiceMetadataRepository {
|
||||
*/
|
||||
private Map<String, Map<RequestMetadataMatcher, DubboRestServiceMetadata>> dubboRestServiceMetadataRepository = newHashMap();
|
||||
|
||||
private Set<String> subscribedServices;
|
||||
// ==================================================================================== //
|
||||
|
||||
|
||||
// =================================== Dependencies =================================== //
|
||||
|
||||
@Autowired
|
||||
private DubboCloudProperties dubboCloudProperties;
|
||||
@ -96,17 +151,124 @@ public class DubboServiceMetadataRepository {
|
||||
@Autowired
|
||||
private JSONUtils jsonUtils;
|
||||
|
||||
@Autowired
|
||||
private InetUtils inetUtils;
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String currentApplicationName;
|
||||
|
||||
@Autowired
|
||||
private DubboMetadataServiceExporter dubboMetadataServiceExporter;
|
||||
|
||||
// ==================================================================================== //
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// Keep the order in following invocations
|
||||
initSubscribedServices();
|
||||
initDubboServiceKeysRepository();
|
||||
retainAvailableSubscribedServices();
|
||||
initSubscribedDubboMetadataServices();
|
||||
initDubboRestServiceMetadataRepository();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata {@link Map} of {@link DubboMetadataService}
|
||||
*
|
||||
* @return non-null read-only {@link Map}
|
||||
*/
|
||||
public Map<String, String> getDubboMetadataServiceMetadata() {
|
||||
|
||||
List<URL> dubboMetadataServiceURLs = dubboMetadataServiceExporter.export();
|
||||
|
||||
// remove the exported URLs of DubboMetadataService
|
||||
removeDubboMetadataServiceURLs(dubboMetadataServiceURLs);
|
||||
|
||||
Map<String, String> metadata = newHashMap();
|
||||
|
||||
addDubboMetadataServiceURLsMetadata(metadata, dubboMetadataServiceURLs);
|
||||
addDubboProtocolsPortMetadata(metadata);
|
||||
|
||||
return Collections.unmodifiableMap(metadata);
|
||||
}
|
||||
|
||||
private void removeDubboMetadataServiceURLs(List<URL> dubboMetadataServiceURLs) {
|
||||
dubboMetadataServiceURLs.forEach(this::unexportURL);
|
||||
}
|
||||
|
||||
private void addDubboMetadataServiceURLsMetadata(Map<String, String> metadata, List<URL> dubboMetadataServiceURLs) {
|
||||
String dubboMetadataServiceURLsJSON = jsonUtils.toJSON(dubboMetadataServiceURLs);
|
||||
metadata.put(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME, dubboMetadataServiceURLsJSON);
|
||||
}
|
||||
|
||||
private void addDubboProtocolsPortMetadata(Map<String, String> metadata) {
|
||||
|
||||
allExportedURLs.values()
|
||||
.stream()
|
||||
.flatMap(v -> v.stream())
|
||||
.forEach(url -> {
|
||||
String protocol = url.getProtocol();
|
||||
String propertyName = getDubboProtocolPropertyName(protocol);
|
||||
String propertyValue = valueOf(url.getPort());
|
||||
metadata.put(propertyName, propertyValue);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property name of Dubbo Protocol
|
||||
*
|
||||
* @param protocol Dubbo Protocol
|
||||
* @return non-null
|
||||
*/
|
||||
public String getDubboProtocolPropertyName(String protocol) {
|
||||
return format(DUBBO_PROTOCOLS_PORT_PROPERTY_NAME_PATTERN, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the {@link Set} of {@link ServiceRestMetadata}
|
||||
*
|
||||
* @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata}
|
||||
*/
|
||||
public void publishServiceRestMetadata(Set<ServiceRestMetadata> serviceRestMetadataSet) {
|
||||
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
|
||||
if (!isEmpty(serviceRestMetadata.getMeta())) {
|
||||
this.serviceRestMetadata.add(serviceRestMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Set} of {@link ServiceRestMetadata}
|
||||
*
|
||||
* @return non-null read-only {@link Set}
|
||||
*/
|
||||
public Set<ServiceRestMetadata> getServiceRestMetadata() {
|
||||
return unmodifiableSet(serviceRestMetadata);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Get The subscribed {@link DubboMetadataService}'s {@link URL URLs}
|
||||
// *
|
||||
// * @return non-null read-only {@link List}
|
||||
// */
|
||||
// public List<URL> getSubscribedDubboMetadataServiceURLs() {
|
||||
// return Collections.unmodifiableList(subscribedDubboMetadataServiceURLs);
|
||||
// }
|
||||
|
||||
public List<URL> findSubscribedDubboMetadataServiceURLs(String serviceName, String group, String version,
|
||||
String protocol) {
|
||||
String serviceKey = URL.buildKey(serviceName, group, version);
|
||||
List<URL> urls = subscribedDubboMetadataServiceURLs.get(serviceKey);
|
||||
|
||||
if (isEmpty(urls)) {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
return hasText(protocol) ?
|
||||
urls.stream().filter(url -> url.getProtocol().equalsIgnoreCase(protocol)).collect(Collectors.toList()) :
|
||||
unmodifiableList(urls)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* The specified service is subscribe or not
|
||||
*
|
||||
@ -117,49 +279,68 @@ public class DubboServiceMetadataRepository {
|
||||
return subscribedServices.contains(serviceName);
|
||||
}
|
||||
|
||||
public void exportURL(URL url) {
|
||||
URL actualURL = url;
|
||||
InetUtils.HostInfo hostInfo = inetUtils.findFirstNonLoopbackHostInfo();
|
||||
String ipAddress = hostInfo.getIpAddress();
|
||||
// To use InetUtils to set IP if they are different
|
||||
// issue : https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/589
|
||||
if (!Objects.equals(url.getHost(), ipAddress)) {
|
||||
actualURL = url.setHost(ipAddress);
|
||||
}
|
||||
this.allExportedURLs.add(actualURL.getServiceKey(), actualURL);
|
||||
}
|
||||
|
||||
public void unexportURL(URL url) {
|
||||
String key = url.getServiceKey();
|
||||
// NPE issue : https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/591
|
||||
List<URL> urls = allExportedURLs.get(key);
|
||||
if (!isEmpty(urls)) {
|
||||
urls.remove(url);
|
||||
allExportedURLs.addAll(key, urls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service name by the {@link URL#getServiceKey() service key}
|
||||
* Get all exported {@link URL urls}.
|
||||
*
|
||||
* @param url {@link URL}
|
||||
* @return the service name if found
|
||||
* @return non-null read-only
|
||||
*/
|
||||
public String getServiceName(URL url) {
|
||||
return getServiceName(url.getServiceKey());
|
||||
public Map<String, List<URL>> getAllExportedUrls() {
|
||||
return unmodifiableMap(allExportedURLs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service name by the {@link URL#getServiceKey() service key}
|
||||
* Get all exported {@link URL#getServiceKey() service keys}
|
||||
*
|
||||
* @param serviceKey the {@link URL#getServiceKey() service key}
|
||||
* @return the service name if found
|
||||
* @return non-null read-only
|
||||
*/
|
||||
public String getServiceName(String serviceKey) {
|
||||
return dubboServiceKeysRepository.get(serviceKey);
|
||||
}
|
||||
|
||||
public void registerURL(URL url) {
|
||||
this.registeredURLs.add(url);
|
||||
}
|
||||
|
||||
public void unregisterURL(URL url) {
|
||||
this.registeredURLs.remove(url);
|
||||
}
|
||||
|
||||
public Collection<URL> getRegisteredUrls() {
|
||||
return Collections.unmodifiableSet(registeredURLs);
|
||||
public Set<String> getAllServiceKeys() {
|
||||
return allExportedURLs.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link URL urls} by the specified {@link ServiceInstance}
|
||||
* Get the {@link URL urls} that {@link DubboMetadataService} exported by the specified {@link ServiceInstance}
|
||||
*
|
||||
* @param serviceInstance {@link ServiceInstance}
|
||||
* @return the mutable {@link URL urls}
|
||||
*/
|
||||
public List<URL> buildURLs(ServiceInstance serviceInstance) {
|
||||
public List<URL> getDubboMetadataServiceURLs(ServiceInstance serviceInstance) {
|
||||
Map<String, String> metadata = serviceInstance.getMetadata();
|
||||
String dubboURLsJSON = metadata.get(DUBBO_URLS_METADATA_PROPERTY_NAME);
|
||||
List<String> urlValues = jsonUtils.toList(dubboURLsJSON);
|
||||
return urlValues.stream().map(URL::valueOf).collect(Collectors.toList());
|
||||
String dubboURLsJSON = metadata.get(DUBBO_METADATA_SERVICE_URLS_PROPERTY_NAME);
|
||||
return jsonUtils.toURLs(dubboURLsJSON);
|
||||
}
|
||||
|
||||
public Integer getDubboProtocolPort(ServiceInstance serviceInstance, String protocol) {
|
||||
String protocolProperty = getDubboProtocolPropertyName(protocol);
|
||||
Map<String, String> metadata = serviceInstance.getMetadata();
|
||||
String protocolPort = metadata.get(protocolProperty);
|
||||
return hasText(protocolPort) ? Integer.valueOf(protocolPort) : null;
|
||||
}
|
||||
|
||||
public List<URL> getExportedURLs(String serviceInterface, String group, String version) {
|
||||
String serviceKey = URL.buildKey(serviceInterface, group, version);
|
||||
return allExportedURLs.getOrDefault(serviceKey, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,6 +392,10 @@ public class DubboServiceMetadataRepository {
|
||||
return match(dubboRestServiceMetadataRepository, serviceName, requestMetadata);
|
||||
}
|
||||
|
||||
public Set<String> getSubscribedServices() {
|
||||
return Collections.unmodifiableSet(subscribedServices);
|
||||
}
|
||||
|
||||
private <T> T match(Map<String, Map<RequestMetadataMatcher, T>> repository, String serviceName,
|
||||
RequestMetadata requestMetadata) {
|
||||
|
||||
@ -255,16 +440,22 @@ public class DubboServiceMetadataRepository {
|
||||
}
|
||||
|
||||
private Set<ServiceRestMetadata> getServiceRestMetadataSet(String serviceName) {
|
||||
DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.newProxy(serviceName);
|
||||
|
||||
Set<ServiceRestMetadata> metadata = Collections.emptySet();
|
||||
try {
|
||||
String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata();
|
||||
metadata = objectMapper.readValue(serviceRestMetadataJsonConfig,
|
||||
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
|
||||
} catch (Exception e) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(e.getMessage(), e);
|
||||
Set<ServiceRestMetadata> metadata = emptySet();
|
||||
|
||||
DubboMetadataService dubboMetadataService = dubboMetadataConfigServiceProxy.getProxy(serviceName);
|
||||
|
||||
if (dubboMetadataService != null) {
|
||||
try {
|
||||
String serviceRestMetadataJsonConfig = dubboMetadataService.getServiceRestMetadata();
|
||||
if (hasText(serviceRestMetadataJsonConfig)) {
|
||||
metadata = objectMapper.readValue(serviceRestMetadataJsonConfig,
|
||||
TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
@ -289,8 +480,16 @@ public class DubboServiceMetadataRepository {
|
||||
|
||||
private void initSubscribedServices() {
|
||||
// If subscribes all services
|
||||
if (ALL_DUBBO_SERVICES.equalsIgnoreCase(dubboCloudProperties.getSubscribedServices())) {
|
||||
subscribedServices = new HashSet<>(discoveryClient.getServices());
|
||||
if (ALL_DUBBO_SERVICES.equals(dubboCloudProperties.getSubscribedServices())) {
|
||||
List<String> services = discoveryClient.getServices();
|
||||
subscribedServices = new HashSet<>(services);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Current application will subscribe all services(size:{}) in registry, " +
|
||||
"a lot of memory and CPU cycles may be used, " +
|
||||
"thus it's strongly recommend you using the externalized property '{}' " +
|
||||
"to specify the services",
|
||||
subscribedServices.size(), "dubbo.cloud.subscribed-services");
|
||||
}
|
||||
} else {
|
||||
subscribedServices = new HashSet<>(dubboCloudProperties.subscribedServices());
|
||||
}
|
||||
@ -302,23 +501,33 @@ public class DubboServiceMetadataRepository {
|
||||
subscribedServices.remove(currentApplicationName);
|
||||
}
|
||||
|
||||
private void initDubboServiceKeysRepository() {
|
||||
private void initSubscribedDubboMetadataServices() {
|
||||
// clear subscribedDubboMetadataServiceURLs
|
||||
subscribedDubboMetadataServiceURLs.clear();
|
||||
|
||||
subscribedServices.stream()
|
||||
.map(discoveryClient::getInstances)
|
||||
.filter(this::isNotEmpty)
|
||||
.forEach(serviceInstances -> {
|
||||
ServiceInstance serviceInstance = serviceInstances.get(0);
|
||||
buildURLs(serviceInstance).forEach(url -> {
|
||||
String serviceKey = url.getServiceKey();
|
||||
String serviceName = url.getParameter(APPLICATION_KEY);
|
||||
dubboServiceKeysRepository.put(serviceKey, serviceName);
|
||||
getDubboMetadataServiceURLs(serviceInstance).forEach(dubboMetadataServiceURL -> {
|
||||
initSubscribedDubboMetadataServiceURLs(dubboMetadataServiceURL);
|
||||
initDubboMetadataServiceProxy(dubboMetadataServiceURL);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void retainAvailableSubscribedServices() {
|
||||
// dubboServiceKeysRepository.values() returns the available services(possible duplicated ones)
|
||||
subscribedServices = new HashSet<>(dubboServiceKeysRepository.values());
|
||||
private void initSubscribedDubboMetadataServiceURLs(URL dubboMetadataServiceURL) {
|
||||
// add subscriptions
|
||||
String serviceKey = dubboMetadataServiceURL.getServiceKey();
|
||||
subscribedDubboMetadataServiceURLs.add(serviceKey, dubboMetadataServiceURL);
|
||||
}
|
||||
|
||||
private void initDubboMetadataServiceProxy(URL dubboMetadataServiceURL) {
|
||||
String serviceName = dubboMetadataServiceURL.getParameter(APPLICATION_KEY);
|
||||
String version = dubboMetadataServiceURL.getParameter(VERSION_KEY);
|
||||
// Initialize DubboMetadataService with right version
|
||||
dubboMetadataConfigServiceProxy.initProxy(serviceName, version);
|
||||
}
|
||||
|
||||
private void initDubboRestServiceMetadataRepository() {
|
||||
|
@ -24,24 +24,30 @@ import org.apache.dubbo.registry.support.FailbackRegistry;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataService;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singleton;
|
||||
import static org.apache.dubbo.common.Constants.APPLICATION_KEY;
|
||||
import static org.apache.dubbo.common.Constants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.Constants.PROTOCOL_KEY;
|
||||
import static org.apache.dubbo.common.Constants.PROVIDER_SIDE;
|
||||
import static org.apache.dubbo.common.Constants.SIDE_KEY;
|
||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
||||
import static org.apache.dubbo.common.Constants.VERSION_KEY;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
@ -56,6 +62,10 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
*/
|
||||
public static final String SERVICES_LOOKUP_INTERVAL_PARAM_NAME = "dubbo.services.lookup.interval";
|
||||
|
||||
protected static final String DUBBO_METADATA_SERVICE_CLASS_NAME = DubboMetadataService.class.getName();
|
||||
|
||||
private static final Set<String> schedulerTasks = new HashSet<>();
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
@ -65,14 +75,27 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
|
||||
private final DiscoveryClient discoveryClient;
|
||||
|
||||
private final DubboServiceMetadataRepository repository;
|
||||
|
||||
private final DubboMetadataServiceProxy dubboMetadataConfigServiceProxy;
|
||||
|
||||
private final JSONUtils jsonUtils;
|
||||
|
||||
|
||||
protected final ScheduledExecutorService servicesLookupScheduler;
|
||||
|
||||
public AbstractSpringCloudRegistry(URL url,
|
||||
DiscoveryClient discoveryClient,
|
||||
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
||||
JSONUtils jsonUtils,
|
||||
ScheduledExecutorService servicesLookupScheduler) {
|
||||
super(url);
|
||||
this.servicesLookupInterval = url.getParameter(SERVICES_LOOKUP_INTERVAL_PARAM_NAME, 60L);
|
||||
this.discoveryClient = discoveryClient;
|
||||
this.repository = dubboServiceMetadataRepository;
|
||||
this.dubboMetadataConfigServiceProxy = dubboMetadataConfigServiceProxy;
|
||||
this.jsonUtils = jsonUtils;
|
||||
this.servicesLookupScheduler = servicesLookupScheduler;
|
||||
}
|
||||
|
||||
@ -122,13 +145,113 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
|
||||
@Override
|
||||
public final void doSubscribe(URL url, NotifyListener listener) {
|
||||
Set<String> serviceNames = getServiceNames(url);
|
||||
doSubscribe(url, listener, serviceNames);
|
||||
|
||||
if (isAdminURL(url)) {
|
||||
// TODO in future
|
||||
} else if (isDubboMetadataServiceURL(url)) { // for DubboMetadataService
|
||||
subscribeDubboMetadataServiceURLs(url, listener);
|
||||
} else { // for general Dubbo Services
|
||||
subscribeDubboServiceURLs(url, listener);
|
||||
}
|
||||
}
|
||||
|
||||
protected void subscribeDubboServiceURLs(URL url, NotifyListener listener) {
|
||||
|
||||
doSubscribeDubboServiceURLs(url, listener);
|
||||
|
||||
submitSchedulerTaskIfAbsent(url, listener);
|
||||
}
|
||||
|
||||
private void submitSchedulerTaskIfAbsent(URL url, NotifyListener listener) {
|
||||
String taskId = url.toIdentityString();
|
||||
if (schedulerTasks.add(taskId)) {
|
||||
schedule(() -> doSubscribeDubboServiceURLs(url, listener));
|
||||
}
|
||||
}
|
||||
|
||||
protected void doSubscribeDubboServiceURLs(URL url, NotifyListener listener) {
|
||||
|
||||
Set<String> subscribedServices = repository.getSubscribedServices();
|
||||
|
||||
subscribedServices.stream()
|
||||
.map(dubboMetadataConfigServiceProxy::getProxy)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(dubboMetadataService -> {
|
||||
List<URL> exportedURLs = getExportedURLs(dubboMetadataService, url);
|
||||
List<URL> allSubscribedURLs = new LinkedList<>();
|
||||
for (URL exportedURL : exportedURLs) {
|
||||
String serviceName = exportedURL.getParameter(APPLICATION_KEY);
|
||||
List<ServiceInstance> serviceInstances = getServiceInstances(serviceName);
|
||||
String protocol = exportedURL.getProtocol();
|
||||
List<URL> subscribedURLs = new LinkedList<>();
|
||||
serviceInstances.forEach(serviceInstance -> {
|
||||
Integer port = repository.getDubboProtocolPort(serviceInstance, protocol);
|
||||
String host = serviceInstance.getHost();
|
||||
if (port == null) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("The protocol[{}] port of Dubbo service instance[host : {}] " +
|
||||
"can't be resolved", protocol, host);
|
||||
}
|
||||
} else {
|
||||
URL subscribedURL = new URL(protocol, host, port, exportedURL.getParameters());
|
||||
subscribedURLs.add(subscribedURL);
|
||||
}
|
||||
});
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("The subscribed URL[{}] will notify all URLs : {}", url, subscribedURLs);
|
||||
}
|
||||
|
||||
allSubscribedURLs.addAll(subscribedURLs);
|
||||
}
|
||||
|
||||
listener.notify(allSubscribedURLs);
|
||||
});
|
||||
}
|
||||
|
||||
private List<ServiceInstance> getServiceInstances(String serviceName) {
|
||||
return hasText(serviceName) ? doGetServiceInstances(serviceName) : emptyList();
|
||||
}
|
||||
|
||||
private List<ServiceInstance> doGetServiceInstances(String serviceName) {
|
||||
List<ServiceInstance> serviceInstances = emptyList();
|
||||
try {
|
||||
serviceInstances = discoveryClient.getInstances(serviceName);
|
||||
} catch (Exception e) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return serviceInstances;
|
||||
}
|
||||
|
||||
private List<URL> getExportedURLs(DubboMetadataService dubboMetadataService, URL url) {
|
||||
String serviceInterface = url.getServiceInterface();
|
||||
String group = url.getParameter(GROUP_KEY);
|
||||
String version = url.getParameter(VERSION_KEY);
|
||||
// The subscribed protocol may be null
|
||||
String subscribedProtocol = url.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 url, NotifyListener listener) {
|
||||
String serviceInterface = url.getServiceInterface();
|
||||
String group = url.getParameter(GROUP_KEY);
|
||||
String version = url.getParameter(VERSION_KEY);
|
||||
String protocol = url.getParameter(PROTOCOL_KEY);
|
||||
List<URL> urls = repository.findSubscribedDubboMetadataServiceURLs(serviceInterface, group, version, protocol);
|
||||
listener.notify(urls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void doUnsubscribe(URL url, NotifyListener listener) {
|
||||
if (isAdminProtocol(url)) {
|
||||
if (isAdminURL(url)) {
|
||||
shutdownServiceNamesLookup();
|
||||
}
|
||||
}
|
||||
@ -144,86 +267,16 @@ public abstract class AbstractSpringCloudRegistry extends FailbackRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> filterServiceNames(Collection<String> serviceNames) {
|
||||
return new LinkedHashSet<>(filter(serviceNames, this::supports));
|
||||
}
|
||||
|
||||
protected abstract boolean supports(String serviceName);
|
||||
|
||||
protected final Set<String> getAllServiceNames() {
|
||||
return new LinkedHashSet<>(discoveryClient.getServices());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service names from the specified {@link URL url}
|
||||
*
|
||||
* @param url {@link URL}
|
||||
* @return non-null
|
||||
*/
|
||||
private Set<String> getServiceNames(URL url) {
|
||||
if (isAdminProtocol(url)) {
|
||||
return getServiceNamesForOps(url);
|
||||
} else {
|
||||
return singleton(getServiceName(url));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAdminProtocol(URL url) {
|
||||
protected boolean isAdminURL(URL url) {
|
||||
return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service names for Dubbo OPS
|
||||
*
|
||||
* @param url {@link URL}
|
||||
* @return non-null
|
||||
*/
|
||||
protected Set<String> getServiceNamesForOps(URL url) {
|
||||
Set<String> serviceNames = getAllServiceNames();
|
||||
return filterServiceNames(serviceNames);
|
||||
}
|
||||
|
||||
protected abstract String getServiceName(URL url);
|
||||
|
||||
private void doSubscribe(final URL url, final NotifyListener listener, final Collection<String> serviceNames) {
|
||||
|
||||
subscribe(url, listener, serviceNames);
|
||||
|
||||
schedule(() -> {
|
||||
subscribe(url, listener, serviceNames);
|
||||
});
|
||||
protected boolean isDubboMetadataServiceURL(URL url) {
|
||||
return DUBBO_METADATA_SERVICE_CLASS_NAME.equals(url.getServiceInterface());
|
||||
}
|
||||
|
||||
protected ScheduledFuture<?> schedule(Runnable runnable) {
|
||||
return this.servicesLookupScheduler.scheduleAtFixedRate(runnable, servicesLookupInterval,
|
||||
servicesLookupInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
protected List<ServiceInstance> getServiceInstances(String serviceName) {
|
||||
return hasText(serviceName) ? discoveryClient.getInstances(serviceName) : emptyList();
|
||||
}
|
||||
|
||||
private void subscribe(final URL url, final NotifyListener listener, final Collection<String> serviceNames) {
|
||||
for (String serviceName : serviceNames) {
|
||||
List<ServiceInstance> serviceInstances = getServiceInstances(serviceName);
|
||||
if (!isEmpty(serviceInstances)) {
|
||||
notifySubscriber(url, listener, serviceInstances);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the Healthy {@link ServiceInstance service instance} to subscriber.
|
||||
*
|
||||
* @param url {@link URL}
|
||||
* @param listener {@link NotifyListener}
|
||||
* @param serviceInstances all {@link ServiceInstance instances}
|
||||
*/
|
||||
protected abstract void notifySubscriber(URL url, NotifyListener listener, List<ServiceInstance> serviceInstances);
|
||||
|
||||
protected <T> Collection<T> filter(Collection<T> collection, Predicate<T> filter) {
|
||||
return collection.stream()
|
||||
.filter(filter)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
@ -17,16 +17,14 @@
|
||||
package org.springframework.cloud.alibaba.dubbo.registry;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.registry.NotifyListener;
|
||||
import org.apache.dubbo.registry.RegistryFactory;
|
||||
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
|
||||
@ -38,38 +36,21 @@ public class SpringCloudRegistry extends AbstractSpringCloudRegistry {
|
||||
private final DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||
|
||||
public SpringCloudRegistry(URL url, DiscoveryClient discoveryClient,
|
||||
ScheduledExecutorService servicesLookupScheduler,
|
||||
DubboServiceMetadataRepository dubboServiceMetadataRepository) {
|
||||
super(url, discoveryClient, servicesLookupScheduler);
|
||||
DubboServiceMetadataRepository dubboServiceMetadataRepository,
|
||||
DubboMetadataServiceProxy dubboMetadataConfigServiceProxy,
|
||||
JSONUtils jsonUtils,
|
||||
ScheduledExecutorService servicesLookupScheduler) {
|
||||
super(url, discoveryClient, dubboServiceMetadataRepository, dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler);
|
||||
this.dubboServiceMetadataRepository = dubboServiceMetadataRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRegister0(URL url) {
|
||||
dubboServiceMetadataRepository.registerURL(url);
|
||||
dubboServiceMetadataRepository.exportURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUnregister0(URL url) {
|
||||
dubboServiceMetadataRepository.unregisterURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supports(String serviceName) {
|
||||
return dubboServiceMetadataRepository.isSubscribedService(serviceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getServiceName(URL url) {
|
||||
return dubboServiceMetadataRepository.getServiceName(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifySubscriber(URL url, NotifyListener listener, List<ServiceInstance> serviceInstances) {
|
||||
List<URL> urls = serviceInstances.stream()
|
||||
.map(dubboServiceMetadataRepository::buildURLs)
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.toList());
|
||||
notify(url, listener, urls);
|
||||
dubboServiceMetadataRepository.unexportURL(url);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import org.apache.dubbo.registry.Registry;
|
||||
import org.apache.dubbo.registry.RegistryFactory;
|
||||
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import org.springframework.cloud.alibaba.dubbo.service.DubboMetadataServiceProxy;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
@ -39,6 +41,10 @@ import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
|
||||
*/
|
||||
public class SpringCloudRegistryFactory implements RegistryFactory {
|
||||
|
||||
public static String PROTOCOL = "spring-cloud";
|
||||
|
||||
public static String ADDRESS = "localhost";
|
||||
|
||||
private static String SERVICES_LOOKUP_SCHEDULER_THREAD_NAME_PREFIX =
|
||||
getProperty("dubbo.services.lookup.scheduler.thread.name.prefix ", "dubbo-services-lookup-");
|
||||
|
||||
@ -50,6 +56,10 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
||||
|
||||
private DubboServiceMetadataRepository dubboServiceMetadataRepository;
|
||||
|
||||
private DubboMetadataServiceProxy dubboMetadataConfigServiceProxy;
|
||||
|
||||
private JSONUtils jsonUtils;
|
||||
|
||||
private volatile boolean initialized = false;
|
||||
|
||||
public SpringCloudRegistryFactory() {
|
||||
@ -63,12 +73,15 @@ public class SpringCloudRegistryFactory implements RegistryFactory {
|
||||
}
|
||||
this.discoveryClient = applicationContext.getBean(DiscoveryClient.class);
|
||||
this.dubboServiceMetadataRepository = applicationContext.getBean(DubboServiceMetadataRepository.class);
|
||||
this.dubboMetadataConfigServiceProxy = applicationContext.getBean(DubboMetadataServiceProxy.class);
|
||||
this.jsonUtils = applicationContext.getBean(JSONUtils.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registry getRegistry(URL url) {
|
||||
init();
|
||||
return new SpringCloudRegistry(url, discoveryClient, servicesLookupScheduler, dubboServiceMetadataRepository);
|
||||
return new SpringCloudRegistry(url, discoveryClient, dubboServiceMetadataRepository,
|
||||
dubboMetadataConfigServiceProxy, jsonUtils, servicesLookupScheduler);
|
||||
}
|
||||
|
||||
public static void setApplicationContext(ConfigurableApplicationContext applicationContext) {
|
||||
|
@ -18,12 +18,15 @@ package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.spring.ReferenceBean;
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.DubboRestServiceMetadata;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||
@ -33,6 +36,7 @@ import org.springframework.validation.DataBinder;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -54,6 +58,9 @@ public class DubboGenericServiceFactory {
|
||||
|
||||
private final ConcurrentMap<Integer, ReferenceBean<GenericService>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
@Autowired
|
||||
private ObjectProvider<List<RegistryConfig>> registryConfigs;
|
||||
|
||||
public GenericService create(DubboRestServiceMetadata dubboServiceMetadata,
|
||||
Map<String, Object> dubboTranslatedAttributes) {
|
||||
|
||||
@ -62,9 +69,9 @@ public class DubboGenericServiceFactory {
|
||||
return referenceBean == null ? null : referenceBean.get();
|
||||
}
|
||||
|
||||
public GenericService create(String serviceName, Class<?> serviceClass) {
|
||||
public GenericService create(String serviceName, Class<?> serviceClass, String version) {
|
||||
String interfaceName = serviceClass.getName();
|
||||
ReferenceBean<GenericService> referenceBean = build(interfaceName, serviceName, null, emptyMap());
|
||||
ReferenceBean<GenericService> referenceBean = build(interfaceName, version, serviceName, emptyMap());
|
||||
return referenceBean.get();
|
||||
}
|
||||
|
||||
@ -85,18 +92,15 @@ public class DubboGenericServiceFactory {
|
||||
|
||||
Integer key = Objects.hash(interfaceName, version, group, dubboTranslatedAttributes);
|
||||
|
||||
ReferenceBean<GenericService> referenceBean = cache.get(key);
|
||||
|
||||
if (referenceBean == null) {
|
||||
referenceBean = new ReferenceBean<>();
|
||||
return cache.computeIfAbsent(key, k -> {
|
||||
ReferenceBean<GenericService> referenceBean = new ReferenceBean<>();
|
||||
referenceBean.setGeneric(true);
|
||||
referenceBean.setInterface(interfaceName);
|
||||
referenceBean.setVersion(version);
|
||||
referenceBean.setGroup(group);
|
||||
bindReferenceBean(referenceBean, dubboTranslatedAttributes);
|
||||
}
|
||||
|
||||
return referenceBean;
|
||||
return referenceBean;
|
||||
});
|
||||
}
|
||||
|
||||
private void bindReferenceBean(ReferenceBean<GenericService> referenceBean, Map<String, Object> dubboTranslatedAttributes) {
|
||||
@ -122,7 +126,12 @@ public class DubboGenericServiceFactory {
|
||||
}
|
||||
});
|
||||
|
||||
// ignore "registries" field and then use RegistryConfig beans
|
||||
dataBinder.setDisallowedFields("registries");
|
||||
|
||||
dataBinder.bind(new MutablePropertyValues(dubboTranslatedAttributes));
|
||||
|
||||
registryConfigs.ifAvailable(referenceBean::setRegistries);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
|
@ -16,21 +16,61 @@
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Dubbo Metadata Service
|
||||
* Dubbo Metadata Service is a core interface for service subscribers,
|
||||
* it must keep the stable of structure in every evolution , makes sure all subscribers' compatibility.
|
||||
* <p>
|
||||
* The interface contract's version must be {@link #VERSION} constant and group must be current Dubbo application name
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public interface DubboMetadataService {
|
||||
|
||||
/**
|
||||
* Get The json content of {@link ServiceRestMetadata} {@link Set}
|
||||
* Current version of the interface contract
|
||||
*/
|
||||
String VERSION = "1.0.0";
|
||||
|
||||
/**
|
||||
* Get the json content of {@link ServiceRestMetadata} {@link Set}
|
||||
*
|
||||
* @return <code>null</code> if present
|
||||
*/
|
||||
String getServiceRestMetadata();
|
||||
|
||||
|
||||
/**
|
||||
* Get all exported {@link URL#getServiceKey() service keys}
|
||||
*
|
||||
* @return non-null read-only {@link Set}
|
||||
*/
|
||||
Set<String> getAllServiceKeys();
|
||||
|
||||
/**
|
||||
* Get all exported Dubbo's {@link URL URLs} {@link Map} whose key is the return value of
|
||||
* {@link URL#getServiceKey()} method and value is the json content of List<URL> of {@link URL URLs}
|
||||
*
|
||||
* @return non-null read-only {@link Map}
|
||||
*/
|
||||
Map<String, String> getAllExportedURLs();
|
||||
|
||||
/**
|
||||
* Get the json content of an exported List<URL> of {@link URL URLs} by the serviceInterface , group and version
|
||||
*
|
||||
* @param serviceInterface The class name of service interface
|
||||
* @param group {@link Service#group() the service group} (optional)
|
||||
* @param version {@link Service#version() the service version} (optional)
|
||||
* @return non-null read-only {@link List}
|
||||
* @see URL
|
||||
*/
|
||||
String getExportedURLs(String serviceInterface, String group, String version);
|
||||
}
|
||||
|
@ -16,16 +16,20 @@
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ProtocolConfig;
|
||||
import org.apache.dubbo.config.ServiceConfig;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@ -42,12 +46,12 @@ public class DubboMetadataServiceExporter {
|
||||
private ApplicationConfig applicationConfig;
|
||||
|
||||
@Autowired
|
||||
private DubboMetadataService dubboMetadataService;
|
||||
private ObjectProvider<DubboMetadataService> dubboMetadataService;
|
||||
|
||||
@Autowired
|
||||
private Supplier<ProtocolConfig> protocolConfigSupplier;
|
||||
|
||||
@Value("${spring.application.name:application}")
|
||||
@Value("${spring.application.name:${dubbo.application.name:application}}")
|
||||
private String currentApplicationName;
|
||||
|
||||
/**
|
||||
@ -57,33 +61,39 @@ public class DubboMetadataServiceExporter {
|
||||
|
||||
/**
|
||||
* export {@link DubboMetadataService} as Dubbo service
|
||||
*
|
||||
* @return the exported {@link URL URLs}
|
||||
*/
|
||||
public void export() {
|
||||
public List<URL> export() {
|
||||
|
||||
if (serviceConfig != null && serviceConfig.isExported()) {
|
||||
return;
|
||||
if (serviceConfig == null || !serviceConfig.isExported()) {
|
||||
|
||||
serviceConfig = new ServiceConfig<>();
|
||||
|
||||
serviceConfig.setInterface(DubboMetadataService.class);
|
||||
// Use DubboMetadataService.VERSION as the Dubbo Service version
|
||||
serviceConfig.setVersion(DubboMetadataService.VERSION);
|
||||
// Use current Spring application name as the Dubbo Service group
|
||||
serviceConfig.setGroup(currentApplicationName);
|
||||
serviceConfig.setRef(dubboMetadataService.getIfAvailable());
|
||||
serviceConfig.setApplication(applicationConfig);
|
||||
serviceConfig.setProtocol(protocolConfigSupplier.get());
|
||||
|
||||
serviceConfig.export();
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString());
|
||||
}
|
||||
}
|
||||
|
||||
serviceConfig = new ServiceConfig<>();
|
||||
|
||||
serviceConfig.setInterface(DubboMetadataService.class);
|
||||
// Use current Spring application name as the Dubbo Service version
|
||||
serviceConfig.setVersion(currentApplicationName);
|
||||
serviceConfig.setRef(dubboMetadataService);
|
||||
serviceConfig.setApplication(applicationConfig);
|
||||
serviceConfig.setProtocol(protocolConfigSupplier.get());
|
||||
|
||||
serviceConfig.export();
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("The Dubbo service[{}] has been exported.", serviceConfig.toString());
|
||||
}
|
||||
return serviceConfig.getExportedUrls();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* unexport {@link DubboMetadataService}
|
||||
*/
|
||||
@PreDestroy
|
||||
public void unexport() {
|
||||
|
||||
if (serviceConfig == null || serviceConfig.isUnexported()) {
|
||||
|
@ -18,8 +18,12 @@ package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.apache.dubbo.rpc.service.GenericService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* {@link DubboMetadataService} {@link InvocationHandler}
|
||||
@ -28,27 +32,29 @@ import java.lang.reflect.Method;
|
||||
*/
|
||||
class DubboMetadataServiceInvocationHandler implements InvocationHandler {
|
||||
|
||||
/**
|
||||
* The method name of {@link DubboMetadataService#getServiceRestMetadata()}
|
||||
*/
|
||||
private static final String METHOD_NAME = "getServiceRestMetadata";
|
||||
|
||||
private static final String[] PARAMETER_TYPES = new String[0];
|
||||
|
||||
private static final String[] PARAMETER_VALUES = new String[0];
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final GenericService genericService;
|
||||
|
||||
public DubboMetadataServiceInvocationHandler(String serviceName, DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||
this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class);
|
||||
public DubboMetadataServiceInvocationHandler(String serviceName, String version, DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||
this.genericService = dubboGenericServiceFactory.create(serviceName, DubboMetadataService.class, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String methodName = method.getName();
|
||||
if (METHOD_NAME.equals(methodName)) {
|
||||
return genericService.$invoke(methodName, PARAMETER_TYPES, PARAMETER_VALUES);
|
||||
Object returnValue = null;
|
||||
try {
|
||||
returnValue = genericService.$invoke(method.getName(), getParameterTypes(method), args);
|
||||
} catch (Throwable e) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return method.invoke(proxy, args);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private String[] getParameterTypes(Method method) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
return Stream.of(parameterTypes).map(Class::getName).toArray(length -> new String[length]);
|
||||
}
|
||||
}
|
||||
|
@ -17,35 +17,68 @@
|
||||
package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.lang.reflect.Proxy.newProxyInstance;
|
||||
|
||||
/**
|
||||
* The proxy of {@link DubboMetadataService}
|
||||
*/
|
||||
public class DubboMetadataServiceProxy implements BeanClassLoaderAware {
|
||||
public class DubboMetadataServiceProxy implements BeanClassLoaderAware, DisposableBean {
|
||||
|
||||
private final DubboGenericServiceFactory dubboGenericServiceFactory;
|
||||
|
||||
private ClassLoader classLoader;
|
||||
|
||||
private final Map<String, DubboMetadataService> dubboMetadataServiceCache = new ConcurrentHashMap<>();
|
||||
|
||||
public DubboMetadataServiceProxy(DubboGenericServiceFactory dubboGenericServiceFactory) {
|
||||
this.dubboGenericServiceFactory = dubboGenericServiceFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* New proxy instance of {@link DubboMetadataService} via the specified service name
|
||||
* Initializes {@link DubboMetadataService}'s Proxy
|
||||
*
|
||||
* @param serviceName the service name
|
||||
* @param version the service version
|
||||
* @return a {@link DubboMetadataService} proxy
|
||||
*/
|
||||
public DubboMetadataService initProxy(String serviceName, String version) {
|
||||
return dubboMetadataServiceCache.computeIfAbsent(serviceName, name -> newProxy(name, version));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a proxy instance of {@link DubboMetadataService} via the specified service name
|
||||
*
|
||||
* @param serviceName the service name
|
||||
* @return a {@link DubboMetadataService} proxy
|
||||
*/
|
||||
public DubboMetadataService newProxy(String serviceName) {
|
||||
return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class},
|
||||
new DubboMetadataServiceInvocationHandler(serviceName, dubboGenericServiceFactory));
|
||||
public DubboMetadataService getProxy(String serviceName) {
|
||||
return dubboMetadataServiceCache.get(serviceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
dubboMetadataServiceCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* New a proxy instance of {@link DubboMetadataService} via the specified service name
|
||||
*
|
||||
* @param serviceName the service name
|
||||
* @param version the service version
|
||||
* @return a {@link DubboMetadataService} proxy
|
||||
*/
|
||||
protected DubboMetadataService newProxy(String serviceName, String version) {
|
||||
return (DubboMetadataService) newProxyInstance(classLoader, new Class[]{DubboMetadataService.class},
|
||||
new DubboMetadataServiceInvocationHandler(serviceName, version, dubboGenericServiceFactory));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
|
||||
/**
|
||||
* Introspective {@link DubboMetadataService} implementation
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class IntrospectiveDubboMetadataService implements DubboMetadataService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Autowired
|
||||
private ObjectProvider<DubboServiceMetadataRepository> dubboServiceMetadataRepository;
|
||||
|
||||
@Autowired
|
||||
private JSONUtils jsonUtils;
|
||||
|
||||
@Override
|
||||
public String getServiceRestMetadata() {
|
||||
Set<ServiceRestMetadata> serviceRestMetadata = getRepository().getServiceRestMetadata();
|
||||
String serviceRestMetadataJsonConfig = null;
|
||||
if (!isEmpty(serviceRestMetadata)) {
|
||||
serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata);
|
||||
}
|
||||
return serviceRestMetadataJsonConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAllServiceKeys() {
|
||||
return getRepository().getAllServiceKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAllExportedURLs() {
|
||||
Map<String, List<URL>> allExportedUrls = getRepository().getAllExportedUrls();
|
||||
if (isEmpty(allExportedUrls)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("There is no registered URL.");
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
allExportedUrls.forEach((serviceKey, urls) -> {
|
||||
result.put(serviceKey, jsonUtils.toJSON(urls));
|
||||
});
|
||||
|
||||
return unmodifiableMap(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportedURLs(String serviceInterface, String group, String version) {
|
||||
List<URL> urls = getRepository().getExportedURLs(serviceInterface, group, version);
|
||||
return jsonUtils.toJSON(urls);
|
||||
}
|
||||
|
||||
private DubboServiceMetadataRepository getRepository() {
|
||||
return dubboServiceMetadataRepository.getIfAvailable();
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.service;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
|
||||
import org.springframework.cloud.alibaba.dubbo.util.JSONUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.springframework.util.ObjectUtils.isEmpty;
|
||||
|
||||
/**
|
||||
* Publishing {@link DubboMetadataService} implementation
|
||||
*
|
||||
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
|
||||
*/
|
||||
public class PublishingDubboMetadataService implements DubboMetadataService {
|
||||
|
||||
/**
|
||||
* 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 from the annotated methods.
|
||||
*/
|
||||
private final Set<ServiceRestMetadata> serviceRestMetadata = new LinkedHashSet<>();
|
||||
|
||||
@Autowired
|
||||
private JSONUtils jsonUtils;
|
||||
|
||||
/**
|
||||
* Publish the {@link Set} of {@link ServiceRestMetadata}
|
||||
*
|
||||
* @param serviceRestMetadataSet the {@link Set} of {@link ServiceRestMetadata}
|
||||
*/
|
||||
public void publishServiceRestMetadata(Set<ServiceRestMetadata> serviceRestMetadataSet) {
|
||||
for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
|
||||
if (!CollectionUtils.isEmpty(serviceRestMetadata.getMeta())) {
|
||||
this.serviceRestMetadata.add(serviceRestMetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceRestMetadata() {
|
||||
String serviceRestMetadataJsonConfig = null;
|
||||
if (!isEmpty(serviceRestMetadata)) {
|
||||
serviceRestMetadataJsonConfig = jsonUtils.toJSON(serviceRestMetadata);
|
||||
}
|
||||
return serviceRestMetadataJsonConfig;
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package org.springframework.cloud.alibaba.dubbo.util;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
@ -25,8 +27,10 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JSON Utilities class
|
||||
@ -44,6 +48,10 @@ public class JSONUtils {
|
||||
this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
}
|
||||
|
||||
public String toJSON(Collection<URL> urls) {
|
||||
return toJSON(urls.stream().map(URL::toFullString).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
public String toJSON(Object object) {
|
||||
String jsonContent = null;
|
||||
try {
|
||||
@ -56,6 +64,11 @@ public class JSONUtils {
|
||||
return jsonContent;
|
||||
}
|
||||
|
||||
public List<URL> toURLs(String urlsJSON) {
|
||||
List<String> list = toList(urlsJSON);
|
||||
return list.stream().map(URL::valueOf).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> toList(String json) {
|
||||
List<String> list = Collections.emptyList();
|
||||
try {
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -1,35 +0,0 @@
|
||||
registry {
|
||||
# file 、nacos 、redis
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file nacos apollo
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "fescar-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
registry {
|
||||
# file 、nacos 、redis
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file nacos apollo
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "fescar-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
registry {
|
||||
# file 、nacos 、redis
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file nacos apollo
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "fescar-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
registry {
|
||||
# file 、nacos 、redis
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file nacos apollo
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "fescar-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>nacos-discovery-example</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>nacos-discovery-example</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>nacos-gateway-example</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>nacos-gateway-example</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -21,6 +21,9 @@
|
||||
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-provider-example</module>
|
||||
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example</module>
|
||||
<module>sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api</module>
|
||||
<module>sentinel-example/sentinel-webflux-example</module>
|
||||
<module>sentinel-example/sentinel-spring-cloud-gateway-example</module>
|
||||
<module>sentinel-example/sentinel-zuul-example</module>
|
||||
<module>nacos-example/nacos-discovery-example</module>
|
||||
<module>nacos-example/nacos-config-example</module>
|
||||
<module>nacos-example/nacos-gateway-example</module>
|
||||
@ -28,10 +31,10 @@
|
||||
<module>ans-example/ans-consumer-feign-example</module>
|
||||
<module>ans-example/ans-consumer-ribbon-example</module>
|
||||
<module>ans-example/ans-provider-example</module>
|
||||
<module>fescar-example/business-service</module>
|
||||
<module>fescar-example/order-service</module>
|
||||
<module>fescar-example/storage-service</module>
|
||||
<module>fescar-example/account-service</module>
|
||||
<module>seata-example/business-service</module>
|
||||
<module>seata-example/order-service</module>
|
||||
<module>seata-example/storage-service</module>
|
||||
<module>seata-example/account-service</module>
|
||||
<module>acm-example/acm-local-example</module>
|
||||
<module>rocketmq-example/rocketmq-consume-example</module>
|
||||
<module>rocketmq-example/rocketmq-produce-example</module>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -1,10 +1,15 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.alibaba.cloud.examples.RocketMQConsumerApplication.MySink;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.Input;
|
||||
import org.springframework.cloud.stream.binder.PollableMessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
|
||||
/**
|
||||
@ -27,10 +32,36 @@ public class RocketMQConsumerApplication {
|
||||
|
||||
@Input("input4")
|
||||
SubscribableChannel input4();
|
||||
|
||||
@Input("input5")
|
||||
PollableMessageSource input5();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RocketMQConsumerApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsumerCustomRunner customRunner() {
|
||||
return new ConsumerCustomRunner();
|
||||
}
|
||||
|
||||
public static class ConsumerCustomRunner implements CommandLineRunner {
|
||||
|
||||
@Autowired
|
||||
private MySink mySink;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws InterruptedException {
|
||||
while (true) {
|
||||
mySink.input5().poll(m -> {
|
||||
String payload = (String) m.getPayload();
|
||||
System.out.println("pull msg: " + payload);
|
||||
}, new ParameterizedTypeReference<String>() {
|
||||
});
|
||||
Thread.sleep(2_000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,10 @@ spring.cloud.stream.bindings.input4.content-type=text/plain
|
||||
spring.cloud.stream.bindings.input4.group=transaction-group
|
||||
spring.cloud.stream.bindings.input4.consumer.concurrency=5
|
||||
|
||||
spring.cloud.stream.bindings.input5.destination=pull-topic
|
||||
spring.cloud.stream.bindings.input5.content-type=text/plain
|
||||
spring.cloud.stream.bindings.input5.group=pull-topic-group
|
||||
|
||||
spring.application.name=rocketmq-consume-example
|
||||
|
||||
server.port=28082
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -9,6 +9,7 @@ import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.Output;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
@ -23,6 +24,9 @@ public class RocketMQProduceApplication {
|
||||
|
||||
@Output("output2")
|
||||
MessageChannel output2();
|
||||
|
||||
@Output("output3")
|
||||
MessageChannel output3();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
@ -31,7 +35,12 @@ public class RocketMQProduceApplication {
|
||||
|
||||
@Bean
|
||||
public CustomRunner customRunner() {
|
||||
return new CustomRunner();
|
||||
return new CustomRunner("output1");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CustomRunner customRunner2() {
|
||||
return new CustomRunner("output3");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ -40,24 +49,45 @@ public class RocketMQProduceApplication {
|
||||
}
|
||||
|
||||
public static class CustomRunner implements CommandLineRunner {
|
||||
|
||||
private final String bindingName;
|
||||
|
||||
public CustomRunner(String bindingName) {
|
||||
this.bindingName = bindingName;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private SenderService senderService;
|
||||
|
||||
@Autowired
|
||||
private MySource mySource;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
int count = 5;
|
||||
for (int index = 1; index <= count; index++) {
|
||||
String msgContent = "msg-" + index;
|
||||
if (index % 3 == 0) {
|
||||
senderService.send(msgContent);
|
||||
}
|
||||
else if (index % 3 == 1) {
|
||||
senderService.sendWithTags(msgContent, "tagStr");
|
||||
}
|
||||
else {
|
||||
senderService.sendObject(new Foo(index, "foo"), "tagObj");
|
||||
if (this.bindingName.equals("output1")) {
|
||||
int count = 5;
|
||||
for (int index = 1; index <= count; index++) {
|
||||
String msgContent = "msg-" + index;
|
||||
if (index % 3 == 0) {
|
||||
senderService.send(msgContent);
|
||||
}
|
||||
else if (index % 3 == 1) {
|
||||
senderService.sendWithTags(msgContent, "tagStr");
|
||||
}
|
||||
else {
|
||||
senderService.sendObject(new Foo(index, "foo"), "tagObj");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.bindingName.equals("output3")) {
|
||||
int count = 50;
|
||||
for (int index = 1; index <= count; index++) {
|
||||
String msgContent = "pullMsg-" + index;
|
||||
mySource.output3()
|
||||
.send(MessageBuilder.withPayload(msgContent).build());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,10 @@ spring.cloud.stream.bindings.output2.content-type=application/json
|
||||
spring.cloud.stream.rocketmq.bindings.output2.producer.transactional=true
|
||||
spring.cloud.stream.rocketmq.bindings.output2.producer.group=myTxProducerGroup
|
||||
|
||||
spring.cloud.stream.bindings.output3.destination=pull-topic
|
||||
spring.cloud.stream.bindings.output3.content-type=text/plain
|
||||
spring.cloud.stream.rocketmq.bindings.output3.producer.group=pull-binder-group
|
||||
|
||||
spring.application.name=rocketmq-produce-example
|
||||
|
||||
server.port=28081
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -14,7 +14,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
@ -17,7 +17,7 @@ package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.alibaba.fescar.core.context.RootContext;
|
||||
import io.seata.core.context.RootContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
@ -16,17 +16,16 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Random;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.fescar.rm.datasource.DataSourceProxy;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
@ -20,17 +20,26 @@ transport {
|
||||
worker-thread-size = 8
|
||||
}
|
||||
}
|
||||
store {
|
||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||
max-branch-session-size = 16384
|
||||
# globe session size , if exceeded throws exceptions
|
||||
max-global-session-size = 512
|
||||
# file buffer size , if exceeded allocate new buffer
|
||||
file-write-buffer-cache-size = 16384
|
||||
# when recover batch read size
|
||||
session.reload.read_size = 100
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.storage-service-fescar-service-group = "localRgroup"
|
||||
vgroup_mapping.account-service-fescar-service-group = "default"
|
||||
#only support single node
|
||||
localRgroup.grouplist = "127.0.0.1:8091"
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
enableDegrade = false
|
||||
#disable
|
||||
disable = false
|
||||
}
|
||||
|
||||
client {
|
||||
async.commit.buffer.limit = 10000
|
||||
lock {
|
@ -0,0 +1,55 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:1001/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "fescar-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -14,7 +14,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.fescar.spring.annotation.GlobalTransactional;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
@ -20,17 +20,46 @@ transport {
|
||||
worker-thread-size = 8
|
||||
}
|
||||
}
|
||||
## transaction log store
|
||||
store {
|
||||
## store mode: file、db
|
||||
mode = "file"
|
||||
|
||||
## file store
|
||||
file {
|
||||
dir = "sessionStore"
|
||||
|
||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||
max-branch-session-size = 16384
|
||||
# globe session size , if exceeded throws exceptions
|
||||
max-global-session-size = 512
|
||||
# file buffer size , if exceeded allocate new buffer
|
||||
file-write-buffer-cache-size = 16384
|
||||
# when recover batch read size
|
||||
session.reload.read_size = 100
|
||||
# async, sync
|
||||
flush-disk-mode = async
|
||||
}
|
||||
|
||||
## database store
|
||||
db {
|
||||
driver_class = ""
|
||||
url = ""
|
||||
user = ""
|
||||
password = ""
|
||||
}
|
||||
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.account-service-fescar-service-group = "localRgroup"
|
||||
vgroup_mapping.business-service-fescar-service-group = "default"
|
||||
#only support single node
|
||||
localRgroup.grouplist = "127.0.0.1:8091"
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
enableDegrade = false
|
||||
#disable
|
||||
disable = false
|
||||
}
|
||||
|
||||
client {
|
||||
async.commit.buffer.limit = 10000
|
||||
lock {
|
@ -0,0 +1,68 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:1001/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
etcd3 {
|
||||
cluster = "default"
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
sofa {
|
||||
serverAddr = "127.0.0.1:9603"
|
||||
application = "default"
|
||||
region = "DEFAULT_ZONE"
|
||||
datacenter = "DefaultDataCenter"
|
||||
cluster = "default"
|
||||
group = "SEATA_GROUP"
|
||||
addressWaitTime = "3000"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "seata-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -14,7 +14,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
@ -24,7 +24,7 @@ import org.springframework.core.env.Environment;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.fescar.rm.datasource.DataSourceProxy;
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.fescar.core.context.RootContext;
|
||||
import io.seata.core.context.RootContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
@ -20,17 +20,46 @@ transport {
|
||||
worker-thread-size = 8
|
||||
}
|
||||
}
|
||||
## transaction log store
|
||||
store {
|
||||
## store mode: file、db
|
||||
mode = "file"
|
||||
|
||||
## file store
|
||||
file {
|
||||
dir = "sessionStore"
|
||||
|
||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||
max-branch-session-size = 16384
|
||||
# globe session size , if exceeded throws exceptions
|
||||
max-global-session-size = 512
|
||||
# file buffer size , if exceeded allocate new buffer
|
||||
file-write-buffer-cache-size = 16384
|
||||
# when recover batch read size
|
||||
session.reload.read_size = 100
|
||||
# async, sync
|
||||
flush-disk-mode = async
|
||||
}
|
||||
|
||||
## database store
|
||||
db {
|
||||
driver_class = ""
|
||||
url = ""
|
||||
user = ""
|
||||
password = ""
|
||||
}
|
||||
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.business-service-fescar-service-group = "localRgroup"
|
||||
vgroup_mapping.order-service-fescar-service-group = "default"
|
||||
#only support single node
|
||||
localRgroup.grouplist = "127.0.0.1:8091"
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
enableDegrade = false
|
||||
#disable
|
||||
disable = false
|
||||
}
|
||||
|
||||
client {
|
||||
async.commit.buffer.limit = 10000
|
||||
lock {
|
@ -0,0 +1,68 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:1001/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
etcd3 {
|
||||
cluster = "default"
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
sofa {
|
||||
serverAddr = "127.0.0.1:9603"
|
||||
application = "default"
|
||||
region = "DEFAULT_ZONE"
|
||||
datacenter = "DefaultDataCenter"
|
||||
cluster = "default"
|
||||
group = "SEATA_GROUP"
|
||||
addressWaitTime = "3000"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "seata-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
# Fescar Example
|
||||
# Seata Example
|
||||
|
||||
## 项目说明
|
||||
|
||||
|
||||
本项目演示如何使用 Fescar Starter 完成 Spring Cloud 应用的分布式事务接入。
|
||||
本项目演示如何使用 Seata Starter 完成 Spring Cloud 应用的分布式事务接入。
|
||||
|
||||
[Fescar](https://github.com/alibaba/fescar) 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题。
|
||||
[Seata](https://github.com/seata/seata) 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题。
|
||||
|
||||
|
||||
|
||||
@ -19,14 +19,14 @@
|
||||
|
||||
1. 创建 示例中 业务所需要的数据库表
|
||||
|
||||
1. 启动 Fescar Server
|
||||
1. 启动 Seata Server
|
||||
|
||||
|
||||
### 配置数据库
|
||||
|
||||
首先,你需要有一个支持 InnoDB 引擎的 MySQL 数据库。
|
||||
|
||||
**注意**: 实际上,Fescar 支持不同的应用使用完全不相干的数据库,但是这里为了简单地演示一个原理,所以我们选择了只使用一个数据库。
|
||||
**注意**: 实际上,Seata 支持不同的应用使用完全不相干的数据库,但是这里为了简单地演示一个原理,所以我们选择了只使用一个数据库。
|
||||
|
||||
将 `account-server`、`order-service`、`storage-service` 这三个应用中的 resources 目录下的 `application.properties` 文件中的如下配置修改成你运行环境中的实际配置。
|
||||
|
||||
@ -42,7 +42,7 @@ mysql.user.password=your mysql server password
|
||||
|
||||
### 创建 undo_log 表
|
||||
|
||||
[Fescar AT 模式]() 需要使用到 undo_log 表。
|
||||
[Seata AT 模式]() 需要使用到 undo_log 表。
|
||||
|
||||
``` $sql
|
||||
-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log
|
||||
@ -93,24 +93,24 @@ CREATE TABLE `account_tbl` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
```
|
||||
|
||||
### 启动 Fescar Server
|
||||
### 启动 Seata Server
|
||||
|
||||
点击这个页面 [https://github.com/alibaba/fescar/releases](https://github.com/alibaba/fescar/releases),下载最新版本的 Fescar Server 端.
|
||||
点击这个页面 [https://github.com/seata/seata/releases](https://github.com/seata/seata/releases),下载最新版本的 Seata Server 端.
|
||||
|
||||
|
||||
进入解压之后的 bin 目录,执行如下命令来启动
|
||||
|
||||
```$shell
|
||||
sh fescar-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA
|
||||
sh seata-server.sh $LISTEN_PORT $MODE(file or db)
|
||||
```
|
||||
|
||||
在这个示例中,采用如下命令来启动 Fescar Server
|
||||
在这个示例中,采用如下命令来启动 Seata Server
|
||||
|
||||
```$shell
|
||||
sh fescar-server.sh 8091 ~/fescar/data/
|
||||
sh seata-server.sh 8091 file
|
||||
```
|
||||
|
||||
**注意** 如果你修改了端口号,那么记得需要在各个示例工程中的 `application.conf` 文件中,修改 grouplist 的值。
|
||||
**注意** 如果你修改了endpoint且注册中心使用默认file类型,那么记得需要在各个示例工程中的 `file.conf` 文件中,修改 grouplist 的值(当registry.conf 中registry.type 或 config.type 为file 时会读取内部的file节点中的文件名,若type不为file将直接从配置类型的对应元数据的注册配置中心读取数据),推荐大家使用 nacos 作为配置注册中心。
|
||||
|
||||
|
||||
## 运行示例
|
||||
@ -146,12 +146,12 @@ http://127.0.0.1:18081/fescar/rest
|
||||
|
||||
## 对 Spring Cloud 支持点
|
||||
|
||||
- 通过 Spring MVC 提供服务的服务提供者,在收到 header 中含有 Fescar 信息的 HTTP 请求时,可以自动还原 Fescar 上下文。
|
||||
- 通过 Spring MVC 提供服务的服务提供者,在收到 header 中含有 Seata 信息的 HTTP 请求时,可以自动还原 Seata 上下文。
|
||||
|
||||
- 支持服务调用者通过 RestTemplate 调用时,自动传递 Fescar 上下文。
|
||||
- 支持服务调用者通过 RestTemplate 调用时,自动传递 Seata 上下文。
|
||||
|
||||
- 支持服务调用者通过 FeignClient 调用时,自动传递 Fescar 上下文。
|
||||
- 支持服务调用者通过 FeignClient 调用时,自动传递 Seata 上下文。
|
||||
|
||||
- 支持 FeignClient 和 Hystrix 同时使用的场景。
|
||||
- 支持 SeataClient 和 Hystrix 同时使用的场景。
|
||||
|
||||
- 支持 FeignClient 和 Sentinel 同时使用的场景。
|
||||
- 支持 SeataClient 和 Sentinel 同时使用的场景。
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -14,7 +14,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-fescar</artifactId>
|
||||
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
@ -19,7 +19,7 @@ package org.springframework.cloud.alibaba.cloud.examples;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.fescar.rm.datasource.DataSourceProxy;
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.fescar.core.context.RootContext;
|
||||
import io.seata.core.context.RootContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
@ -20,17 +20,46 @@ transport {
|
||||
worker-thread-size = 8
|
||||
}
|
||||
}
|
||||
## transaction log store
|
||||
store {
|
||||
## store mode: file、db
|
||||
mode = "file"
|
||||
|
||||
## file store
|
||||
file {
|
||||
dir = "sessionStore"
|
||||
|
||||
# branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
|
||||
max-branch-session-size = 16384
|
||||
# globe session size , if exceeded throws exceptions
|
||||
max-global-session-size = 512
|
||||
# file buffer size , if exceeded allocate new buffer
|
||||
file-write-buffer-cache-size = 16384
|
||||
# when recover batch read size
|
||||
session.reload.read_size = 100
|
||||
# async, sync
|
||||
flush-disk-mode = async
|
||||
}
|
||||
|
||||
## database store
|
||||
db {
|
||||
driver_class = ""
|
||||
url = ""
|
||||
user = ""
|
||||
password = ""
|
||||
}
|
||||
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.order-service-fescar-service-group = "localRgroup"
|
||||
vgroup_mapping.storage-service-fescar-service-group = "default"
|
||||
#only support single node
|
||||
localRgroup.grouplist = "127.0.0.1:8091"
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
enableDegrade = false
|
||||
#disable
|
||||
disable = false
|
||||
}
|
||||
|
||||
client {
|
||||
async.commit.buffer.limit = 10000
|
||||
lock {
|
@ -0,0 +1,68 @@
|
||||
registry {
|
||||
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:1001/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
consul {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:8500"
|
||||
}
|
||||
etcd3 {
|
||||
cluster = "default"
|
||||
serverAddr = "http://localhost:2379"
|
||||
}
|
||||
sofa {
|
||||
serverAddr = "127.0.0.1:9603"
|
||||
application = "default"
|
||||
region = "DEFAULT_ZONE"
|
||||
datacenter = "DefaultDataCenter"
|
||||
cluster = "default"
|
||||
group = "SEATA_GROUP"
|
||||
addressWaitTime = "3000"
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk
|
||||
type = "file"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "seata-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"resource": "resource",
|
||||
"resource": "/hello",
|
||||
"controlBehavior": 0,
|
||||
"count": 1,
|
||||
"grade": 1,
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -28,12 +28,17 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.boot</groupId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.dubbo.config.annotation.Reference;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
public class FooServiceConsumer {
|
||||
|
||||
@Reference(version = "${foo.service.version}", application = "${dubbo.application.id}",
|
||||
url = "dubbo://localhost:12345", timeout = 30000)
|
||||
@Reference(version = "${foo.service.version}", application = "${dubbo.application.id}", url = "dubbo://localhost:12345", timeout = 30000)
|
||||
private FooService fooService;
|
||||
|
||||
public String hello(String name) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@ -21,18 +21,24 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>sentinel-dubbo-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.boot</groupId>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
@ -1,20 +1,15 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.dubbo.config.annotation.Service;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
@Service(
|
||||
version = "${foo.service.version}",
|
||||
application = "${dubbo.application.id}",
|
||||
protocol = "${dubbo.protocol.id}",
|
||||
registry = "${dubbo.registry.id}"
|
||||
)
|
||||
@Service(version = "${foo.service.version}", application = "${dubbo.application.id}", protocol = "${dubbo.protocol.id}", registry = "${dubbo.registry.id}")
|
||||
public class FooServiceImpl implements FooService {
|
||||
|
||||
@Override
|
||||
public String hello(String name) {
|
||||
return "hello, " + name;
|
||||
}
|
||||
@Override
|
||||
public String hello(String name) {
|
||||
return "hello, " + name;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>sentinel-spring-cloud-gateway-example</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>Example demonstrating how to use sentinel with spring cloud gateway</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.alibaba.csp</groupId>-->
|
||||
<!--<artifactId>sentinel-datasource-nacos</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.alibaba.csp</groupId>-->
|
||||
<!--<artifactId>sentinel-datasource-zookeeper</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.alibaba.csp</groupId>-->
|
||||
<!--<artifactId>sentinel-datasource-apollo</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
<!-- define in spring-boot-autoconfigure module -->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.fasterxml.jackson.dataformat</groupId>-->
|
||||
<!--<artifactId>jackson-dataformat-xml</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@Configuration
|
||||
public class MySCGConfiguration {
|
||||
|
||||
@Bean
|
||||
public BlockRequestHandler blockRequestHandler() {
|
||||
return new BlockRequestHandler() {
|
||||
@Override
|
||||
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
|
||||
return ServerResponse.status(444)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.body(fromObject("SCS Sentinel block"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@RestController
|
||||
public class RulesWebFluxController {
|
||||
|
||||
@GetMapping("/api")
|
||||
public Mono<Set<ApiDefinition>> apiRules() {
|
||||
return Mono.just(GatewayApiDefinitionManager.getApiDefinitions());
|
||||
}
|
||||
|
||||
@GetMapping("/gateway")
|
||||
public Mono<Set<GatewayFlowRule>> apiGateway() {
|
||||
return Mono.just(GatewayRuleManager.getRules());
|
||||
}
|
||||
|
||||
@GetMapping("/flow")
|
||||
public Mono<List<FlowRule>> apiFlow() {
|
||||
return Mono.just(FlowRuleManager.getRules());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SentinelSpringCloudGatewayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
//GatewayCallbackManager.setRequestOriginParser(s -> "123");
|
||||
SpringApplication.run(SentinelSpringCloudGatewayApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"apiName": "some_customized_api",
|
||||
"predicateItems": [
|
||||
{
|
||||
"pattern": "/product/baz"
|
||||
},
|
||||
{
|
||||
"pattern": "/product/foo/**",
|
||||
"matchStrategy": 1
|
||||
},
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"pattern": "/spring-cloud/**"
|
||||
},
|
||||
{
|
||||
"pattern": "/spring-cloud-alibaba/**"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"apiName": "another_customized_api",
|
||||
"predicateItems": [
|
||||
{
|
||||
"pattern": "/ahas"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
@ -0,0 +1,37 @@
|
||||
server:
|
||||
port: 18085
|
||||
spring:
|
||||
application:
|
||||
name: sentinel-spring-cloud-gateway
|
||||
cloud:
|
||||
gateway:
|
||||
enabled: true
|
||||
discovery:
|
||||
locator:
|
||||
lower-case-service-id: true
|
||||
routes:
|
||||
# Add your routes here.
|
||||
- id: aliyun_route
|
||||
uri: https://www.aliyun.com/
|
||||
predicates:
|
||||
- Path=/product/**
|
||||
- id: httpbin_route
|
||||
uri: https://httpbin.org
|
||||
predicates:
|
||||
- Path=/httpbin/**
|
||||
filters:
|
||||
- RewritePath=/httpbin/(?<segment>.*), /$\{segment}
|
||||
|
||||
sentinel:
|
||||
datasource.ds2.file:
|
||||
file: "classpath: gateway.json"
|
||||
ruleType: gw-flow
|
||||
datasource.ds1.file:
|
||||
file: "classpath: api.json"
|
||||
ruleType: gw-api-group
|
||||
transport:
|
||||
dashboard: localhost:8080
|
||||
filter:
|
||||
enabled: true
|
||||
|
||||
management.endpoints.web.exposure.include: "*"
|
@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"resource": "some_customized_api",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"resource": "httpbin_route",
|
||||
"count": 0,
|
||||
"paramItem": {
|
||||
"parseStrategy": 2,
|
||||
"fieldName": "Spring-Cloud-Alibaba"
|
||||
}
|
||||
},
|
||||
{
|
||||
"resource": "httpbin_route",
|
||||
"count": 0,
|
||||
"paramItem": {
|
||||
"parseStrategy": 3,
|
||||
"fieldName": "name"
|
||||
}
|
||||
}
|
||||
]
|
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<version>0.9.1.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
<artifactId>sentinel-webflux-example</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<description>Example demonstrating how to use sentinel with webflux</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.alibaba.csp</groupId>-->
|
||||
<!--<artifactId>sentinel-datasource-nacos</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.alibaba.csp</groupId>-->
|
||||
<!--<artifactId>sentinel-datasource-zookeeper</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.alibaba.csp</groupId>-->
|
||||
<!--<artifactId>sentinel-datasource-apollo</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
<!-- define in spring-boot-autoconfigure module -->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.fasterxml.jackson.dataformat</groupId>-->
|
||||
<!--<artifactId>jackson-dataformat-xml</artifactId>-->
|
||||
<!--</dependency>-->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@Configuration
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
public BlockRequestHandler blockRequestHandler() {
|
||||
return new BlockRequestHandler() {
|
||||
@Override
|
||||
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange,
|
||||
Throwable t) {
|
||||
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.body(fromObject("block"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SentinelWebFluxApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SentinelWebFluxApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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 org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.reactor.SentinelReactorTransformer;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
|
||||
*/
|
||||
@RestController
|
||||
public class SentinelWebFluxController {
|
||||
|
||||
@GetMapping("/mono")
|
||||
public Mono<String> mono() {
|
||||
return Mono.just("simple string")
|
||||
// transform the publisher here.
|
||||
.transform(new SentinelReactorTransformer<>("mono"));
|
||||
}
|
||||
|
||||
@GetMapping("/flux")
|
||||
public Flux<String> flux() {
|
||||
return Flux.fromArray(new String[] { "a", "b", "c" })
|
||||
// transform the publisher here.
|
||||
.transform(new SentinelReactorTransformer<>("flux"));
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user