Zademy

Spring Boot 4 の RestClient:同期通信のモダン化

spring-boot; spring-framework; restclient; http-client
1414 単語

Spring Boot 4.0 の到来は Spring Framework 7 を基盤に、Java アプリケーションの HTTP 通信処理における重要なパラダイムシフトを示します。重点はモダンアーキテクチャの採用、RestTemplate の技術的負債の除去、Java 21+ の並行性の完全活用です。

主要新機能と改善

RestClient は Spring Framework 6.1(Spring Boot 3.2)で導入され、RestTemplate の現代的代替として同期かつ柔軟な選択肢を提供します。Spring Boot 4 ではこのツールが同期開発の標準として確立します。

新しい同期クライアント抽象

RestClient は HTTP リクエスト送信のための流動的でビルダー式 API を提供する同期 HTTP クライアントです。伝統的 Spring MVC スタックを使用するアプリケーションのデフォルトクライアントとして設計されています。

機能説明
流動 API デザインメソッドチェーンでリクエスト構築、WebClient 構文を模倣し、可読性向上と繰り返しコード(ボイラープレート)削減。
専用エラーハンドリングHTTP ステータスコード(4xx と 5xx)に基づくエラーハンドリングを onStatus() メソッドで統合サポート。
簡素化カスタマイズAPI メソッドで直接ヘッダー、クエリーパラメータ、ルート変数を追加。
インターセプターとフィルターリクエストやレスポンスを変更できるインターセプターをサポート、ロギングや認証タスクに理想的。

宣言的 HTTP サービスクライアント

Spring Boot 4 で最も顕著な新機能は ネイティブかつ改善された宣言的 HTTP サービスクライアントサポート です。

このアプローチは「Feign キラー」として知られ、外部サービスとの通信を 注釈付き純粋 Java インターフェース で定義でき、RestClient 実装の手動作成を不要にします。

  • 設定簡素化: Spring Framework 7 は @ImportHttpServices 注釈を導入、Spring Boot 4 の自動設定と組み合わせ、クライアントプロキシを Spring bean として作成する手順を簡素化し、HttpServiceProxyFactory の煩雑な手動コードを排除。

性能と Project Loom との整合性

RestClient は同期(ブロッキング)ですが、Project Loom(仮想スレッド - VTs)が Java 21+ で提供する 性能とスケーラビリティ向上 と本質的に関連しています。

仮想スレッド並行性

以前、RestTemplate の同期コードは I/O 待機中に高価なプラットフォームスレッドを消費しスケーラビリティを制限していました。RestClient は JVM 最適化の恩恵を受けます:仮想スレッドが I/O 呼び出し(HTTP リクエストなど)を行うと、迅速に「パーク」(基盤プラットフォームスレッドを解放)し、そのプラットフォームスレッド(キャリアスレッド)が別のタスクを実行できるようにします。

効率

これにより、シンプルブロッキングコードを使用する Spring MVC アプリケーションが RestClient で I/O 結合ワークロードの極高並行を処理でき、リアクティブプログラミング(WebClient)と同等のスケーラビリティを実現しつつコード複雑性は低く抑えます。VTs は従来のプラットフォームスレッドよりはるかに軽量(約 1KB あたり)です(プラットフォームスレッドは 1〜8 MB を使用する可能性があります)。

性能設定

spring.threads.virtual.enabledtrue のとき、Spring Boot 4 で VT 使用のクライアント設定は自動化可能。接続と読取タイムアウトは spring.http.clients.connect-timeoutspring.http.clients.read-timeout などの統一設定プロパティで集中管理。

新しい構文:RestTemplate との比較と例

構文比較:RestClient vs. RestTemplate

最も顕著な変更は RestClient での 流動 API 採用で、RestTemplate の冗長でオーバーロードされたテンプレートパターンを置き換えます。

機能RestTemplate(旧スタイル)RestClient(現代流動スタイル)
ステータスSpring Framework 6.1 から非推奨;Spring Framework 8.0 で削除予定。同期の事実上の標準
基本作成var restTemplate = new RestTemplate();var restClient = RestClient.create();
取得(GET)String res = restTemplate.getForObject(url, String.class);String res = restClient.get().uri(url).retrieve().body(String.class);
送信(POST)ResponseEntity<T> res = restTemplate.postForEntity(url, request, T.class);ResponseEntity<T> res = restClient.post().uri(url).body(request).retrieve().toEntity(T.class);

いくつかの明確で説明された例(RestClient

設定 Bean 作成

Spring Boot では RestClient.Builder を注入してグローバル設定(ベース URL、ヘッダーなど)で bean を作成するのが推奨されます。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;

@Configuration
public class RestClientConfiguration {

    @Bean
    public RestClient githubRestClient(RestClient.Builder builder) {
        // すべてのリクエストでベース URL とデフォルトヘッダーを設定
        return builder
            .baseUrl("https://api.github.com")
            .defaultHeader("Accept", "application/json")
            .build();
    }
}

ルート変数とクエリーパラメータ付き GET リクエスト

URI で変数を注入し、クエリーパラメータを追加する方法を示します。

// 'githubRestClient' が注入済みと仮定

public String getRepositoryInfo(String owner, String repo, boolean verbose) {
    String uriTemplate = "/repos/{owner}/{repo}";

    return githubRestClient.get()
        .uri(uriTemplate, owner, repo) // {owner} と {repo} にマッピング
        .queryParam("verbose", verbose) // ?verbose=true または false を追加
        .retrieve()
        .body(String.class);
}

POST リクエスト(リソース作成)

クライアントは Java オブジェクト(例:NewUserDTO)を JSON に自動シリアライズし、レスポンスを処理します。

import org.springframework.http.MediaType;

public User createNewUser(NewUserDTO userData) {
    return githubRestClient.post()
        .uri("/users")
        .contentType(MediaType.APPLICATION_JSON) // Content-Type 設定
        .body(userData) // JSON にシリアライズされるオブジェクト
        .retrieve()
        .body(User.class); // レスポンスを User オブジェクトに逆シリアライズ
}

HTTP ステータスベースのエラーハンドリング

RestClient が汎用 RestClientException をスローする前に特定のエラーハンドリングを定義できます。

import org.springframework.http.HttpStatus;

public User safeGetUser(long id) {
    return githubRestClient.get()
        .uri("/users/{id}", id)
        .retrieve()
        .onStatus(HttpStatus.NOT_FOUND, (request, response) -> {
            // 404 の特定ハンドリング
            System.out.println("ユーザーが見つかりません、デフォルトを返します");
            // 例外をスローするか、この場合デフォルト値を返す
            throw new CustomResourceNotFoundException("ユーザー ID " + id + " が見つかりません");
        })
        .onStatus(HttpStatus::is5xxServerError, (request, response) -> {
            // 5xx(サーバーエラー)のハンドリング
            throw new RuntimeException("内部サービスエラー。");
        })
        .body(User.class);
}

宣言的 HTTP クライアント(Spring Boot 4)

これが最もモダンなパターンで、@HttpExchange 注釈のインターフェースを使用します。

// 1. クライアントインターフェース(契約定義)
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;

@HttpExchange(url = "https://api.external.com/api/v1") // ベース URL
public interface ExternalApi {
    @GetExchange("/items/{itemId}") // GET https://api.external.com/api/v1/items/{itemId} にマッピング
    Item getItem(@PathVariable String itemId);
}

// 2. サービスでの使用(Spring Boot 4.0 は @ImportHttpServices 設定で自動プロキシ注入)
@Service
public class ItemService {
    private final ExternalApi externalApi;

    // 生成されたプロキシ実装が注入
    public ItemService(ExternalApi externalApi) {
        this.externalApi = externalApi;
    }

    public Item findItem(String id) {
        // ローカルメソッド呼び出しのように感じる
        return externalApi.getItem(id);
    }
}

推奨: RestTemplate は Spring Framework 8.0 で削除される予定で、RestClient の新同期モデルは仮想スレッド向けに最適化されています。すべての Spring MVC プロジェクトを RestClient に移行し、新しいサービス間クライアントには宣言的アプローチ(@HttpExchange)を採用することを強く推奨します。これにより、より清潔で保守しやすいコードが保証され、モダン高並行 Java に備えます。