Dev Study
← 解説「3つの比較と Spring Boot との関係」に戻る

サンプルコードで身につける: 3つの比較と Spring Boot との関係

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1Ant で Boot の実行可能 JAR を作る: リファレンスの例そのままの build.xml と ivy.xml

4.1.1 のリファレンス(Build Systems)に載っている + の例を、依存だけ にして写したものです。Ivy が依存を compile と lib/runtime に取ってきて(強調した )、 の が を作ります(強調した build)。依存は に1本だけ書き(強調した dependency)、は Ivy がたどります。この例には resources をコピーする手順が無いので、 は に入りません。

build.xml(33行)と ivy.xml(11行)。Boot 4.1.1 リファレンスの例を写したもの設定ファイル
<project
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:spring-boot="antlib:org.springframework.boot.ant"
name="myapp" default="build">
 
<property name="spring-boot.version" value="4.1.1" />
 
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve pattern="lib/[conf]/[artifact]-[type]-[revision].[ext]" />
</target>
 
<target name="classpaths" depends="resolve">
<path id="compile.classpath">
<fileset dir="lib/compile" includes="*.jar" />
</path>
</target>
 
<target name="init" depends="classpaths">
<mkdir dir="build/classes" />
</target>
 
<target name="compile" depends="init" description="compile">
<javac srcdir="src/main/java" destdir="build/classes" classpathref="compile.classpath" />
</target>
 
<target name="build" depends="compile">
<spring-boot:exejar destfile="build/myapp.jar" classes="build/classes">
<spring-boot:lib>
<fileset dir="lib/runtime" />
</spring-boot:lib>
</spring-boot:exejar>
</target>
</project>
 
# ivy.xml
<ivy-module version="2.0">
<info organisation="com.example" module="demo" />
<configurations>
<conf name="compile" description="everything needed to compile this module" />
<conf name="runtime" extends="compile" description="everything needed to run this module" />
</configurations>
<dependencies>
<dependency org="org.springframework.boot" name="spring-boot-starter-webmvc"
rev="${spring-boot.version}" conf="compile" />
</dependencies>
</ivy-module>

2ant を実行して、出来た JAR を起動する

の起動には で Ivy の JAR のディレクトリと、spring-boot-antlib とその実行時依存5本(spring-boot-loader-tools、spring-core など)のディレクトリを渡しました。antlib の JAR 1本だけでは になります(末尾)。 の build まで resolve → classpaths → init → compile → build の順に進み、exejar がローダを埋め込んで JAR を作ります。 で起動すると /hello は 200 を返しましたが、application.properties が無いのでログに [demo] が出ません。ログ中の ms と seconds は共有環境での1回の値です。

$ ant -lib <ivy の dir> -lib <antlib と依存の dir> → $ java -jar build/myapp.jar → $ curl -i /hello(成功した2回目のログ)コマンド出力
resolve:
[ivy:retrieve] :: resolving dependencies :: com.example#demo;working@...
[ivy:retrieve] confs: [compile, runtime]
[ivy:retrieve] found org.springframework.boot#spring-boot-starter-webmvc;4.1.1 in public
...(found 41行)
[ivy:retrieve] 76 artifacts copied, 0 already retrieved (38403kB/66ms)
classpaths:
init:
[mkdir] Created dir: /bt/l9-compare/ant-boot/build/classes
compile:
[javac] /bt/l9-compare/ant-boot/build.xml:23: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
[javac] Compiling 2 source files to /bt/l9-compare/ant-boot/build/classes
build:
[echo] Using start class com.example.demo.DemoApplication
[echo] Using destination directory /bt/l9-compare/ant-boot/build
[mkdir] Created dir: /bt/l9-compare/ant-boot/build/dependency
[echo] Extracting spring-boot-loader to /bt/l9-compare/ant-boot/build/dependency
[copy] Copying 1 resource to /bt/l9-compare/ant-boot/build/dependency
[echo] Embedding spring-boot-loader v4.1.1...
[jar] Building jar: /bt/l9-compare/ant-boot/build/myapp.jar
BUILD SUCCESSFUL
 
$ java -jar build/myapp.jar
:: Spring Boot :: (v4.1.1)
2026-10-03T00:25:53.670Z INFO 1 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication using Java 25.0.4.1 with PID 1 (/bt/l9-compare/ant-boot/build/myapp.jar started by root in /)
2026-10-03T00:25:54.144Z INFO 1 --- [ main] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2026-10-03T00:25:54.150Z INFO 1 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 0.658 seconds (process running for 0.88)
 
$ curl -i http://127.0.0.1:18411/hello
HTTP/1.1 200
Content-Type: application/json
Content-Length: 19
 
{"message":"hello"}
 
# antlib の JAR 1本だけを -lib に置いたときの1回目(抜粋)
# java.lang.NoClassDefFoundError: org/springframework/util/StringUtils

3同じソースから出来た3つの JAR の対比

同じ DemoApplication + HelloController + application.properties を、 の 、 の 、Ant の exejar でビルドした結果です。Maven と Gradle の は34本で名前も版も一致し、Ant は38本です。も Ant 版だけ項目が少なく、Spring-Boot-Version、、 がありません。この回に java -jar で起動したのは Ant 版だけで、Maven 版は後のレッスンで起動し、Gradle 版は起動していません。

3つの実行可能 JAR(Boot 4.1.1。Maven 3.9.16 / Gradle 9.7.1 / Ant 1.10.18 + Ivy 2.6.0 + spring-boot-antlib 4.1.1)表
出来た JAR
Maven : target/demo-0.0.1-SNAPSHOT.jar
(包む前の JAR は .jar.original 3,244 B に改名)
Gradle : build/libs/demo-0.0.1-SNAPSHOT.jar
(別に jar タスクが -plain.jar 2,065 B を作る)
Ant : build/myapp.jar(他の JAR は作らない)
 
サイズ / エントリ数 / ローダのクラス
Maven : 19,905,045 B / 170 / 99
Gradle : 19,903,503 B / 167 / 99
Ant : 20,109,103 B / 168 / 99
 
BOOT-INF/lib
Maven : 34本
Gradle : 34本(Maven と名前・版が一致)
Ant : 38本
 
BOOT-INF/classes
Maven : クラス2個 + application.properties
Gradle : 同上(+ 空の static/ templates/)
Ant : クラス2個だけ
 
マニフェスト
Maven : Main-Class / Start-Class / Spring-Boot-Version
Spring-Boot-Classpath-Index / Layers-Index
Created-By: Maven JAR Plugin 3.5.1
Gradle : 同上(Created-By は無し)
Ant : Main-Class / Start-Class
Spring-Boot-Classes / Spring-Boot-Lib だけ
Ant-Version: Apache Ant 1.10.18
 
そのほかの入りもの
Maven : META-INF/maven/.../pom.xml, pom.properties
Gradle : -
Ant : META-INF/LICENSE.txt, NOTICE.txt
 
java -jar での起動
Maven : この回は未起動(後のレッスンで起動と計測)
Gradle : この回は未起動(エントリ一覧は Maven と一致)
Ant : 起動して /hello → 200

4BOOT-INF/lib の差分: この ivy.xml では BOM が効かない

Maven(左)と Ant(右)の BOOT-INF/lib を並べた差分です。Gradle は Maven と同一でした。Ant 版にはの無い starter の JAR 5本が入り、Maven/Gradle のが足す がありません。版も JAR 3本( と micrometer の2系統)で違います。Maven/Gradle は Boot の が commons-logging を 1.3.6 に、micrometer を 1.17.1 に上書きしますが、リファレンスの例を写した ivy.xml では各 が直接書いた 1.3.5 と 1.16.7 のままでした。Ivy 側で BOM に当たるものを書く方法は試していません。

$ diff <(Maven の BOOT-INF/lib 一覧) <(Ant の BOOT-INF/lib 一覧)(Ivy のファイル名から [type] の部分 -jar-・-bundle- を取り除いて比較)コマンド出力
1c1
< commons-logging-1.3.6.jar
---
> commons-logging-1.3.5.jar
12,13c12,13
< micrometer-commons-1.17.1.jar
< micrometer-observation-1.17.1.jar
---
> micrometer-commons-1.16.7.jar
> micrometer-observation-1.16.7.jar
22d21
< spring-boot-jarmode-tools-4.1.1.jar
23a23,27
> spring-boot-starter-4.1.1.jar
> spring-boot-starter-jackson-4.1.1.jar
> spring-boot-starter-logging-4.1.1.jar
> spring-boot-starter-tomcat-4.1.1.jar
> spring-boot-starter-tomcat-runtime-4.1.1.jar
 
$ jar tf spring-boot-starter-4.1.1.jar # 4,767 B。クラス無し
META-INF/MANIFEST.MF
META-INF/LICENSE.txt
META-INF/NOTICE.txt
$ (そのマニフェストから)
Implementation-Title: Core starter, including auto-configuration support, logging and YAML
Spring-Boot-Jar-Type: dependencies-starter
 
# Gradle の dependencies 出力では、同じ上書きが -> で見える
# commons-logging:commons-logging:1.3.5 -> 1.3.6
# io.micrometer:micrometer-observation:1.16.7 -> 1.17.1

57つの観点で3つを並べる

このセクションで各ツールを見てきた7つの観点を、観点ごとに Ant・Maven・Gradle の順で並べました。違いは「置き場所・手順・依存を誰が決めるか」と「2回目に何を飛ばすか」に集まります。1.0 の年(Ant は単独の最初の正式版 1.1)と が生成するものも添えました。Gradle 1.0 のリリースノートは、依存の解決を Ivy から自前の仕組みに移したと書いていて、Ant+Ivy と Gradle は依存の取り方の系譜でつながっています。

Ant 1.10.18 / Maven 3.9.16 / Gradle 9.7.1 と Spring Boot 4.1.1(出典は各公式文書と、このセクションの実測)表
1. 設定ファイルと書き方
Ant : build.xml(XML)
Maven : pom.xml(XML)
Gradle : build.gradle(Groovy)か build.gradle.kts(Kotlin)
+ settings.gradle(.kts)
 
2. 置き場所は誰が決めるか
Ant : 自分(全部 <property> に書く)
Maven : Maven の規約(src/main/java など)
Gradle : Maven の規約を借りる
 
3. 手順の決め方
Ant : <target> と depends を自分で書く
Maven : ライフサイクルのフェーズにゴールが束縛される
(順番は固定)
Gradle : プラグインがタスクと依存関係(DAG)を登録する
 
4. 依存の手に入れ方
Ant : 人が lib/ に置く。Ivy を足せば取ってくる
(この回の ivy.xml では BOM は効かなかった)
Maven : 座標 → Maven Central → ~/.m2/repository
Gradle : 座標 → Maven Central → ~/.gradle/caches
 
5. 2回目に飛ばすもの
Ant : javac・copy・jar は更新時刻で判定。テストは毎回
Maven : compiler は Nothing to compile。テストは毎回。
spring-boot:repackage が毎回 JAR を書き直す
(jar:jar は Building jar を出さない)
Gradle : タスクごとに入出力のハッシュ(UP-TO-DATE)。
テストも飛ばす
 
6. 出来上がるもの
Ant : build.xml 次第(今回は build/myapp.jar)
Maven : target/<artifactId>-<version>.jar
+ 包む前の .jar.original
Gradle : build/libs/<name>-<version>.jar
+ jar タスクが別に作る -plain.jar
 
7. Spring Boot の乗り方
Ant : spring-boot-antlib(exejar)+ Ivy。
Boot のリファレンスの言葉では
not particularly well supported
Maven : spring-boot-maven-plugin(repackage など11ゴール)
Gradle : org.springframework.boot プラグイン(bootJar など)
 
常駐プロセス
Ant : 無い
Maven : 無い(既定)
Gradle : デーモン(既定オン)
 
1.0 の年(Ant は 1.1)
Ant : 1.1 2000-07-19(単独の最初の正式版)
Maven : 1.0 2004-07-13(1.0-beta-2 は 2002-03-30)
Gradle : 1.0 2012-06-12(0.7 は 2009-07-20)
 
start.spring.io が生成するもの
Ant : 生成しない
Maven : maven-project
Gradle : gradle-project(Groovy。既定)
gradle-project-kotlin

図やコードに出てくる用語(タップで説明)