Contents
1 概要 ― JDK 21 と Spring Boot 3.2 の位置付け
| 項目 | 主な特徴 | 現在の採用状況・根拠 |
|---|---|---|
| JDK 21 (LTS) | パターンマッチング for switch、シーリングレコード、Record Patterns などで記述量が削減。公式 LTS サポートは 2027 年まで続く。 |
Oracle の LTS カタログと OpenJDK のダウンロード統計で、2024‑2025 年に最もダウンロードされた Java バージョンのひとつ([OpenJDK Survey 2024])。 |
| Spring Boot 3.2 (2024‑11 リリース) | Jakarta EE 10 完全対応、AOT コンパイルによる起動時間短縮・メモリフットプリント削減。 GraalVM Native Image と併用したベンチマークで「起動時間が約30%短縮」(Spring Boot 3.2 Release Notes) が報告されている。 |
Spring の公式サイトに掲載された導入事例 (数千社以上) が増加中。 |
ポイント
JDK 21 と Spring Boot 3.2 は同じ「Java 17 以降必須」という前提で設計されているため、互換性の心配が少なく、最新機能をそのまま活用できる。
2 IDE のセットアップとデバッグ手順
2.1 必要なツール
| ツール | バージョン例 | インストール方法 |
|---|---|---|
| IntelliJ IDEA (Community/Ultimate) | 2024.x | JetBrains 公式サイトからダウンロード |
| Visual Studio Code + Java Extension Pack | 最新 | VS Code Marketplace でインストール |
| JDK 21 (Temurin, Zulu 等) | 21.0.x | AdoptOpenJDK/Eclipse Temurin のバイナリを取得 |
2.2 SDK 設定
- IntelliJ IDEA
File → Project Structure → Platform Settings → SDKsに JDK 21 を登録。-
Project → Project SDKでも同じ JDK を選択。 -
VS Code
- コマンドパレット (
Ctrl+Shift+P) → Java: Configure Java Runtime。 - 表示される一覧から JDK 21 のインストール先を選ぶか、
settings.jsonに
json
"java.home": "/path/to/jdk-21"
を追記。
2.3 デバッグ構成(共通)
| IDE | 手順 |
|---|---|
| IntelliJ | Run → Edit Configurations → + → Spring Boot。メインクラスを選択し、必要なら環境変数 SPRING_PROFILES_ACTIVE=dev を設定。ブレークポイントはコード上でクリックして有効化。 |
| VS Code | .vscode/launch.json に次のスニペットを追加: |
json
{
"type": "java",
"name": "Debug Spring Boot",
"request": "launch",
"mainClass": "com.example.hellospringboot.HelloSpringbootApplication",
"projectName": "hello-springboot"
}
デバッグビューから「Start Debugging」すればブレークポイントが有効になる。 |
3 Spring Initializr でのプロジェクト雛形作成
3.1 Maven 用手順
- https://start.spring.io にアクセス
- Project: Maven Project、Language: Java、Spring Boot: 3.2.x、Java: 21 を選択
- Group/Artifact を入力し、依存関係に
Spring Web,Spring Data JPA,Validation,Lombokを追加 - 「GENERATE」→ ZIP ダウンロード → IDE にインポート
重要な pom.xml 部分(抜粋)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<properties> <java.version>21</java.version> <spring-boot.version>3.2.0</spring-boot.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> |
3.2 Gradle 用手順(Groovy DSL)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
plugins { id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = JavaVersion.VERSION_21 repositories { mavenCentral() } |
補足:Gradle Kotlin DSL でも同様に
kotlin("jvm") version "1.9.x"等を組み合わせれば利用可能です。
4 REST API の最小構成とバリデーションの正しい記述
4.1 アノテーション一覧(初心者向け解説)
| アノテーション | 役割 |
|---|---|
@SpringBootApplication |
起動クラスに付与し、コンポーネントスキャン・自動設定を有効化 |
@RestController |
@Controller + @ResponseBody の合成。JSON を直接返す |
@RequestMapping / @GetMapping / @PostMapping |
HTTP メソッドとパスのマッピング |
@Autowired (推奨は コンストラクタインジェクション) |
Bean を DI コンテナから注入 |
@Valid + jakarta.validation.* アノテーション |
入力 DTO の制約チェックを自動実行 |
4.2 実装例(Jakarta Validation に統一)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.example.hellospringboot; import org.springframework.web.bind.annotation.*; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; @RestController @RequestMapping("/api") public class HelloController { @GetMapping("/greet") public String greet(@RequestParam(defaultValue = "World") String name) { return "Hello, " + name + "!"; } /** DTO にバリデーションアノテーションを付与 */ public record MessageDto(@NotBlank(message = "content must not be blank") String content) {} @PostMapping("/echo") public MessageDto echo(@Valid @RequestBody MessageDto dto) { return dto; } } |
- ポイント
@Validとjakarta.validation系アノテーション (@NotBlank) が同一パッケージにあるため、表記揺れは発生しません。- バリデーションエラーは Spring Boot の
MethodArgumentNotValidExceptionハンドラで JSON 形式のエラーメッセージとして自動返却されます(カスタマイズしたい場合は@ControllerAdviceを実装)。
4.3 動作確認 (Postman)
| メソッド | URL | リクエスト例 | 期待結果 |
|---|---|---|---|
| GET | http://localhost:8080/api/greet?name=Spring |
- | "Hello, Spring!" |
| POST | http://localhost:8080/api/echo |
{ "content": "test" } (raw JSON) |
同上の JSON がそのまま返る |
5 AOT コンパイルと GraalVM の関係 ― 初心者向けに解説
- AOT(Ahead‑Of‑Time)コンパイル
-
Spring Boot 3.x はビルド時にアプリケーションのクラスメタデータを解析し、不要なリフレクションやプロキシ生成コードを事前に生成します。これにより 起動時に行うクラススキャンが削減される ため、JVM 起動時間とヒープ使用量が小さくなります。
-
GraalVM Native Image
-
AOT が生成したメタデータを利用して、
native-imageコマンドで「ネイティブ実行ファイル」を作成できます。ネイティブバイナリは JVM の JIT コンパイルが不要なため、数百ミリ秒単位の超高速起動が可能です(公式ベンチマーク: 1.2 s → 0.8 s 程度)。 -
実装手順(概要)
bash
# 1️⃣ Spring Boot の AOT プラグインを有効化 (pom.xml または build.gradle に追加)
./mvnw -Pnative spring-boot:build-image # Maven 用例
# 2️⃣ GraalVM が提供するnative-imageが内部で呼び出され、Docker イメージが生成される
docker run --rm -p 8080:8080 your-app:latest -
注意点
- ネイティブビルドは OS とアーキテクチャに依存(Linux x86_64 が公式サポート)ので、CI 環境は同一環境で実行する必要があります。
- すべてのライブラリがネイティブ対応しているわけではなく、
Reflectionを多用するサードパーティーは--initialize-at-run-time=オプションで除外設定が必要です。
6 データベース連携とテスト基礎
6.1 H2 メモリ DB(開発・テスト)
src/main/resources/application.yml
|
1 2 3 4 5 6 7 8 9 10 11 |
spring: datasource: url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: update # エンティティ変更を自動で反映 show-sql: true |
エンティティ例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.example.todo; import jakarta.persistence.*; @Entity public class Todo { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private boolean done; // getter / setter (Lombok @Data でも可) } |
リポジトリ(インタフェースだけで完結)
|
1 2 3 4 5 6 |
package com.example.todo; import org.springframework.data.jpa.repository.JpaRepository; public interface TodoRepository extends JpaRepository<Todo, Long> {} |
6.2 本番 MySQL 用プロファイル
src/main/resources/application-prod.yml
|
1 2 3 4 5 6 7 8 9 10 11 |
spring: datasource: url: jdbc:mysql://db.example.com:3306/tododb?useSSL=false&serverTimezone=UTC username: prod_user password: ${MYSQL_PASSWORD} jpa: hibernate: ddl-auto: validate # 起動時にスキーマが正しいかだけチェック properties: hibernate.dialect: org.hibernate.dialect.MySQL8Dialect |
起動時は --spring.profiles.active=prod を付与すれば MySQL が使用されます。
6.3 統合テスト(JUnit 5 + SpringBootTest)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package com.example.todo; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.beans.factory.annotation.Autowired; import static org.assertj.core.api.Assertions.*; @SpringBootTest // アプリケーションコンテキスト全体を起動 class TodoRepositoryTests { @Autowired private TodoRepository repo; @Test void createAndFind() { Todo t = new Todo(); t.setTitle("Write tests"); repo.save(t); assertThat(repo.findById(t.getId())) .isPresent() .hasValueSatisfying(todo -> assertThat(todo.getTitle()).isEqualTo("Write tests")); } } |
- テストはデフォルトで H2 が使用されるため、本番 DB へ影響しません。
@DataJpaTestを使えばリポジトリだけをスライスして高速テストが可能です。
7 Docker 化と CI/CD 入門
7.1 Dockerfile(マルチステージでサイズ最小化)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# ---------- Build stage ---------- FROM eclipse-temurin:21-jdk-alpine AS build WORKDIR /app COPY mvnw pom.xml ./ COPY .mvn .mvn RUN ./mvnw dependency:go-offline -B # 依存解決だけ先に実行 COPY src src RUN ./mvnw package -DskipTests # ---------- Runtime stage ---------- FROM eclipse-temurin:21-jdk-alpine VOLUME /tmp ARG JAR_FILE=target/*.jar COPY --from=build /app/${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"] |
7.2 docker‑compose.yml(開発用と本番用を切替可能)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
version: "3.9" services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: tododb ports: - "3306:3306" app: build: . ports: - "8080:8080" environment: SPRING_PROFILES_ACTIVE: prod # 本番プロファイルを使用 depends_on: db: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"] interval: 30s timeout: 10s retries: 3 |
ヒント:
depends_onにcondition: service_healthyとヘルスチェックを入れると、DB が起動完了するまでアプリが待機します。
7.3 GitHub Actions(CI → CD)
.github/workflows/ci.yml
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
name: CI on: push: branches: [ main ] jobs: build-test-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up JDK 21 uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '21' - name: Cache Maven packages uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Build & Test run: ./mvnw -B verify - name: Build Docker image run: docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} . - name: Push Docker image uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - run: | docker push ghcr.io/${{ github.repository }}:${{ github.sha }} |
- キャッシュ により依存取得が高速化し、GitHub Actions の実行時間が平均 30% 短縮されています(公式ドキュメント参照)。
8 よくあるエラーと対処法(2025 年版)
| No | エラー例 | 主な原因 | 推奨解決策 |
|---|---|---|---|
| 1 | java.lang.UnsupportedClassVersionError |
ビルド時の JDK と実行時 JDK が不一致 | Maven/Gradle の java.version を 21 に統一し、CI でも同じバージョンを使用 |
| 2 | org.hibernate.exception.SQLGrammarException |
DDL 未適用(テーブルが存在しない) | spring.jpa.hibernate.ddl-auto=update で自動作成、または Flyway・Liquibase でマイグレーション管理 |
| 3 | Port 8080 already in use |
ローカルに別プロセスがバインド | application.yml の server.port を変更するか、lsof -i:8080 で占有プロセスを停止 |
| 4 | Failed to load ApplicationContext |
プロファイル名のミス (prod と production が混在) |
起動オプション --spring.profiles.active=prod を明示し、application-*.yml の命名規則を統一 |
| 5 | BeanCreationException: No qualifying bean of type … |
コンポーネント走査範囲外(パッケージ構造が分散) | @SpringBootApplication が置かれたクラスのサブパッケージにすべてのコンポーネントを配置 |
| 6 | org.springframework.dao.DataIntegrityViolationException |
DTO のバリデーション未実装で DB 制約違反 | jakarta.validation アノテーション (@NotBlank, @Size) を付与し、@Valid と共に受け取る |
| 7 | Connection refused (MySQL) |
コンテナ起動順序が逆 | docker-compose.yml の depends_on と healthcheck を設定 |
| 8 | ClassNotFoundException: jakarta.* |
依存が javax.* 系に残っている |
全ての Spring Boot 3.x 関連ライブラリを jakarta.* バージョンに置き換える |
| 9 | OutOfMemoryError (Docker) |
コンテナメモリ上限がデフォルト 256 MiB | docker run -m 512m … または compose の mem_limit: を設定 |
| 10 | Failed to configure a DataSource |
環境変数 MYSQL_PASSWORD が未定義 |
GitHub Actions の Secrets に MYSQL_PASSWORD を登録し、workflow で参照 |
※上記は 2025 年版 として実務で頻出したケースをピックアップしています。
9 学習リソース(2025 年最新版)
| 種類 | 推奨アイテム | 主な対象 |
|---|---|---|
| 書籍 | 「Spring Boot 3 実践入門」 (技術評論社, 2024/10) | 初心者から中級者まで、実装例が豊富 |
| 書籍 | 「Java 21 新機能徹底解説」 (オライリー・ジャパン, 2025/2) | JDK 21 の全新機能を体系的に学べる |
| オンラインコース | Udemy – Spring Boot 3 完全マスター(山田太郎、2025 更新版) | ハンズオン中心でプロジェクト構築までカバー |
| オンラインコース | Coursera – Modern Java with JDK 21(Google Cloud 提供) | JVM の内部構造やパフォーマンスチューニングに焦点 |
| 記事・ブログ | Qiita 「Spring Boot 入門:基礎から実践まで」(リンク) | コードスニペットが豊富で検索しやすい |
| 記事・ブログ | tasukehub 「【2025年完全版】Spring Boot 入門」(リンク) | 初心者向けに図解と手順が丁寧 |
10 まとめ
- JDK 21 と Spring Boot 3.2 は、LTS と最新機能のバランスが取れた組み合わせであり、2024‑2025 年期の新規プロジェクトに適しています。
- 開発環境は IntelliJ IDEA か VS Code のいずれでも同等に構築でき、
java.home設定だけで統一できます。 - Spring Initializr を使えば Maven・Gradle どちらのビルドツールも数クリックで雛形が生成可能です。
jakarta.validation系を正しく利用し、表記揺れを防ぎましょう。- AOT コンパイルと GraalVM Native Image の組み合わせは 起動時間短縮 と メモリ削減 を実現しますが、ビルド環境の統一が必須です。
- データベースは開発時に H2、 本番で MySQL へプロファイル切替えるだけでシームレスに移行できます。
- Docker と GitHub Actions による CI/CD パイプラインを整備すれば、ローカルと本番環境の差異はほぼ解消します。
- 本稿で紹介した「よくあるエラー」一覧は、トラブルシューティング時に即座に参照できるチェックリストとして活用してください。
次のステップ:この記事を手元に置き、実際に
spring initでプロジェクトを作成し、Docker と CI/CD のパイプラインまで構築してみましょう。疑問点は上記の学習リソースや公式ドキュメント(Spring Boot Docs、[OpenJDK LTSページ])を参照してください。