歡迎訪問我的GitHub
https://github.com/zq2599/blog_demos
內容:所有原創文章分類匯總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等;
本篇概覽
- 本文是《Spring Cloud Gateway實戰》系列的第二篇,通過前文咱們了解到Spring Cloud Gateway的核心是路由配置,然后在本地application.yml中配置了一條路由,但這種修改本地組態檔的方式缺乏靈活性,未必能滿足靈活多變的業務需求,因此,本篇的目的就是找出本地配置之外的其他配置方式來,滿足各種實際需求;
- 總的來說以下三種方式都是常用的:
- 目標地址支持用服務名(取代之前的IP+埠);
- 支持在nacos上配置;
- 支持寫代碼的方式配置;
- 另外還有一種更加靈活的配置方式:動態代理,因為涉及到不少的代碼所以會單獨出一篇文章詳細介紹
原始碼下載
- 本篇實戰中的完整原始碼可在GitHub下載到,地址和鏈接資訊如下表所示(https://github.com/zq2599/blog_demos):
| 名稱 | 鏈接 | 備注 |
|---|---|---|
| 專案主頁 | https://github.com/zq2599/blog_demos | 該專案在GitHub上的主頁 |
| git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該專案原始碼的倉庫地址,https協議 |
| git倉庫地址(ssh) | [email protected]:zq2599/blog_demos.git | 該專案原始碼的倉庫地址,ssh協議 |
- 這個git專案中有多個檔案夾,本篇的原始碼在spring-cloud-tutorials檔案夾下,如下圖紅框所示:

準備作業
-
正式開始前需要再做一點準備作業,整個《Spring Cloud Gateway實戰》系列中,所有請求最后都會被路由到provider-hello這個web上去,該服務目前只有一個web介面/hello/str,現在咱們再給它增加一個,后面的實戰會用到
-
新增加的web介面來自LBTest.java,可見非常簡單:
package com.bolingcavalry.provider.controller;
import com.bolingcavalry.common.Constants;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
@RestController
@RequestMapping("/lbtest")
public class LBTest {
private String dateStr(){
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
}
/**
* 回傳字串型別
* @return
*/
@GetMapping("/str")
public String helloStr() {
return Constants.LB_PREFIX + ", " + dateStr();
}
}
- 上述代碼中的Constants.LB_PREFIX來自子工程common:
package com.bolingcavalry.common;
public interface Constants {
String HELLO_PREFIX = "Hello World";
String LB_PREFIX = "Load balance";
}
-
寫完代碼后,先確保nacos已經啟動
-
在啟動provider-hello工程,啟動成功后去看nacos,確認已經注冊:

- 準備完畢,可以開始實戰了
目標地址支持用服務名(取代之前的IP+埠)
- 咱們從最簡單的開始,先看前文的路由配置,如下圖紅框,目標地址是IP+埠:

-
玩過Spring Cloud的您自然看出了問題所在:沒有注冊發現,確實,這樣將地址和埠寫死在組態檔中是不合適的,咱們先來解決這個問題;
-
新增名為gateway-by-loadbalance的子工程,其pom.xml中的依賴情況如下,可見重點是spring-cloud-starter-loadbalancer:
<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 路由策略使用lb的方式是,這個依賴一定要有 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--nacos:注冊中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
-
啟動類的代碼省去了(和前文的一樣)
-
配置資訊如下,重點是uri的值lb://provider-hello,用了前綴lb:,后面的provider-hello就是在nacos注冊的服務名:
server:
#服務埠
port: 8085
spring:
application:
name: gateway-by-loadbalance
cloud:
nacos:
# 注冊中心的配置
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: path_route_lb
uri: lb://provider-hello
predicates:
- Path=/lbtest/**
- 單元測驗類:
package com.bolingcavalry.gateway;
import com.bolingcavalry.common.Constants;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
@ExtendWith(SpringExtension.class)
@AutoConfigureWebTestClient
public class HelloTest {
@Autowired
private WebTestClient webClient;
@Test
void testLoadBalance() {
webClient.get()
.uri("/lbtest/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 驗證狀態
.expectStatus().isOk()
// 驗證結果,注意結果是字串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.LB_PREFIX)));
}
}
- 運行單元測驗,通過,可見上述配置可以通過前綴lb:準確找到服務:

支持在nacos上配置
-
將所有配置資訊寫在application.yml中有個問題:不能遠程配置,這在應用數量較多的場景就不方便了,好在nacos提供了遠程配置的能力,應用啟動后可以從nacos取得自己的配置資訊,咱們來試試
-
新增名為gateway-nacos-config的子工程,其pom.xml中的依賴情況如下,請注意里面的中文注釋,每指明了每一個依賴的作用:
<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 使用bootstrap.yml的時候,這個依賴一定要有 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<!-- 路由策略使用lb的方式是,這個依賴一定要有 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--nacos:配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--nacos:注冊中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
- 本地的組態檔bootstrap.yml,非常簡單,就是nacos的地址和遠程配置資訊:
spring:
application:
name: gateway-nacos-config
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yml
group: DEFAULT_GROUP
- 接下來再nacos增加一個組態檔,操作如下圖紅框:

- 增加一個配置,要注意的地方如下(配置資訊的文本稍后給出,便于復制):

- 上圖中完整的配置資訊如下:
server:
port: 8083
spring:
cloud:
gateway:
routes:
- id: path_route_addr
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
- id: path_route_lb
uri: lb://provider-hello
predicates:
- Path=/lbtest/**
- 測驗類中的兩個測驗方法如下所示,和前面沒有任何區別:
@Test
void testHelloPredicates() {
webClient.get()
.uri("/hello/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 驗證狀態
.expectStatus().isOk()
// 驗證結果,注意結果是字串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.HELLO_PREFIX)));
}
@Test
void testLoadBalance() {
webClient.get()
.uri("/lbtest/str")
.accept(MediaType.APPLICATION_JSON)
.exchange()
// 驗證狀態
.expectStatus().isOk()
// 驗證結果,注意結果是字串格式
.expectBody(String.class).consumeWith(result -> assertTrue(result.getResponseBody().contains(Constants.LB_PREFIX)));
}
- 運行單元測驗類,測驗通過,證明從nacos獲取組態檔成功:

寫代碼的方式配置
-
前面的幾個例子,路由資訊都是寫在組態檔中的,其實還有一種方式:寫代碼配置路由,能自己寫代碼來配置,這靈活性就更強了
-
新增名為gateway-by-code的子工程,其pom.xml檔案參照前面工程的即可
-
接下來的本例的重點,在配置類中增加一個RouteLocator型別的bean,通過以下代碼即可增加一個路由:
package com.bolingcavalry.gateway.cofig;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customizeRoute(RouteLocatorBuilder builder) {
return builder
.routes()
.route(
// 第一個引數是路由的唯一身份
"path_route_lb",
// 第二個引數是個lambda實作,
// 設定了配套條件是按照請求路徑匹配,以及轉發地址,
// 注意lb://表示這是個服務名,要從
r -> r.path("/lbtest/**").uri("lb://provider-hello")
)
.build();
}
}
- 上述代碼只配置了一個路由,還有一個在組態檔中,這樣就能驗證代碼和組態檔能不能同時生效了:
server:
#服務埠
port: 8084
spring:
application:
name: gateway-by-code
cloud:
nacos:
discovery:
# nacos服務地址
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: path_route_addr
uri: http://127.0.0.1:8082
predicates:
- Path=/hello/**
-
測驗類和之前工程的一模一樣,就不占用篇幅了,依舊是兩個測驗方法testHelloPredicates和testLoadBalance
-
執行單元測驗可以順利通過,證明代碼配置路由沒有問題:

- 至此,負載均衡、nacos配置、代碼配置的實體咱們都嘗試過了,它們合起來會給實際生存環境的配置帶來很大的方便,希望能夠給您一些參考
缺陷和解決之道
- 上述配置方式雖多,但有一個共同的問題:每當配置變動后,Gateway應用需要重啟才能生效,這在請求不間斷的生產環境是難以接受的
- 為了讓最新的路由配置能在Gateway應用不重啟的前提下生效,接下來的文章咱們一起去探索動態路由是如何實作的
你不孤單,欣宸原創一路相伴
- Java系列
- Spring系列
- Docker系列
- kubernetes系列
- 資料庫+中間件系列
- DevOps系列
歡迎關注公眾號:程式員欣宸
微信搜索「程式員欣宸」,我是欣宸,期待與您一同暢游Java世界...
https://github.com/zq2599/blog_demos
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/353581.html
標籤:其他
