Ketika kita menekan Enter pada perintah gradle build, Gradle tidak langsung mengompilasi apa pun. Sebelum task pertama berjalan, Gradle menempuh dua tahap persiapan: mengenali peserta build, lalu mengevaluasi seluruh build script menjadi DAG task. Keseluruhan perjalanan terbagi dalam tiga tahap resmi — initialization, configuration, dan execution — dan memahami batas antar tahap adalah kunci menulis build script yang cepat serta bekerja sesuai dugaan. Pada chapter ini kita akan menelusuri ketiga tahap tersebut, membahas konfigurasi lazy yang menjaga tahap konfigurasi tetap ringan, dan mengenal build cache yang memperpendek tahap eksekusi.
Tiga Tahap Build #
Tahap initialization berjalan paling awal: Gradle membaca settings.gradle.kts, menentukan proyek mana saja yang ikut build, dan membuat satu objek Project untuk masing-masing. Tahap configuration mengevaluasi build.gradle.kts setiap proyek — kode Kotlin di dalamnya benar-benar dieksekusi untuk mendaftarkan task, plugin, dan dependency, lalu Gradle menyusun DAG untuk task yang kita minta. Tahap execution barulah menjalankan aksi task dalam urutan graf: mengompilasi, menguji, mengemas.
Program berikut memetakan alur ketiga tahap untuk perintah gradle :app:build pada build multi-proyek:
public class TahapBuild {
// Peserta build hasil membaca settings.gradle.kts.
private static final String[] PROYEK = {"aplikasi-gudang (root)", "app", "lib-util"};
// Task yang terdaftar di subproyek 'app' (meniru plugin java).
private static final String[] TASK_APP = {
"compileJava", "processResources", "classes", "jar", "assemble",
"compileTestJava", "test", "check", "build"
};
public static void main(String[] args) {
System.out.println("$ gradle :app:build");
System.out.println();
System.out.println("[initialization]");
System.out.println(" membaca settings.gradle.kts");
System.out.println(" peserta build: " + String.join(", ", PROYEK));
System.out.println();
System.out.println("[configuration]");
System.out.println(" mengevaluasi build.gradle.kts setiap proyek");
System.out.println(" task terdaftar di 'app': " + TASK_APP.length + " task");
System.out.println(" DAG untuk ':app:build' tersusun");
System.out.println();
System.out.println("[execution]");
for (int i = 0; i < TASK_APP.length; i++) {
System.out.printf(" %d. :app:%s%n", i + 1, TASK_APP[i]);
}
}
}Output yang Dihasilkan:
$ gradle :app:build
[initialization]
membaca settings.gradle.kts
peserta build: aplikasi-gudang (root), app, lib-util
[configuration]
mengevaluasi build.gradle.kts setiap proyek
task terdaftar di 'app': 9 task
DAG untuk ':app:build' tersusun
[execution]
1. :app:compileJava
2. :app:processResources
3. :app:classes
4. :app:jar
5. :app:assemble
6. :app:compileTestJava
7. :app:test
8. :app:check
9. :app:buildTiga pengamatan dari simulasi di atas:
- Blok
[initialization]: daftar peserta build lahir darisettings.gradle.kts— hanya berkas inilah yang dibaca pada tahap pertama; build script belum tersentuh. - Blok
[configuration]: seluruhbuild.gradle.ktsdievaluasi meski kita hanya meminta task milikapp— konfigurasilib-utiltetap dibaca karena taskappdapat bergantung padanya. - Blok
[execution]: task berjalan dalam urutan prasyarat —compileJavasebelumclasses,classessebelumjar. Di antara cabang yang tidak saling bergantung (cabangassembledan cabangcheck), urutan interleaving tidak dijamin tetap; yang pasti hanya relasi prasyarat.
Configuration Phase dan Lazy Configuration #
Tahap konfigurasi berjalan pada setiap pemanggilan Gradle — termasuk gradle tasks, gradle clean, bahkan build yang akhirnya tidak melakukan apa-apa. Konsekuensinya: kode berat di dalam blok konfigurasi membuat setiap perintah terasa lambat, seberat apa pun task yang diminta.
// EAGER: blok langsung dievaluasi saat configuration phase
tasks.create("cetakEager") {
println("dievaluasi setiap build, apa pun task yang diminta")
}
// LAZY: dievaluasi hanya jika task benar-benar dijalankan
tasks.register("cetakLazy") {
doLast {
println("hanya berjalan saat task ini dieksekusi")
}
}Perbedaannya letak letaknya println: pada varian eager, kode di tingkat task berjalan saat konfigurasi; pada varian lazy, kode di dalam doLast baru berjalan saat eksekusi. API modern Gradle membangun budaya lazy ini lebih jauh lewat tipe Provider dan Property — nilai seperti versi Java atau nama berkas output dibungkus sehingga penyelesaiannya tertunda sampai benar-benar dibutuhkan, memungkinkan Gradle melewatkan pekerjaan yang hasilnya tidak dipakai.
Build Cache dan Eksekusi Ulang #
Tahap eksekusi punya dua lapis penghematan. Lapis pertama adalah incremental build dari chapter sebelumnya: task dengan input dan output yang tak berubah ditandai UP-TO-DATE. Lapis kedua adalah build cache: hasil eksekusi task diarsipkan berdasarkan hash input-nya, sehingga output dapat diambil kembali bahkan setelah direktori build dihapus bersih atau dari mesin lain lewat remote cache.
gradle clean build --build-cacheDengan flag --build-cache, urutan clean lalu build tidak mengompilasi ulang semuanya — task-task yang cache-nya cocok cukup menyalin kembali output dari arsip cache. Tim besar mengkonfigurasi remote cache bersama di CI sehingga developer lokal menerima hasil kompilasi yang sama tanpa menunggu mesin masing-masing menyelesaikannya.
Tiga tahap lifecycle ini menjelaskan bagaimana Gradle menyiapkan dan menjalankan pekerjaan. Pertanyaan berikutnya menyangkut apa yang masuk classpath pada tahap eksekusi: bagaimana dependency dideklarasikan lewat konfigurasi seperti implementation dan api, dan bagaimana version catalog merapikan seluruhnya. Chapter berikutnya membahasnya.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
TahapBuild.java
Unduh berkaspublic class TahapBuild {
// Peserta build hasil membaca settings.gradle.kts.
private static final String[] PROYEK = {"aplikasi-gudang (root)", "app", "lib-util"};
// Task yang terdaftar di subproyek 'app' (meniru plugin java).
private static final String[] TASK_APP = {
"compileJava", "processResources", "classes", "jar", "assemble",
"compileTestJava", "test", "check", "build"
};
public static void main(String[] args) {
System.out.println("$ gradle :app:build");
System.out.println();
System.out.println("[initialization]");
System.out.println(" membaca settings.gradle.kts");
System.out.println(" peserta build: " + String.join(", ", PROYEK));
System.out.println();
System.out.println("[configuration]");
System.out.println(" mengevaluasi build.gradle.kts setiap proyek");
System.out.println(" task terdaftar di 'app': " + TASK_APP.length + " task");
System.out.println(" DAG untuk ':app:build' tersusun");
System.out.println();
System.out.println("[execution]");
for (int i = 0; i < TASK_APP.length; i++) {
System.out.printf(" %d. :app:%s%n", i + 1, TASK_APP[i]);
}
}
}