第 6 章 Web アプリ開発 ― Spring MVC/WebFlux/HTTP クライアント
第 6 章 Web アプリ開発 ― Spring MVC/WebFlux/HTTP クライアント
(Spring Boot 3.5 GA・Java 17+ 前提)
5‑1 Spring MVC ― テンプレート & 従来型サーブレットスタック
5‑1‑1 最小構成と自動設定
spring-boot-starter-web
を依存に追加すると、DispatcherServlet・Jackson・Thymeleaf/Mustache の各 Bean が自動登録される。(spring.io)- コントローラは最上位パッケージ配下に配置し、
@GetMapping
等で URL を割り当てる。
@Controller
class HomeController {
@GetMapping("/")
String index(Model model) {
model.addAttribute("msg", "Hello, Spring MVC!");
return "index"; // src/main/resources/templates/index.html
}
}
ポイント : Boot 3.x では Jakarta Servlet 6.0 依存に移行しているため import は
jakarta.servlet.*
になる。
5‑1‑2 テンプレートエンジン選択
エンジン | 依存 (starter) | 特徴 |
---|---|---|
Thymeleaf | spring-boot-starter-thymeleaf |
HTML5 方言で自然テンプレートを保つ。レイアウトは [Layout Dialect] で拡張可。(github.com) |
Mustache | spring-boot-starter-mustache |
ロジックレス。1 ファイル=1 View の静的サイト生成に向く。(docs.spring.io) |
Boot が自動生成する SpringTemplateEngine
/ Mustache.Compiler
は キャッシュ ON が既定。開発時は spring.thymeleaf.cache=false
にして再読み込みを有効化する。
5‑1‑3 静的リソースと WebJar
- classpath :
/static
,/public
,/META-INF/resources
直下は 「/」に直結 して公開される。(baeldung.com, docs.spring.io) - WebJar(例:
org.webjars.npm:bootstrap
)を利用すると/webjars/bootstrap/5.3.3/js/bootstrap.bundle.js
のように配信可能。CDN を嫌う企業内ネットワークで便利。
5‑1‑4 フォーム処理とバリデーション
- DTO に
@NotNull
,@Size
等の Jakarta Bean Validation アノテーションを付与。 - コントローラ引数に
@Valid
とBindingResult
を置く。 - エラーは
th:errors="*{field}"
で表示。
@PostMapping("/signup")
String signup(@Valid @ModelAttribute UserForm form, BindingResult rs) {
if (rs.hasErrors()) return "signup";
service.create(form);
return "redirect:/";
}
5‑1‑5 HttpMessageConverters とコンテンツネゴシエーション
- Boot は 23 種 の
HttpMessageConverter
を自動登録し、Accept
ヘッダと拡張子で JSON ↔ XML ↔ YAML を切替える。 - カスタム MIME を追加したい場合は
WebMvcConfigurer#extendMessageConverters
を実装するだけでよい。
5‑1‑6 Virtual Threads 併用時の MVC
spring.threads.virtual.enabled=true
(Java 21 以上)で リクエスト処理スレッドが仮想スレッド化 される。(docs.spring.io, github.com)- I/O 待ちが長いがリアクティブに書き換えるほどではない API では 同一コードでスループットを向上 できる。
@Async
や@Scheduled
も自動で仮想スレッド実行になるため、スレッドプールサイズ調整の負荷が減る。
5‑2 Spring WebFlux ― リアクティブ & ノンブロッキング
5‑2‑1 WebFlux を選択する判断軸
要件 | MVC (Servlet) | WebFlux (Reactive) |
---|---|---|
高同時接続 / SSE / WebSocket | △(従来スレッドモデル) | ◎(ノンブロッキング I/O) |
レガシー同期ライブラリ利用 | ◎ | △(ブロッキング注意) |
既存コード資産 | ◎ | ▲(Mono/Flux へ書換え) |
Virtual Threads で MVC の同時実行性が向上したとはいえ、バックプレッシャー制御・ストリーミング応答 が必要な場合は WebFlux が依然有利 (master-spring-ter.medium.com)。
5‑2‑2 アノテーション vs 機能的エンドポイント
アノテーション方式(従来型)
@RestController
class GreetingHandler {
@GetMapping("/hello/{name}")
Mono<Greet> hello(@PathVariable String name) {
return Mono.just(new Greet("Hi " + name));
}
}
機能的エンドポイント
@Configuration
class Routes {
@Bean
RouterFunction<ServerResponse> router() {
return RouterFunctions.route()
.GET("/hello/{name}",
req -> ServerResponse.ok()
.bodyValue("Hi " + req.pathVariable("name")))
.build();
}
}
- 関数型は Bean 生成だけでルーティング が完結し、AOT・Native Image でメモリ削減効果が大きい。(medium.com, docs.spring.io)
5‑2‑3 Netty サーバーとチューニング
spring-boot-starter-webflux
⇒ Reactor Netty が既定。HTTP/2 は自動有効(JDK 11+)(docs.spring.io)。- スレッド数は
reactor.netty.ioWorkerCount
、メモリはreactor.netty.pool.maxConnections
で制御。
5‑2‑4 Virtual Threads との共存シナリオ
- WebFlux の ブロッキング回避サポート は仮想スレッドにも適用され (
@Blocking
相当の制御不要)。 - ただし Reactor コンテキスト ⇆ 仮想スレッドの切替コスト があるため、IO 待ちが短い高速ストリームでは従来のイベントループが優位。(medium.com, medium.com)
5‑2‑5 Reactive Data & Test
- R2DBC/MongoDB Reactive Driver と組み合わせ、完全ノンブロッキングパイプライン を構築。
@WebFluxTest
+WebTestClient
でエンドポイントを バインドレスで高速テスト。
5‑3 宣言的 HTTP クライアント ― RestClient / WebClient
5‑3‑1 RestClient(同期・ブロッキング)
- Spring Boot 3.2 で導入された 関数型 API。
RestTemplate
より ビルダー中心 かつ レコード/kotlin data class に自然マッピング。(docs.spring.io, docs.spring.io)
@Service
class CatService(RestClient.Builder builder) {
private final RestClient client =
builder.baseUrl("https://api.example.com").build();
Cat find(String id) {
return client.get().uri("/cats/{id}", id)
.retrieve().body(Cat.class);
}
}
- HttpMessageConverters と
ClientHttpRequestFactory
は Boot が注入。タイムアウトはbuilder.requestFactory(factory)
で個別指定。
5‑3‑2 WebClient(非同期・リアクティブ)
Mono
/Flux
を返して バックプレッシャー対応。- サーバーと同じ Reactor Netty を共有することで 接続プールを統合 し、メトリクスも併用できる。(docs.spring.io)
5‑3‑3 SSL バンドルとセキュア通信
- Boot 3.5 の SSL Bundles を
RestClientSsl
/WebClientSsl
でバインドし、証明書設定を 1 行で適用可能。(docs.spring.io, docs.spring.io)
@Bean
RestClient secure(RestClient.Builder builder, RestClientSsl ssl) {
return builder.apply(ssl.fromBundle("corp-tls")).build();
}
5‑3‑4 ベストプラクティス
項目 | RestClient | WebClient |
---|---|---|
共通ヘッダ | builder.defaultHeader() |
builder.defaultHeader() |
ログ/監視 | RestClientCustomizer → ExchangeFilterFunction で集中管理 |
ExchangeFilterFunction |
Retries / Circuit Breaker | Resilience4j Decorators | reactor.retry or Resilience4j |
テスト | MockRestServiceServer |
WebClient.builder().exchangeFunction(...) |
Virtual Threads × RestClient :
spring.threads.virtual.enabled=true
で ブロッキング呼び出しもスレッド浪費を抑制。外部 API 呼び出しを大量に並列化する際に特に有効。(stackoverflow.com)
まとめ
本章では Servlet 型 Spring MVC と Reactive 型 WebFlux の使い分け、さらに 新世代 HTTP クライアント (RestClient/WebClient) を一気通貫で解説しました。次章では Actuator・Micrometer を軸に 運用・モニタリング 機能を深掘りします。