SpringCloud元件: GateWay整合Eureka轉發服務請求

恆宇少年發表於2019-05-05

在上一篇文章Spring Cloud GateWay 路由轉發規則介紹中我們講解了SpringCloud Gateway內部提供的斷言、謂語,讓我們可以組合更精確的業務場景進行請求,既然SpringCloud GateWay擔任了閘道器的角色,在之前Zuul可以通過服務名進行自動轉發,SpringCloud Gateway是否可以實現自動轉發呢?

初始化Gateway服務

Spring Cloud Gateway可以根據配置的斷言、謂語進行滿足條件轉發,也可以自動同步服務註冊中心的服務列表進行指定serviceId字首進行轉發,這裡的serviceId是業務服務的spring.application.name配置引數。

SpringCloud 版本控制依賴

SpringCloud的版本依賴新增到pom.xml內,如下所示:

//...
<properties>
  <java.version>1.8</java.version>
  <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<!--Spring Cloud 版本控制-->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring-cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
//...
複製程式碼

我們本章使用Eureka作為服務註冊中心來完成服務請求轉發講解,需要把Spring Cloud Gateway閘道器專案作為一個Client註冊到Eureka Server,先來看下新增的依賴,pom.xml如下所示:

//...
<dependencies>
  <!--Spring Cloud Gateway-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
  </dependency>
  <!--Eureka Client-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>
</dependencies>
//....
複製程式碼

接下來我們需要開啟Gateway服務註冊中心的發現配置,開啟後才能自動同步服務註冊中心的服務列表application.yml配置檔案如下所示:

# 服務名稱
spring:
  application:
    name: spring-cloud-gateway
  # 開啟 Gateway 服務註冊中心服務發現
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
# Eureka Server 配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10000/eureka/
# 配置Gateway日誌等級,輸出轉發細節資訊
logging:
  level:
    org.springframework.cloud.gateway: debug
複製程式碼

配置引數解釋如下所示:

  • spring.application.name:服務名
  • spring.cloud.gateway.discovery.locator.enabled:開啟SpringCloud Gateway的註冊中心發現配置,開啟後可自動從服務註冊中心拉取服務列表,通過各個服務的spring.application.name作為字首進行轉發,該配置預設為false
  • eureka.client.service-url.defaultZone:配置Eureka Server預設的空間地址
  • logging.level.org.springframework.cloud.gateway:設定SpringCloud Gateway日誌等級為debug,用於輸出轉發的細節日誌,方便檢視細節流程。

註冊閘道器到Eureka

在入口類新增對應的註解,開啟服務自動註冊,如下所示:

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudGatewayApplication.class, args);
    }
}
複製程式碼

服務註冊中心

對應上面閘道器配置的Eureka Server的地址,我們需要新增對應的配置,pom.xml如下所示:

//...
<dependencies>
  <!--Eureka Server-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  </dependency>
</dependencies>
//...
複製程式碼

新增依賴後對Eureka Server進行配置,配置檔案application.yml如下所示:

# 服務名
spring:
  application:
    name: sample-eureka-server
# 埠號    
server:
  port: 10000

# Eureka 配置資訊
eureka:
  client:
    service-url:
      defaultZone: http://localhost:${server.port}/eureka/
    fetch-registry: false
    register-with-eureka: false
複製程式碼

這裡我們修改預設的埠號為10000,為了匹配在閘道器專案的配置資訊,至於fetch-registryregister-with-eureka可以去我之前的文章檢視,SpringCloud元件:將服務提供者註冊到Eureka叢集

開啟Eureka Server

我們通過@EnableEurekaServer註解來開啟服務,如下所示:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
複製程式碼

閘道器服務註冊中心我們都已經準備好了,下面我們可以編寫業務邏輯服務,來驗證SpringCloud Gateway具體是否可以根據serviceId進行轉發請求。

單服務

我們簡單編寫一個GET請求地址,輸出字串資訊,pom.xml新增依賴如下所示:

<dependencies>
  <!--Web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!--Eureka Client-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>
</dependencies>
複製程式碼

配置檔案application.yml如下所示:

# 服務名
spring:
  application:
    name: user-service
# 註冊到Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10000/eureka/
# 服務埠號
server:
  port: 9090

複製程式碼

配置該服務的服務名稱為user-service,這裡對應SpringCloud GatewayserviceId

註冊服務到Eureka

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class UserServiceApplication {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(UserServiceApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
        logger.info("「「「「「使用者服務啟動完成.」」」」」");
    }

    @GetMapping(value = "/index")
    public String index() {
        return "this is user index";
    }
}
複製程式碼

user-service提供了/index的請求地址,當訪問時,會對應輸出this is user index

測試服務請求轉發

接下來我們進行驗證,測試順序如下所示:

第一步:啟動Eureka Server

第二步:啟動SpringCloud Gateway

啟動成功後控制檯會列印響應的註冊到Eureka的日誌資訊,如下所示:

DiscoveryClient_SPRING-CLOUD-GATEWAY/192.168.1.56:spring-cloud-gateway: registering service...
Netty started on port(s): 8080
複製程式碼

SpringCloud Gateway內部通過Netty完成WebServer的請求轉發。

第三步:啟動user-service服務

啟動成功後控制檯列印相應註冊日誌,如下所示:

DiscoveryClient_USER-SERVICE/192.168.1.56:user-service:9090: registering service...
Tomcat started on port(s): 9090 (http) with context path ''
複製程式碼

第四步:測試訪問

SpringCloud Gateway會每間隔30秒進行重新拉取服務列表後路由重定義操作,日誌資訊如下所示:

# Spring Cloud Gateway
RouteDefinition CompositeDiscoveryClient_SPRING-CLOUD-GATEWAY applying {pattern=/SPRING-CLOUD-GATEWAY/**} to Path
RouteDefinition CompositeDiscoveryClient_SPRING-CLOUD-GATEWAY applying filter {regexp=/SPRING-CLOUD-GATEWAY/(?<remaining>.*), replacement=/${remaining}} to RewritePath
RouteDefinition matched: CompositeDiscoveryClient_SPRING-CLOUD-GATEWAY
# User Service
RouteDefinition CompositeDiscoveryClient_USER-SERVICE applying {pattern=/USER-SERVICE/**} to Path
RouteDefinition CompositeDiscoveryClient_USER-SERVICE applying filter {regexp=/USER-SERVICE/(?<remaining>.*), replacement=/${remaining}} to RewritePath
RouteDefinition matched: CompositeDiscoveryClient_USER-SERVICE
複製程式碼

通過上面的日誌資訊我們已經可以推斷出SpringCloud Gateway對映spring.application.name的值作為服務路徑字首,不過是大寫的,預計我們可以通過http://localhost:8080/USER-SERVICE/index訪問到對應的資訊。

訪問測試如下:

~ curl http://localhost:8080/USER-SERVICE/index
this is user index
複製程式碼

通過閘道器訪問具體服務的格式:http://閘道器IP:閘道器埠號/serviceId/**

多服務的負載均衡

如果Eureka Server上有兩個相同serviceId的服務時,SpringCloud Gateway會自動完成負載均衡。

複製一個user-service服務例項,修改服務埠號,如下所示:

# 服務名稱
spring:
  application:
    name: user-service
# Eureka Server
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10000/eureka/
# 服務埠號
server:
  port: 9091
複製程式碼

在複製的專案內使用相同的spring.application.name保持serviceId一致,只做埠號的修改,為了區分GateWay完成了負載均衡,我們修改/index請求的返回內容如下所示:

@GetMapping(value = "/index")
public String index() {
  return "this is user lb index";
}
複製程式碼

訪問http://localhost:8080/USER-SERVICE/index,輸出內容如下所示:

this is user lb index
this is user index
this is user lb index
this is user index
...
複製程式碼

總結

通過本章的講解,我們已經對SpringCloud Gateway的轉發有一個簡單的理解,通過從服務註冊中心拉取服務列表後,自動根據serviceId對映路徑字首,同名服務多例項時會自動實現負載均衡。

原始碼位置

Giteegitee.com/hengboy/spr…

ApiBootgitee.com/hengboy/api…github.com/hengboy/api…

相關文章