最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?WebFlux?與?WebClient?使用指南及最佳實踐

 更新時間:2025年07月03日 15:47:15   作者:千層冷面  
WebClient是Spring WebFlux模塊提供的非阻塞、響應(yīng)式HTTP客戶端,基于Project Reactor實現(xiàn),適用于高并發(fā)場景spring?webclient,本文給大家介紹Spring?WebFlux與WebClient使用指南及最佳實踐,感興趣的朋友一起看看吧

Spring WebFlux 與 WebClient 使用指南

1. WebClient 概述

WebClient 是 Spring WebFlux 模塊提供的非阻塞、響應(yīng)式 HTTP 客戶端,基于 Project Reactor 實現(xiàn),適用于高并發(fā)場景。
核心優(yōu)勢

  • 支持異步非阻塞 I/O,提升吞吐量。
  • 鏈式 API 設(shè)計,便于組合操作。
  • 集成 Spring 生態(tài),支持自動編解碼(JSON、XML)。

2. 核心依賴配置

pom.xml 中添加依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

3. WebClient 的創(chuàng)建與配置

3.1 全局配置(推薦)

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() {
        return WebClient.builder()
            .baseUrl("https://api.example.com") // 基礎(chǔ) URL
            .defaultHeader("Accept", "application/json")
            .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create()
                    .responseTimeout(Duration.ofSeconds(30)) // 響應(yīng)超時
            )
            .build();
    }
}

3.2 臨時創(chuàng)建(按需使用)

WebClient client = WebClient.create("https://api.example.com");

4. 發(fā)送 HTTP 請求

4.1 GET 請求(攜帶 Token)

public Mono<User> getUser(String id, String token) {
    return webClient.get()
        .uri("/users/{id}", id) // 路徑參數(shù)
        .header("Token-Test", token) // 自定義 Token
        .retrieve()
        .bodyToMono(User.class); // 解析為對象
}

4.2 POST 請求(發(fā)送數(shù)組 Body)

public Mono<String> postUsers(List<User> users, String token) {
    return webClient.post()
        .uri("/users/batch")
        .header("Token-Test", token)
        .contentType(MediaType.APPLICATION_JSON)
        .bodyValue(users) // 發(fā)送 List 集合
        .retrieve()
        .bodyToMono(String.class);
}

5. 錯誤處理

5.1 HTTP 錯誤處理(onStatus)

.onStatus(HttpStatus::isError, response ->
    response.bodyToMono(String.class)
        .flatMap(errorBody -> {
            String msg = String.format("狀態(tài)碼: %d, 錯誤信息: %s", 
                response.rawStatusCode(), errorBody);
            log.error(msg);
            return Mono.error(new ServiceException(msg));
        })
)

5.2 非 HTTP 錯誤處理(doOnError)

.doOnError(error -> {
    if (!(error instanceof ServiceException)) {
        log.error("非 HTTP 錯誤: {}", error.getMessage());
    }
})

6. 同步與異步調(diào)用

6.1 異步調(diào)用(subscribe)

webClient.get()
    .uri("/data")
    .retrieve()
    .bodyToMono(String.class)
    .subscribe(
        data -> log.info("成功: {}", data),
        error -> log.error("失敗: {}", error)
    );

6.2 同步調(diào)用(block,僅用于測試或特殊場景)

try {
    String result = webClient.get()
        .uri("/data")
        .retrieve()
        .bodyToMono(String.class)
        .block(Duration.ofSeconds(10)); // 阻塞等待
} catch (Exception e) {
    log.error("請求失敗", e);
}

7. 統(tǒng)一響應(yīng)結(jié)構(gòu)

7.1 定義統(tǒng)一響應(yīng)類

public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(200, "Success", data);
    }
    public static <T> ApiResponse<T> error(int code, String message) {
        return new ApiResponse<>(code, message, null);
    }
}

7.2 轉(zhuǎn)換響應(yīng)

public Mono<ApiResponse<User>> getUser(String id) {
    return webClient.get()
        .uri("/users/{id}", id)
        .retrieve()
        .bodyToMono(User.class)
        .map(ApiResponse::success) // 包裝為成功響應(yīng)
        .onErrorResume(e -> 
            Mono.just(ApiResponse.error(500, e.getMessage()))
        );
}

8. 日志與監(jiān)控

8.1 成功日志

.doOnSuccess(response -> 
    log.info("請求成功: {}", response)
)

8.2 錯誤日志

.doOnError(error -> 
    log.error("請求失敗: {}", error.getMessage())
)

9. 高級配置

9.1 超時與重試

.clientConnector(new ReactorClientHttpConnector(
    HttpClient.create()
        .responseTimeout(Duration.ofSeconds(30)) // 響應(yīng)超時
)
.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))) // 指數(shù)退避重試

9.2 連接池配置

HttpClient.create()
    .baseUrl("https://api.example.com")
    .tcpConfiguration(tcpClient -> 
        tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
    )

10. 常見問題與最佳實踐

10.1 避免手動調(diào)用subscribe

  • 錯誤示例
    // Service 層中手動調(diào)用 subscribe(不推薦)
    public void sendData() {
        webClient.post().subscribe(); // 可能導(dǎo)致資源泄漏
    }
  • 正確做法
    在 Controller 或調(diào)用方返回 Mono/Flux,由框架處理訂閱。

10.2 統(tǒng)一異常處理

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Mono<ApiResponse<?>> handleServiceException(ServiceException e) {
        return Mono.just(ApiResponse.error(500, e.getMessage()));
    }
}

10.3 性能優(yōu)化

  • 復(fù)用 WebClient 實例:避免頻繁創(chuàng)建新實例。
  • 合理設(shè)置超時:根據(jù)接口 SLA 調(diào)整響應(yīng)和連接超時。

附錄:完整代碼示例

發(fā)送 POST 請求并處理錯誤

public Mono<ApiResponse<String>> syncData(List<User> users, String token) {
    String uri = UriComponentsBuilder.fromUriString("https://api.example.com")
        .path("/batch")
        .queryParam("source", "web")
        .queryParamIfPresent("type", Optional.ofNullable("test".equals(activeProfile) ? "test" : null))
        .build()
        .toUriString();
    return webClient.post()
        .uri(uri)
        .header("Token-Test", token)
        .headers(headers -> {
             if ("test".equals(activeProfile)) {
                 headers.add("type", "test"); // 僅測試環(huán)境添加
             }
         })
        .contentType(MediaType.APPLICATION_JSON)
        .bodyValue(users)
        .retrieve()
        .onStatus(HttpStatus::isError, response ->
                response.bodyToMono(String.class)
                        .flatMap(error -> {
                            String msg = String.format("狀態(tài)碼:%d, 錯誤信息: %s", response.rawStatusCode(), error);
                            log.error(msg);
                            return Mono.error(new RuntimeException(msg));
                        })
        )
        .bodyToMono(ApiResponse.class)  // 解析為自定義響應(yīng)對象
         // 檢查業(yè)務(wù)狀態(tài)碼
        .flatMap(result -> {
            if (result.getStatusCode() != 200) {
                String msg = String.format("業(yè)務(wù)錯誤: code=%d, message=%s",
                        result.getStatusCode(), result.getMessage());
                log.error(msg);
                return Mono.error(new ServiceException(msg));
            }
            return Mono.just(result);
        })
         // 成功記錄日志
        .doOnSuccess(success -> log.info("請求成功"))
         // 失敗記錄日志
        .doOnError(error -> log.error("失敗", error.getMessage()))
        .onErrorResume(e -> 
           Mono.just(ApiResponse.error(500, e.getMessage()))
        );
}

通過本文檔,您可全面掌握 WebClient 的核心用法、錯誤處理策略及性能優(yōu)化技巧。建議結(jié)合項目需求靈活調(diào)整配置,遵循響應(yīng)式編程最佳實踐。

到此這篇關(guān)于Spring WebFlux 與 WebClient 使用指南及最佳實踐的文章就介紹到這了,更多相關(guān)Spring WebFlux WebClient 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java使用dbcp2數(shù)據(jù)庫連接池

    java使用dbcp2數(shù)據(jù)庫連接池

    這篇文章主要為大家詳細介紹了java使用dbcp2數(shù)據(jù)庫連接池的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • springboot 如何修改默認端口及application.properties常用配置

    springboot 如何修改默認端口及application.properties常用配置

    這篇文章主要介紹了springboot 如何修改默認端口及application.properties常用配置操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • eclipse/intellij idea 查看java源碼和注釋方法

    eclipse/intellij idea 查看java源碼和注釋方法

    下面小編就為大家?guī)硪黄猠clipse/intellij idea 查看java源碼和注釋方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 關(guān)于Java單個TCP(Socket)連接發(fā)送多個文件的問題

    關(guān)于Java單個TCP(Socket)連接發(fā)送多個文件的問題

    這篇文章主要介紹了關(guān)于Java單個TCP(Socket)連接發(fā)送多個文件的問題,每次我只能使用一個 Socket 發(fā)送一個文件,沒有辦法做到連續(xù)發(fā)送文件,本文來解決這個問題,需要的朋友可以參考下
    2023-04-04
  • Java數(shù)據(jù)庫連接池之c3p0簡介_動力節(jié)點Java學(xué)院整理

    Java數(shù)據(jù)庫連接池之c3p0簡介_動力節(jié)點Java學(xué)院整理

    這篇文章主要為大家詳細介紹了Java數(shù)據(jù)庫連接池之c3p0簡介的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java大數(shù)運算BigInteger與進制轉(zhuǎn)換詳解

    Java大數(shù)運算BigInteger與進制轉(zhuǎn)換詳解

    這篇文章主要介紹了Java大數(shù)運算BigInteger與進制轉(zhuǎn)換詳解,Java 提供了 BigInteger(大整數(shù))類和 BigDecimal(大浮點數(shù))類用于大數(shù)運算,這兩個類都繼承自 Number 類(抽象類),由于 BigInteger 在大數(shù)運算中更常見,需要的朋友可以參考下
    2023-09-09
  • lombok?子類中如何使用@Builder問題

    lombok?子類中如何使用@Builder問題

    這篇文章主要介紹了lombok?子類中如何使用@Builder問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Java 中 synchronized 的使用方式和鎖升級

    Java 中 synchronized 的使用方式和鎖升級

    Java中的synchronized關(guān)鍵字用于實現(xiàn)線程同步,保證同一時刻只有一個線程可以訪問被同步的代碼塊或方法,JVM引入了鎖升級機制,從無鎖狀態(tài)開始,根據(jù)競爭情況逐步升級為偏向鎖、輕量級鎖和重量級鎖,以提高性能,感興趣的朋友一起看看吧
    2025-03-03
  • MyBatis-plus 模糊查詢的使用

    MyBatis-plus 模糊查詢的使用

    這篇文章主要介紹了MyBatis-plus 模糊查詢的使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2020-09-09
  • Spring框架學(xué)習之Cache抽象詳解

    Spring框架學(xué)習之Cache抽象詳解

    這篇文章主要為大家介紹了Spring框架學(xué)習中Cache抽象詳解示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-10-10

最新評論

丁青县| 邹平县| 静海县| 贡觉县| 新龙县| 蒙阴县| 凌云县| 元氏县| 连江县| 陆丰市| 兴山县| 枣阳市| 武定县| 云梦县| 若羌县| 阳原县| 顺昌县| 纳雍县| 泰宁县| 怀柔区| 成都市| 溧水县| 休宁县| 南康市| 名山县| 巴彦县| 梨树县| 洛浦县| 浦东新区| 峨山| 齐齐哈尔市| 美姑县| 凭祥市| 白银市| 滕州市| 灵璧县| 平江县| 镇宁| 左贡县| 鄄城县| 吉水县|