Spring Boot入門
本番へ出すための次の一歩
このレッスンでは、ここまで作ってきたアプリケーションを実際に動かして届けるために必要なことと、次に学ぶべき範囲の地図を手に入れます。
ビルドと実行可能 jar
Spring Boot のアプリケーションは、1本の jar ファイルに固めて配れます。Maven なら次のコマンドです。
ターミナル
./mvnw clean package
java -jar target/myapp-0.0.1-SNAPSHOT.jarGradle なら ./gradlew bootJar で同じことができます。出来上がった jar には、アプリケーションのクラスだけでなく、依存しているライブラリと Tomcat 本体まで入っています。だから Java さえ入っていれば java -jar の一行で起動します。動かす側に Tomcat を設置して war を置く、という昔ながらの手順が不要になったのが、Spring Boot がもたらした大きな変化のひとつです。
この jar を fat jar や実行可能 jar と呼びます。中身は普通の jar とは少し構造が違い、BOOT-INF の下にアプリケーションのクラスと依存ライブラリが分けて置かれています。起動時に Spring Boot 独自のクラスローダーがそこを読みます。
コマンドの頭に付いている ./mvnw は Maven Wrapper です。開発者ごとに Maven のバージョンが違って挙動が変わる事故を避けるため、プロジェクトが使うバージョンを自分で取りに行く仕組みです。CI でも同じものを使えば、手元と同じ結果になります。
プロファイルで環境を切り替える
開発中はローカルのデータベース、本番はクラウドのデータベース、という切り替えが必要になります。これを担うのがプロファイルです。
設定ファイルを環境ごとに分けて置きます。
プレーンテキスト
src/main/resources/
application.yml 共通の設定
application-dev.yml dev のときだけ追加で読まれる
application-prod.yml prod のときだけ追加で読まれるどれを使うかは起動時に指定します。
ターミナル
java -jar myapp.jar --spring.profiles.active=prod環境変数 SPRING_PROFILES_ACTIVE でも同じ指定ができます。共通の application.yml が先に読まれ、そのうえにプロファイル固有のファイルが重ねられるので、違うところだけを書けば済みます。
プロファイルは Bean にも効きます。@Profile("dev") を付けた Bean は dev のときだけ登録されます。開発中だけダミーのメール送信を使う、といった切り替えに向いています。
ここで大事な原則をひとつ挙げます。パスワードや API キーを設定ファイルに直接書かないことです。ソースコードの管理下に秘密が入ると、取り消すのが非常に難しくなります。環境変数や外部の秘密管理の仕組みから読ませます。Spring Boot は ${DB_PASSWORD} のような記法で環境変数を設定値に差し込めます。
Spring Security の入口
ここまでのアプリケーションは、誰でも全部のエンドポイントを呼べる状態です。実際のサービスでは、誰であるかを確かめる認証と、その人に何を許すかを決める認可が要ります。この2つを担うのが Spring Security です。
依存を追加した瞬間に、すべてのエンドポイントがログインを要求するようになります。これは驚かされる挙動ですが、既定で閉じておくという方針の表れです。開けるほうを明示的に書く形になります。
Java
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated());
return http.build();
}
}仕組みの中心はフィルタチェーンです。リクエストがコントローラに届く前に、認証用のフィルタが順番に並んでいて、そこを通り抜けたものだけが先へ進みます。このコースでフィルタチェーンを扱ったときに書いた「順番に通して、途中で止まったらそこで返す」という構造が、そのまま本物にも当てはまります。
次に学ぶ順番としては、まずフォームログインで認証の流れをつかみ、それから REST API 向けにトークンを使う方式へ進むのが分かりやすいです。パスワードは必ずハッシュ化して保存する、という点だけは最初から守ってください。
Actuator で状態を覗く
動かし始めると、生きているかどうかを外から確かめる口が必要になります。Spring Boot Actuator は、そのための入口を用意してくれます。
| エンドポイント | 分かること |
|---|---|
/actuator/health | 生きているか、依存先につながっているか |
/actuator/info | アプリケーションのバージョンなどの情報 |
/actuator/metrics | メモリ、スレッド、リクエスト数などの計測値 |
既定では health と info だけが公開されます。ほかを出したい場合は設定で明示します。これも既定で閉じるという方針です。health はコンテナオーケストレーションの死活監視の宛先としてそのまま使えます。ただし内部の詳細を誰にでも見せてよいわけではないので、公開範囲は必ず絞ってください。
Docker で持ち運ぶ
実行可能 jar があれば、コンテナ化は短く書けます。
dockerfile
FROM eclipse-temurin:21-jre
COPY target/myapp-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]これで、どこでも同じ環境で動く単位ができます。設定は環境変数で外から渡せるので、同じイメージを dev と prod の両方で使い回せます。同じものを動かしているという確信が持てることが、コンテナ化のいちばんの利点です。
このコースで書いた裏側と、本物の対応表
このコースの演習は、Spring のアノテーションを使わずに pure Java で書いてきました。それは Spring を避けたかったからではなく、アノテーションを1行書いたときにフレームワークが何を判断しているのかを、手で追える形にしたかったからです。書いたものが実際には何に対応していたのかを、ここで一覧にして振り返ります。
| 演習で自分の手で書いたもの | 本物の Spring での対応 |
|---|---|
| Map に登録して型で取り出す小さなコンテナ | DI コンテナ、@Component、@Bean |
| コンストラクタで依存を受け取る組み立て | コンストラクタインジェクション、@Autowired |
| インスタンスを1つだけ保持するか毎回作るかの分岐 | @Scope の singleton と prototype |
| メソッドとパスを表と突き合わせる照合 | @RequestMapping、@GetMapping、@PostMapping |
| パスの一部を切り出して変数にする処理 | @PathVariable |
| クエリ文字列を分解して既定値を当てる処理 | @RequestParam の defaultValue |
| 入力の値を1件ずつ規則に照らして集める判定 | @Valid と Bean Validation の各制約 |
| 違反の一覧をまとめて返す組み立て | BindingResult、MethodArgumentNotValidException |
| エンティティから公開してよい項目だけを選ぶ変換 | DTO、record、マッパー |
| 状況に応じて数値のステータスを選ぶ分岐 | ResponseEntity、@ResponseStatus |
| 順番に通して途中で止める仕組み | フィルタチェーン、OncePerRequestFilter |
| 条件が揃ったときだけ既定の部品を用意する判断 | 自動構成、@ConditionalOnMissingBean |
| 呼び出し回数を数える偽の実装 | Mockito のモック、@MockBean、verify |
| メソッドとパスからレスポンスを決めて期待と比べる処理 | MockMvc の perform と andExpect |
この表を見て、それぞれの行で自分が何を書いたかを思い出せるなら、このコースの目的は達成されています。アノテーションは魔法ではなく、ここに並んだ判断を代わりにやってくれる短い指示です。だから予想外の動きをしたときも、裏で何を判断しているのかを考えれば原因に辿り着けます。
次に学ぶものの地図
最後に、ここから先の道筋を挙げます。順番はおおよそ学びやすい並びです。
- Spring Data JPA を掘り下げる — 関連の張り方、遅延読み込み、N+1 問題への対処。データベースを使うアプリケーションでは、性能問題のほとんどがここに集まります
- トランザクションの理解を深める —
@Transactionalが既定では非検査例外だけでロールバックすること、同じクラス内の呼び出しでは効かないこと。この2つは実務で必ず一度は踏みます - Spring Security — 認証と認可、パスワードのハッシュ化、トークンによる API 保護
- テストを厚くする — Testcontainers で本物のデータベースを使った結合テスト。組み込みデータベースとの差で落ちる問題を潰せます
- 観測できるようにする — 構造化ログ、メトリクス、分散トレーシング。動かし始めてから効いてきます
- CI と CD — テストを自動で回し、通ったものだけを自動で配る仕組み
どれから始めても構いませんが、一度に広げないことをお勧めします。小さなアプリケーションを1本作り、それをビルドして、コンテナに入れて、実際に動くところまで運ぶ。この一往復を経験すると、ここに挙げた項目がなぜ必要なのかが自分の言葉で分かるようになります。フレームワークの学習は、機能を覚える作業ではなく、困りごとと解決策を結びつける作業です。まず困ってください。そのときに、このコースで見てきた裏側の知識が効いてきます。