VS Code + Docker で Java 開発 - Spring Boot (Maven/Gradle)
はじめに
この記事は「VS Code + Docker + Gemini CLI で Java 開発(Maven 版)」の続きです。前回は、伝統的な Maven プロジェクトの構築と開発サイクルについて解説しました。
今回はその発展形として、モダンな Java アプリ開発のデファクトスタンダードである Spring Boot フレームワークを導入します。本記事では、ビルドツールが異なる 2 つのサンプルプロジェクトを通して、Spring Boot の強力な機能と、Maven と Gradle それぞれでのプロジェクト管理方法を探ります。
-
java-app004
: Maven をベースにした Spring Boot プロジェクト -
java-app005
: Gradle をベースにした Spring Boot プロジェクト
これらのプロジェクトは、どちらも単純なメッセージを出力するアプリを実装するものなので、提供する機能は少ないです。ただし、Spring Boot というフレームワークを使っているため、このフレームワークを知らない人がコードを見ると、マジックワードがたくさん出てきて複雑に感じるはずです。
しかし、自分で実装することを考えたら手間のかかる機能があらかじめ用意されているので、簡単なアプリを作成するなら、このフレームワークを使えるようになっておいた方が良いです。特に、Java で新規の Web アプリを実装する場合は、Spring Boot の採用を検討する価値があります。
ということで、Gradle、Maven に続いて、VS Code で Spring Boot アプリを開発する方法について説明することにしました。
サンプルコード
GitHub にサンプルコードを用意したので、先に紹介しておきます。
dvc-java-gemini-01 のタグをつけてあります。
タグ | 説明 |
---|---|
dvc-java-gemini-01 | 今回、解説するもの |
開発コンテナ用については、次の記事の「Gemini CLI 向け Dev Container のセットアップ」 の内容を理解している前提での説明となっています。ご了承ください。
環境の用意
本記事では、開発環境の差異をなくし、すぐに Java 開発を始められるように、Visual Studio Code の Dev Containers 拡張機能と、筆者が提供する開発コンテナーイメージ hiro345g/dvc:jdk-202507
を使用します。
hiro345g/dvc:jdk-202507
をベースとすることで、必要なツール(JDK, Maven, Gradle, Spring Boot CLI など)の用意が簡単に済む開発コンテナを用意できます。
ここでは、次のようなフォルダ構成で環境を用意するとします。
dvc-java-gemini/
├── .devcontainer/
│ ├── Dockerfile
│ ├── compose.yaml
│ └── devcontainer.json
├── java-app004/
└── java-app005/
Dev Container の設定は、.devcontainer
フォルダに用意します。
devcontainer.json
このファイルは、Dev Container の主要な設定ファイルです。これまでのものと違う点は、Spring Boot Extension 用の拡張機能を追加してあることです。
devcontainer.json の詳細
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
"name": "dvc-java-gemini",
"dockerComposeFile": "./compose.yaml",
"service": "dvc-java-gemini",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// `google.gemini-cli-vscode-ide-companion` 対応の暫定対応。
// `host.docker.internal` を別用途で使うことを優先する場合は、
// `"postCreateCommand":` の行はコメントアウトすること。
"postCreateCommand": "echo '127.0.0.1 host.docker.internal' | sudo tee -a /etc/hosts",
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.defaultProfile.linux": "bash"
},
"extensions": [
"vscjava.vscode-java-pack", // Java Extension Pack
"vmware.vscode-boot-dev-pack", // Spring Boot Extension Pack
"shengchen.vscode-checkstyle", // Checkstyle
"ms-azuretools.vscode-containers", // Container Tools
"docker.docker", // Docker DX
"eamodio.gitlens", // Git Lens
"donjayamanne.githistory", // Git History
"mhutchie.git-graph", // Git Graph
"google.gemini-code-assist", // Gemini Code Assist
"google.gemini-cli-vscode-ide-companion" // Gemini CLI
]
}
}
}
compose.yaml
このファイルは、Docker Compose を使って開発環境コンテナのビルドと実行を定義します。
Maven や Gradle を使う場合、必要なパッケージをローカルにダウンロードしてキャッシュします。これについては、開発コンテナ用 Docker イメージに含める方法と、Docker ボリュームへ保存する方法があります。基本はキャッシュなので、筆者は Docker イメージには含めず、Docker ボリュームへ保存するようにしています。
そのため、ここでは、Maven (.m2
) と Gradle (.gradle
) のキャッシュ用フォルダを Docker ボリュームとしてマウントします。これにより、開発コンテナを一度破棄してから、起動しなおすことがあっても、ダウンロードした依存関係が保持され、ビルドが高速になります。
そのかわり、Docker ボリュームを別途管理する必要があります。管理しやすくするために、name: dvc-java-gemini-m2
のように自分でボリューム名を指定するようにしています。
compose.yaml の詳細
name: dvc-java-gemini
services:
dvc-java-gemini:
build: .
image: dvc-java-gemini:0.0.2
container_name: dvc-java-gemini
hostname: dvc-java-gemini
tty: true
volumes:
# dvc-java-gemini の Docker Compose プロジェクト用フォルダを
# /workspaces/dvc-java-gemini にバインドマウント
- type: bind
source: ..
target: /workspaces/dvc-java-gemini
# Gemini 設定用フォルダをバインドマウント
- type: bind
source: ../.gemini
target: /home/node/.gemini
# Maven 用フォルダを Docker ボリュームへマウント
- type: volume
source: dvc-java-gemini-m2
target: /home/node/.m2
# Gradle 用フォルダを Docker ボリュームへマウント
- type: volume
source: dvc-java-gemini-gradle
target: /home/node/.gradle
volumes:
dvc-java-gemini-m2:
name: dvc-java-gemini-m2
dvc-java-gemini-gradle:
name: dvc-java-gemini-gradle
Dockerfile
コンテナイメージの具体的な構築手順を定義します。ここでは、SDKMAN! を使って springboot 3.5.6
をインストールしています。また、Gradle や Maven がローカルにダウンロードしたファイルを保存するユーザーホーム配下のフォルダを用意して、マウントできるようにしてあります。
Dockerfile の詳細
FROM hiro345g/dvc:jdk-202507
# パッケージインストールのため root
USER root
# Linux で Gemini CLI を使う場合で、認証時に xdg-utils が必要と
# なることがあるため、インストールしておく。
RUN apt-get update \
&& apt-get install -y xdg-utils \
&& apt-get -y autoremove \
&& apt-get -y clean \
&& rm -rf /var/cache/apt /var/lib/apt/lists
# ここから node ユーザーによる作業
USER node
# SDKMAN! のインストール先を指定
ENV SDKMAN_DIR=/usr/local/sdkman
# gemini-cli を node ユーザーでグローバルインストール
RUN npm install -g @google/gemini-cli
# sdk コマンドを使えるように設定
RUN bash -c 'echo "[[ -s \"/usr/local/sdkman/bin/sdkman-init.sh\" ]] && source \"/usr/local/sdkman/bin/sdkman-init.sh\"" >> /home/node/.bashrc'
# SDKMAN! による spring コマンドのインストール
RUN bash -c 'source /usr/local/sdkman/bin/sdkman-init.sh && sdk install springboot 3.5.6'
# Gradle, Maven 用ユーザーフォルダの用意
RUN bash -c 'mkdir /home/node/.m2 && mkdir /home/node/.gradle'
これらの設定により、VS Code でこのリポジトリを開き、「Reopen in Container」を選択するだけで、誰でも同じ開発環境を即座に再現できます。
前回までの開発コンテナの削除
今回の開発コンテナを使う前に、前回までの開発コンテナを起動している場合は、それを削除(docker compose down
)しておきます。Docker in WSL Ubuntu の場合は WSL Ubuntu のターミナル、Docker Desktop の場合は Git Bash で次のコマンドを実行します。他の方法でもコンテナを削除できれば良いです。
docker compose -p dvc-java-gemini down
イメージのビルド
あらかじめ dvc-java-gemini:0.0.2
のイメージを docker compose build
でビルドしておくようにします。手元の Docker in WSL Ubuntu では、dvc-java-gemini:0.0.1
イメージがある環境だと、dvc-java-gemini:0.0.2
のイメージを見つけることができなくなって、エラーとなってしまいました。
Docker Desktop を使っている場合は、Git Bash でコマンド実行するとし、~/workspace/dvc-java-gemini/.devcontainer/
に compose.yaml
ファイルがあるとして、次のコマンドを実行します。
PROJECT_DIR=~/workspace/dvc-java-gemini
COMPOSE_FILE="${PROJECT_DIR}/.devcontainer/compose.yaml"
docker compose -f "${COMPOSE_FILE}" build
Docker in WSL Ubuntu を使っている場合は、ターミナルで WSL Ubuntu を開きます。compose.yaml
の Windows 側のパスが Docker Desktop を使っている場合と同じ Git Bash 上で ~/workspace/dvc-java-gemini/.devcontainer/compose.yaml
の場合は、~
を /mnt/c/Users/user001
と置き換えたパスを指定すれば良いです。
PROJECT_DIR=/mnt/c/Users/user001/workspace/dvc-java-gemini
COMPOSE_FILE="${PROJECT_DIR}/.devcontainer/compose.yaml"
docker compose -f "${COMPOSE_FILE}" build
実行例は次のようになります。
$ PROJECT_DIR=/mnt/c/Users/user001/workspace/dvc-java-gemini
$ COMPOSE_FILE="${PROJECT_DIR}/.devcontainer/compose.yaml"
$ docker compose -f "${COMPOSE_FILE}" build
[+] Building 65.2s (12/12) FINISHED
(略)
=> [internal] load metadata for docker.io/hiro345g/dvc:jdk-202507 (略)
(略)
=> exporting to image (略)
(略)
✔ dvc-java-gemini:0.0.2 Built
開発コンテナの開始と拡張機能の無効化
準備ができたら、VS Code を起動します。
cd ${PROJECT_DIR}
code .
通知に「コンテナーで再度開く」が表示されたら、それをクリックします。
開発コンテナーが開くと、自動で Java Extension Pack
拡張機能などがインストールされて有効化されます。ただし、用意してある環境では java-app004
と java-app005
の両方に対して Java プロジェクトの自動認識がされてしまい、事前準備の重い処理が動いてしまいます。
処理が終わるのを待っていても良いのですが、一番良いのは、このワークスペース(/home/node/workspace/dvc-java-gemini
)では Java Extension Pack
拡張機能を無効化しておくことです。拡張機能のビューを表示して、開発コンテナー:dvc-java-gemini:インストール済み
の一覧に含まれる Java Extension Pack
拡張機能を無効化します。これに含まれる拡張機能を無効化するかの確認ダイアログが表示されたら「はい」をクリックして全部無効化します。
Java Extension Pack
拡張機能を無効化
この後、java-app004.code-workspace
や java-app005.code-workspace
を開いたときに、Java Extension Pack
拡張機能を有効化するようにしてください。
Spring Boot とは
Spring Boot は、Java アプリ開発で広く使われている Spring Framework を、より迅速かつ容易に利用できるように設計されたフレームワークです。公式のサイトは次の URL で公開されています。
このフレームワークの目的は、開発者が複雑な設定に時間を費やすことなく、アプリのビジネスロジックの実装に集中できるようにすることです。
主な特徴は次のとおりです。
- 自動設定 (Auto-Configuration)
- スタンドアロン実行
- スターター依存関係 (Starter Dependencies)
自動設定 (Auto-Configuration) とは、プロジェクトに含まれるライブラリを検知し、それに応じて必要となるであろう設定を自動的に行うことです。例えば、データベースを使うアプリについて、Spring Boot を使わない場合の Java アプリでは、定型的なデータベース接続用のコードを開発者が記述する必要がありました。Spring Boot では、この自動設定が対応する範囲が非常に広いため、開発者が記述しないといけないデータベース接続用のコードが非常に少なくなっています。
スタンドアロン実行とは、Web アプリでも単体の JAR ファイルで実行できることです。通常の Java で実装した Web アプリだと、別途 Apache Tomcat サーバーなどの Jakarta EE コンテナが必要となります。しかし、Spring Boot を使うと、Tomcat のような Jakarta EE コンテナをアプリに内蔵することが簡単にできます。そのため、別途サーバーを用意しなくても、JAR ファイルを実行するだけでアプリを起動できます。
スターター依存関係 (Starter Dependencies) とは、「Web アプリ開発」や「データベースアクセス」といった特定の機能ごとに、必要となるライブラリ一式をまとめた「スターター」が提供されていることです。これにより、依存関係の管理の手間が大幅に簡素化できます。
これらの特徴により、Spring Boot は本番環境に対応した堅牢なアプリや、マイクロサービスを迅速に構築するためのデファクトスタンダードとなっています。
Spring Boot プロジェクトの概要
ここで用意してある java-app004
と java-app005
は、ビルドツールは異なりますが、アプリの機能としては全く同じものです。どちらも Spring Boot を基盤としたスタンドアロンのコンソールアプリであり、CommandLineRunner
という仕組みを利用して、起動後に特定の処理を実行して終了します。
最初から Web アプリを動かそうとすると、必要となる前提知識の量が跳ね上がります。まずは、ここで紹介する Spring Boot アプリの基本構造について理解してから、次の Spring Boot アプリ開発へステップを踏みながら進むのが良いと考えています。ということで、本記事では、あえて単純な機能しか持たないアプリとしてあります。
なお、ここでは java-app004/src
にあるものについて説明しています。java-app005/src
にあるものは app004
を app005
に変更するなど、パッケージ名やクラス名に若干の変更をしてありますが、内容的には同じプログラムとなっています。そのため、説明は省略しています。
ここで、Java のソースコードを参照するときは、VS Code で java-app004.code-workspace
のワークスペースを開いてから、Java Extension Pack
拡張機能を有効化します。それから、Java のコードをエディタで開くと、Java Extension Pack
拡張機能によるフォーマットや文法チェックが利用できる実際の開発画面での確認ができます。
java-app004.code-workspace
を開いた VS Code 画面
最近使ったワークスペースを開く
java-app004.code-workspace
を開いている状態から、初めて java-app005.code-workspace
を開くには、一度 /home/node/workspace/dvc-java-gemini
のワークスペースに戻ってから、そこで VS Code の「エクスプローラー」から java-app005.code-workspace
をエディタで開き、「ワークスペースを開く」ボタンをクリックします。
こういった手順を踏む場合は、VS Code のメニューにある「ファイル」-「最近使用した項目を開く」を使うと、ワークスペースの切り替えが楽にできます。
最近使用した項目を開く
ターミナルに慣れている場合は、java-app005.code-workspace
をターミナルから code
コマンドで開いても良いです。その場合は、java-app004.code-workspace
を開いている VS Code の画面で開発コンテナのターミナルを開き、次のコマンドを実行します。ただし、こちらは新しく開発コンテナーをアタッチした VS Code の画面が表示されます。
code /workspace/dvc-java-gemini/java-app005/java-app005.code-workspace
アプリの構成
java-app004、java-app005 の Spring Boot アプリの起動の仕組みは、主に 3 つのクラスによって成り立っています。
JavaApp004Application
App
GreetingProperties
JavaApp004Application:
このクラスは、@SpringBootApplication
アノテーションが付与された、アプリ起動の起点(エントリーポイント)となるものです。
package internal.dev.javaapp004;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* Main application class for java-app004.
*/
@SpringBootApplication(scanBasePackages = "internal.dev")
@EnableConfigurationProperties(GreetingProperties.class)
public class JavaApp004Application {
/**
* Default constructor.
*/
public JavaApp004Application() {
// Default constructor
}
/**
* Main entry point for the application.
*
* @param args command line arguments.
*/
public static void main(String[] args) {
SpringApplication.run(JavaApp004Application.class, args);
}
}
-
@SpringBootApplication
: 設定クラスの宣言、自動設定の有効化、コンポーネントのスキャンという 3 つの重要な機能をまとめて提供します。scanBasePackages
を指定することで、DI コンテナが管理するコンポーネントを探す範囲をinternal.dev
パッケージ以下に限定しています。 -
@EnableConfigurationProperties(GreetingProperties.class)
:GreetingProperties
クラスをプロパティファイル(application.properties
)から値を読み込むための設定クラスとして有効にします。 -
SpringApplication.run(...)
: 組み込み Web サーバーの起動や DI コンテナの初期化などを含む、Spring Boot アプリの起動処理を実行します。
GreetingProperties:
このクラスは @ConfigurationProperties(prefix = "greeting")
アノテーションを持ち、application.properties
ファイル内の greeting.
から始まるプロパティをマッピングするためのクラスです。
このクラスを用意することで、アプリの挙動を開発時と運用時とで変えることが簡単にできるようになります。
package internal.dev.javaapp004;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for greeting messages.
*/
@ConfigurationProperties(prefix = "greeting")
public class GreetingProperties {
private String message;
/**
* Default constructor.
*/
public GreetingProperties() {
// Default constructor
}
/**
* Gets the greeting message.
*
* @return The greeting message.
*/
public String getMessage() {
return message;
}
/**
* Sets the greeting message.
*
* @param message The greeting message to set.
*/
public void setMessage(String message) {
this.message = message;
}
}
ここでは、greeting.message
というキーの値が、このクラスの message
フィールドに自動的に設定されるようにしてあります。これにより、設定値を型安全に扱うことができます。
App:
このクラスは、CommandLineRunner
インターフェースを実装し、アプリのメインロジックを記述します。
package internal.dev;
import internal.dev.javaapp004.GreetingProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
/**
* The main application class.
*/
@Component
public class App implements CommandLineRunner {
/** The logger. */
private static final Logger logger = LoggerFactory.getLogger(App.class);
private final GreetingProperties greetingProperties;
/**
* Constructs the App with GreetingProperties.
*
* @param greetingProperties The properties for greeting.
*/
public App(GreetingProperties greetingProperties) {
this.greetingProperties = greetingProperties;
}
@Override
public void run(String... args) throws Exception {
logger.info("This is an info message.");
logger.warn("This is a warning message.");
logger.error("This is an error message.");
logger.info("Message from .env: {}", greetingProperties.getMessage());
}
/**
* Returns a greeting message.
*
* @return The greeting from .env file
*/
public String getGreeting() {
return greetingProperties.getMessage();
}
}
-
@Component
: このクラスが Spring の DI コンテナによって管理されるべきコンポーネント(部品)であることを示します。 -
CommandLineRunner
: このインターフェースを実装すると、run
メソッドが Spring Boot アプリの起動処理が完了した後に自動的に呼び出されます。ここに、コンソールアプリのエントリーとなる処理を記述するのが最適です。 -
コンストラクタインジェクション:
App
クラスはコンストラクタでGreetingProperties
を受け取ります。Spring の DI コンテナが、@EnableConfigurationProperties
で有効化されたGreetingProperties
のインスタンスを自動的に生成し、コンストラクタを通じて注入(DI)します。
プロパティファイル
Spring Boot では、src/main/resources
ディレクトリに置かれた application.properties
ファイルを使って、アプリの挙動を柔軟に設定できます。
このプロジェクトでは、さらにプロファイルという機能を利用して、アプリ実行時の設定を簡単に切り替えられるようにしています。ここでは、2 つのプロファイルを用意してあります。
プロファイル | 説明 |
---|---|
dev |
開発環境用 |
prod |
運用環境用 |
プロファイル機能と設定の優先順位
Spring Boot は、有効になっているプロファイルに応じて、読み込むプロパティファイルを変更することができます。
application.properties
application-{profile}.properties
application.properties:
これは、すべてのプロファイルで共通して読み込まれる基本設定ファイルです。
このファイルで使用するプロファイルを指定することができます。プロファイルを指定するために使うプロパティは、 spring.profiles.active
です。
application-{profile}.properties:
これは、spring.profiles.active
で指定されたプロファイルに応じた設定ファイルとなります。例えば、プロファイル dev
を用意する場合は、application-dev.properties
ファイルを作成します。ここで定義された値は、application.properties
の共通設定を上書きします。
このプロジェクトでは、application.properties
に spring.profiles.active=dev
と記述しているため、デフォルトでは dev
プロファイルが有効になります。
spring.profiles.active=dev
プロファイルごとの設定ファイル
application-dev.properties
は、dev
プロファイル(開発環境用)が有効な場合に読み込まれます。
greeting.message=This is a message for the dev environment.
application-prod.properties
は、prod
プロファイル(運用環境用)が有効な場合に読み込まれます。Maven でビルドまたは実行する際に -P prod
オプションを付けると、こちらの設定が有効になります。
greeting.message=This is a message for the prod environment.
ロギング設定との連携
このプロファイル機能は、ロギング設定にも活用できます。logback.xml
の中で <springProfile>
タグを使うと、有効なプロファイルに応じてログのレベルや出力先を切り替えることができます。
ここでは、開発環境ではコンソール出力とログファイルへの出力とし、運用環境ではログファイルのみに出力とすることを基本とし、ログレベルも調整して設定します。
<configuration>
<!-- ... Appender definitions ... -->
<!-- dev profile -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</springProfile>
<!-- prod profile -->
<springProfile name="prod">
<root level="WARN">
<appender-ref ref="FILE" />
</root>
</springProfile>
</configuration>
dev
プロファイルでは、ログレベルは INFO
で、コンソール (STDOUT
) とファイル (FILE
) の両方に出力される指定となっています。
prod
プロファイルでは、ログレベルは WARN
に引き上げられ、出力先はファイルのみに限定される指定となっています。これにより、運用環境で不必要なログが出力されるのを防いてでいます。
JUnit 5 でのテスト
Spring Boot は spring-boot-starter-test
を通じて、JUnit 5 をベースとした強力なテスト環境を提供します。
ここでは、サンプルとして JavaApp004ApplicationTests.java
を用意してあります。
package internal.dev.javaapp004;
import static org.junit.jupiter.api.Assertions.assertEquals;
import internal.dev.App;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class JavaApp004ApplicationTests {
@Autowired
private App app;
@Test
void testGetGreeting() {
assertEquals("Hello from test-application.properties!", app.getGreeting());
}
}
@SpringBootTest
は、テスト実行時に実際のアプリ起動に近い形で DI コンテナをセットアップします。このとき、src/test/resources
内の設定ファイルが優先的に読み込まれます。
@Autowired
は、DI コンテナに登録されている App
クラスのインスタンスを、テストクラスのフィールドに自動的に注入します。これにより、実際のコンポーネントを使った統合テストが容易になります。
testGetGreeting
メソッドでは、src/test/resources/application.properties
に定義された greeting.message
の値が正しく読み込まれていることを検証しています。
src/test/resources/application.properties
の内容は次のようにしてあります。
greeting.message=Hello from test-application.properties!
java-app004
Maven によるビルド: java-app004
は、Java プロジェクトで長年広く使われているビルドツールである Maven を採用しています。
プロジェクト構造(Maven 版)
標準的な Maven のディレクトリ構成に従っています。ビルド設定は pom.xml
に記述されます。
java-app004/
├── src/
│ └── main/
│ ├── java/...
│ └── resources/...
├── .gitignore
├── mvnw # Maven Wrapper
├── pom.xml # Maven ビルド設定
└── README.md
pom.xml
)
ビルド設定 (Spring Boot プロジェクトの pom.xml
から、Spring Boot 関連の主な設定を抜粋したものが以下になります。
<!-- Spring Boot のバージョン管理を集約 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!-- 基本的な Spring Boot 機能のスターター -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 開発時の生産性を向上させるためのツール -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- @ConfigurationProperties を使うために必要 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- テスト用のスターター (JUnit 5, Mockito などを含む) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 実行可能な JAR を作成するためのプラグイン -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
主要な依存関係とプラグインは以下の通りです。
-
<parent>
:spring-boot-starter-parent
を指定することで、多数のライブラリのバージョンが一元管理され、互換性の問題を気にする必要がなくなります。 -
spring-boot-starter
: DI コンテナ、ロギング、自動設定など、Spring Boot の中核機能を提供します。 -
spring-boot-devtools
: 開発時の生産性を向上させるためのツールです。ファイルの変更を検知してアプリを自動的に再起動する機能などを提供します。 -
spring-boot-configuration-processor
:@ConfigurationProperties
を使用したクラス(GreetingProperties
)のメタデータを生成し、IDE での入力補完などを可能にするための依存関係です。 -
spring-boot-maven-plugin
: 依存ライブラリをすべて含んだ「実行可能な JAR (fat JAR)」を生成します。
ここに次の依存関係とプラグインを追加して、pom.xml
を完成させました。
-
lombok
:@Getter
や@Setter
、コンストラクタなどをアノテーションで自動生成し、Java の定型的なコードを削減します。 -
maven-checkstyle-plugin
: Google Java Style Guide への準拠をビルド時に自動的にチェックします。 -
maven-javadoc-plugin
: Javadoc コメントから API ドキュメントを生成します。 -
<profiles>
: Maven のプロファイルを定義します。dev
、prod
、debug
の各プロファイルがあり、ビルドや実行の挙動を切り替えるために使用されます。例えばprod
プロファイルでは、Spring Boot のprod
プロファイルを有効にして JAR をパッケージングします。
Maven プロファイル
pom.xml
の <profiles>
セクションでは、Maven のプロファイルを定義し、ビルドや実行の挙動を切り替えることができます。
ここで、Spring Boot アプリ用のプロファイルは対象範囲が Spring Boot アプリですが、こちらは運用環境と開発環境全体を対象としたものとなる点に注意してください。Maven プロジェクトでは、Spring Boot アプリが依存するパッケージや、開発で使用する周辺ツールのバージョン管理は Maven ですることになります。
この場合、例えばフォーマッターやスタイルチェッカーは何を使うのか、開発時と運用時とで周辺ツールの設定をどのように変更するのか、といったことは Spring Boot アプリとは別に管理する必要があります。そういった管理ができるように、Maven のプロファイルがあります。
java-app004
の Maven プロジェクトでは、次の 3 つのプロファイルを用意してあります。
プロファイル | 説明 |
---|---|
dev |
開発環境用 |
prod |
運用環境用 |
debug |
デバッグ実行用 |
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<replace
file="${project.build.outputDirectory}/application.properties"
token="spring.profiles.active=dev"
value="spring.profiles.active=prod" />
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>debug</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005
</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
dev
プロファイルについては、<activation><activeByDefault>true</activeByDefault></activation>
により、プロファイルが明示的に指定されない場合のデフォルトとして設定されています。
prod
プロファイルについては、-P prod
で有効になります。プロパティ spring.profiles.active
を prod
にすることで、Spring Boot アプリを実行するときに、prod
プロファイルを有効にします。
なお、ここでは ビルド時に -P prod
が指定されたときは、application.properties
ファイル内の spring.profiles.active
の値を prod
にするようにしてあります。アプリ実行時に spring.profiles.active
を指定する方法でプロファイルを切り替える場合は必要ありませんが、Maven のプロファイル利用の例として置換処理をしています。置換処理には、maven-antrun-plugin
プラグインを使っています。replace
要素の指定で spring.profiles.active=dev
を spring.profiles.active=prod
に置き換えています。
debug
プロファイルについては、-P debug
で有効になります。spring-boot-maven-plugin
の設定で、リモートデバッグを有効にするための jvmArguments
を追加します。
完成版の `pom.xml`
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.6</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>internal.dev</groupId>
<artifactId>java-app004</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java-app004</name>
<description>Demo project for Spring Boot</description>
<url />
<licenses>
<license />
</licenses>
<developers>
<developer />
</developers>
<scm>
<connection />
<developerConnection />
<tag />
<url />
</scm>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<versionRange>[3.4.0,)</versionRange>
<goals>
<goal>check</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.4.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>10.17.0</version>
</dependency>
</dependencies>
<configuration>
<configLocation>google_checks.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<linkXRef>false</linkXRef>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.8.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.2</version>
<reportSets>
<reportSet>
<reports>
<report>ci-management</report>
<report>dependencies</report>
<report>dependency-info</report>
<report>dependency-management</report>
<report>distribution-management</report>
<report>index</report>
<report>issue-management</report>
<report>licenses</report>
<report>mailing-lists</report>
<report>modules</report>
<!-- <report>plugin-management</report> -->
<report>plugins</report>
<report>scm</report>
<report>summary</report>
<report>team</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>3.4.0</version>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<replace
file="${project.build.outputDirectory}/application.properties"
token="spring.profiles.active=dev"
value="spring.profiles.active=prod" />
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>debug</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005
</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
mvnw
)
ビルドと実行(このプロジェクトでは、Maven のプロファイル機能を利用して、環境に応じたビルドや実行が可能です。
mvnw
)
ビルド(dev プロファイルでのビルド (デフォルト):
次のコマンドを実行すると、dev
プロファイルが有効な状態でアプリがビルドされます。
./mvnw clean install
実行例は次のようになります。最後に BUILD SUCCESS
のメッセージが表示されたら成功です。失敗すると、このメッセージは表示されずに処理が終了します。
node ➜ /workspaces/dvc-java-gemini/java-app004 $ ./mvnw clean install
(略)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 48.819 s
[INFO] Finished at: 2025-09-27T23:18:40Z
[INFO] ------------------------------------------------------------------------
なお、処理の途中に、パッケージダウンロードのメッセージが表示されるなどします。処理のログとして使えるので、確認したいことがある場合に役立ちます。
prod プロファイルでのビルド:
本番環境向けのビルドを行うには、-P prod
オプションを指定します。これにより、Spring Boot の prod
プロファイルが有効化された JAR ファイルが生成されます。
./mvnw clean install -P prod
dev
プロファイルでのビルドと同様に、最後に BUILD SUCCESS
のメッセージが表示されたら成功です。
ビルド結果の jar の実行:
ビルド結果の jar は、どちらのプロファイルも target/java-app004-0.0.1-SNAPSHOT.jar
にあります。これは、ビルド時のログからわかります。
[INFO]
[INFO] --- jar:3.4.2:jar (default-jar) @ java-app004 ---
[INFO] Building jar: /workspaces/dvc-java-gemini/java-app004/target/java-app004-0.0.1-SNAPSHOT.jar
これを実行するには java -jar
コマンドを使います。
java -jar target/java-app004-0.0.1-SNAPSHOT.jar
ビルド時に指定したプロファイルによって、動作が変わります。dev
プロファイルのものはコンソールにメッセージ出力をしますが、prod
プロファイルのものは出力しません。実行例は、この後に説明する「 実行(mvnw
)」の方で示すので、ここでは省略します。
なお、コンソール出力を抑制したい場合は、次のようにログレベルの変更指定(--logging.level.root=ERROR
)と、Spring のバナー非表示の指定(--spring.main.banner-mode=off
)をします。
java -jar target/java-app004-0.0.1-SNAPSHOT.jar \
--logging.level.root=ERROR \
--spring.main.banner-mode=off
このとき、ch.qos.logback
関連のログ出力は残ります。これを抑制したい場合は、Logback設定ファイル(logback-spring.xml
)を使えば良いようですが、ここでは対応していません。
mvnw
)
実行(dev プロファイルでの実行 (デフォルト):
-P
オプションを指定しない場合、デフォルトで dev
プロファイルが有効になります。
./mvnw spring-boot:run
実行例は次のようになります。Message from .env:
の値から、dev
プロファイル用のプロパティファイルが読み込まれていることがわかります。
node ➜ /workspaces/dvc-java-gemini/java-app004 $ ./mvnw spring-boot:run
(略)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.5.6)
(略)
2025-09-27 23:20:24.836 [restartedMain] INFO i.d.javaapp004.JavaApp004Application - Started (略)
2025-09-27 23:20:24.851 [restartedMain] INFO internal.dev.App - This is an info message.
2025-09-27 23:20:24.852 [restartedMain] WARN internal.dev.App - This is a warning message.
2025-09-27 23:20:24.852 [restartedMain] ERROR internal.dev.App - This is an error message.
2025-09-27 23:20:24.853 [restartedMain] INFO internal.dev.App - Message from .env: This is a message for the dev environment.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.903 s
[INFO] Finished at: 2025-09-27T23:20:25Z
[INFO] ------------------------------------------------------------------------
prod プロファイルでの実行:
本番環境用の設定で実行するには、-P prod
オプションを指定します。
./mvnw spring-boot:run -P prod
次に実行例を示します。先に現在時刻を確認するために、date -u
コマンドを実行しておきましょう。ログの時刻を記録するにあたって、タイムゾーンは UTC としてあるので、-u
オプションを指定します。ちなみに、日本の東京のタイムゾーンを使う場合は、TZ='Asia/Tokyo'
の環境変数を指定します。
node ➜ /workspaces/dvc-java-gemini/java-app004 $ date -u
2025年 9月 27日 土曜日 23:23:00 UTC
node ➜ /workspaces/dvc-java-gemini/java-app004 $ TZ='Asia/Tokyo' date
2025年 9月 28日 日曜日 08:23:06 JST
ここでは、時刻確認をしてから、mvnw
コマンドでアプリを実行し、その後に tail
コマンドでログを確認しています。tail
コマンドはファイルの末尾のテキストを表示するときに使うコマンドです。
dev
プロファイルと違って、コンソール出力にはアプリによるメッセージ出力はなく、ログファイルの log/app.log
にメッセージ出力がされていることがわかります。
node ➜ /workspaces/dvc-java-gemini/java-app004 $ TZ=C date
2025年 9月 27日 土曜日 23:37:53
node ➜ /workspaces/dvc-java-gemini/java-app004 $ ./mvnw spring-boot:run -P prod
[INFO] Scanning for projects...
(略)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.5.6)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.250 s
[INFO] Finished at: 2025-09-27T23:38:15Z
[INFO] ------------------------------------------------------------------------
node ➜ /workspaces/dvc-java-gemini/java-app004 $ tail logs/app.log
2025-09-27 23:38:14.746 [restartedMain] WARN internal.dev.App - This is a warning message.
2025-09-27 23:38:14.750 [restartedMain] ERROR internal.dev.App - This is an error message.
debug プロファイルでの実行:
デバッグモードでアプリを起動し、リモートデバッガの接続をポート 5005
で待ち受けるには、-P debug
オプションを指定します。
./mvnw spring-boot:run -P debug
デバッガを接続しないで、アプリを強制終了するには、起動したターミナルで Ctrl + C
を入力します。
ドキュメントとレポートの生成(Maven 版)
Maven のプラグインを使って、テストレポートや API ドキュメントを生成できます。
テストレポートを含むサイトを生成するには次のコマンドを実行します。
./mvnw site
レポートは target/site/surefire-report.html
に生成されます。
Javadoc だけ生成することもできます。その場合は次のコマンドを実行します。
./mvnw javadoc:javadoc
Java API ドキュメントは target/site/apidocs/
に生成されます。
生成されたものについて、JDK 18 以降に付属する jwebserver
コマンドを使用して target/site
をドキュメントルートとする Web サーバーを起動することで、Web ブラウザから確認できます。
cd target/site
jwebserver -p 8000
Dev Container 内で実行する場合は、-b 0.0.0.0
を指定してすべてのネットワークインターフェースにバインドすることで、ホストマシンのブラウザからアクセスできるようになります。
cd target/site
jwebserver -b 0.0.0.0 -p 8000
以上で、Maven 版の説明はおしまいです。
java-app005
Gradle によるビルド: java-app005
は、java-app004
と全く同じ機能を持つプロジェクトですが、ビルドツールとしてよりモダンで柔軟な Gradle を採用しています。
プロジェクト構造(Gradle 版)
pom.xml
の代わりに build.gradle
と settings.gradle
がビルド設定を担います。
java-app005/
├── src/
│ └── main/
│ ├── java/...
│ └── resources/...
├── .gitignore
├── gradlew # Gradle Wrapper
├── build.gradle # Gradle ビルドスクリプト
└── README.md
build.gradle
)
ビルド設定 (Gradle のビルドスクリプトは、XML ではなく Groovy や Kotlin といったプログラミング言語で記述するため、より柔軟で可読性が高いとされています。さらにこのプロジェクトでは、依存関係のバージョンを gradle/libs.versions.toml
というバージョンカタログファイルで一元管理する、モダンなアプローチを採用しています。
libs.versions.toml
)
バージョンカタログ (このファイルでは、プロジェクト全体で使用する依存関係を [versions]
、[libraries]
、[plugins]
の 3 つのセクションで一元管理します。
[versions]
springBoot = "3.5.6"
springDependencyManagement = "1.1.6"
checkstyleTool = "10.17.0"
[libraries]
lombok = { group = "org.projectlombok", name = "lombok" }
junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher" }
spring-boot-starter = { group = "org.springframework.boot", name = "spring-boot-starter" }
spring-boot-devtools = { group = "org.springframework.boot", name = "spring-boot-devtools" }
spring-boot-starter-test = { group = "org.springframework.boot", name = "spring-boot-starter-test" }
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "springBoot" }
spring-dependency-management = { id = "io.spring.dependency-management", version.ref = "springDependencyManagement" }
[versions]
には、ライブラリやプラグインのバージョン番号を変数として定義します。これにより、複数の場所で使われるバージョンをまとめて更新できます。
[libraries]
には、依存するライブラリを定義し、build.gradle
から参照するためのエイリアス(例: spring-boot-starter
)を設定します。
[plugins]
には、ビルドに使用する Gradle プラグインを定義します。ここでもエイリアス(例: spring-boot
)を設定し、バージョンは [versions]
セクションで定義した変数を参照しています。
build.gradle
)
ビルドスクリプト (build.gradle
では、バージョンカタログで定義したエイリアスを使って、プラグインや依存関係を簡潔に記述します。
plugins {
alias(libs.plugins.spring.boot)
alias(libs.plugins.spring.dependency.management)
id 'java'
id 'checkstyle'
}
group = 'internal.dev'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation libs.spring.boot.starter
developmentOnly libs.spring.boot.devtools
compileOnly libs.lombok
annotationProcessor libs.lombok
testImplementation libs.spring.boot.starter.test
testRuntimeOnly libs.junit.platform.launcher
}
// ... (checkstyle, profiles, etc.)
plugins
には、プロジェクトで使用する Gradle プラグインを宣言します。alias
には、バージョンカタログ (libs.versions.toml
) で定義されたプラグインのエイリアスを参照して適用します。例えば alias(libs.plugins.spring.boot)
は、Spring Boot プラグインを適用します。id
には、プラグインの ID を直接指定して適用します。java
プラグインは Java のコンパイルやテストなどの基本的なタスクを、checkstyle
プラグインはコードの静的解析機能を提供します。
group
と version
には、それぞれ、アプリを開発しているグループ情報とバージョン情報を指定します。なお、Maven では、パッケージの識別に Maven コーディネート(Maven coordinates)を使います。このアプリも Maven コーディネートを持ち、その値の決定には、これらの指定が影響します。Maven コーディネートは、group:artifact:version
というフォーマットで決まる識別子で、settings.gradle
の rootProject.name
が artifact
として使われ、build.gradle
ファイルで指定する group
と version
と合わせて決まります。
java { toolchain { ... } }
には、プロジェクトで使用する Java のバージョン(ツールチェーン)を指定します。ここでは Java 21 が設定されています。
repositories { ... }
には、依存関係をダウンロードしてくるリポジトリを指定します。mavenCentral()
は、Maven Central リポジリを使用することを意味します。
dependencies { ... }
には、プロジェクトの依存ライブラリを定義します。implementation
, developmentOnly
, compileOnly
, annotationProcessor
, testImplementation
などは「コンフィグレーション」と呼ばれ、依存関係がどのクラスパスに含まれるか(コンパイル時、実行時、テスト時など)を決定します。libs.spring.boot.starter
のように、バージョンカタログで定義したライブラリのエイリアスを参照して、タイプセーフに依存関係を追加できます。
Gradle でのプロファイル対応
build.gradle
の末尾には、Maven のプロファイルと同様の機能を実現するための設定が記述されています。
// プロファイルの指定がない場合は 'dev' を使う
ext.profile = project.hasProperty('profile') ? project.getProperty('profile') : 'dev'
// application.properties 内のプレースホルダを置換するフィルター
tasks.withType(ProcessResources) {
filesMatching('**/application.properties') {
expand(profile: project.ext.profile)
}
}
// bootRun タスクにプロファイルを渡す
tasks.withType(org.springframework.boot.gradle.tasks.run.BootRun) {
args = ["--spring.profiles.active=${profile}"]
}
// debug プロパティがあればデバッグ用のJVM引数を追加
if (project.hasProperty('debug')) {
tasks.withType(JavaExec) {
jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005']
}
}
// bootJar タスクで生成されるJARのマニフェストにプロファイルを含める
tasks.withType(org.springframework.boot.gradle.tasks.bundling.BootJar) {
manifest {
attributes(
'Spring-Boot-Profiles': profile
)
}
}
// 現在のプロファイルを表示するタスク
task showProfile {
doLast {
println "Current profile: ${profile}"
}
}
ext.profile = ...
は、Gradle のコマンドラインで -Pprofile=...
というプロパティが指定されていればその値を、なければ 'dev'
を profile
という変数に設定するというものです。
tasks.withType(ProcessResources)
は、タスク実行時にリソースに対して処理をするもので、ここでは application.properties
内の ${profile}
をプロパティで指定された値に置換するというものです。
このため、java-app005
では、src/main/resources/application.properties
の内容は次のようになっています。
spring.profiles.active=${profile}
tasks.withType(BootRun)
は、bootRun
タスク実行時に、--spring.profiles.active
引数として上記の profile
変数の値を渡すようにするというものです。
if (project.hasProperty('debug'))
は、-Pdebug
というプロパティが指定された場合に、リモートデバッグ用の JVM 引数を設定するというものです。
tasks.withType(BootJar)
は、build
タスクで実行可能な JAR ファイルを生成する際に、その JAR のマニフェストファイルに有効なプロファイルを記録するというものです。
gradlew
)
ビルドと実行(このプロジェクトでは、Gradle のプロパティ機能を利用して、環境に応じたビルドや実行が可能です。
gradlew
)
ビルド(dev プロファイルでのビルド (デフォルト):
次のコマンドを実行すると、dev
プロファイルが有効な状態でアプリがビルドされます。
./gradlew build
prod プロファイルでのビルド:
本番環境向けのビルドを行うには、-Pprofile=prod
プロパティを指定します。これにより、Spring Boot の prod
プロファイルが有効化された JAR ファイルが生成されます。ここでは、確実にプロファイルが適用されるように、clean
をしてから build
するように指定しています。
./gradlew clean build -Pprofile=prod
gradlew
)
実行(dev プロファイルでの実行 (デフォルト):
-P
オプションを指定しない場合、デフォルトで dev
プロファイルが有効になります。
./gradlew bootRun
prod プロファイルでの実行:
本番環境用の設定で実行するには、-Pprofile=prod
プロパティを指定します。
./gradlew bootRun -Pprofile=prod
debug プロファイルでの実行:
デバッグモードでアプリを起動し、リモートデバッガの接続をポート 5005
で待ち受けるには、-Pdebug
プロパティを指定します。
./gradlew bootRun -Pdebug
ドキュメントとレポートの生成(Gradle 版)
Gradle でも、標準タスクでドキュメントなどを生成できます。
テストを実行するには、次のコマンドを実行します。
./gradlew test
これで、レポートが build/reports/tests/test/index.html
に生成されます。
Javadoc を生成するには、次のコマンドを実行します。
./gradlew javadoc
これで、Java API ドキュメントが build/docs/javadoc/
に生成されます。
ビルドツールの比較まとめ
Maven と Gradle は、Java のエコシステムにおける 2 大ビルドツールです。基本的なタスクの対応関係は以下のようになります。
目的 | Maven (./mvnw ) |
Gradle (./gradlew ) |
---|---|---|
ビルド(テスト含む) | clean install |
build |
アプリ実行 | spring-boot:run |
bootRun |
テストのみ実行 | test |
test |
スタイルチェック | checkstyle:check |
check |
Javadoc 生成 | javadoc:javadoc |
javadoc |
依存関係の表示 | dependency:tree |
dependencies |
一般的に、Gradle はビルドスクリプトの柔軟性やパフォーマンス(強力なキャッシュ機能)の点で優れていると言われる一方、Maven はその規約の強さと長い歴史から、よりシンプルで安定したプロジェクト管理が可能という特徴があります。
ワークスペースファイル
java-app004
と java-app005
には、それぞれ java-app004.code-workspace
と java-app005.code-workspace
という VS Code のワークスペース設定ファイルが含まれています。これにより、プロジェクトごとに最適化された開発環境(設定、タスク、デバッグ構成)を定義できます。
ワークスペースファイルの共通部分
両方のワークスペースファイルには、Java 開発を快適に進めるための共通設定が含まれています。
{
"settings": {
// JavaのランタイムとしてDev Container内のJDK 21を指定
"java.configuration.runtimes": [
{
"name": "JavaSE-21",
"path": "/usr/local/sdkman/candidates/java/21.0.7-tem",
"default": true
}
],
// フォーマッターやCheckstyleの設定
"editor.formatOnSave": true,
"java.format.settings.url": "eclipse-java-google-style.xml",
"java.format.settings.profile": "GoogleStyle",
"java.checkstyle.configuration": "${workspaceFolder}/google_checks.xml"
// ... その他
},
"extensions": {
// Java, Spring Boot, Git関連の推奨拡張機能を定義
"recommendations": [
"vscjava.vscode-java-pack",
"vmware.vscode-boot-dev-pack",
"shengchen.vscode-checkstyle"
// ...
]
}
}
settings
は、JDK のパス、Google Java Style Guide に準拠したフォーマッター、Checkstyle のルールなど、コーディングスタイルと実行環境を統一するための設定です。
extensions
は、ワークスペースを開いた際に VS Code が推奨する拡張機能のリストです。Java Extension Pack や Spring Boot Extension Pack などが含まれており、開発に必要な拡張機能が何かわかるようになっています。
ワークスペースファイル(Maven 用の設定)
java-app004.code-workspace
には、Maven プロジェクトに特化した設定が含まれています。
{
"settings": {
// Mavenがターミナルで使うJDKをJAVA_HOMEに設定
"maven.terminal.useJavaHome": true,
// Mavenプロジェクトの表示形式を階層表示に
"maven.view": "hierarchical"
},
"launch": {
// "Run dev profile" などのデバッグ構成
"configurations": [
{
"type": "java",
"name": "Run dev profile",
"request": "launch",
"mainClass": "internal.dev.javaapp004.JavaApp004Application",
"args": "--spring.profiles.active=dev",
"projectName": "java-app004"
}
// ...
]
},
"tasks": {
// "Build Maven Project" などのタスク構成
"tasks": [
{
"label": "Build Maven Project",
"type": "shell",
"command": "./mvnw clean install",
// ...
}\n ]
}
}
settings
には、Maven 拡張機能の挙動を調整する設定が含まれています。
launch
には、dev
や prod
といった Spring Boot のプロファイルを切り替えてアプリケーションを起動するためのデバッグ構成が定義されています。
tasks
には、./mvnw clean install
のような Maven コマンドを、VS Code のタスクとして簡単に実行できるように定義されています。
ワークスペースファイル(Gradle 用の設定)
java-app005.code-workspace
も同様に、Gradle プロジェクトに特化した設定が含まれています。
{
"launch": {
"configurations": [
{
"type": "java",
"name": "Run dev profile",
"request": "launch",
"mainClass": "internal.dev.javaapp005.JavaApp005Application",
"projectName": "java-app005",
"args": "--spring.profiles.active=dev"
}
// ...
]
},
"tasks": {
"tasks": [
{
"label": "Build Gradle Project",
"type": "shell",
"command": "./gradlew build",
// ...
}
]
}
}
Maven 用との主な違いは、launch
と tasks
で実行されるコマンドが ./gradlew
をベースにしている点です。これにより、VS Code の UI から Gradle のビルドや実行を直感的に操作できます。
まとめ
今回は、Spring Boot を使ったモダンな Java コンソールアプリを、Maven と Gradle という 2 つの異なるビルドツールで構築・管理する方法を見てきました。
まず、VS Code の Dev Container を利用することで、JDK や各種ビルドツール、拡張機能がすべてセットアップされた一貫性のある開発環境を簡単に用意できることを示しました。これにより、環境構築の手間を大幅に削減できます。
次に、Spring Boot を導入することで、自動設定やスターター依存関係によって、ビルド設定の簡素化、依存関係管理の自動化、定型コードの削減といった多くのメリットが得られることを確認しました。これにより、開発者は面倒な設定作業から解放され、アプリケーションの本質的なロジック開発に集中できます。
さらに、Maven と Gradle という Java エコシステムの 2 大ビルドツールについて、それぞれの特徴を比較しました。
-
Maven (
java-app004
) は、規約に基づいたアプローチとpom.xml
での設定が特徴です。<parent>
や<profiles>
を活用して、依存関係のバージョン管理やビルドの挙動を制御します。 -
Gradle (
java-app005
) は、Groovy による柔軟なビルドスクリプトと、バージョンカタログ (libs.versions.toml
) を使ったモダンな依存関係管理が特徴です。-P
オプションでプロパティを渡すことで、ビルドや実行の挙動を動的に変更します。
どちらのツールもプロファイル機能(Maven の <profiles>
、Gradle のプロパティ)と Spring Boot のプロファイルを連携させることで、開発、本番、デバッグといった異なる環境に合わせた設定の切り替えをスマートに行えることを学びました。
最後に、VS Code のワークスペースファイル (.code-workspace
) が、プロジェクト固有の設定(JDK のパス、フォーマッター、Checkstyle など)や、ビルド・デバッグ用のタスクと起動構成を定義する上で、いかに強力な役割を果たすかを見てきました。
これまでのシリーズを通して、シンプルな Java プロジェクトから、ビルドツールを使った管理、そして Spring Boot フレームワークの導入へと、プロジェクトが進化していく過程を見てきました。これらの各段階で、Dev Container、ビルドツール、そして VS Code の高度な機能を組み合わせることが、現代の Java 開発をいかに効率的で快適なものにするか、実感いただけたのではないでしょうか。
Discussion