Spring Boot 4 の RestClient:同期通信のモダン化
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.enabled が true のとき、Spring Boot 4 で VT 使用のクライアント設定は自動化可能。接続と読取タイムアウトは spring.http.clients.connect-timeout と spring.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 に備えます。