サンプルコードで身につける: Maven と Gradle がビルドでやっていること
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1mvn clean package のログを上から読む
依存を取得済みの状態で を実行したログの抜粋です。--- で始まる行がの1つの実行で、8つが順に動いています(区切りだけの行は落とし、ほかの省略は ... で示しています)。 を呼んでいるのは compiler:compile と compiler:testCompile の2つで、最後の が を包み直しています。
13:26:01.946 [INFO] Scanning for projects......13:26:02.144 [INFO] Building demo 0.0.1-SNAPSHOT...13:26:02.224 [INFO] --- clean:3.5.0:clean (default-clean) @ demo ---13:26:02.240 [INFO] Deleting /work/spring-maven/target13:26:02.242 [INFO] --- resources:3.5.0:resources (default-resources) @ demo ---13:26:02.262 [INFO] Copying 1 resource from src/main/resources to target/classes...13:26:02.266 [INFO] --- compiler:3.15.0:compile (default-compile) @ demo ---13:26:02.300 [INFO] Recompiling the module because of changed source code.13:26:02.303 [INFO] Compiling 2 source files with javac [debug parameters release 25] to target/classes13:26:02.513 [INFO] --- resources:3.5.0:testResources (default-testResources) @ demo ---...13:26:02.515 [INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ demo ---...13:26:02.518 [INFO] Compiling 1 source file with javac [debug parameters release 25] to target/test-classes13:26:02.562 [INFO] --- surefire:3.5.6:test (default-test) @ demo ---...13:26:02.877 [INFO] Running com.example.demo.DemoApplicationTests...13:26:03.668 [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.785 s -- in com.example.demo.DemoApplicationTests...13:26:03.679 [INFO] --- jar:3.5.1:jar (default-jar) @ demo ---13:26:03.754 [INFO] Building jar: /work/spring-maven/target/demo-0.0.1-SNAPSHOT.jar13:26:03.769 [INFO] --- spring-boot:4.1.1:repackage (repackage) @ demo ---13:26:03.865 [INFO] Replacing main artifact /work/spring-maven/target/demo-0.0.1-SNAPSHOT.jar with repackaged archive, adding nested dependencies in BOOT-INF/.13:26:03.865 [INFO] The original artifact has been renamed to /work/spring-maven/target/demo-0.0.1-SNAPSHOT.jar.original13:26:03.866 [INFO] BUILD SUCCESS13:26:03.866 [INFO] Total time: 1.926 s...
2空のローカルリポジトリから何を取ってくるか
を空にしてから を1回実行したログの先頭と、終わったあとの集計です。最初に親の を取りに行き、そこから合計 533 ファイルを取得しました。JAR は171本ありますが実行時に使うのは34本で、残りはテスト用の依存と、compiler や などのプラグイン、そのプラグイン自身の依存です。
13:19:30.840 [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/4.1.1/spring-boot-starter-parent-4.1.1.pom13:19:31.005 [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/4.1.1/spring-boot-starter-parent-4.1.1.pom (14 kB at 87 kB/s)13:19:31.015 [INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-dependencies/4.1.1/spring-boot-dependencies-4.1.1.pom13:19:31.081 [INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-dependencies/4.1.1/spring-boot-dependencies-4.1.1.pom (141 kB at 2.1 MB/s)...13:21:10.520 [INFO] BUILD SUCCESS13:21:10.520 [INFO] Total time: 01:39 minDownloaded from の行数 533(3回とも同じ)~/.m2/repository のファイル数 1,428うち JAR 171うち POM 362~/.m2/repository の大きさ 80,852 KB実行時に使う JAR 34テストまで含めたクラスパス 71
3Gradle のタスク一覧と、変更なしの2回目
同じアプリを 9.7.1 でビルドしたときの出力です。何も変えずにもう一度実行すると、すべて になってテストも走りません(363ms)。 は同じ「変更なし」でもテストを毎回実行し、2.03〜2.05 秒かかりました。
$ ./gradlew --console=plain clean build> Task :clean> Task :compileJava> Task :processResources> Task :classes> Task :resolveMainClassName> Task :bootJar> Task :jar> Task :assemble> Task :compileTestJava> Task :processTestResources NO-SOURCE> Task :testClassesOpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended> Task :test> Task :check> Task :buildBUILD SUCCESSFUL in 1s8 actionable tasks: 8 executedConsider enabling configuration cache to speed up this build: https://docs.gradle.org/9.7.1/userguide/configuration_cache_enabling.html$ ./gradlew --console=plain build> Task :compileJava UP-TO-DATE> Task :processResources UP-TO-DATE> Task :classes UP-TO-DATE> Task :resolveMainClassName UP-TO-DATE> Task :bootJar UP-TO-DATE> Task :jar UP-TO-DATE> Task :assemble UP-TO-DATE> Task :compileTestJava UP-TO-DATE> Task :processTestResources NO-SOURCE> Task :testClasses UP-TO-DATE> Task :test UP-TO-DATE> Task :check UP-TO-DATE> Task :build UP-TO-DATEBUILD SUCCESSFUL in 363ms7 actionable tasks: 7 up-to-dateConsider enabling configuration cache to speed up this build: https://docs.gradle.org/9.7.1/userguide/configuration_cache_enabling.html
4ビルドが終わっても残る JVM と、--no-daemon の実際
Gradle はビルドのあとも(常駐の )を残します。起動33秒後に見た待機中の は 841,768 KB でした(1回の観測で、設定や稼働時間で変わります)。 を付けても、この構成では「使い捨てのデーモン」が別に起動され、ビルドの最後に止められました。
$ ./gradlew --statusPID STATUS INFO9746 IDLE 9.7.1$ ps -eo pid,rss,etime,args | grep gradle9746 841768 00:33 /opt/java/openjdk/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED ...$ ./gradlew --console=plain --no-daemon clean buildTo honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.Daemon will be stopped at the end of the build> Task :clean> Task :compileJava...BUILD SUCCESSFUL in 4s8 actionable tasks: 8 executed...$ ./gradlew --statusNo Gradle daemons are running.
5npm・Cargo と並べる: 道具と依存をどこに置くか
空の状態から1回ビルドしたあとに、手元に何がどれだけ置かれたかを並べた実測値です。Maven と Gradle はプロジェクトの外の共有の場所に置き、npm はプロジェクトの中の node_modules に展開し、 はソースを取ってきて にコンパイル結果を置きます。数え方がそれぞれ違うので、本数どうしの大小は比べられません。
道具 置き場所 取ってきたもの 大きさMaven ~/.m2/repository 1,428 ファイル(JAR 171・POM 362) 80,852 KB~/.m2/wrapper Maven 本体(mvnw が取得) 11M(du -h の表示)Gradle ~/.gradle/caches 1,278 ファイル(JAR 98) 97,512 KB~/.gradle/wrapper Gradle の配布物(gradlew が取得) 165M(du -h の表示)npm プロジェクト内の node_modules 389 パッケージ・9,976 ファイル 171,276 KB(開発用の依存を含む)Cargo cargo のレジストリ Cargo.lock で 55 パッケージ 51,928 KBプロジェクト内の target コンパイル結果(release) 117,504 KB