微服務系列-使用WebFlux的WebClient進行Spring Boot 微服務通訊範例

2023-11-13 15:01:01

公眾號「架構成長指南」,專注於生產實踐、雲原生、分散式系統、巨量資料技術分享。

概述

在之前的教學中,我們看到了使用 RestTemplate 的 Spring Boot 微服務通訊範例
從 5.0 開始,RestTemplate處於維護模式,很快就會被棄用。因此 Spring 團隊建議使用org.springframework.web.reactive.client.WebClient ,它支援同步、非同步和流場景。

在本教學中,我們將學習如何使用WebClient在多個微服務之間進行 REST API 呼叫(同步通訊)。

WebClient是一個非阻塞的響應式使用者端,用於執行 HTTP 請求,通過底層 HTTP 使用者端庫(例如 Reactor Netty)來實現。

要在 Spring boot 專案中使用WebClient,我們必須將Spring WebFlux依賴項新增到類路徑中。

我們需要做什麼

下面將建立兩個微服務,例如 部門服務 和 使用者服務,並且我們將使用WebClient從 使用者服務 到 部門服務 進行 REST API 呼叫 ,以獲取特定的使用者部門資料。

基礎設定

我們在上一篇文章中建立了兩個微服務: 使用 RestTemplate 的 Spring Boot 微服務通訊範例。

第1步:新增Spring WebFlux依賴

開啟user-service專案的pom.xml檔案並新增以下依賴項:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>
		<dependency>
			<groupId>io.netty</groupId>
			<artifactId>netty-resolver-dns-native-macos</artifactId>
			<classifier>osx-aarch_64</classifier>
		</dependency>

可以看到上面還新增了netty-resolver-dns-native-macos的pom,原因是如果不新增此報會丟擲相關異常,問題詳情

第2步:將WebClient設定為Spring Bean

package io.wz.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.client.WebClient;

@SpringBootApplication
public class UserServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }

    @Bean
    public WebClient webClient(){
        return WebClient.builder().build();
    }
}

第三步:注入並使用WebClient呼叫REST API

讓我們注入WebClient並使用它來進行 REST API 呼叫:

 DepartmentDto departmentDto = webClient.get()
                 .uri("http://localhost:8080/api/departments/" + user.getDepartmentId())
                         .retrieve()
                                 .bodyToMono(DepartmentDto.class)
                                         .block();

下面是UserServiceImpl類的完整程式碼, 供大家參考:

package io.wz.userservice.service.impl;

import io.wz.userservice.dto.DepartmentDto;
import io.wz.userservice.dto.ResponseDto;
import io.wz.userservice.dto.UserDto;
import io.wz.userservice.entity.User;
import io.wz.userservice.repository.UserRepository;
import io.wz.userservice.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

@Service
@AllArgsConstructor
public class UserServiceImpl implements UserService {

    private UserRepository userRepository;
    private WebClient webClient;

    @Override
    public User saveUser(User user) {
        return userRepository.save(user);
    }

    @Override
    public ResponseDto getUser(Long userId) {

        ResponseDto responseDto = new ResponseDto();
        User user = userRepository.findById(userId).get();
        UserDto userDto = mapToUser(user);

        DepartmentDto departmentDto = webClient.get()
                .uri("http://localhost:8080/api/departments/" + user.getDepartmentId())
                .retrieve()
                .bodyToMono(DepartmentDto.class)
                .block();
        responseDto.setUser(userDto);
        responseDto.setDepartment(departmentDto);

        return responseDto;
    }

    private UserDto mapToUser(User user){
        UserDto userDto = new UserDto();
        userDto.setId(user.getId());
        userDto.setFirstName(user.getFirstName());
        userDto.setLastName(user.getLastName());
        userDto.setEmail(user.getEmail());
        return userDto;
    }
}

下面執行兩個微服務並進行測試。

測試:啟動兩個微服務

首先啟動部門服務專案,然後啟動使用者服務專案,一旦兩個專案都啟動並在不同的埠上執行。接下來,我們呼叫Get User REST API來測試user-service REST API 對Department-service 的呼叫。

獲取使用者 REST API:


請注意,響應結果包含了使用者的部門。這說明我們已成功使用WebClient從使用者服務到部門服務進行 REST API 呼叫。

結論

在本教學中,我們學習了 如何使用WebClient 在多個微服務之間進行 REST API 呼叫(同步通訊)。

原始碼下載:
github
gitee