Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。
目前 Spring Cloud Alibaba 提供了如下功能:
Spring Cloud Alibaba 也提供了丰富的 examples。
Spring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。
如果您是 Maven Central 用户,请将我们的 BOM 添加到您的 pom.xml 中的 部分。 这将允许您省略任何Maven依赖项的版本,而是将版本控制委派给BOM。
com.alibaba.cloud spring-cloud-alibaba-dependencies 2021.0.4.0 pom import
在下面的章节中,假设您使用的是 Spring Cloud Alibaba bom,相关 starter 依赖将不包含版本号。
Nacos 是一个 Alibaba 开源的、易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
使用 Spring Cloud Alibaba Nacos Discovery,可基于 Spring Cloud 的编程模型快速接入 Nacos 服务注册功能。
服务发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于 服务的动态扩缩容。Nacos Discovery 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery 也将服务实例自身的一些元数据信息-例如 host,port, 健康检查URL,主页等内容注册到 Nacos。Nacos 的获取和启动方式可以参考 Nacos 官网。
如果要在您的项目中使用 Nacos 来实现服务注册/发现,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alibaba-nacos-discovery 的 starter。
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery
Nacos Discovery 适配了 Netflix Ribbon,可以使用 RestTemplate 或 OpenFeign 进行服务的调用。
具体启动方式参考 Nacos 官网。
Nacos Server 启动后,进入 http://ip:8848 查看控制台(默认账号名/密码为 nacos/nacos):
Figure 1. Nacos Dashboard
关于更多的 Nacos Server 版本,可以从 release 页面 下载最新的版本。
以下步骤向您展示了如何将一个服务注册到 Nacos。
pom.xml
4.0.0 open.source.test nacos-discovery-test 1.0-SNAPSHOT nacos-discovery-test org.springframework.boot spring-boot-starter-parent ${spring.boot.version} UTF-8 UTF-8 1.8 org.springframework.cloud spring-cloud-dependencies ${spring.cloud.version} pom import com.alibaba.cloud spring-cloud-alibaba-dependencies ${spring.cloud.alibaba.version} pom import org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery org.springframework.boot spring-boot-maven-plugin
application.properties
server.port=8081 spring.application.name=nacos-provider spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 management.endpoints.web.exposure.include=*
NOTE | 如果不想使用 Nacos 作为您的服务注册与发现,可以将 spring.cloud.nacos.discovery 设置为 false。 |
---|---|
@SpringBootApplication @EnableDiscoveryClient public class NacosProviderDemoApplication { public static void main(String[] args) { SpringApplication.run(NacosProviderDemoApplication.class, args); } @RestController public class EchoController { @GetMapping(value = "/echo/{string}") public String echo(@PathVariable String string) { return "Hello Nacos Discovery " + string; } } }
这个时候你就可以在 Nacos的控制台上看到注册上来的服务信息了。
Consumer 应用可能还没像启动一个 Provider 应用那么简单。因为在 Consumer 端需要去调用 Provider 端提供的REST 服务。例子中我们使用最原始的一种方式, 即显示的使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问。 pom.xml 和 application.properties 的配置可以参考 1.2 小结。启动一个 Consumer应用的示例代码如下所示:
NOTE | 通过带有负载均衡的RestTemplate 和 FeignClient 也是可以访问的。 |
---|---|
@SpringBootApplication @EnableDiscoveryClient public class NacosConsumerApp { @RestController public class NacosController{ @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private RestTemplate restTemplate; @Value("${spring.application.name}") private String appName; @GetMapping("/echo/app-name") public String echoAppName(){ //使用 LoadBalanceClient 和 RestTemplate 结合的方式来访问 ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider"); 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); } } //实例化 RestTemplate 实例 @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(NacosConsumerApp.class,args); } }
这个例子中我们注入了一个 LoadBalancerClient 的实例,并且手动的实例化一个 RestTemplate,同时将 spring.application.name 的配置值 注入到应用中来, 目的是调用 Provider 提供的服务时,希望将当前配置的应用名给显示出来。
NOTE | 在启动 Consumer 应用之前请先将 Nacos 服务启动好。具体启动方式可参考 Nacos 官网。 |
---|---|
启动后,访问 Consumer 提供出来的 http://ip:port/echo/app-name 接口。我这里测试启动的 port是 8082。访问结果如下所示:
访问地址:http://127.0.0.1:8082/echo/app-name 访问结果:Hello Nacos Discovery nacos-consumer
Nacos Discovery 内部提供了一个 Endpoint, 对应的 endpoint id 为 nacosdiscovery。
Endpoint 暴露的 json 中包含了两种属性:
这是 Endpoint 暴露的 json 示例:
{ "subscribe": [ { "jsonFromServer": "", "name": "nacos-provider", "clusters": "", "cacheMillis": 10000, "hosts": [ { "instanceId": "30.5.124.156#8081#DEFAULT#nacos-provider", "ip": "30.5.124.156", "port": 8081, "weight": 1.0, "healthy": true, "enabled": true, "cluster": { "serviceName": null, "name": null, "healthChecker": { "type": "TCP" }, "defaultPort": 80, "defaultCheckPort": 80, "useIPPort4Check": true, "metadata": { } }, "service": null, "metadata": { } } ], "lastRefTime": 1541755293119, "checksum": "e5a699c9201f5328241c178e804657e11541755293119", "allIPs": false, "key": "nacos-provider", "valid": true } ], "NacosDiscoveryProperties": { "serverAddr": "127.0.0.1:8848", "endpoint": "", "namespace": "", "logName": "", "service": "nacos-provider", "weight": 1.0, "clusterName": "DEFAULT", "metadata": { }, "registerEnabled": true, "ip": "30.5.124.201", "networkInterface": "", "port": 8082, "secure": false, "accessKey": "", "secretKey": "" } }
pom.xml
org.springframework.cloud spring-cloud-loadbalancer
application.properties
spring.cloud.loadbalancer.ribbon.enabled=false spring.cloud.loadbalancer.nacos.enabled=true
更多关于 Nacos Discovery Starter 的配置项如下所示:
配置项 | Key | 默认值 | 说明 |
---|---|---|---|
服务端地址 | spring.cloud.nacos.discovery.server-addr | Nacos Server 启动监听的ip地址和端口 | |
服务名 | spring.cloud.nacos.discovery.service | ${spring.application.name} | 注册的服务名 |
权重 | spring.cloud.nacos.discovery.weight | 1 | 取值范围 1 到 100,数值越大,权重越大 |
网卡名 | spring.cloud.nacos.discovery.network-interface | 当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址 | |
注册的IP地址 | spring.cloud.nacos.discovery.ip | 优先级最高 | |
注册的IP地址类型 | spring.cloud.nacos.discovery.ip-type | IPv4 | 可以配置IPv4和IPv6两种类型,如果网卡同类型IP地址存在多个,希望制定特定网段地址,可使用spring.cloud.inetutils.preferred-networks配置筛选地址 |
注册的端口 | spring.cloud.nacos.discovery.port | -1 | 默认情况下不用配置,会自动探测 |
命名空间 | spring.cloud.nacos.discovery.namespace | 常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等 | |
AccessKey | spring.cloud.nacos.discovery.access-key | 当要上阿里云时,阿里云上面的一个云账号名 | |
SecretKey | spring.cloud.nacos.discovery.secret-key | 当要上阿里云时,阿里云上面的一个云账号密码 | |
Metadata | spring.cloud.nacos.discovery.metadata | 使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息 | |
日志文件名 | spring.cloud.nacos.discovery.log-name | ||
集群 | spring.cloud.nacos.discovery.cluster-name | DEFAULT | Nacos集群名称 |
接入点 | spring.cloud.nacos.discovery.endpoint | 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 | |
是否集成LoadBalancer | spring.cloud.loadbalancer.nacos.enabled | false | |
是否开启Nacos Watch | spring.cloud.nacos.discovery.watch.enabled | true | 可以设置成false来关闭 watch |
Nacos 是一个 Alibaba 开源的、易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
使用 Spring Cloud Alibaba Nacos Config,可基于 Spring Cloud 的编程模型快速接入 Nacos 配置管理功能。
如果要在您的项目中使用 Nacos 来实现配置管理,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alibaba-nacos-config 的 starter。
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config
Nacos Config 使用 DataId 和 GROUP 确定一个配置。
下图表示 DataId 使用 myDataid, GROUP 使用 DEFAULT_GROUP,配置格式为 Properties 的一个配置项:
Figure 2. Nacos Config Item
具体启动方式参考 Spring Cloud Alibaba Nacos Discovery 小节的 “Nacos Server 启动” 章节。
Nacos Server 启动完毕后,添加如何配置:
Data ID: nacos-config.properties Group : DEFAULT_GROUP 配置格式: Properties 配置内容: user.name=nacos-config-properties user.age=90
NOTE | 注意DataId是以 properties(默认的文件扩展名方式)为扩展名。 |
---|---|
如果要在您的项目中使用 Nacos 来实现应用的外部化配置,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alibaba-nacos-config 的 starter。
com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config
现在创建一个标准的 Spring Boot 应用。
@SpringBootApplication public class NacosConfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigApplication.class, args); String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); System.err.println("user name :"+userName+"; age: "+userAge); } }
NOTE | 注意当您spring-cloud-alibaba的版本为 ```2021.1时,由于nacos获取配置时bootstrap.yml 文件将先于application.yml文件加载. 根据spring的官方文档中提及 [bootstrap]( |
---|---|
org.springframework.cloud spring-cloud-starter-bootstrap 3.1.1
在运行此 NacosConfigApplication 之前, 必须使用 bootstrap.properties 配置文件来配置 Nacos Server 地址,例如:
bootstrap.properties
# DataId 默认使用 `spring.application.name` 配置跟文件扩展名结合(配置格式默认使用 properties), GROUP 不配置默认使用 DEFAULT_GROUP。因此该配置文件对应的 Nacos Config 配置的 DataId 为 nacos-config.properties, GROUP 为 DEFAULT_GROUP spring.application.name=nacos-config spring.cloud.nacos.config.server-addr=127.0.0.1:8848
NOTE | 注意当你使用域名的方式来访问 Nacos 时,spring.cloud.nacos.config.server-addr 配置的方式为 域名:port。 例如 Nacos 的域名为abc.com.nacos,监听的端口为 80,则 spring.cloud.nacos.config.server-addr=abc.com.nacos:80。 注意 80 端口不能省略。 |
---|---|
启动这个 Example,可以看到如下输出结果:
2018-11-02 14:24:51.638 INFO 32700 --- [main] c.a.demo.provider.ConfigApplication : Started ConfigApplication in 14.645 seconds (JVM running for 15.139) user name :nacos-config-properties; age: 90 2018-11-02 14:24:51.688 INFO 32700 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a8c5e74: startup date [Fri Nov 02 14:24:51 CST 2018]; root of context hierarchy
Nacos Config 除了支持 properties 格式以外,也支持 yaml 格式。这个时候只需要完成以下两步:
1、在应用的 bootstrap.properties 配置文件中显示的声明 DataId 文件扩展名。如下所示
bootstrap.properties
spring.cloud.nacos.config.file-extension=yaml
2、在 Nacos 的控制台新增一个DataId为yaml为扩展名的配置,如下所示:
Data ID: nacos-config.yaml Group : DEFAULT_GROUP 配置格式: YAML 配置内容: user.name: nacos-config-yaml user.age: 68
这两步完成后,重启测试程序,可以看到如下输出结果。
2018-11-02 14:59:00.484 INFO 32928 --- [main] c.a.demo.provider.ConfigApplication:Started ConfigApplication in 14.183 seconds (JVM running for 14.671) user name :nacos-config-yaml; age: 68 2018-11-02 14:59:00.529 INFO 32928 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@265a478e: startup date [Fri Nov 02 14:59:00 CST 2018]; root of context hierarchy
Nacos Config 默认支持配置的动态更新,启动 Spring Boot 应用测试的代码如下:
@SpringBootApplication public class ConfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigApplication.class, args); while(true) { //当动态配置刷新时,会更新到 Enviroment中,因此这里每隔一秒中从Enviroment中获取配置 String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); System.err.println("user name :" + userName + "; age: " + userAge); TimeUnit.SECONDS.sleep(1); } } }
如下所示,当变更user.name时,应用程序中能够获取到最新的值:
user name :nacos-config-yaml; age: 68 user name :nacos-config-yaml; age: 68 user name :nacos-config-yaml; age: 68 2018-11-02 15:04:25.069 INFO 32957 --- [-127.0.0.1:8848] o.s.boot.SpringApplication : Started application in 0.144 seconds (JVM running for 71.752) 2018-11-02 15:04:25.070 INFO 32957 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@10c89124: startup date [Fri Nov 02 15:04:25 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6520af7 2018-11-02 15:04:25.071 INFO 32957 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6520af7: startup date [Fri Nov 02 15:04:24 CST 2018]; root of context hierarchy //从 Enviroment 中 读取到更改后的值 user name :nacos-config-yaml-update; age: 68 user name :nacos-config-yaml-update; age: 68
NOTE | 你可以通过配置 spring.cloud.nacos.config.refresh.enabled=false 来关闭动态刷新 |
---|---|
Nacos Config 在加载配置的时候,不仅仅加载了以 DataId 为 ${spring.application.name}.${file-extension:properties} 为前缀的基础配置,还加载了DataId为 ${spring.application.name}-${profile}.${file-extension:properties} 的基础配置。在日常开发中如果遇到多套环境下的不同配置,可以通过Spring 提供的 ${spring.profiles.active} 这个配置项来配置。
spring.profiles.active=develop
NOTE | ${spring.profiles.active} 当通过配置文件来指定时必须放在 bootstrap.properties 文件中。 |
---|---|
Nacos 上新增一个DataId为:nacos-config-develop.yaml的基础配置,如下所示:
Data ID: nacos-config-develop.yaml Group : DEFAULT_GROUP 配置格式: YAML 配置内容: current.env: develop-env
启动 Spring Boot 应用测试的代码如下:
@SpringBootApplication public class ConfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigApplication.class, args); while(true) { String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); //获取当前部署的环境 String currentEnv = applicationContext.getEnvironment().getProperty("current.env"); System.err.println("in "+currentEnv+" enviroment; "+"user name :" + userName + "; age: " + userAge); TimeUnit.SECONDS.sleep(1); } } }
启动后,可见控制台的输出结果:
in develop-env enviroment; user name :nacos-config-yaml-update; age: 68 2018-11-02 15:34:25.013 INFO 33014 --- [ Thread-11] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6f1c29b7: startup date [Fri Nov 02 15:33:57 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@63355449
如果需要切换到生产环境,只需要更改 ${spring.profiles.active} 参数配置即可。如下所示:
spring.profiles.active=product
同时生产环境上 Nacos 需要添加对应 DataId 的基础配置。例如,在生产环境下的 Naocs 添加了DataId为:nacos-config-product.yaml的配置:
Data ID: nacos-config-product.yaml Group : DEFAULT_GROUP 配置格式: YAML 配置内容: current.env: product-env
启动测试程序,输出结果如下:
in product-env enviroment; user name :nacos-config-yaml-update; age: 68 2018-11-02 15:42:14.628 INFO 33024 --- [Thread-11] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6aa8e115: startup date [Fri Nov 02 15:42:03 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@19bb07ed
NOTE | 此案例中我们通过 spring.profiles.active= |
---|---|
Nacos 内部有 Namespace 的概念:
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
在没有明确指定 ${spring.cloud.nacos.config.namespace} 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespace。如果需要使用自定义的命名空间,可以通过以下配置来实现:
spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7
NOTE | 该配置必须放在 bootstrap.properties 文件中。此外 spring.cloud.nacos.config.namespace 的值是 namespace 对应的 id,id 值可以在 Nacos 的控制台获取。并且在添加配置时注意不要选择其他的 namespae,否则将会导致读取不到正确的配置。 |
---|---|
在没有明确指定 ${spring.cloud.nacos.config.group} 配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现:
spring.cloud.nacos.config.group=DEVELOP_GROUP
NOTE | 该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值一定要和 spring.cloud.nacos.config.group 的配置值一致。 |
---|---|
Nacos Config 从 0.2.1 版本后,可支持自定义 Data Id 的配置。关于这部分详细的设计可参考 这里。 一个完整的配置案例如下所示:
spring.application.name=opensource-service-provider spring.cloud.nacos.config.server-addr=127.0.0.1:8848 # config external configuration # 1、Data Id 在默认的组 DEFAULT_GROUP,不支持配置的动态刷新 spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties # 2、Data Id 不在默认的组,不支持动态刷新 spring.cloud.nacos.config.ext-config[1].data-id=ext-config-common02.properties spring.cloud.nacos.config.ext-config[1].group=GLOBALE_GROUP # 3、Data Id 既不在默认的组,也支持动态刷新 spring.cloud.nacos.config.ext-config[2].data-id=ext-config-common03.properties spring.cloud.nacos.config.ext-config[2].group=REFRESH_GROUP spring.cloud.nacos.config.ext-config[2].refresh=true
可以看到:
NOTE | 多个 Data Id 同时配置时,他的优先级关系是 spring.cloud.nacos.config.ext-config[n].data-id 其中 n 的值越大,优先级越高。 |
---|---|
NOTE | spring.cloud.nacos.config.ext-config[n].data-id 的值必须带文件扩展名,文件扩展名既可支持 properties,又可以支持 yaml/yml。 此时 spring.cloud.nacos.config.file-extension 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。 |
---|---|
通过自定义扩展的 Data Id 配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件。
为了更加清晰的在多个应用间配置共享的 Data Id ,你可以通过以下的方式来配置:
spring.cloud.nacos.config.shared-dataids=bootstrap-common.properties,all-common.properties spring.cloud.nacos.config.refreshable-dataids=bootstrap-common.properties
可以看到:
NOTE | 通过 spring.cloud.nacos.config.shared-dataids 来支持多个共享配置的 Data Id 时, 多个共享配置间的一个优先级的关系我们约定:按照配置出现的先后顺序,即后面的优先级要高于前面。 |
---|---|
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 的值也必须明确给出文件扩展名。 |
---|---|
Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置
当三种方式共同使用时,他们的一个优先级关系是: A < B < C
Nacos Config 内部提供了一个 Endpoint, 对应的 endpoint id 为 nacos-config。
Endpoint 暴露的 json 中包含了三种属性:
这是 Endpoint 暴露的 json 示例:
{ "NacosConfigProperties": { "serverAddr": "127.0.0.1:8848", "encode": null, "group": "DEFAULT_GROUP", "prefix": null, "fileExtension": "properties", "timeout": 3000, "endpoint": null, "namespace": null, "accessKey": null, "secretKey": null, "contextPath": null, "clusterName": null, "name": null, "sharedDataids": "base-common.properties,common.properties", "refreshableDataids": "common.properties", "extConfig": null }, "RefreshHistory": [{ "timestamp": "2019-07-29 11:20:04", "dataId": "nacos-config-example.properties", "md5": "7d5d7f1051ff6571e2ec9f90887d9d91" }], "Sources": [{ "lastSynced": "2019-07-29 11:19:04", "dataId": "common.properties" }, { "lastSynced": "2019-07-29 11:19:04", "dataId": "base-common.properties" }, { "lastSynced": "2019-07-29 11:19:04", "dataId": "nacos-config-example.properties" }] }
通过设置 spring.cloud.nacos.config.enabled = false 来完全关闭 Spring Cloud Nacos Config
更多关于 Nacos Config Starter 的配置项如下所示:
配置项 | Key | 默认值 | 说明 |
---|---|---|---|
服务端地址 | spring.cloud.nacos.config.server-addr | Nacos Server 启动监听的ip地址和端口 | |
配置对应的 DataId | spring.cloud.nacos.config.name | 先取 prefix,再取 name,最后取 spring.application.name | |
配置对应的 DataId | spring.cloud.nacos.config.prefix | 先取 prefix,再取 name,最后取 spring.application.name | |
配置内容编码 | spring.cloud.nacos.config.encode | 读取的配置内容对应的编码 | |
GROUP | spring.cloud.nacos.config.group | DEFAULT_GROUP | 配置对应的组 |
文件扩展名 | spring.cloud.nacos.config.fileExtension | properties | 配置项对应的文件扩展名,目前支持 properties 和 yaml(yml) |
获取配置超时时间 | spring.cloud.nacos.config.timeout | 3000 | 客户端获取配置的超时时间(毫秒) |
接入点 | spring.cloud.nacos.config.endpoint | 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 | |
命名空间 | spring.cloud.nacos.config.namespace | 常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等 | |
AccessKey | spring.cloud.nacos.config.accessKey | 当要上阿里云时,阿里云上面的一个云账号名 | |
SecretKey | spring.cloud.nacos.config.secretKey | 当要上阿里云时,阿里云上面的一个云账号密码 | |
Nacos Server 对应的 context path | spring.cloud.nacos.config.contextPath | Nacos Server 对外暴露的 context path | |
集群 | spring.cloud.nacos.config.clusterName | 配置成Nacos集群名称 | |
共享配置 | spring.cloud.nacos.config.sharedDataids | 共享配置的 DataId, “,” 分割 | |
共享配置动态刷新 | spring.cloud.nacos.config.refreshableDataids | 共享配置中需要动态刷新的 DataId, “,” 分割 | |
自定义 Data Id 配置 | spring.cloud.nacos.config.extConfig | 属性是个集合,内部由 Config POJO 组成。Config 有 3 个属性,分别是 dataId, group 以及 refresh |
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
如果要在您的项目中引入 Sentinel,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alibaba-sentinel 的 starter。
[source,yaml]com.alibaba.cloud spring-cloud-starter-alibaba-sentinel
下面这个例子就是一个最简单的使用 Sentinel 的例子:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(ServiceApplication.class, args); } } @RestController public class TestController { @GetMapping(value = "/hello") @SentinelResource("hello") public String hello() { return "Hello Sentinel"; } }
@SentinelResource 注解用来标识资源是否被限流、降级。上述例子上该注解的属性 ‘hello’ 表示资源名。
@SentinelResource 还提供了其它额外的属性如 blockHandler,blockHandlerClass,fallback 用于表示限流或降级的操作,更多内容可以参考 Sentinel注解支持。
以上例子都是在 WebServlet 环境下使用的,Sentinel 目前已经支持 WebFlux,需要配合 spring-boot-starter-webflux 依赖触发 sentinel-starter 中 WebFlux 相关的自动化配置。
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(ServiceApplication.class, args); } } @RestController public class TestController { @GetMapping("/mono") @SentinelResource("hello") public Monomono() { return Mono.just("simple string") .transform(new SentinelReactorTransformer<>("otherResourceName")); } }
Sentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。您只需要对应用进行简单的配置,就可以使用这些功能。
注意: 集群资源汇总仅支持 500 台以下的应用集群,有大概 1 - 2 秒的延时。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AS5GYbTX-1687339692240)(null)]
Figure 3. Sentinel Dashboard
开启该功能需要3个步骤:
您可以从 release 页面 下载最新版本的控制台 jar 包。
您也可以从最新版本的源码自行构建 Sentinel 控制台:
Sentinel 控制台是一个标准的 SpringBoot 应用,以 SpringBoot 的方式运行 jar 包即可。
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
如若8080端口冲突,可使用 -Dserver.port=新端口 进行设置。
application.yml
spring: cloud: sentinel: transport: port: 8719 dashboard: localhost:8080
这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
更多 Sentinel 控制台的使用及问题参考: Sentinel控制台
Sentinel 适配了 OpenFeign 组件。如果想使用,除了引入 sentinel-starter 的依赖外还需要 2 个步骤:
org.springframework.cloud spring-cloud-starter-openfeign
这是一个 FeignClient 的简单使用示例:
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class) public interface EchoService { @GetMapping(value = "/echo/{str}") String echo(@PathVariable("str") String str); } class FeignConfiguration { @Bean public EchoServiceFallback echoServiceFallback() { return new EchoServiceFallback(); } } class EchoServiceFallback implements EchoService { @Override public String echo(@PathVariable("str") String str) { return "echo fallback"; } }
NOTE | Feign 对应的接口中的资源名策略定义:httpmethod:protocol://requesturl。@FeignClient 注解中的所有属性,Sentinel 都做了兼容。 |
---|---|
EchoService 接口中方法 echo 对应的资源名为 GET:http://service-provider/echo/{str}。
Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造 RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。
@Bean @SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class) public RestTemplate restTemplate() { return new RestTemplate(); }
@SentinelRestTemplate 注解的属性支持限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)的处理。
其中 blockHandler 或 fallback 属性对应的方法必须是对应 blockHandlerClass 或 fallbackClass 属性中的静态方法。
该方法的参数跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中参数多出了一个 BlockException 参数用于获取 Sentinel 捕获的异常。
比如上述 @SentinelRestTemplate 注解中 ExceptionUtil 的 handleException 属性对应的方法声明如下:
public class ExceptionUtil { public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) { ... } }
NOTE | 应用启动的时候会检查 @SentinelRestTemplate 注解对应的限流或降级方法是否存在,如不存在会抛出异常 |
---|---|
@SentinelRestTemplate 注解的限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)属性不强制填写。
当使用 RestTemplate 调用被 Sentinel 熔断后,会返回 RestTemplate request block by sentinel 信息,或者也可以编写对应的方法自行处理返回信息。这里提供了 SentinelClientHttpResponse 用于构造返回信息。
Sentinel RestTemplate 限流的资源规则提供两种粒度:
NOTE | 以 https://www.taobao.com/test 这个 url 并使用 GET 方法为例。对应的资源名有两种粒度,分别是 GET:https://www.taobao.com 以及 GET:https://www.taobao.com/test |
---|---|
SentinelProperties 内部提供了 TreeMap 类型的 datasource 属性用于配置数据源信息。
比如配置 4 个数据源:
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json spring.cloud.sentinel.datasource.ds1.file.rule-type=flow #spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json #spring.cloud.sentinel.datasource.ds1.file.data-type=custom #spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter #spring.cloud.sentinel.datasource.ds1.file.rule-type=flow spring.cloud.sentinel.datasource.ds2.nacos.server-addr=127.0.0.1:8848 spring.cloud.sentinel.datasource.ds2.nacos.data-id=sentinel spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP spring.cloud.sentinel.datasource.ds2.nacos.data-type=json spring.cloud.sentinel.datasource.ds2.nacos.rule-type=degrade spring.cloud.sentinel.datasource.ds3.zk.path = /Sentinel-Demo/SYSTEM-CODE-DEMO-FLOW spring.cloud.sentinel.datasource.ds3.zk.server-addr = localhost:2181 spring.cloud.sentinel.datasource.ds3.zk.rule-type=authority spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test spring.cloud.sentinel.datasource.ds4.apollo.rule-type=param-flow
这种配置方式参考了 Spring Cloud Stream Binder 的配置,内部使用了 TreeMap 进行存储,comparator 为 String.CASE_INSENSITIVE_ORDER 。
NOTE | d1, ds2, ds3, ds4 是 ReadableDataSource 的名字,可随意编写。后面的 file ,zk ,nacos , apollo 就是对应具体的数据源。 它们后面的配置就是这些具体数据源各自的配置。 |
---|---|
每种数据源都有两个共同的配置项: data-type、 converter-class 以及 rule-type。
data-type 配置项表示 Converter 类型,Spring Cloud Alibaba Sentinel 默认提供两种内置的值,分别是 json 和 xml (不填默认是json)。 如果不想使用内置的 json 或 xml 这两种 Converter,可以填写 custom 表示自定义 Converter,然后再配置 converter-class 配置项,该配置项需要写类的全路径名(比如 spring.cloud.sentinel.datasource.ds1.file.converter-class=org.springframework.cloud.alibaba.cloud.examples.JsonFlowRuleListConverter)。
rule-type 配置表示该数据源中的规则属于哪种类型的规则(flow,degrade,authority,system, param-flow, gw-flow, gw-api-group)。
NOTE | 当某个数据源规则信息加载失败的情况下,不会影响应用的启动,会在日志中打印出错误信息。 |
---|---|
NOTE | 默认情况下,xml 格式是不支持的。需要添加 jackson-dataformat-xml 依赖后才会自动生效。 |
---|---|
关于 Sentinel 动态数据源的实现原理,参考: 动态规则扩展
参考 Sentinel 网关限流
若想跟 Sentinel Starter 配合使用,需要加上 spring-cloud-alibaba-sentinel-gateway 依赖,同时需要添加 spring-cloud-starter-gateway 依赖来让 spring-cloud-alibaba-sentinel-gateway 模块里的 Spring Cloud Gateway 自动化配置类生效:
com.alibaba.cloud spring-cloud-starter-alibaba-sentinel com.alibaba.cloud spring-cloud-alibaba-sentinel-gateway org.springframework.cloud spring-cloud-starter-gateway
Sentinel 内部提供了一个 Endpoint, 对应的 endpoint id 为 sentinel。
Endpoint 暴露的 json 中包含了多种属性:
这是 Endpoint 暴露的 json 示例:
{ "blockPage": null, "appName": "sentinel-example", "consoleServer": "localhost:8080", "coldFactor": "3", "rules": { "flowRules": [{ "resource": "GET:http://www.taobao.com", "limitApp": "default", "grade": 1, "count": 0.0, "strategy": 0, "refResource": null, "controlBehavior": 0, "warmUpPeriodSec": 10, "maxQueueingTimeMs": 500, "clusterMode": false, "clusterConfig": null }, { "resource": "/test", "limitApp": "default", "grade": 1, "count": 0.0, "strategy": 0, "refResource": null, "controlBehavior": 0, "warmUpPeriodSec": 10, "maxQueueingTimeMs": 500, "clusterMode": false, "clusterConfig": null }, { "resource": "/hello", "limitApp": "default", "grade": 1, "count": 1.0, "strategy": 0, "refResource": null, "controlBehavior": 0, "warmUpPeriodSec": 10, "maxQueueingTimeMs": 500, "clusterMode": false, "clusterConfig": null }] }, "metricsFileCharset": "UTF-8", "filter": { "order": -2147483648, "urlPatterns": ["/*"], "enabled": true }, "totalMetricsFileCount": 6, "datasource": { "ds1": { "file": { "dataType": "json", "ruleType": "FLOW", "converterClass": null, "file": "...", "charset": "utf-8", "recommendRefreshMs": 3000, "bufSize": 1048576 }, "nacos": null, "zk": null, "apollo": null, "redis": null } }, "clientIp": "30.5.121.91", "clientPort": "8719", "logUsePid": false, "metricsFileSize": 52428800, "logDir": "...", "heartbeatIntervalMs": 10000 }
下表显示当应用的 ApplicationContext 中存在对应的Bean的类型时,会进行自动化设置:
存在Bean的类型 | 操作 | 作用 |
---|---|---|
UrlCleaner | WebCallbackManager.setUrlCleaner(urlCleaner) | 资源清理(资源(比如将满足 /foo/:id 的 URL 都归到 /foo/* 资源下)) |
UrlBlockHandler | WebCallbackManager.setUrlBlockHandler(urlBlockHandler) | 自定义限流处理逻辑 |
RequestOriginParser | WebCallbackManager.setRequestOriginParser(requestOriginParser) | 设置来源信息 |
Spring Cloud Alibaba Sentinel 提供了这些配置选项
配置项 | 含义 | 默认值 |
---|---|---|
spring.application.name or project.name | Sentinel项目名 | |
spring.cloud.sentinel.enabled | Sentinel自动化配置是否生效 | true |
spring.cloud.sentinel.eager | 是否提前触发 Sentinel 初始化 | false |
spring.cloud.sentinel.transport.port | 应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer | 8719 |
spring.cloud.sentinel.transport.dashboard | Sentinel 控制台地址 | |
spring.cloud.sentinel.transport.heartbeat-interval-ms | 应用与Sentinel控制台的心跳间隔时间 | |
spring.cloud.sentinel.transport.client-ip | 此配置的客户端IP将被注册到 Sentinel Server 端 | |
spring.cloud.sentinel.filter.order | Servlet Filter的加载顺序。Starter内部会构造这个filter | Integer.MIN_VALUE |
spring.cloud.sentinel.filter.url-patterns | 数据类型是数组。表示Servlet Filter的url pattern集合 | /* |
spring.cloud.sentinel.filter.enabled | Enable to instance CommonFilter | true |
spring.cloud.sentinel.metric.charset | metric文件字符集 | UTF-8 |
spring.cloud.sentinel.metric.file-single-size | Sentinel metric 单个文件的大小 | |
spring.cloud.sentinel.metric.file-total-count | Sentinel metric 总文件数量 | |
spring.cloud.sentinel.log.dir | Sentinel 日志文件所在的目录 | |
spring.cloud.sentinel.log.switch-pid | Sentinel 日志文件名是否需要带上pid | false |
spring.cloud.sentinel.servlet.block-page | 自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL | |
spring.cloud.sentinel.flow.cold-factor | https://github.com/alibaba/Sentinel/wiki/限流--- %E5%86%B7%E5%90%AF%E5%8A%A8[冷启动因子] | 3 |
spring.cloud.sentinel.scg.fallback.mode | Spring Cloud Gateway 熔断后的响应模式(选择 redirect or response) | |
spring.cloud.sentinel.scg.fallback.redirect | Spring Cloud Gateway 响应模式为 ‘redirect’ 模式对应的重定向 URL | |
spring.cloud.sentinel.scg.fallback.response-body | Spring Cloud Gateway 响应模式为 ‘response’ 模式对应的响应内容 | |
spring.cloud.sentinel.scg.fallback.response-status | Spring Cloud Gateway 响应模式为 ‘response’ 模式对应的响应码 | 429 |
spring.cloud.sentinel.scg.fallback.content-type | Spring Cloud Gateway 响应模式为 ‘response’ 模式对应的 content-type | application/json |
NOTE | 请注意。这些配置只有在 Servlet 环境下才会生效,RestTemplate 和 Feign 针对这些配置都无法生效 |
---|---|
RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
具有以下特点:
下载 RocketMQ最新的二进制文件,并解压
解压后的目录结构如下:
apache-rocketmq ├── LICENSE ├── NOTICE ├── README.md ├── benchmark ├── bin ├── conf └── lib
nohup sh bin/mqnamesrv & tail -f ~/logs/rocketmqlogs/namesrv.log
nohup sh bin/mqbroker -n localhost:9876 & tail -f ~/logs/rocketmqlogs/broker.log
发送消息:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
发送成功后显示:SendResult [sendStatus=SEND_OK, msgId= …
接收消息:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
接收成功后显示:ConsumeMessageThread_%d Receive New Messages: [MessageExt…
sh bin/mqshutdown broker sh bin/mqshutdown namesrv
Spring Cloud Stream 是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot 来创建具有生产级别的单机 Spring 应用,并且使用 Spring Integration 与 Broker 进行连接。
Spring Cloud Stream 提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。
Spring Cloud Stream 内部有两个概念:Binder 和 Binding。
比如 Kafka 的实现 KafkaMessageChannelBinder,RabbitMQ 的实现 RabbitMessageChannelBinder 以及 RocketMQ 的实现 RocketMQMessageChannelBinder。
Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁,实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0K0X9JD-1687339681776)(null)]
Figure 4. Spring Cloud Stream
使用 Spring Cloud Stream 完成一段简单的消息发送和消息接收代码:
MessageChannel messageChannel = new DirectChannel(); // 消息订阅 ((SubscribableChannel) messageChannel).subscribe(new MessageHandler() { @Override public void handleMessage(Message> message) throws MessagingException { System.out.println("receive msg: " + message.getPayload()); } }); // 消息发送 messageChannel.send(MessageBuilder.withPayload("simple msg").build());
这段代码所有的消息类都是 spring-messaging 模块里提供的。屏蔽具体消息中间件的底层实现,如果想用更换消息中间件,在配置文件里配置相关消息中间件信息以及修改 binder 依赖即可。
Spring Cloud Stream 底层基于这段代码去做了各种抽象。
如果要在您的项目中引入 RocketMQ Binder,需要引入如下 maven 依赖:
xncom.alibaba.cloud spring-cloud-stream-binder-rocketmq
或者可以使用 Spring Cloud Stream RocketMQ Starter:
com.alibaba.cloud spring-cloud-starter-stream-rocketmq
这是 Spring Cloud Stream RocketMQ Binder 的实现架构:
Figure 5. SCS RocketMQ Binder
RocketMQ Binder 的重构优化去除了对 RocketMQ-Spring框架的依赖 。 RocketMQ Binder 核心类 RocketMQMessageChannelBinder 实现了 Spring Cloud Stream 规范,内部会构建 RocketMQInboundChannelAdapter 和 RocketMQProducerMessageHandler。
RocketMQProducerMessageHandler 会基于 Binding 配置通过 RocketMQProduceFactory构造 RocketMQ Producer,其内部会把 spring-messaging 模块内 org.springframework.messaging.Message 消息类转换成 RocketMQ 的消息类 org.apache.rocketmq.common.message.Message,然后发送出去。
RocketMQInboundChannelAdapter 也会基于 Binding 配置通过 RocketMQConsumerFactory构造 DefaultMQPushConsumer,其内部会启动 RocketMQ Consumer 接收消息。
NOTE | 与 RocketMQ-Spring 框架的兼容需要手动处理 |
---|---|
目前 Binder 支持在 Header 中设置相关的 key 来进行 RocketMQ Message 消息的特性设置。
比如 TAGS、KEYS、TRANSACTIONAL_ARGS 等 RocketMQ 消息对应的标签,详情见 com.alibaba.cloud.stream.binder.rocketmq.constant.RocketMQConst
MessageBuilder builder = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, "binder") .setHeader(RocketMQHeaders.KEYS, "my-key"); Message message = builder.build(); output().send(message);
或者使用StreamBridge
MessageBuilder builder = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, "binder") .setHeader(RocketMQHeaders.KEYS, "my-key"); Message message = builder.build(); streamBridge.send("producer-out-0", message);
NOTE | 更多使用请参考样例: RocketMQ Example |
---|---|
spring.cloud.stream.rocketmq.binder.name-server
RocketMQ NameServer 地址(老版本使用 namesrv-addr 配置项)。Default: 127.0.0.1:9876.
spring.cloud.stream.rocketmq.binder.access-key
阿里云账号 AccessKey。Default: null.
spring.cloud.stream.rocketmq.binder.secret-key
阿里云账号 SecretKey。Default: null.
spring.cloud.stream.rocketmq.binder.enable-msg-trace
是否为 Producer 和 Consumer 开启消息轨迹功能Default: true.
spring.cloud.stream.rocketmq.binder.customized-trace-topic
消息轨迹开启后存储的 topic 名称。Default: RMQ_SYS_TRACE_TOPIC.
下面的这些配置是以 spring.cloud.stream.rocketmq.bindings.
enable
是否启用 Consumer。默认值: true.
subscription
Consumer 基于 TAGS 订阅,多个 tag 以 || 分割。更多见 com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties.subscription默认值: empty.
messageModel
Consumer 消费模式。如果想让每一个的订阅者都能接收到消息,可以使用广播模式。更多见 org.apache.rocketmq.common.protocol.heartbeat.MessageModel默认值: CLUSTERING.
consumeFromWhere
Consumer 从哪里开始消费。更多见 org.apache.rocketmq.common.consumer.ConsumeFromWhere默认值: CONSUME_FROM_LAST_OFFSET.
下面的这些配置是 Consumer Push 模式相关的配置。 spring.cloud.stream.rocketmq.bindings.
orderly
是否同步消费消息模式默认值: false.
delayLevelWhenNextConsume
异步消费消息模式下消费失败重试策略:-1,不重复,直接放入死信队列0,broker 控制重试策略>0,client 控制重试策略默认值: 0.
suspendCurrentQueueTimeMillis
同步消费消息模式下消费失败后再次消费的时间间隔。默认值: 1000.
其他更多参数见 com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties.Push
下面的这些配置是 Consumer Pull 模式相关的配置。 spring.cloud.stream.rocketmq.bindings.
pullThreadNums
消费时拉取的线程数默认值: 20.
pollTimeoutMillis
拉取时的超时毫秒数默认值: 1000 * 5.
其他更多参数见 com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties.Pull.
NOTE | 更多参数见 com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQConsumerProperties |
---|---|
下面的这些配置是以 spring.cloud.stream.rocketmq.bindings.
enable
是否启用 Producer。默认值: true.
group
Producer group name。默认值: empty.
maxMessageSize
消息发送的最大字节数。默认值: 8249344.
producerType
消息生产者类型,普通或者事务。更多见 com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties.ProducerType.默认值: Normal.
transactionListener
事务消息监听器的beanName,在 producerType=Trans 时才有效;必须是实现 org.apache.rocketmq.client.producer.TransactionListener 接口的Spring Bean。
sendType
消息发送类型(同步、异步、单向)。更多见com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties.SendType.默认值: Sync.
sendCallBack
消息发送后回调函数的beanName,在 sendType=Async 时才有效;必须是实现 org.apache.rocketmq.client.producer.SendCallback 接口的Spring Bean。
vipChannelEnabled
是否在 Vip Channel 上发送消息。默认值: true.
sendMessageTimeout
发送消息的超时时间(毫秒)。默认值: 3000.
compressMessageBodyThreshold
消息体压缩阀值(当消息体超过 4k 的时候会被压缩)。默认值: 4096.
retryTimesWhenSendFailed
在同步发送消息的模式下,消息发送失败的重试次数。默认值: 2.
retryTimesWhenSendAsyncFailed
在异步发送消息的模式下,消息发送失败的重试次数。默认值: 2.
retryAnotherBroker
消息发送失败的情况下是否重试其它的 broker。默认值: false.
NOTE | 生产者其他更多参数请见: com.alibaba.cloud.stream.binder.rocketmq.properties.RocketMQProducerProperties |
---|---|
使用阿里云 MQ 服务需要配置 AccessKey、SecretKey 以及云上的 NameServer 地址。
NOTE | 0.1.2 & 0.2.2 & 0.9.0 才支持该功能 |
---|---|
spring.cloud.stream.rocketmq.binder.access-key=YourAccessKey spring.cloud.stream.rocketmq.binder.secret-key=YourSecretKey spring.cloud.stream.rocketmq.binder.name-server=NameServerInMQ
NOTE | topic 和 group 请以 实例id% 为前缀进行配置。比如 topic 为 “test”,需要配置成 “实例id%test” .NameServer 的获取(配置中请去掉 http:// 前缀) |
---|---|
RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。
具有以下特点:
下载 RocketMQ最新的二进制文件,并解压
解压后的目录结构如下:
apache-rocketmq ├── LICENSE ├── NOTICE ├── README.md ├── benchmark ├── bin ├── conf └── lib
nohup sh bin/mqnamesrv & tail -f ~/logs/rocketmqlogs/namesrv.log
nohup sh bin/mqbroker -n localhost:9876 & tail -f ~/logs/rocketmqlogs/broker.log
发送消息:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
发送成功后显示:SendResult [sendStatus=SEND_OK, msgId= …
接收消息:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
接收成功后显示:ConsumeMessageThread_%d Receive New Messages: [MessageExt…
sh bin/mqshutdown broker sh bin/mqshutdown namesrv
Spring Cloud Stream 是一个用于构建基于消息的微服务应用框架。它基于 SpringBoot 来创建具有生产级别的单机 Spring 应用,并且使用 Spring Integration 与 Broker 进行连接。
Spring Cloud Stream 提供了消息中间件配置的统一抽象,推出了 publish-subscribe、consumer groups、partition 这些统一的概念。
Spring Cloud Stream 内部有两个概念:Binder 和 Binding。
比如 Kafka 的实现 KafkaMessageChannelBinder,RabbitMQ 的实现 RabbitMessageChannelBinder 以及 RocketMQ 的实现 RocketMQMessageChannelBinder。
Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁,实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可,屏蔽了开发者与底层消息中间件的接触。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6WgoEyss-1687339681449)(null)]
Figure 6. Spring Cloud Stream
使用 Spring Cloud Stream 完成一段简单的消息发送和消息接收代码:
MessageChannel messageChannel = new DirectChannel(); // 消息订阅 ((SubscribableChannel) messageChannel).subscribe(new MessageHandler() { @Override public void handleMessage(Message> message) throws MessagingException { System.out.println("receive msg: " + message.getPayload()); } }); // 消息发送 messageChannel.send(MessageBuilder.withPayload("simple msg").build());
这段代码所有的消息类都是 spring-messaging 模块里提供的。屏蔽具体消息中间件的底层实现,如果想用更换消息中间件,在配置文件里配置相关消息中间件信息以及修改 binder 依赖即可。
Spring Cloud Stream 底层基于这段代码去做了各种抽象。
如果要在您的项目中引入 RocketMQ Binder,需要引入如下 maven 依赖:
com.alibaba.cloud spring-cloud-stream-binder-rocketmq
或者可以使用 Spring Cloud Stream RocketMQ Starter:
com.alibaba.cloud spring-cloud-starter-stream-rocketmq
这是 Spring Cloud Stream RocketMQ Binder 的实现架构:
Figure 7. SCS RocketMQ Binder
RocketMQ Binder 的实现依赖于 RocketMQ-Spring 框架。
RocketMQ-Spring 框架是 RocketMQ 与 Spring Boot 的整合,RocketMQ Spring 主要提供了 3 个特性:
RocketMQ Binder 的核心类 RocketMQMessageChannelBinder 实现了 Spring Cloud Stream 规范,内部构建会 RocketMQInboundChannelAdapter 和 RocketMQMessageHandler。
RocketMQMessageHandler 会基于 Binding 配置构造 RocketMQTemplate,RocketMQTemplate 内部会把 spring-messaging 模块内 org.springframework.messaging.Message 消息类转换成 RocketMQ 的消息类 org.apache.rocketmq.common.message.Message,然后发送出去。
RocketMQInboundChannelAdapter 也会基于 Binding 配置构造 RocketMQListenerBindingContainer,RocketMQListenerBindingContainer 内部会启动 RocketMQ Consumer 接收消息。
NOTE | 在使用 RocketMQ Binder 的同时也可以配置 rocketmq.** 用于触发 RocketMQ Spring 相关的 AutoConfiguration |
---|---|
目前 Binder 支持在 Header 中设置相关的 key 来进行 RocketMQ Message 消息的特性设置。
比如 TAGS、DELAY、TRANSACTIONAL_ARG、KEYS、WAIT_STORE_MSG_OK、FLAG 表示 RocketMQ 消息对应的标签,
MessageBuilder builder = MessageBuilder.withPayload(msg) .setHeader(RocketMQHeaders.TAGS, "binder") .setHeader(RocketMQHeaders.KEYS, "my-key") .setHeader(MessageConst.PROPERTY_DELAY_TIME_LEVEL, "1"); Message message = builder.build(); output().send(message);
SCS RocketMQ Binder 支持 MessageSource,可以进行消息的拉取,例子如下:
@SpringBootApplication @EnableBinding(MQApplication.PolledProcessor.class) public class MQApplication { private final Logger logger = LoggerFactory.getLogger(MQApplication.class); public static void main(String[] args) { SpringApplication.run(MQApplication.class, args); } @Bean public ApplicationRunner runner(PollableMessageSource source, MessageChannel dest) { return args -> { while (true) { boolean result = source.poll(m -> { String payload = (String) m.getPayload(); logger.info("Received: " + payload); dest.send(MessageBuilder.withPayload(payload.toUpperCase()) .copyHeaders(m.getHeaders()) .build()); }, new ParameterizedTypeReference() { }); if (result) { logger.info("Processed a message"); } else { logger.info("Nothing to do"); } Thread.sleep(5_000); } }; } public static interface PolledProcessor { @Input PollableMessageSource source(); @Output MessageChannel dest(); } }
spring.cloud.stream.rocketmq.binder.name-server
RocketMQ NameServer 地址(老版本使用 namesrv-addr 配置项)。Default: 127.0.0.1:9876.
spring.cloud.stream.rocketmq.binder.access-key
阿里云账号 AccessKey。Default: null.
spring.cloud.stream.rocketmq.binder.secret-key
阿里云账号 SecretKey。Default: null.
spring.cloud.stream.rocketmq.binder.enable-msg-trace
是否为 Producer 和 Consumer 开启消息轨迹功能Default: true.
spring.cloud.stream.rocketmq.binder.customized-trace-topic
消息轨迹开启后存储的 topic 名称。Default: RMQ_SYS_TRACE_TOPIC.
spring.cloud.stream.rocketmq.binder.access-channel
商业版rocketmq消息轨迹topic自适应,值为CLOUDDefault: null.
下面的这些配置是以 spring.cloud.stream.rocketmq.bindings.
enable
是否启用 Consumer。默认值: true.
tags
Consumer 基于 TAGS 订阅,多个 tag 以 || 分割。默认值: empty.
sql
Consumer 基于 SQL 订阅。默认值: empty.
broadcasting
Consumer 是否是广播消费模式。如果想让所有的订阅者都能接收到消息,可以使用广播模式。默认值: false.
orderly
Consumer 是否同步消费消息模式。默认值: false.
delayLevelWhenNextConsume
异步消费消息模式下消费失败重试策略:-1,不重复,直接放入死信队列0,broker 控制重试策略>0,client 控制重试策略默认值: 0.
suspendCurrentQueueTimeMillis
同步消费消息模式下消费失败后再次消费的时间间隔。默认值: 1000.
下面的这些配置是以 spring.cloud.stream.rocketmq.bindings.
enable
是否启用 Producer。默认值: true.
group
Producer group name。默认值: empty.
maxMessageSize
消息发送的最大字节数。默认值: 8249344.
transactional
是否发送事务消息。默认值: false.
sync
是否使用同步得方式发送消息。默认值: false.
vipChannelEnabled
是否在 Vip Channel 上发送消息。默认值: true.
sendMessageTimeout
发送消息的超时时间(毫秒)。默认值: 3000.
compressMessageBodyThreshold
消息体压缩阀值(当消息体超过 4k 的时候会被压缩)。默认值: 4096.
retryTimesWhenSendFailed
在同步发送消息的模式下,消息发送失败的重试次数。默认值: 2.
retryTimesWhenSendAsyncFailed
在异步发送消息的模式下,消息发送失败的重试次数。默认值: 2.
retryNextServer
消息发送失败的情况下是否重试其它的 broker。默认值: false.
使用阿里云 MQ 服务需要配置 AccessKey、SecretKey 以及云上的 NameServer 地址。
NOTE | 0.1.2 & 0.2.2 & 0.9.0 才支持该功能 |
---|---|
spring.cloud.stream.rocketmq.binder.access-key=YourAccessKey spring.cloud.stream.rocketmq.binder.secret-key=YourSecretKey spring.cloud.stream.rocketmq.binder.name-server=NameServerInMQ spring.cloud.stream.rocketmq.binder.access-channel=CLOUD
NOTE | topic 和 group 请以 实例id% 为前缀进行配置。比如 topic 为 “test”,需要配置成 “实例id%test” |
---|---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G1TYlfDc-1687339677994)(https://spring-cloud-alibaba.oss-cn-beijing.aliyuncs.com/MQ.png)]
Figure 8. NameServer 的获取(配置中请去掉 http:// 前缀)
ANS(Application Naming Service) 是隶属于阿里云 EDAS 产品的组件, Spring Cloud AliCloud ANS 提供了 Spring Cloud 规范下商业版的服务注册与发现,可以让用户方便的在本地开发,同时也可以运行在云环境里。
NOTE | 目前 EDAS 已经支持直接部署 Nacos Discovery 应用 |
---|---|
如果要在您的项目中引入 ANS,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alicloud-ans 的 starter。
com.alibaba.cloud spring-cloud-starter-alicloud-ans
当客户端引入了 Spring Cloud AliCloud ANS Starter 以后,服务的元数据会被自动注册到注册中心,比如IP、端口、权重等信息。客户端会与服务端保持心跳,来证明自己可以正常提供服务。
以下是一个简单的应用示例。
@SpringBootApplication @EnableDiscoveryClient @RestController public class ProviderApplication { @RequestMapping("/") public String home() { return "Hello world"; } public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
既然服务会被注册到注册中心,那么肯定需要配置注册中心的地址,在 application.properties 中,还需要配置上以下地址。
# 应用名会被作为服务名称使用,因此会必选 spring.application.name=ans-provider server.port=18081 # 以下就是注册中心的IP和端口配置 spring.cloud.alicloud.ans.server-list=127.0.0.1 spring.cloud.alicloud.ans.server-port=8080
NOTE | 此时没有启动注册中心,启动应用会报错,因此在应用启动之前,应当首先启动注册中心。 |
---|---|
ANS 使用的注册中心有两种,一种是完全免费的轻量版配置中心,主要用于开发和本地调试,一种是云上注册中心,ANS 依托于阿里云 EDAS 产品提供服务注册的功能。通常情况下,可以使用轻量版配置中心作为开发和测试环境,使用云上的 EDAS 作为灰度和生产环境。
轻量版配置中心的下载和启动方式可参考 这里
NOTE | 只需要进行第1步(下载轻量配置中心)和第2步(启动轻量配置中心)即可,第3步(配置hosts)在与 ANS 结合使用时,不需要操作。 |
---|---|
启动完轻量版配置中心以后,直接启动 ProviderApplication ,即可将服务注册到轻量版配置中心,由于轻量版配置中心的默认端口是8080,因此你可以打开 http://127.0.0.1:8080 ,点击左侧"服务列表",查看注册上来的服务。
使用云上注册中心,可以省去服务端的维护工作,同时稳定性也会更有保障。当使用云上注册中心时,代码部分和使用轻量配置中心并没有区别,但是配置上会有一些区别。
以下是一个简单的使用云上配置中心的配置示例。
# 应用名会被作为服务名称使用,因此是必选 spring.application.name=ans-provider # 端口配置自由配置即可 server.port=18081 # 以下就是注册中心的IP和端口配置,因为默认就是127.0.0.1和8080,因此以下两行配置也可以省略 spring.cloud.alicloud.ans.server-mode=EDAS spring.cloud.alicloud.access-key=你的阿里云AK spring.cloud.alicloud.secret-key=你的阿里云SK spring.cloud.alicloud.edas.namespace=cn-xxxxx
server-mode 的默认值为 LOCAL ,如果要使用云上注册中心,则需要更改为 EDAS 。
access-key 和 secret-key 则是阿里云账号的 AK/SK,需要首先注册阿里云账号,然后登陆 阿里云AK/SK管理页面 ,即可看到 AccessKey ID 和 Access Key Secret ,如果没有的话,需要点击"创建 AccessKey"按钮创建。
namespace 是阿里云 EDAS 产品的概念,用于隔离不同的环境,比如测试环境和生产环境。要获取 namespace 需要 开通 EDAS 服务,按量计费模式下开通是免费的,开通以后进入 EDAS控制台,即可看到对应的 namespace,比如 cn-hangzhou。
NOTE | EDAS 提供应用托管服务,如果你将应用托管到 EDAS,那么 EDAS 将会自动为你填充所有配置。 |
---|---|
Spring Cloud AliCloud ACM 是阿里云提供的商业版应用配置管理(Application Configuration Management) 产品 在 Spring Cloud 应用侧的客户端实现,且目前完全免费。
使用 Spring Cloud AliCloud ACM,可基于 Spring Cloud 的编程模型快速接入 ACM 配置管理功能。
NOTE | 目前 EDAS 已经支持直接部署 Nacos Config 应用 |
---|---|
如果要在您的项目中引入 ACM,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alicloud-acm 的 starter。
com.alibaba.cloud spring-cloud-starter-alicloud-acm
当客户端引入了 Spring Cloud AliCloud ACM Starter 以后,应用启动时会自动从配置管理的服务端获取配置信息,并注入到 Spring 的 Environment 中。
以下是一个简单的应用示例。
@SpringBootApplication public class ProviderApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApplication.class, args); String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); System.err.println("user name :"+userName+"; age: "+userAge); } }
在从配置中心服务端获取配置信息之前,还需要配置服务端的地址,在 bootstrap.properties 中,还需要配置以下信息。
# 必选,应用名会被作为从服务端获取配置 key 的关键词组成部分 spring.application.name=acm-config server.port=18081 # 以下就是配置中心服务端的IP和端口配置 spring.cloud.alicloud.acm.server-list=127.0.0.1 spring.cloud.alicloud.acm.server-port=8080
NOTE | 此时没有启动配置中心,启动应用会报错,因此在应用启动之前,应当首先启动配置中心。 |
---|---|
ACM 使用的配置中心有两种,一种是本地运行的轻量版配置中心,主要用于开发和本地调试,一种是阿里云产品 ACM。通常情况下,可以使用轻量版配置中心作为开发和测试环境,使用云上的 ACM 作为灰度和生产环境。
轻量版配置中心的下载和启动方式可参考 这里
NOTE | 只需要执行文档中的第1步 (下载轻量配置中心) 和第2步 (启动轻量配置中心)。 |
---|---|
使用云上 ACM ,可以省去服务端的维护工作,同时稳定性也会更有保障。当使用云上配置中心时,代码部分和使用轻量配置中心并没有区别,但是配置上会有一些区别。
以下是一个简单的使用云上配置中心的配置示例,配置详情需要在 ACM控制台查询
# 应用名会被作为从服务端获取配置 key 的关键词组成部分,因此是必选 spring.application.name=acm-config # 端口配置自由配置即可 server.port=18081 # 以下就是配置中心的IP和端口配置 spring.cloud.alicloud.acm.server-mode=EDAS spring.cloud.alicloud.access-key=你的阿里云AK spring.cloud.alicloud.secret-key=你的阿里云SK spring.cloud.alicloud.acm.endpoint=acm.aliyun.com spring.cloud.alicloud.acm.namespace=你的 ACM namespace,需要在 ACM 控制台查询
NOTE | EDAS 提供应用托管服务,如果你将应用托管到 EDAS,那么 EDAS 将会自动为你填充所有与业务无关的配置。 |
---|---|
Group: DEFAULT_GROOUP DataId: acm-config.properties Content: user.name=james user.age=18
NOTE | DataId 的格式为 {prefix}.{file-extension},prefix 默认从配置 spring.application.name 中取值,file-extension 默认的值为 “properties”。 |
---|---|
启动这个Example,可以在控制台看到打印出的值正是我们在轻量版配置中心上预先配置的值。
user name :james; age: 18
spring-cloud-starter-alicloud-acm 中 DataId 默认的文件扩展名是 properties。除去 properties 格式之外,也支持 yaml 格式。 支持通过 spring.cloud.alicloud.acm.file-extension 来配置文件的扩展名,yaml 格式可以配置成 yaml 或 yml。
NOTE | 修改文件扩展名后,在配置中心中的 DataID 以及 Content 的格式都必须做相应的修改。 |
---|---|
spring-cloud-starter-alicloud-acm 默认支持配置的动态更新,当您在配置中心修改配置的内容时,会发布 Spring 中的 RefreshEvent 事件。 带有 @RefreshScope 和 @ConfigurationProperties 注解的类会自动刷新。
NOTE | 你可以通过配置 spring.cloud.alicloud.acm.refresh.enabled=false 来关闭动态刷新。 |
---|---|
spring-cloud-starter-alicloud-acm 在加载配置的时候,首先会加载 DataId 为{spring.application.name}.{file-extension}的配置,当 spring.profiles.active 中配置有内容时,还会依次去加载 spring.profile 对应的内容, DataId 的格式为{spring.application.name}-{profile}.{file-extension}的配置,且后者的优先级高于前者。
spring.profiles.active 属于配置的元数据,所以也必须配置在 bootstrap.properties 或 bootstrap.yaml 中。比如可以在 bootstrap.properties 中增加如下内容。
spring.profiles.active={profile-name}
Note: 也可以通过 JVM 参数 -Dspring.profiles.active=develop 或者 --spring.profiles.active=develop 这类优先级更高的方式来配置,只需遵循 Spring Boot 规范即可。
ACM Client 与 Server 通信的超时时间默认是 3000ms,可以通过 spring.cloud.alicloud.acm.timeout 来修改超时时间,单位为 ms 。
在没有明确指定 {spring.cloud.alicloud.acm.group} 配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现:
spring.cloud.alicloud.acm.group=DEVELOP_GROUP
NOTE | 该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值要和 spring.cloud.alicloud.acm.group 的配置值一致。 |
---|---|
ACM 提供了一种多个应用之间共享配置中心的同一个配置的推荐方式,供多个应用共享一些配置时使用,您在使用的时候需要添加在 bootstrap 中添加一个配置项 spring.application.group。
spring.application.group=company.department.team
这时应用在获取上文提到的自身所独有的配置之前,会先依次从这些 DataId 去获取,分别是 company:application.properties, company.department:application.properties, company.department.team:application.properties。 然后,还会从 {spring.application.group}:{spring.application.name}.{file-extension} 中获取,越往后优先级越高,最高的仍然是应用自身所独有的配置。
NOTE | 共享配置中 DataId 默认后缀为 properties,可以通过 spring.cloud.alicloud.acm.file-extension 配置. {spring.application.group}:{spring.application.name}.{file-extension} 。 |
---|---|
NOTE | 如果设置了 spring.profiles.active ,DataId 的格式还支持 {spring.application.group}:{spring.application.name}-{spring.profiles.active}.{file-extension}。优先级高于 {spring.application.group}:{spring.application.name}.{file-extension} |
---|---|
ACM 对应的 Actuator 监控地址为 /acm,其中 config 代表了 ACM 元数据配置的信息,runtime.sources 对应的是从 ACM 服务端获取的配置的信息及最后刷新时间, runtime.refreshHistory 对应的是动态刷新的历史记录。
OSS(Object Storage Service)是阿里云的一款对象存储服务产品, Spring Cloud AliCloud OSS 提供了Spring Cloud规范下商业版的对象存储服务,提供简单易用的API,并且支持与 Spring 框架中 Resource 的整合。
如果要在您的项目中引入 OSS,使用 group ID 为 org.springframework.cloud 和 artifact ID 为 spring-cloud-starter-alicloud-oss 的 starter。
com.alibaba.cloud spring-cloud-starter-alicloud-oss
使用 Spring Cloud AliCloud OSS 之前,需要在 application.properties 中加入以下配置。
spring.cloud.alicloud.access-key=你的阿里云AK spring.cloud.alicloud.secret-key=你的阿里云SK spring.cloud.alicloud.oss.endpoint=***.aliyuncs.com
access-key 和 secret-key 是阿里云账号的AK/SK,需要首先注册阿里云账号,然后登陆 阿里云AK/SK管理页面 ,即可看到 AccessKey ID 和 Access Key Secret ,如果没有的话,需要点击"创建AccessKey"按钮创建。
endpoint可以到 OSS 的 官方文档中查看,根据所在的 region ,填写对应的 endpoint 即可。
Spring Cloud Alicloud OSS 中的 OSS API 基于阿里云官方OSS SDK提供,具备上传、下载、查看等所有对象存储类操作API。
一个简单的使用 OSS API 的应用如下。
@SpringBootApplication public class OssApplication { @Autowired private OSS ossClient; @RequestMapping("/") public String home() { ossClient.putObject("bucketName", "fileName", new FileInputStream("/your/local/file/path")); return "upload success"; } public static void main(String[] args) throws URISyntaxException { SpringApplication.run(OssApplication.class, args); } }
在上传文件之前,首先需要 注册阿里云账号 ,如果已经有的话,请 开通OSS服务。
进入 OSS控制台,点击左侧"新建Bucket",按照提示创建一个Bucket,然后将bucket名称替换掉上面代码中的"bucketName",而"fileName"取任意文件名,"/your/local/file/path"取任意本地文件路径,然后 curl http://127.0.0.1:端口/ 即可上传文件,可以到 OSS控制台查看效果。
更多关于 OSS API 的操作,可以参考 OSS官方SDK文档。
Spring Cloud AliCloud OSS 整合了 Spring 框架的 Resource 规范,可以让用户很方便的引用 OSS 的资源。
一个简单的使用 Resource 的例子如下。
@SpringBootApplication public class OssApplication { @Value("oss://bucketName/fileName") private Resource file; @GetMapping("/file") public String fileResource() { try { return "get file resource success. content: " + StreamUtils.copyToString( file.getInputStream(), Charset.forName(CharEncoding.UTF_8)); } catch (Exception e) { return "get resource fail: " + e.getMessage(); } } public static void main(String[] args) throws URISyntaxException { SpringApplication.run(OssApplication.class, args); } }
NOTE | 以上示例运行的前提是,在 OSS 上需要有名为"bucketName"的Bucket,同时在该Bucket下,存在名为"fileName"的文件。 |
---|---|
Spring Cloud AliCloud OSS 除了 AccessKey/SecretKey 的授权方式以外,还支持 STS 授权方式。 STS 是临时访问令牌的方式,一般用于授权第三方,临时访问自己的资源。
作为第三方,也就是被授权者,只需要配置以下内容,就可以访问临时被授权的资源。
spring.cloud.alicloud.oss.authorization-mode=STS spring.cloud.alicloud.oss.endpoint=***.aliyuncs.com spring.cloud.alicloud.oss.sts.access-key=你被授权的AK spring.cloud.alicloud.oss.sts.secret-key=你被授权的SK spring.cloud.alicloud.oss.sts.security-token=你被授权的ST
其中 spring.cloud.alicloud.oss.authorization-mode 是枚举类型,此时填写 STS ,代表采用 STS 的方式授权。 endpoint可以到 OSS 的 官方文档中查看,根据所在的 region ,填写对应的 endpoint 即可。
access-key、secret-key和security-token需要由授权方颁发,如果对 STS 不了解的话,可以参考 STS官方文档。
除了基本的配置项以外, Spring Cloud AliCloud OSS 还支持很多额外的配置,也是在 application.properties 文件中。
以下是一些简单的示例。
spring.cloud.alicloud.oss.authorization-mode=STS spring.cloud.alicloud.oss.endpoint=***.aliyuncs.com spring.cloud.alicloud.oss.sts.access-key=你被授权的AK spring.cloud.alicloud.oss.sts.secret-key=你被授权的SK spring.cloud.alicloud.oss.sts.security-token=你被授权的ST spring.cloud.alicloud.oss.config.connection-timeout=3000 spring.cloud.alicloud.oss.config.max-connections=1000
如果想了解更多的配置项,可以参考 OSSClient配置项 的末尾表格。
NOTE | 通常情况下,都需要将 OSSClient配置项 末尾表格中的参数名更换成"-"连接,且所有字母小写。例如 ConnectionTimeout,对应 connection-timeout。 |
---|---|
SchedulerX(分布式任务调度) 是隶属于阿里云EDAS产品的组件, Spring Cloud AliCloud SchedulerX 提供了在Spring Cloud的配置规范下,分布式任务调度的功能支持。SchedulerX可提供秒级、精准、高可靠、高可用的定时任务调度服务,并支持多种类型的任务调度,如简单单机任务、简单多机任务、脚本任务以及网格任务。
如果要在您的项目中引入 SchedulerX,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alicloud-schedulerX 的 starter。
com.alibaba.cloud spring-cloud-starter-alicloud-schedulerX
当客户端引入了 Spring Cloud AliCloud SchedulerX Starter 以后,只需要进行一些简单的配置,就可以自动初始化SchedulerX的任务调度服务。
以下是一个简单的应用示例。
@SpringBootApplication public class ScxApplication { public static void main(String[] args) { SpringApplication.run(ScxApplication.class, args); } }
在application.properties中,需要加上以下配置。
server.port=18033 # 其中cn-test是SchedulerX的测试区域 spring.cloud.alicloud.scx.group-id=*** spring.cloud.alicloud.edas.namespace=cn-test
在获取group-id之前,需要首先 注册阿里云账号 ,然后 开通EDAS服务 ,并 开通分布式任务管理组件 。
其中group-id的获取,请参考 这里。
NOTE | 在创建group的时候,要选择"测试"区域。 |
---|---|
简单任务是最常用的任务类型,只需要实现 ScxSimpleJobProcessor 接口即可。
以下是一个简单的单机类型任务示例。
public class SimpleTask implements ScxSimpleJobProcessor { @Override public ProcessResult process(ScxSimpleJobContext context) { System.out.println("-----------Hello world---------------"); ProcessResult processResult = new ProcessResult(true); return processResult; } }
进入 SchedulerX任务列表 页面,选择上方"测试"区域,点击右上角"新建Job",创建一个Job,即如下所示。
Job分组:测试——***-*-*-**** Job处理接口:org.springframework.cloud.alibaba.cloud.examples.SimpleTask 类型:简单Job单机版 定时表达式:默认选项——0 * * * * ? Job描述:无 自定义参数:无
以上任务类型选择了"简单Job单机版",并且制定了Cron表达式为"0 * * * * ?",这意味着,每过一分钟,任务将会被执行且只执行一次。
更多任务类型,请参考 SchedulerX官方文档。
以上使用的都是SchedulerX的"测试"区域,主要用于本地调试和测试。
在生产级别,除了上面的group-id和namespace以外,还需要一些额外的配置,如下所示。
server.port=18033 # 其中cn-test是SchedulerX的测试区域 spring.cloud.alicloud.scx.group-id=*** spring.cloud.alicloud.edas.namespace=*** # 当应用运行在EDAS上时,以下配置不需要手动配置。 spring.cloud.alicloud.access-key=*** spring.cloud.alicloud.secret-key=*** # 以下配置不是必须的,请参考SchedulerX文档 spring.cloud.alicloud.scx.domain-name=***
其中group-id与之前的获取方式一样,namespace则是从EDAS控制台左侧"命名空间"列表中获取命名空间ID。
NOTE | group-id必须创建在namespace当中。 |
---|---|
access-key以及secret-key为阿里云账号的AK/SK信息,如果应用在EDAS上部署,则不需要填写这两项信息,否则请前往 安全信息管理获取。
domain-name并不是必须的,具体请参考 SchedulerX官方文档。
短信服务(Short Message Service)是阿里云为用户提供的一种通信服务的能力。 Spring Cloud AliCloud SMS 实现了与 SMS 的简单集成,提供更为简单易用的 API,可以基于 Spring Cloud Alibaba SMS 来快速的接入阿里云的 SMS 服务。
如果要在您的项目中引入 SMS,使用 group ID 为 com.alibaba.cloud 和 artifact ID 为 spring-cloud-starter-alicloud-sms 的 starter。
com.alibaba.cloud spring-cloud-starter-alicloud-sms
使用 Spring Cloud AliCloud SMS 之前,需要在 application.properties 中加入以下配置。
spring.cloud.alicloud.access-key=你的阿里云 AK spring.cloud.alicloud.secret-key=你的阿里云 SK
access-key 和 secret-key 是阿里云账号的 AK/SK,需要首先注册阿里云账号,然后登陆 阿里云AK/SK管理页面 ,即可看到 AccessKey ID 和 Access Key Secret ,如果没有的话,需要点击"创建AccessKey"按钮创建。
Spring Cloud Alicloud SMS 中的 SMS API 基于阿里云官方 SMS SDK ,提供具备单个短信发送、多个短信批量发送、短信查询、短信消息(短信回执消息 和 上行短信消息) 类型操作API。
一个简单的使用 SMS API 发送短信的应用如下。
@SpringBootApplication public class SmsApplication { @Autowired private ISmsService smsService; /** * 短信发送 Example * @param code * @return */ @RequestMapping("/batch-sms-send.do") public SendBatchSmsResponse batchsendCheckCode( @RequestParam(name = "code") String code) { // 组装请求对象-具体描述见控制台-文档部分内容 SendSmsRequest request = new SendSmsRequest(); // 必填:待发送手机号 request.setPhoneNumbers("152******"); // 必填:短信签名-可在短信控制台中找到 request.setSignName("******"); // 必填:短信模板-可在短信控制台中找到 request.setTemplateCode("******"); // 可选:模板中的变量替换JSON串,如模板内容为"【企业级分布式应用服务】,您的验证码为${code}"时,此处的值为 request.setTemplateParam("{\"code\":\"" + code + "\"}"); SendSmsResponse sendSmsResponse ; try { sendSmsResponse = smsService.sendSmsRequest(request); } catch (ClientException e) { e.printStackTrace(); sendSmsResponse = new SendSmsResponse(); } return sendSmsResponse ; } public static void main(String[] args) throws URISyntaxException { SpringApplication.run(SmsApplication.class, args); } }
在发送短信之前,首先需要 注册阿里云账号 ,如果已经有的话,请 开通 SMS 服务。
更多关于 SMS 发送短信的步骤,可以参考 SMS 官方 短信发送API(SendSms)—JAVA 文档。
NOTE | 由于早期的 SMS sdk 版本的问题,如果短信发送失败,请将代码中含有明确指定 MethodType 为 POST 的这行代码给删除掉。如果还有问题,请第一时间联系我们。 |
---|---|
Spring Cloud Alicloud SMS 封装的 API 接口为了降低学习的成本,尽量保持和官网提供的 API 以及 Example 保持一致。
参考以下的 Example ,来快速开发一个具有批量短信发送的功能。在 Controller 中或者新建一个 Controler 新增如下代码:
/** * 批量短信发送 Example * @param code * @return */ @RequestMapping("/batch-sms-send.do") public SendBatchSmsResponse batchsendCheckCode( @RequestParam(name = "code") String code) { // 组装请求对象 SendBatchSmsRequest request = new SendBatchSmsRequest(); // 使用 GET 提交 request.setMethod(MethodType.GET); // 必填:待发送手机号。支持JSON格式的批量调用,批量上限为100个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式 request.setPhoneNumberJson("[\"177********\",\"130********\"]"); // 必填:短信签名-支持不同的号码发送不同的短信签名 request.setSignNameJson("[\"*******\",\"*******\"]"); // 必填:短信模板-可在短信控制台中找到 request.setTemplateCode("******"); // 必填:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败 request.setTemplateParamJson( "[{\"code\":\"" + code + "\"},{\"code\":\"" + code + "\"}]"); SendBatchSmsResponse sendSmsResponse ; try { sendSmsResponse = smsService .sendSmsBatchRequest(request); return sendSmsResponse; } catch (ClientException e) { e.printStackTrace(); sendSmsResponse = new SendBatchSmsResponse(); } return sendSmsResponse ; }
NOTE | 这里设置请求的 MethodType 为 GET,和官网给出的例子还有些不一样。这是因为依赖的阿里云 POP API 版本不一致导致不兼容的问题,设置为 GET 即可。 |
---|---|
更多的参数说明可 参考这里
参考以下的 Example ,可以快速开发根据某个指定的号码查询短信历史发送状态。在 Controller 中或者新建一个 Controler 新增如下代码:
/** * * 短信查询 Example * @param telephone * @return */ @RequestMapping("/query.do") public QuerySendDetailsResponse querySendDetailsResponse( @RequestParam(name = "tel") String telephone) { // 组装请求对象 QuerySendDetailsRequest request = new QuerySendDetailsRequest(); // 必填-号码 request.setPhoneNumber(telephone); // 必填-短信发送的日期 支持30天内记录查询(可查其中一天的发送数据),格式yyyyMMdd request.setSendDate("20190103"); // 必填-页大小 request.setPageSize(10L); // 必填-当前页码从1开始计数 request.setCurrentPage(1L); try { QuerySendDetailsResponse response = smsService.querySendDetails(request); return response; } catch (ClientException e) { e.printStackTrace(); } return new QuerySendDetailsResponse(); }
更多的参数说明,可 参考这里
通过订阅 SmsReport 短信状态报告,可以获知每条短信的发送情况,了解短信是否达到终端用户的状态与相关信息。这些工作已经都被 Spring Cloud AliCloud SMS 封装在内部了。你只需要完成以下两步即可。
1、在 application.properties 配置文件中(也可以是 application.yaml)配置 SmsReport 的队列名称。
application.properties
spring.cloud.alicloud.sms.report-queue-name=Alicom-Queue-********-SmsReport
2、 实现 SmsReportMessageListener 接口,并初始化一个 Spring Bean 。
/** * 如果需要监听短信是否被对方成功接收,只需实现这个接口并初始化一个 Spring Bean 即可。 */ @Component public class SmsReportMessageListener implements org.springframework.cloud.alicloud.sms.SmsReportMessageListener { @Override public boolean dealMessage(Message message) { // 在这里添加你的处理逻辑 //do something System.err.println(this.getClass().getName() + "; " + message.toString()); return true; } }
更多关于 Message 的消息体格式可 参考这里。
通过订阅SmsUp上行短信消息,可以获知终端用户回复短信的内容。这些工作也已经被 Spring Cloud AliCloud SMS 封装好了。你只需要完成以下两步即可。
1、 在 application.properties 配置文件中(也可以是 application.yaml)配置 SmsReport 的队列名称。
application.properties
spring.cloud.alicloud.sms.up-queue-name=Alicom-Queue-********-SmsUp
2、实现 SmsUpMessageListener 接口,并初始化一个 Spring Bean 。
/** * 如果发送的短信需要接收对方回复的状态消息,只需实现该接口并初始化一个 Spring Bean 即可。 */ @Component public class SmsUpMessageListener implements org.springframework.cloud.alicloud.sms.SmsUpMessageListener { @Override public boolean dealMessage(Message message) { // 在这里添加你的处理逻辑 //do something System.err.println(this.getClass().getName() + "; " + message.toString()); return true; } }
更多关于 Message 的消息体格式可 参考这里。
Spring Cloud Alibaba Sidecar 是一个用来快速完美整合 Spring Cloud 与 异构微服务 的框架,灵感来自 Spring Cloud Netflix Sidecar,目前支持的服务发现组件:
非Spring Cloud应用,统称异构微服务。比如你的遗留项目,或者非JVM应用。
原因有两点:
既然没有,索性自己写了。
加依赖:
com.alibaba.cloud spring-cloud-starter-alibaba-sidecar
写配置:
server: port: 8070 spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: discovery: locator: enabled: true application: name: node-service sidecar: # 异构微服务的IP ip: 127.0.0.1 # 异构微服务的端口 port: 8060 # 异构微服务的健康检查URL health-check-url: http://localhost:8060/health.json management: endpoint: health: show-details: always
配置比较简单,就是把Alibaba Sidecar注册到Nacos上,然后添加了几行Alibaba Sidecar的配置。
我准备了一个NodeJS编写的简单微服务。
var http = require('http'); var url = require("url"); var path = require('path'); // 创建server var server = http.createServer(function(req, res) { // 获得请求的路径 var pathname = url.parse(req.url).pathname; res.writeHead(200, { 'Content-Type' : 'application/json; charset=utf-8' }); // 访问http://localhost:8060/,将会返回{"index":"欢迎来到首页"} if (pathname === '/') { res.end(JSON.stringify({ "index" : "欢迎来到首页" })); } // 访问http://localhost:8060/health,将会返回{"status":"UP"} else if (pathname === '/health.json') { res.end(JSON.stringify({ "status" : "UP" })); } // 其他情况返回404 else { res.end("404"); } }); // 创建监听,并打印日志 server.listen(8060, function() { console.log('listening on localhost:8060'); });
为你的Spring Cloud微服务整合Ribbon,然后构建 http://node-service/ ,就可以请求到异构微服务的 / 了。
示例:
Ribbon请求 http://node-service/ 会请求到 http://localhost:8060/ ,以此类推。
至于断路器,正常为你的Spring Cloud微服务整合Sentinel或者Hystirx、Resilience4J即可 。
由于Alibaba Sidecar基于Spring Cloud Gateway,而网关自带转发能力。
示例:
如果你有一个Spring Cloud微服务叫做 spring-cloud-microservice ,那么NodeJS应用只需构建 http://localhost:8070/spring-cloud-microservice/ ,Alibaba Sidecar就会把请求转发到 spring-cloud-microservice 的 / 。
而Spring Cloud Gateway是整合了Ribbon的,所以实现了负载均衡;Spring Cloud Gateway还可以整合Sentinel或者Hystirx、Resilience4J,所以也带有了断路器。
Alibaba Sidecar的设计和Sidecar基本一致,优缺点和Sidecar的优缺点也是一样的。
优点:
缺点: