Zademy

Spring Boot 4 と Spring Framework 7:高速で安全なマイクロサービスのための Java の新時代

Java
SpringBoot; Java
3149 単語

こんにちは、開発者コミュニティの皆さん!Spring Boot 4.0 のリリース(2025 年 11 月から利用可能)、そして Spring Framework 7.0 は、Java エコシステムにおける重要なマイルストーンを示しています。これは単なる増分アップデートではなく、モダンでモジュラー、クラウドネイティブ、パフォーマンス重視の Java アーキテクチャへと確実に前進する一歩です。

パフォーマンスを最適化し、コードを簡素化し、設計段階でアプリケーションをより安全にしたいなら、このバージョンには必要なツールが揃っています。ここでは、最も重要な変更点を深く分析します。

最低要件:モダン性を擁護する

Spring Boot 4 はモダン化の道を続け、効率的なプラットフォームを保証するために技術スタックを引き上げます:

  • Java (JDK):最低要件は引き続き Java 17 です。しかし、Java 21 以上(理想的には Java 25)の使用を強く推奨します。これにより、Virtual Threads(仮想スレッド)など、JVM の最新機能を活用できます。Virtual Threads は伝統的なリアクティブプログラミング(WebFlux)と競合し、置き換える可能性があります。
  • Jakarta EE 11:Jakarta EE 11 への完全な対応により、Servlet 6.1、JPA 3.2、Bean Validation 3.1 などの最新技術を採用します。
  • Kotlin:現在は 2.2 以上 が必要です。
  • GraalVM:GraalVM 24 以上を完全サポートし、ネイティブイメージ生成を最適化します。

パフォーマンスへの大きな飛躍:モジュラー化と AOT

目に見えないが最も重要な改善の一つは、Spring Boot のコアのモジュラー化です。

モジュラー化:荷物を解く

以前は、spring-boot-autoconfigure モジュールは、使用しなくてもほぼすべての設定ロジックを含む巨大なアーティファクトでした。これにより「クラスパスノイズ」が発生しました。

解決策:Spring Boot 4 はこの巨大なモジュールを、必要に応じてのみロードされる、より小さく焦点を絞ったアーティファクトに分割しました。現在、自動設定は専門化されたモジュールに分散されています。

具体的な利点

  1. 高速起動:スキャンするコードが減り、起動時間が短縮されます。
  2. メモリ消費の削減:実際に必要なものだけをロードします。
  3. より良い開発体験:IDE が正確な提案を提供し、関係のないクラスやプロパティを表示しません。
  4. 最適化されたネイティブイメージ:GraalVM を使ったネイティブイメージ生成がより効率的になります。

AOT コンパイルと GraalVM

Spring Boot 4 は GraalVM 24 以上 と完全に統合されています。AOT(Ahead-of-Time)処理は大幅に最適化されています:

  • コンパイル時間の短縮
  • 起動時のメモリフットプリント削減
  • デッドコード除去のための静的解析の向上
  • reflection hints の互換性向上

新しい @ConfigurationPropertiesSource 注釈により、さらに細かいモジュラー化が可能になり、アプリケーションに関連する設定プロパティだけが処理されます。

Null 安全性:NullPointerException の終焉

歴史的に、Java での null の扱いは、本番環境でのエラーの絶え間ない原因でした。Spring Framework 7 と Spring Boot 4 は、製品群全体で JSpecify を null 安全性(Null Safety)の標準として採用しました。

JSpecify とは何か?

JSpecify は、Google、JetBrains、Meta、Oracle などのテックジャイアントが支援する共同標準です。値がnullable(null になる可能性がある)かnon-nullable(null にならない)かを明示的に示す注釈を提供します。

注釈意味比喩
@Nullableこの値はnullable赤信号(停止して確認!)
@NonNullこの値はnon-nullable緑信号(前進!)
@NullMarkedデフォルトルールを設定:明示的に示されない限りすべて NonNull安全ゾーン

ゲームチェンジャー:@NullMarked

package-info.java ファイルを作成することで、パッケージ全体を null 安全としてマークできます:

// src/main/java/com/tuempresa/servicio/package-info.java
@org.jspecify.annotations.NullMarked
package com.tuempresa.servicio;

これにより、IDE(IntelliJ IDEA 2025.3+ など)は、non-nullable コンテキストで nullable 値を使用しようとしたときに、コードを書いている最中に警告を表示します。

実用的な例

@NullMarked
package com.ejemplo.usuarios;

public class UsuarioService {

    // IDE は null を渡そうとしたときに警告を出す
    public Usuario crearUsuario(@NonNull String nombre, @Nullable String apellido) {
        // nombre は決して null ではない - 直接安全に使用可能
        String nombreCompleto = nombre.toUpperCase();

        // apellido は null の可能性がある - 確認が必要
        if (apellido != null) {
            nombreCompleto += " " + apellido.toUpperCase();
        }

        return new Usuario(nombreCompleto);
    }
}

これにより、本番環境での NullPointerException リスクが大幅に削減され、開発段階で問題を検出できます。

宣言的 HTTP クライアント:Feign の"殺し屋"

Spring Boot 4 は、宣言的 HTTP クライアントにより、service-to-service コミュニケーションを簡素化します。これは外部依存関係(Spring Cloud OpenFeign など)の必要性を排除する、長年待ち望まれた機能です。

RestTemplate とはおさらば

RestTemplate は Spring Framework 7 で正式に非推奨となり、将来的なバージョンで削除されます。コードは冗長で、テストが難しく、Java のモダンな機能を活用していませんでした。

新時代:RestClient と @HttpExchange

RestClientRestTemplate のモダンな代替で、流暢な API とビルダースタイルを提供します。しかし、最も革命的なのは @HttpExchange を使った宣言的 HTTP クライアントの作成能力です。

宣言的クライアントの例

package com.tuempresa.clients;

import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.PostExchange;
import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

@HttpExchange("/api/productos")
public interface ProductoClient {

    @GetExchange("/{id}")
    Producto obtenerProducto(@PathVariable("id") String id);

    @GetExchange
    List<Producto> listarProductos();

    @PostExchange
    Producto crearProducto(@RequestBody Producto producto);
}

クライアント設定

@Configuration
public class ClientConfig {

    @Bean
    public ProductoClient productoClient(RestClient.Builder builder) {
        RestClient restClient = builder
            .baseUrl("https://api.ejemplo.com")
            .build();

        HttpServiceProxyFactory factory = HttpServiceProxyFactory
            .builderFor(RestClientAdapter.create(restClient))
            .build();

        return factory.createClient(ProductoClient.class);
    }
}

利点

  • ゼロボイラープレート:呼び出す内容を定義するだけで、呼び出し方を定義する必要はありません
  • テストしやすい:インターフェースを簡単にモックできます
  • 型安全:Java の型システムを活用
  • ネイティブ統合:追加の依存関係は不要

Spring Boot 4 はまた、これらのクライアントの自動設定を改善し、clientType 属性を使用してクライアントコードを変更せずに RestClient(デフォルト)と WebClient(リアクティブケース向け)の間を切り替えることができます。

レジリエンスと API バージョニング

このバージョンは、フレームワークのコアに直接統合された重要なアーキテクチャパターンを導入します。

ネイティブレジリエンス

以前は外部の Spring Retry プロジェクトに依存していたレジリエンス注釈が、Spring Framework 7 に統合されました:

  • @Retryable:メソッドが失敗した場合にリトライロジックを適用
  • @ConcurrencyLimit:メソッドへの同時呼び出しを制限
  • @EnableResilientMethods:beans でこれらの注釈を有効化

レジリエンスの例

@Service
@EnableResilientMethods
public class PagoService {

    @Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public PagoRespuesta procesarPago(PagoRequest request) {
        // 失敗した場合、1 秒間隔で最大 3 回リトライ
        return pagoGateway.procesar(request);
    }

    @ConcurrencyLimit(maxConcurrency = 10)
    public Report generarReporte() {
        // 最大 10 個の同時呼び出し
        return reportService.generar();
    }
}

ネイティブ API バージョニング

Spring Framework 7 は REST API バージョニングの"悪夢"を解決します。@RequestMapping とそのバリエーションで version 属性を使用できるようになりました:

バージョニング付き Controller の例

@RestController
@RequestMapping("/api/pedidos")
public class PedidoController {

    // バージョン 1:シンプルなレスポンス
    @GetMapping(version = "1", produces = MediaType.APPLICATION_JSON_VALUE)
    public List<PedidoV1> getPedidosV1() {
        return pedidoService.obtenerPedidosSimples();
    }

    // バージョン 2:メタデータ付きのリッチレスポンス
    @GetMapping(version = "2", produces = MediaType.APPLICATION_JSON_VALUE)
    public PedidoResponseV2 getPedidosV2() {
        return pedidoService.obtenerPedidosCompletos();
    }
}

集中設定

@Configuration
public class ApiVersioningConfig implements WebMvcConfigurer {

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // ヘッダー戦略
        configurer.apiVersioning(builder -> builder
            .strategy(VersionStrategy.HEADER)
            .headerName("API-Version")
        );

        // またはパス戦略:/v1/pedidos, /v2/pedidos
        // またはクエリーパラメータ戦略:/pedidos?version=1
    }
}

バージョニング戦略は集中管理され、controllers を書き直すことなく戦略(パス、ヘッダー、クエリーパラメータ)を変更できます。

高精細オブザーバビリティ

cloud-native アプリケーションにとって、モニタリング能力は不可欠です。Spring Boot 4 はオブザーバビリティを大幅に改善します。

OpenTelemetry との統合

  • Micrometer 2.0:パフォーマンスが向上して更新
  • ネイティブ OpenTelemetry:Spring Boot 4 に公式スターターが含まれる
  • 自動相関:ログ、メトリクス、トレースが自動的に相関付け

@Observed 注釈

任意のメソッドに対して自動的にメトリクスとトレースを生成:

@Service
public class InventarioService {

    @Observed(name = "inventario.verificar", contextualName = "verificarDisponibilidad")
    public boolean verificarDisponibilidad(String productoId) {
        // 自動的に以下のメトリクスを生成:
        // - 実行時間
        // - 呼び出し回数
        // - エラーレート
        return inventarioRepository.existeStock(productoId);
    }
}

SSL ヘルスモニタリング

Actuator は現在、SSL 証明書の自動モニタリングを実行します。証明書が期限切れになる(デフォルトで 14〜30 日前)と、/actuator/health エンドポイントが明示的に報告します:

{
  "status": "UP",
  "components": {
    "ssl": {
      "status": "WARNING",
      "details": {
        "certificate": "api.ejemplo.com",
        "expiresIn": "12 days",
        "expiryDate": "2025-12-05"
      }
    }
  }
}

これは、本番環境で証明書が予期せず期限切れになったときのパニックを避けるための"救命胴衣"です。

コアの変化:Client パターン

Spring を使用したことがあるなら、Templates(例:JdbcTemplateRestTemplateJmsTemplate)を使用したことがあるでしょう。Spring Framework 7 は現在、builders と関数型インターフェースに基づく新しいClient パターンへと、"Template Method" パターンから積極的に移行しています。

旧パターン新パターン(代替/選択肢)ステータス
RestTemplateRestClient / @HttpExchange非推奨
JdbcTemplate / NamedParameterJdbcTemplateJdbcClient共存
JmsTemplateJmsClient新規

JdbcClient:よりクリーンなコード

新しい JdbcClient は冗長性を排除し、より直感的で読みやすいビルダーパターンを採用しています:

以前(JdbcTemplate)

public List<Persona> findAll() {
    return jdbcTemplate.query(
        "SELECT id, nombre, edad FROM persona",
        new RowMapper<Persona>() {
            @Override
            public Persona mapRow(ResultSet rs, int rowNum) throws SQLException {
                Persona p = new Persona();
                p.setId(rs.getLong("id"));
                p.setNombre(rs.getString("nombre"));
                p.setEdad(rs.getInt("edad"));
                return p;
            }
        }
    );
}

現在(JdbcClient)

public List<Persona> findAll() {
    return jdbcClient.sql("SELECT id, nombre, edad FROM persona")
        .query((rs, rowNum) -> new Persona(
            rs.getLong("id"),
            rs.getString("nombre"),
            rs.getInt("edad")
        ))
        .list();
}

// または自動マッピングでもっとシンプル
public List<Persona> findAll() {
    return jdbcClient.sql("SELECT * FROM persona")
        .query(Persona.class)
        .list();
}

パラメータ付きクエリ

public Optional<Persona> findById(Long id) {
    return jdbcClient.sql("SELECT * FROM persona WHERE id = :id")
        .param("id", id)
        .query(Persona.class)
        .optional();
}

書き込み操作

public int actualizarEdad(Long id, int nuevaEdad) {
    return jdbcClient.sql("UPDATE persona SET edad = :edad WHERE id = :id")
        .param("edad", nuevaEdad)
        .param("id", id)
        .update();
}

この新しいアプローチは:

  • より簡潔で読みやすい
  • lambdas とメソッド参照を活用
  • Optional との統合が向上し、null の安全な扱いが可能
  • AOT と GraalVM へのサポートが改善

テストの改善

Spring Boot 4 はテスト機能に重要な改善を導入します:

より細かいテストスライス

新しいテストスライスにより、アプリケーションコンテキスト全体をロードせずに特定コンポーネントをテスト可能:

@HttpServiceClientTest
class ProductoClientTest {

    @Autowired
    private ProductoClient productoClient;

    @Test
    void deberiaObtenerProducto() {
        // HTTP クライアントに必要な設定だけをロード
        Producto producto = productoClient.obtenerProducto("123");
        assertThat(producto).isNotNull();
    }
}

改良された TestRestTemplate

新しい RestClient との統合が向上し、型指定されたレスポンスのサポートも改善:

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class IntegrationTest {

    @Autowired
    private TestRestClient restClient;

    @Test
    void deberiaCrearUsuario() {
        Usuario nuevoUsuario = new Usuario("Juan", "Pérez");

        Usuario creado = restClient.post()
            .uri("/api/usuarios")
            .body(nuevoUsuario)
            .exchange()
            .expectStatus().isCreated()
            .expectBody(Usuario.class)
            .returnResult();

        assertThat(creado.getId()).isNotNull();
    }
}

Spring Boot 3 からの移行

Spring Boot 3 から Spring Boot 4 への移行にはいくつかの点に注意が必要です:

強制的な変更

  1. Jackson 3.x:Jackson 2.x から 3.x への更新
  2. Jakarta 名前空間javax.* から jakarta.* への完全移行
  3. Java 17 最低要件:Java 21+ の使用を推奨
  4. Kotlin 2.2+:Kotlin を使用している場合

重要な非推奨

  • RestTemplateRestClient または宣言的クライアント
  • Spring Security では lambda 設定が必須
  • 設定プロパティのいくつかが名前変更

移行ツール

Spring は OpenRewrite を使用して移行の大半を自動化することを推奨します:

<plugin>
    <groupId>org.openrewrite.maven</groupId>
    <artifactId>rewrite-maven-plugin</artifactId>
    <version>5.42.0</version>
    <configuration>
        <activeRecipes>
            <recipe>org.openrewrite.java.spring.boot4.UpgradeSpringBoot_4_0</recipe>
        </activeRecipes>
    </configuration>
</plugin>

このプラグインは以下を自動化できます:

  • 依存関係の更新
  • javax → jakarta 名前空間の変更
  • 非推奨 API の移行
  • 設定ファイルの更新

結論:なぜ Spring Boot 4 に移行するのか?

Spring Boot 4 と Spring Framework 7 は、Java アプリケーションをより軽量、予測可能、高速、安全にするために設計されています。

主な利点

  1. パフォーマンス:モジュラー化と AOT が起動時間とメモリ消費を大幅に改善
  2. 安全性:JSpecify が本番環境での NPE を削減
  3. 生産性:よりクリーンで宣言的な API がボイラープレートを削減
  4. レジリエンス:ネイティブ統合されたレジリエンスパターン
  5. オブザーバビリティ:一流のモニタリングとトレース
  6. クラウドネイティブ:コンテナとクラウド環境向けに最適化

モダンな建築家のメタファー

Spring Boot 4 をモダンな建築家に例えると、以前はほとんどすべてがオプションの重い工具箱を持っていました。今では指示が明確(JSpecify)、統合された安全メカニズム(レジリエンス)、最適化された建材(モジュラー化)がある専門的で軽量な工具があり、結果としてより速く建設でき、本質的により安定した建物(アプリケーション)になります。

移行は価値があるのか?

はい、間違いなく。些細なことではありません(依存関係の更新と設定の調整が必要)が、生産性、パフォーマンス、保守性の向上は、この変化への投資がすぐに回収されることを意味します。

Spring Boot 4 と Spring Framework 7 は単なるバージョンアップではなく、今後 10 年間のエンタープライズ Java 開発の基盤です。未来に向けてアプリケーションを構築しているなら、これが構築すべきプラットフォームです。