概述
框架版本
| 框架名稱 | 版本號 |
|---|---|
| Spring Boot | 2.2.7.RELEASE |
| Spring Cloud | Hoxton.SR6 |
| Spring Cloud Alibaba | 2.2.6.RELEASE |
基礎(chǔ)依賴
| 依賴名稱 | 說明 |
|---|---|
| spring-boot-starter-actuator | 提供微服務(wù)的監(jiān)控支持 |
| spring-cloud-starter-alibaba-nacos-discovery | 提供基于 Nacos 的注冊中心支持,完成服務(wù)的注冊與發(fā)現(xiàn)。 |
| spring-cloud-starter-alibaba-nacos-config | 提供基于 Nacos 的配置中心支持,完成服務(wù)的配置文件管理。 |
基礎(chǔ)支撐環(huán)境
基礎(chǔ)支撐環(huán)境需要開發(fā)者自行安裝,安裝方法請參考其他文檔或網(wǎng)絡(luò)上的一些資料。
| 環(huán)境 | 版本 | 說明 |
|---|---|---|
| Nacos | 2.0.2 | 由阿里云提供的開源微服務(wù)引擎,主要提供微服務(wù)的注冊、發(fā)現(xiàn)、配置、Bus等功能。 |
| Sentinel Dashboard | 1.8.2 | 由阿里云提供的 Sentinel 控制臺,為開發(fā)者實現(xiàn)限流、降級等操作提供可視化界面。 |
業(yè)務(wù)微服務(wù)搭建
業(yè)務(wù)微服務(wù)是為分布式系統(tǒng)提供業(yè)務(wù)支持,是開發(fā)者編寫代碼最多也是最頻繁的服務(wù)。
創(chuàng)建微服務(wù)項目
打開 Intellij IDEA,找到File -> New -> Project,會打開如下窗口:

點擊下一步,開始填寫項目的基本信息,我們以創(chuàng)建用戶服務(wù)為例,配置如下:

如果不了解各個配置項的含義,請先學(xué)習(xí) Maven,然后再來看此文檔。配置完成后點擊
Finish完成項目創(chuàng)建。創(chuàng)建完成后,項目的目錄結(jié)構(gòu)如下:
創(chuàng)建必須的文件和包
創(chuàng)建配置文件
在src/main/resources目錄下分別創(chuàng)建application.yaml和bootstrap.yaml配置文件,application 和 bootstrap 的區(qū)別就是 bootstrap 的加載優(yōu)先于 application,并且 bootstrap 中的配置不能被本地屬性覆蓋。因此,當(dāng)我們使用配置中心來管理配置時 bootstrap.yaml必須創(chuàng)建。當(dāng)然,如果我們所有的想要將所有的配置都依托于配置中心來管理,我們也可以只創(chuàng)建一個bootstrap.yaml配置文件。
總結(jié):一些公共屬性,在運(yùn)行期可以通過程序來修改的配置在application.yaml文件中,如:業(yè)務(wù)參數(shù)等。而作為引導(dǎo)加載的一些不可覆蓋的屬性配置在bootstrap.yaml文件中,如:數(shù)據(jù)庫配置、加解密的密鑰等。不過一般情況下建議,可以修改的屬性采用數(shù)據(jù)庫來存儲,比如建立一個系統(tǒng)參數(shù)表。
創(chuàng)建基礎(chǔ)包和啟動類
基礎(chǔ)包是當(dāng)前微服務(wù)所使用包的根,后續(xù)所有創(chuàng)建類和子包都包含在根包下。找到src/main/java目錄,創(chuàng)建一個名為com.cloud的根包,一般情況下除了遵循域名倒寫的規(guī)范外,盡量保證名稱與pom.xml的groupId一致,增強(qiáng)代碼的可移植性。
在根包com.cloud下創(chuàng)建一個AppStart.java的類作為啟動類,注意:啟動的類的名稱不要太過于奇葩,能夠見名知意即可,另外,所有微服務(wù)的啟動類名稱最好保持統(tǒng)一,這樣便于團(tuán)隊協(xié)作時減少溝通。
配置相關(guān)依賴
打開項目根目錄下的pom.xml文件,配置所需的依賴 jar 包和 maven 的相關(guān)插件。
基本的pom.xml文件結(jié)構(gòu)如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cloud</groupId>
<artifactId>cloud-user-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- pom 文件的屬性配置 -->
<properties>
</properties>
<!-- Spring Boot 版本控制(統(tǒng)一SpringBoot組件版本) -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath />
</parent>
<!-- 依賴管理器 -->
<dependencyManagement>
</dependencyManagement>
<!-- 配置相關(guān)依賴 -->
<dependencies>
</dependencies>
<!-- Maven 的構(gòu)建配置 -->
<build>
<!-- 配置相關(guān)插件 -->
<plugins>
</plugins>
</build>
</project>
配置文件結(jié)構(gòu)說明:
- properties:一般用于配置依賴的版本信息或一些配置的屬性參數(shù);
- parent:配置當(dāng)前 Maven 項目的父依賴,這里一般配置的是
spring-boot-starter-parent; - dependencyManagement:依賴管理器,一般用于配置 Spring Cloud 的
dependencies,為后續(xù)使用 Spring Cloud 相關(guān)組件提供統(tǒng)一的版本; - dependencies:依賴列表,這里配置的都是具體的依賴,比如我們使用的 web支持、數(shù)據(jù)庫支持、工具包等;
- build:Maven 的構(gòu)建配置,一般這里會配置一些打包插件和打包時的一些規(guī)則,比如 springboot 的打包插件、maven 的打包插件、打包時跳過單元測試等。
完整的配置文件如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cloud</groupId>
<artifactId>cloud-user-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- pom 文件的屬性配置 -->
<properties>
<java.version>1.8</java.version>
<charset>UTF-8</charset>
</properties>
<!-- Spring Boot 版本控制(統(tǒng)一SpringBoot組件版本) -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath />
</parent>
<!-- 依賴管理器 -->
<dependencyManagement>
<dependencies>
<!-- Spring Cloud 原生依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Alibaba 依賴 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 配置相關(guān)依賴 -->
<dependencies>
<!-- Spring Boot 監(jiān)視器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Spring Boot Web 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Nacos 注冊中心依賴 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Spring Cloud Nacos 配置中心依賴 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
<!-- Maven 的構(gòu)建配置 -->
<build>
<!-- 配置相關(guān)插件 -->
<plugins>
<!-- 打包時跳過單元測試 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<!-- Spring Boot Maven 打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Maven 打包插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${charset}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
上文中只是包含了能夠支持 Spring Cloud 微服務(wù)最基本的依賴,至于其他的一些依賴并不是所有服務(wù)都需要,后面講到具體的知識點時會單獨(dú)介紹。
配置 Nacos
實際開發(fā)過程中,我們可能會共用 Nacos 服務(wù),所以本章節(jié)介紹搭建一個 Spring Cloud 的微服務(wù)需要在 Nacos 上配置哪些東西。
注意:同一個項目,最好保證在同一個命名空間,同一個組下,否則無法實現(xiàn)服務(wù)調(diào)用。雖然有其他辦法解決,但處理起來比較麻煩。
創(chuàng)建命名空間
如果我們很多個項目共用一個 Nacos 服務(wù),可以在 Nacos 中創(chuàng)建相應(yīng)的命名空間來區(qū)分和管理微服務(wù)。進(jìn)入 Nacos 控制臺,找到命名空間,點擊新建命名空間,填入?yún)?shù)說明如下:
- 命名空間ID(不填則自動生成):命名空間的唯一標(biāo)識,如果不填寫,系統(tǒng)會默認(rèn)使用 UUID 作為命名空間ID。此處一般都選擇自動生成,如果為了方便記憶也可以手工填寫。
- 命名空間名:這里填寫的是命名空間的名字,此名稱會顯示在其他的一些配置面板上。
- 描述:這里填寫的是對命名空間的一個簡單描述。
本次我們創(chuàng)建了一個cloud的命名空間。
創(chuàng)建微服務(wù)的配置文件
在 Nacos 控制臺找到配置管理 -> 配置列表,上方選擇我們上一步創(chuàng)建好的命名空間,然后點擊最右側(cè)的+按鈕,如下圖所示:

在創(chuàng)建頁面需要填入的參數(shù)說明如下:
- Data ID:配置文件的唯一標(biāo)識,一般格式為:微服務(wù)名稱-部署環(huán)境類型.后綴名。實際使用中后綴也可以省略不寫。
- Group:配置文件的分組,可以對配置文件進(jìn)行分組管理,其實主要是為了便于查詢。默認(rèn)為:DEFAULT_GROUP。
- 描述:配置文件的描述信息。
- 配置格式:包含 TEXT、JSON、XML、YAML、HTML、Properties 幾種配置書寫格式。
- 配置內(nèi)容:具體的配置內(nèi)容。
我們以創(chuàng)建用戶服務(wù)的配置文件為例,具體填寫的參數(shù)如下:
- Data ID:cloud-user-service-dev.yaml,其中 dev 是指我們的開發(fā)環(huán)境,后面會介紹它在框架搭建中的作用。
- Group:BUSINESS_GROUP,這里我們定一個了一個業(yè)務(wù)組,如果微服務(wù)不多(20個以內(nèi))則不需要單獨(dú)去指定組。
- 描述:用戶服務(wù)配置。
- 配置格式:YAML。
- 配置內(nèi)容:test: hello test,此配置只是為了測試,后面我們會將具體微服務(wù)的配置移植到這里。
配置完成后點擊發(fā)布按鈕保存配置文件信息。
編寫bootstrap.yaml配置文件
配置文件內(nèi)容如下:
server:
port: 10001
spring:
profiles:
active: dev
application:
name: cloud-user-service
output:
ansi:
enabled: always
---
spring:
profiles: dev
cloud:
nacos:
server-addr: 172.16.1.180:8848
discovery:
namespace: 02ed4eca-207e-4e27-9e9e-b486080f6f1c
config:
namespace: 02ed4eca-207e-4e27-9e9e-b486080f6f1c
file-extension: yaml
prefix: ${spring.application.name}
配置說明
server.port:Spring Boot 內(nèi)置容器的端口號,如果是 Tomcat 則為 Tomcat 端口號。
spring.profiles.active:當(dāng)前激活的配置,dev-開發(fā)環(huán)境。上線時還會添加 pro-生產(chǎn)環(huán)境。
spring.application.name:微服務(wù)名稱。
spring.output.ansi.enabled:一般取值為
always,即輸出帶彩色的日志。spring.profiles:配置文件標(biāo)識,
spring.profiles.active的值與此對應(yīng)。spring.cloud.nacos.server-addr:Nacos 服務(wù)的地址。
spring.cloud.nacos.discovery.namespace:注冊中心的命名空間,即注冊到哪個命名空間下,此處填寫的是命名空間ID。
spring.cloud.nacos.discovery.group:注冊中心組名,即注冊到哪個組下。
spring.cloud.nacos.config.namespace:配置中心的命名空間,即拉取哪個命名空間下的配置。
spring.cloud.nacos.config.file-extension:配置中心創(chuàng)建的配置文件擴(kuò)展名。
spring.cloud.nacos.config.prefix:配置中心創(chuàng)建的配置文件前綴,一般為微服務(wù)名稱。
特別說明:prefix、profiles、file-extension構(gòu)成一個完整的配置文件名,此名稱與配置中心創(chuàng)建的配置文件 Data ID 要保持一致。按照上文的配置方式,即配置中心的 Data ID為:cloud-user-service-dev.yaml。
編寫啟動類
在根包com.cloud下創(chuàng)建一個AppStart的類,完整代碼如下:
package com.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication(scanBasePackages = {"com.cloud"})
@EnableDiscoveryClient
public class AppStart {
public static void main(String[] args) {
SpringApplication.run(AppStart.class, args);
}
}
注解說明
@SpringBootApplication(scanBasePackages = {"com.cloud"})注解指定了 Spring Boot 應(yīng)用程序的掃描的根包,即我們最開始的時候創(chuàng)建的根包路徑。@EnableDiscoveryClient注解的作用是在微服務(wù)中開啟注冊中心客戶端。
微服務(wù)測試
創(chuàng)建一個com.cloud.api.TestApi類,代碼如下:
package com.cloud.api;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test/*")
public class TestApi {
@Value("${test:123}")
private String test;
@GetMapping("hello")
public Object testCase() {
return test;
}
}
代碼中讀取了配置中心的配置文件內(nèi)容,并通過接口返回。代碼編寫完成后,啟動微服務(wù)。啟動之后,進(jìn)入 Nacos 控制臺,找到服務(wù)管理 -> 服務(wù)列表,如果看到微服務(wù)注冊到列表中,即說明微服務(wù)的注冊發(fā)現(xiàn)功能可用。頁面如下:

打開瀏覽器輸入:
http://127.0.0.1/test/hello,顯示頁面如下:
頁面中打印的內(nèi)容是我們在前面創(chuàng)建的配置文件中的配置內(nèi)容,如果一致,說明配置中心功能可用。
網(wǎng)關(guān)微服務(wù)搭建
本次使用的是 Spring Cloud Gateway 作為微服務(wù)網(wǎng)關(guān)。
網(wǎng)關(guān)微服務(wù)的搭建相對于業(yè)務(wù)微服務(wù)的搭建大同小異,搭建步驟可以參考業(yè)務(wù)微服務(wù)的搭建步驟。本章節(jié)重點介紹不同的部分。
配置相關(guān)依賴
注意:Gateway 使用的是 Netty 提供網(wǎng)絡(luò)服務(wù),并且使用 Webflux 實現(xiàn)的響應(yīng)式編程。因此在 pom.xml 文件中不可以配置
spring-boot-starter-web。
按照業(yè)務(wù)微服務(wù)的搭建方法新建一個springcloud-gateway項目,然后在 pom.xml 配置文件中添加 Gateway 依賴
<!-- Spring Cloud Gateway 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
編寫bootstrap.yaml配置文件
本次我們以前面創(chuàng)建的用戶服務(wù)為例,來實現(xiàn)網(wǎng)關(guān)的路由。
server:
port: 9527
spring:
profiles:
active: dev
application:
name: springcloud-gateway
output:
ansi:
enabled: always
---
spring:
profiles: dev
cloud:
nacos:
server-addr: 172.16.1.180:8848
discovery:
namespace: 02ed4eca-207e-4e27-9e9e-b486080f6f1c
register-enabled: false
config:
file-extension: yaml
prefix: ${spring.application.name}
namespace: 02ed4eca-207e-4e27-9e9e-b486080f6f1c
gateway:
routes:
- id: cloud-user-service
uri: lb://cloud-user-service
predicates:
- Path=/user/**
default-filters:
- StripPrefix=1
配置說明:
spring.cloud.nacos.discovery.register-enabled:是否開啟服務(wù)注冊,如果為 false,則只發(fā)現(xiàn)不注冊。網(wǎng)關(guān)不需要讓其他服務(wù)發(fā)現(xiàn),但要能夠發(fā)現(xiàn)其他服務(wù),因此這里設(shè)置為 false,即不向注冊中心注冊網(wǎng)關(guān)服務(wù)。
-
spring.cloud.gateway.routes:網(wǎng)關(guān)路由配置
- id:路由ID,一般為微服務(wù)名稱,沒有實際的作用,只是作為路由規(guī)則的唯一標(biāo)識。
- uri:路由地址,支持多種協(xié)議。其中
lb://使用的是負(fù)載均衡協(xié)議,因此后面的地址為要路由到的微服務(wù)名字,因為對微服務(wù)進(jìn)行負(fù)載是很常見的,如果使用 http 協(xié)議,則需要為每個負(fù)載節(jié)點配置路由規(guī)則。如果使用負(fù)載均衡協(xié)議,則只需要為服務(wù)創(chuàng)建路由規(guī)則,而無需關(guān)心具體的負(fù)載節(jié)點。此協(xié)議也是最常用的協(xié)議。 - predicates:路由斷言,一個路由規(guī)則中可以有很多個斷言,這里的
- Path就是其中一種,代表路徑匹配斷言。其他的規(guī)則官網(wǎng)上都有,可以自己去查閱。
-
spring.cloud.gateway.default-filters:網(wǎng)關(guān)的默認(rèn)過濾器,此過濾器對有所有路由規(guī)則有效,如果是但對為某個路由規(guī)則編寫過濾器,可以在
routes下配置filters。- StripPrefix:跳過前綴,其值是指訪問路徑的 level,比如:/user/test/hello,如果 StripPrefix 為 1,則實際訪問微服務(wù)的路徑為 /test/hello,即第一級被跳過。默認(rèn)為0,如果為 0,則通過網(wǎng)關(guān)訪問到微服務(wù)的實際路徑為 /user/test/hello,如果微服務(wù)沒有提供此路徑的接口,則返回 404。
網(wǎng)關(guān)測試
創(chuàng)建一個com.cloud.filter.TestFilter的過濾器類,具體代碼如下:
package com.cloud.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 測試過濾器
*/
@Component
public class TestFilter implements GlobalFilter, Ordered {
/**
* 過濾規(guī)則
* @param exchange 信息交換對象,內(nèi)部包含 HTTP 請求的相關(guān)實例
* @param chain 過濾鏈
* @return 返回 Mono 對象
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 此處編寫過濾規(guī)則
System.out.println("==========> 我是測試過濾器");
return chain.filter(exchange);
}
/**
* 排序規(guī)則
* @return 返回排序編號(值越小,執(zhí)行順序越早)
*/
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
實際開發(fā)中,我們?nèi)绻枰帉懢唧w的過濾規(guī)則都按照此方法編寫。代碼編寫完成后,啟動網(wǎng)關(guān)服務(wù)。修改用戶服務(wù)的測試接口代碼如下:
package com.cloud.api;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test/*")
public class TestApi {
@Value("${test:123}")
private String test;
@GetMapping("hello")
public Object testCase() {
return "用戶服務(wù)返回:" + test;
}
}
這樣,我們在通過網(wǎng)關(guān)路由時,就可以清楚的看到是否真的調(diào)用了用戶服務(wù)的接口。修改完畢后記得重啟用戶服務(wù)。
打開瀏覽器,輸入http://127.0.0.1:9527/user/test/hello,返回如下頁面:

從頁面中,我們可以看到,網(wǎng)關(guān)確實調(diào)用了用戶服務(wù),也正常返回了用戶服務(wù)測試接口的信息。接下來查看日志輸出,如下圖所示:

這里可以看到,我們在網(wǎng)關(guān)過濾器輸出的一段話,在控制臺被打印出來了,證明我們編寫的過濾器也是可用的。