1. Spring Cloud Alibaba 介紹
Spring Cloud Alibaba 為分布式應用程序開發提供了一站式解決方案。它包含了開發分布式應用程序所需的所有組件,使得你可以輕松地使用Spring Cloud開發應用程序。
使用Spring Cloud Alibaba,只需要添加一些注釋和少量配置即可將Spring Cloud應用程序連接到Alibaba的分布式解決方案,並使用Alibaba中間件構建分布式應用程序系統。
特性:
- 流量控制和服務降級:Sentinel進行流量控制,斷路和系統自適應保護。
- 服務注冊和發現:實例可以在Nachos中注冊,並且客戶端可以使用Spring管理的Bean發現實例。支持Ribbon。
- 分布式配置:使用Nacos作為數據存儲。
- 事件驅動:建立與Spring Cloud Stream RocketMQ Binder連接的高度可擴展的事件驅動型微服務。
- 消息總線:利用Spring Cloud Bus RocketMQ鏈接分布式系統的節點。
- 分布式事務:支持高性能、易於使用的分布式事務。
- Dubbo RPC :通過Dubbo RPC擴展Spring Cloud服務之間調用的通信協議。
- 阿里雲對象存儲:阿里雲對象存儲服務(OSS)是一種加密、安全、經濟高效且易於使用的對象存儲服務,可讓您在雲中存儲,備份和存檔大量數據。
依賴管理:
1 <dependencyManagement>
2 <dependencies>
3 <dependency>
4 <groupId>com.alibaba.cloud</groupId>
5 <artifactId>spring-cloud-alibaba-dependencies</artifactId>
6 <version>2.1.0.RELEASE</version>
7 <type>pom</type>
8 <scope>import</scope>
9 </dependency>
10 </dependencies>
11 </dependencyManagement>
2. Spring Cloud Alibaba Nacos Discovery
Nacos是一個易於使用的動態服務發現、配置和服務管理平台。
服務注冊與發現:服務發現是微服務體系架構中的關鍵組件之一。在這樣的體系結構中,為每個客戶端手動配置服務列表可能是不太現實的,並且使動態擴展極為困難。Nacos Discovery幫助您自動將服務注冊到Nacos Server,並且Nacos Server會跟蹤服務並動態刷新服務列表。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Nacos Discovery集成了Netflix Ribbon 、RestTemplate或OpenFeign,可用於服務之間的調用
2.1. Start a Provider Application
首先,創建一個提供者服務
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.11.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>com.cjs.example</groupId>
12 <artifactId>nacos-discovery-provider-example</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>nacos-discovery-provider-example</name>
15
16 <properties>
17 <java.version>1.8</java.version>
18 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20 </properties>
21
22 <dependencyManagement>
23 <dependencies>
24 <dependency>
25 <groupId>org.springframework.cloud</groupId>
26 <artifactId>spring-cloud-dependencies</artifactId>
27 <version>Greenwich.SR4</version>
28 <type>pom</type>
29 <scope>import</scope>
30 </dependency>
31 <dependency>
32 <groupId>com.alibaba.cloud</groupId>
33 <artifactId>spring-cloud-alibaba-dependencies</artifactId>
34 <version>2.1.0.RELEASE</version>
35 <type>pom</type>
36 <scope>import</scope>
37 </dependency>
38 </dependencies>
39 </dependencyManagement>
40
41 <dependencies>
42 <dependency>
43 <groupId>org.springframework.boot</groupId>
44 <artifactId>spring-boot-starter-actuator</artifactId>
45 </dependency>
46 <dependency>
47 <groupId>org.springframework.boot</groupId>
48 <artifactId>spring-boot-starter-web</artifactId>
49 </dependency>
50 <dependency>
51 <groupId>com.alibaba.cloud</groupId>
52 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
53 </dependency>
54 </dependencies>
55
56 <build>
57 <plugins>
58 <plugin>
59 <groupId>org.springframework.boot</groupId>
60 <artifactId>spring-boot-maven-plugin</artifactId>
61 </plugin>
62 </plugins>
63 </build>
64
65 </project>
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=*
如果您不想使用Nacos進行服務注冊和發現,可以設置spring.cloud.nacos.discovery為false
1 package com.cjs.example.nacos;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 import org.springframework.web.bind.annotation.GetMapping;
7 import org.springframework.web.bind.annotation.PathVariable;
8 import org.springframework.web.bind.annotation.RestController;
9
10 @SpringBootApplication
11 @EnableDiscoveryClient
12 public class NacosDiscoveryProviderExampleApplication {
13
14 public static void main(String[] args) {
15 SpringApplication.run(NacosDiscoveryProviderExampleApplication.class, args);
16 }
17
18 @RestController
19 public class EchoController {
20 @GetMapping(value = "/echo/{string}")
21 public String echo(@PathVariable String string) {
22 return "Hello Nacos Discovery " + string;
23 }
24 }
25
26 }
注意,務必先啟動Nacos
wget https://github.com/alibaba/nacos/releases/download/1.1.4/nacos-server-1.1.4.tar.gz
tar -zxf nacos-server-1.1.4.tar.gz
cd nacos/bin
sh startup.sh -m standalone
sh shutdown.sh
2.2. Start a Consumer Application
創建一個消費者服務
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.11.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>com.cjs.example</groupId>
12 <artifactId>nacos-discovery-consumer-example</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>nacos-discovery-consumer-example</name>
15
16 <properties>
17 <java.version>1.8</java.version>
18 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20 </properties>
21
22 <dependencyManagement>
23 <dependencies>
24 <dependency>
25 <groupId>org.springframework.cloud</groupId>
26 <artifactId>spring-cloud-dependencies</artifactId>
27 <version>Greenwich.SR4</version>
28 <type>pom</type>
29 <scope>import</scope>
30 </dependency>
31 <dependency>
32 <groupId>com.alibaba.cloud</groupId>
33 <artifactId>spring-cloud-alibaba-dependencies</artifactId>
34 <version>2.1.0.RELEASE</version>
35 <type>pom</type>
36 <scope>import</scope>
37 </dependency>
38 </dependencies>
39 </dependencyManagement>
40
41 <dependencies>
42 <dependency>
43 <groupId>org.springframework.boot</groupId>
44 <artifactId>spring-boot-starter-actuator</artifactId>
45 </dependency>
46 <dependency>
47 <groupId>org.springframework.boot</groupId>
48 <artifactId>spring-boot-starter-web</artifactId>
49 </dependency>
50 <dependency>
51 <groupId>com.alibaba.cloud</groupId>
52 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
53 </dependency>
54 <dependency>
55 <groupId>org.springframework.cloud</groupId>
56 <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
57 </dependency>
58 <dependency>
59 <groupId>org.springframework.cloud</groupId>
60 <artifactId>spring-cloud-starter-openfeign</artifactId>
61 </dependency>
62 </dependencies>
63
64 <build>
65 <plugins>
66 <plugin>
67 <groupId>org.springframework.boot</groupId>
68 <artifactId>spring-boot-maven-plugin</artifactId>
69 </plugin>
70 </plugins>
71 </build>
72
73 </project>
application.properties
server.port=8082
spring.application.name=nacos-consumer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=*
使用RestTemplate或者FeignClient調用遠程服務
1 package com.cjs.example.nacos;
2
3 import org.springframework.beans.factory.annotation.Autowired;
4 import org.springframework.beans.factory.annotation.Value;
5 import org.springframework.boot.SpringApplication;
6 import org.springframework.boot.autoconfigure.SpringBootApplication;
7 import org.springframework.cloud.client.ServiceInstance;
8 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
9 import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
10 import org.springframework.cloud.openfeign.EnableFeignClients;
11 import org.springframework.cloud.openfeign.FeignClient;
12 import org.springframework.context.annotation.Bean;
13 import org.springframework.web.bind.annotation.GetMapping;
14 import org.springframework.web.bind.annotation.PathVariable;
15 import org.springframework.web.bind.annotation.RestController;
16 import org.springframework.web.client.RestTemplate;
17
18 @SpringBootApplication
19 @EnableDiscoveryClient
20 @EnableFeignClients
21 public class NacosDiscoveryConsumerExampleApplication {
22
23 public static void main(String[] args) {
24 SpringApplication.run(NacosDiscoveryConsumerExampleApplication.class, args);
25 }
26
27
28 @RestController
29 public class NacosController{
30
31 @Autowired
32 private LoadBalancerClient loadBalancerClient;
33 @Autowired
34 private RestTemplate restTemplate;
35
36 @Value("${spring.application.name}")
37 private String appName;
38
39 /**
40 * 使用RestTemplate調用遠程服務
41 */
42 @GetMapping("/echo/app-name")
43 public String echoAppName(){
44 // Access through the combination of LoadBalanceClient and RestTemplate
45 ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
46 String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
47 System.out.println("request path:" +path);
48 return restTemplate.getForObject(path,String.class);
49 }
50
51 // Instantiate RestTemplate Instance
52 @Bean
53 public RestTemplate restTemplate(){
54 return new RestTemplate();
55 }
56
57
58 // ----------------------------------------
59
60 @Autowired
61 private EchoService echoService;
62 /**
63 * 使用FeignClient調用遠程服務
64 */
65 @GetMapping("/sayHello")
66 public String sayHello() {
67 return echoService.echo("hello");
68 }
69 }
70
71 /**
72 * 使用FeignClient進行遠程調用
73 */
74 @FeignClient(name = "nacos-provider")
75 public interface EchoService {
76 @GetMapping("/echo/{str}")
77 String echo(@PathVariable("str") String str);
78 }
79 }
訪問地址:
http://127.0.0.1:8082/echo/app-name
http://127.0.0.1:8082/sayHello
看一下Nacos控制台,默認用戶名密碼是nacos/nacos
http://127.0.0.1:8848/nacos/index.html
更多Nacos Discovery配置,請參見 com.alibaba.cloud.nacos.NacosDiscoveryProperties
3. Spring Cloud Alibaba Nacos Config
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
Nacos Config使用DataId和GROUP來確定配置。
首先,在控制台創建好配置項
然后,新建一個bootstrap.properties文件
bootstrap.properties
1 spring.application.name=nacos-config-example
2 spring.cloud.nacos.config.server-addr=127.0.0.1:8848
3
4 #spring.cloud.nacos.config.shared-dataids=nacos-config-dev.properties
5 #spring.cloud.nacos.config.file-extension=properties
6 #spring.cloud.nacos.config.group=DEFAULT_GROUP
7
8 spring.cloud.nacos.config.ext-config[0].data-id=nacos-config-dev.properties
9 spring.cloud.nacos.config.ext-config[0].refresh=true
更多配置項,參見 com.alibaba.cloud.nacos.NacosConfigProperties
application.properties
1 server.port=8083
2 management.endpoints.web.exposure.include=*
NacosConfigExampleApplication.java
1 package com.cjs.example.nacos;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5 import org.springframework.context.ConfigurableApplicationContext;
6
7 import java.util.concurrent.TimeUnit;
8
9 @SpringBootApplication
10 public class NacosConfigExampleApplication {
11
12 public static void main(String[] args) throws InterruptedException {
13 ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigExampleApplication.class, args);
14
15 while (true) {
16 String userName = applicationContext.getEnvironment().getProperty("user.name");
17 String userAge = applicationContext.getEnvironment().getProperty("user.age");
18 System.err.println("user name:" + userName + "; age: " + userAge);
19 TimeUnit.SECONDS.sleep(1);
20 }
21 }
22
23 }
讀取配置還可以使用@Value注解,例如:
1 package com.cjs.example.nacos;
2
3 import org.springframework.beans.factory.annotation.Value;
4 import org.springframework.cloud.context.config.annotation.RefreshScope;
5 import org.springframework.web.bind.annotation.GetMapping;
6 import org.springframework.web.bind.annotation.RestController;
7
8 @RefreshScope
9 @RestController
10 public class TestController {
11
12 @Value("${user.name}")
13 private String username;
14
15 @Value("${user.age}")
16 private Integer userAge;
17
18 @GetMapping("/hi")
19 public String hi() {
20 System.out.println(username);
21 System.out.println(userAge);
22 return "ok";
23 }
24
25 }
修改配置后,立即生效
關於配置項,可以看代碼
3.1. Nacos Config 支持 profile level
Nacos Config 加載配置時,會加載兩種格式的配置文件:
${spring.application.name}.${file-extension:properties}
${spring.application.name}-${profile}.${file-extension:properties}
如果你需要用不同的配置來區分不同的環境,你可以使用${spring.profiles.active}來指定
什么意思呢?舉個例子:
這跟Spring Boot里面的application-dev.properties、application-test.properties類似,
只不過用Nacos Config的話,我們就不需要application-${profile}.properties這樣的配置文件了
假設你的應用名稱是hello,那么無論是hello.properties,還是hello-dev.properties,Nacos Config都認識,都會加重它們
約定優於配置
約定優於配置
約定優於配置
如果按照上面的配置,那么在bootstrap.properties中根本需要指定data-id,只需指定spring.profiles.active
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.profiles.active=prod
當然啦,在真實環境中,肯定是通過-Dspring.profiles.active=<profile>參數來指定的
3.2. Nacos Config 數據結構
在Nacos Config中,是通過DataId和Group來確定一個配置的
DataID的格式是這樣的:
${prefix} - ${spring.profiles.active} . ${file-extension}
- prefix :默認值是spring.application.name的值,也可以通過spring.cloud.nacos.config.prefix來指定
- spring.profiles.active :是與當前環境一致的profile
- file-extension :所配置的內容的數據格式,默認是properties
group的默認值是DEFAULT_GROUP,可以通過spring.cloud.nacos.config.group指定
自動注入
Nacos Config Starter實現org.springframework.cloud.bootstrap.config.PropertySourceLocator接口,並將順序設置為0。
在Spring Cloud應用程序的啟動階段,從Nacos Server端獲取相應的數據,並將獲取的數據轉換為PropertySource並注入到Spring Environment的PropertySources屬性中。 因此@Value注解也可以直接獲取Nacos Server端的配置。
動態刷新
默認情況下,Nacos Config Starter為成功獲取到的所有Nacos配置項添加監聽功能。 當它檢測到服務器配置中的更改時,它將實時觸發org.springframework.cloud.context.refresh.ContextRefresher的刷新方法。
通過spring.cloud.nacos.config.enabled=false可以禁用自動刷新
強烈推薦,在class上添加 @RefreshScope 或者 @ConfigurationProperties
自定義namespace
命名空間用於隔離不同租戶的配置。在不同的命名空間中,Group和Data ID可以相同。命名空間的典型場景是隔離不同環境的配置,例如,開發/測試環境與生產環境(配置和服務等)之間的隔離。
默認的命名空間是Public,也就是說不指定命名空間就是Public
可以通過spring.cloud.nacos.config.namespace來手動指定
自定義Groups
通過spring.cloud.nacos.config.group指定
自定義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 is in the default group of DEFAULT_GROUP, and dynamic refresh of configurations is not supported.
spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties
# 2. Data Id is not in the default group, and dynamic refresh of configurations is not supported.
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 is not in the default group and dynamic referesh of configurations is supported.
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
可以看到這里配置了3個Data Id
當配置多個Data Id時,優先級由spring.cloud.nacos.config.ext-config[n].data-id中的n決定。數值越大,優先級越高。
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
spring.cloud.nacos.config.shared-dataids 指定了哪些Data Id是共享的(公共的),用逗號分隔
spring.cloud.nacos.config.refreshable-dataids 用於控制哪些Data Id可以動態刷新,如果不配置,則所有的共享數據都不會動態刷新
注意:
- 如果用spring.cloud.nacos.config.shared-dataids配置了多個共享data id,那么它們之間的優先級取決於它們再配置文件中出現的順序,也就是說后面的優先級高於前面的。
- 當使用spring.cloud.nacos.config.shared-dataids時,后面必須帶文件擴展名。可以是 properties 或者 yaml/yml。spring.cloud.nacos.config.file-extension對自定義的data id文件擴展名不起作用。
- 當使用spring.cloud.nacos.config.refreshable-dataids指定哪些data id支持動態刷新時,被指定的這些data id要帶上文件擴展名,換言之,要和之前指定的data-id的一樣
4. 文檔
Spring Cloud Alibaba 特性:
- 流量控制和服務降級:支持WebServlet 、WebFlux 、OpenFeign 、RestTemplate 、Dubbo訪問限制和服務降級功能。 它可以在運行時通過控制台實時修改限流和降級規則,並且還支持限流和降級的監控指標。
- 服務注冊和發現:可以注冊服務,並且客戶端可以使用Spring托管的bean發現實例,自動集成Ribbon。
- 分布式配置:支持分布式系統中的外部配置,配置更改后實時自動刷新。
- RPC服務:擴展Spring Cloud客戶端RestTemplate和OpenFeign以支持調用Dubbo RPC服務。
- 事件驅動:支持構建與共享消息傳遞系統連接的高度可擴展的事件驅動型微服務。
- 分布式事務:支持具有高性能和易用性的分布式事務解決方案。
- 阿里雲對象存儲:大規模,安全,低成本和高度可靠的雲存儲服務。支持隨時隨地在任何應用程序中存儲和訪問任何類型的數據。
https://spring.io/projects/spring-cloud
https://spring.io/projects/spring-cloud-alibaba
https://github.com/alibaba/spring-cloud-alibaba
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html