Kode Java yang selama ini kita tulis berjalan di terminal: program mulai dari main, membaca input, mencetak hasil, lalu berhenti. Aplikasi web bekerja dengan pola yang berbeda — program hidup lama di dalam server, menunggu permintaan HTTP datang dari peramban pengguna, memprosesnya, dan mengirim balasan. Dunia Java menyediakan banyak lapisan teknologi untuk pekerjaan tersebut, mulai dari spesifikasi resmi sampai framework yang menyembunyikan detail protokol. Banyaknya pilihan ini sering membuat pendatang baru bingung memilih titik masuk, sehingga chapter ini pertama-tama memetakan ekosistem secara menyeluruh sebelum kita menyelami tiap komponennya.
Spesifikasi dan Implementasi #
Ide paling penting untuk dipahami sebelum melangkah: komunitas Java memisahkan spesifikasi dari implementasi. Spesifikasi adalah dokumen kontrak — daftar interface, anotasi, dan aturan perilaku yang harus dipenuhi. Implementasi adalah pustaka konkret yang mewujudkan kontrak tersebut. Kita sudah bertemu pola ini pada Chapter JDBC: kode Anda memakai java.sql.Connection, sedangkan driver MySQL atau PostgreSQL yang bekerja di balik layar.
Di wilayah web, keluarga spesifikasinya bernama Jakarta EE (dahulu Java EE), dengan anggota penting seperti Jakarta Servlet (pemroses permintaan), Jakarta RESTful Web Services (API REST beranotasi), dan Jakarta CDI (dependency injection). Apache Tomcat, Eclipse Jetty, WildFly, dan Open Liberty adalah implementasinya. Kode yang hanya bergantung pada spesifikasi dapat dipindahkan antar implementasi tanpa penulisan ulang.
Peta Lapisan Teknologi #
Kita dapat menyusun pilihan teknologi web Java menjadi lima lapisan, dari yang paling dekat dengan protokol sampai yang paling dekat dengan kebutuhan bisnis:
| Lapisan | Contoh | Peran |
|---|---|---|
| Spesifikasi | Jakarta Servlet, Jakarta REST, Jakarta CDI | Kontrak API resmi |
| Wadah web (servlet container) | Apache Tomcat, Eclipse Jetty | Menjalankan servlet, mengelola koneksi HTTP |
| Platform lengkap | WildFly, Open Liberty | Implementasi profil Jakarta EE utuh |
| Framework aplikasi | Spring Boot, Quarkus | Wadah tertanam, konfigurasi otomatis, integrasi siap pakai |
| Framework ringan | Javalin | API sederhana di atas Jetty, cocok untuk layanan kecil |
Spring Boot patut dibedakan dari Jakarta EE: Spring bukan spesifikasi Jakarta, melainkan framework dengan ekosistem sendiri yang menyertakan Tomcat tertanam sehingga aplikasi menjadi berkas JAR mandiri — tidak perlu lagi memasang server terpisah. Pada sisi lain, Quarkus menargetkan lingkungan kontainer dengan waktu startup dan konsumsi memori yang rendah.
Dalam berkas pom.xml, dependensi servlet dinyatakan dengan scope provided karena wadah web sudah membawa implementasinya saat aplikasi dijalankan:
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<scope>provided</scope>
</dependency>Membaca Peta lewat Kode #
Mari kita wujudkan peta di atas sebagai program Java murni. PetaEkosistem memodelkan setiap teknologi sebagai record dengan lapisan dan perannya, mengelompokkannya dengan stream, lalu menutup dengan tabel keputusan sederhana:
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class PetaEkosistem {
record Teknologi(String nama, String lapisan, String peran) {}
record Keputusan(String situasi, String pilihan, String alasan) {}
public static void main(String[] args) {
List<Teknologi> peta = List.of(
new Teknologi("Jakarta Servlet", "Spesifikasi", "kontrak pemroses permintaan web"),
new Teknologi("Jakarta RESTful WS", "Spesifikasi", "anotasi REST di atas Servlet"),
new Teknologi("Jakarta CDI", "Spesifikasi", "dependency injection dan scope bean"),
new Teknologi("Apache Tomcat", "Wadah web", "implementasi Jakarta Servlet"),
new Teknologi("Eclipse Jetty", "Wadah web", "implementasi Jakarta Servlet"),
new Teknologi("WildFly", "Platform", "implementasi profil Jakarta EE"),
new Teknologi("Open Liberty", "Platform", "implementasi profil Jakarta EE"),
new Teknologi("Spring Boot", "Framework aplikasi", "wadah tertanam + ekosistem starter"),
new Teknologi("Quarkus", "Framework aplikasi", "dioptimalkan untuk kontainer"),
new Teknologi("Javalin", "Framework ringan", "pembungkus Jetty yang ringkas"));
System.out.println("== Jumlah teknologi per lapisan ==");
Map<String, List<Teknologi>> perLapisan = peta.stream()
.collect(Collectors.groupingBy(
Teknologi::lapisan, LinkedHashMap::new, Collectors.toList()));
perLapisan.forEach((lapisan, daftar) ->
System.out.printf("%-20s %d%n", lapisan, daftar.size()));
System.out.println();
System.out.println("== Isi setiap lapisan ==");
perLapisan.forEach((lapisan, daftar) -> {
System.out.println("[" + lapisan + "]");
for (Teknologi t : daftar) {
System.out.printf(" %-16s - %s%n", t.nama(), t.peran());
}
});
System.out.println();
System.out.println("== Saran pilihan per situasi ==");
List<Keputusan> keputusan = List.of(
new Keputusan("API kecil untuk tugas kuliah", "Javalin",
"satu dependensi, langsung berjalan"),
new Keputusan("Monolith aplikasi perusahaan", "Spring Boot",
"ekosistem matang, banyak integrasi siap pakai"),
new Keputusan("Layanan mikro hemat memori", "Quarkus",
"startup cepat dan jejak RAM kecil"),
new Keputusan("Aplikasi yang harus portabel antar vendor", "Jakarta EE di WildFly",
"kode hanya bergantung pada spesifikasi"));
for (Keputusan k : keputusan) {
System.out.printf("%-45s -> %-22s (%s)%n", k.situasi(), k.pilihan(), k.alasan());
}
}
}Output yang Dihasilkan:
== Jumlah teknologi per lapisan ==
Spesifikasi 3
Wadah web 2
Platform 2
Framework aplikasi 2
Framework ringan 1
== Isi setiap lapisan ==
[Spesifikasi]
Jakarta Servlet - kontrak pemroses permintaan web
Jakarta RESTful WS - anotasi REST di atas Servlet
Jakarta CDI - dependency injection dan scope bean
[Wadah web]
Apache Tomcat - implementasi Jakarta Servlet
Eclipse Jetty - implementasi Jakarta Servlet
[Platform]
WildFly - implementasi profil Jakarta EE
Open Liberty - implementasi profil Jakarta EE
[Framework aplikasi]
Spring Boot - wadah tertanam + ekosistem starter
Quarkus - dioptimalkan untuk kontainer
[Framework ringan]
Javalin - pembungkus Jetty yang ringkas
== Saran pilihan per situasi ==
API kecil untuk tugas kuliah -> Javalin (satu dependensi, langsung berjalan)
Monolith aplikasi perusahaan -> Spring Boot (ekosistem matang, banyak integrasi siap pakai)
Layanan mikro hemat memori -> Quarkus (startup cepat dan jejak RAM kecil)
Aplikasi yang harus portabel antar vendor -> Jakarta EE di WildFly (kode hanya bergantung pada spesifikasi)Beberapa bagian program ini layak dibedah satu per satu:
- Baris 13-23 (
List<Teknologi> peta = List.of(...)): data peta disimpan sebagai daftar immutable berisi record.List.ofmenjamin urutan sisip tetap sehingga output program tidak berubah antar eksekusi. - Baris 26-28 (
Collectors.groupingBy(...)): stream dikelompokkan berdasarkanlapisan(). FactoryLinkedHashMap::newdipakai sebagai penampung hasil agar urutan grup mengikuti urutan kemunculan pertama — bila memakaiHashMapbiasa, urutan grup tetap stabil di Java, namunLinkedHashMapmembuat niat kita eksplisit. - Baris 34-39 (
perLapisan.forEach(...)): setiap lapisan dicetak bersama anggotanya. Format%-16smeratakan kolom nama agar tabel mudah dibaca. - Baris 43-51 (
List<Keputusan> keputusan): tabel keputusan memodelkan pemilihan teknologi sebagai data, bukan sebagai aturan hard-coded di dalamif-else— pola yang sama dipakai tim arsitektur ketika mendokumentasikan standar teknologi.
Titik Masuk Course Ini #
Course ini memilih jalur dari bawah ke atas: kita pelajari protokol HTTP dulu, lalu servlet sebagai mesin pemroses permintaan, session dan cookie sebagai cara mengingat pengguna, template rendering untuk halaman HTML, Jakarta EE sebagai platform, dan akhirnya REST API lengkap dengan validasi, penanganan kesalahan, serta keamanan. Jalur ini sengaja dipilih karena framework apa pun di tabel di atas pada akhirnya berdiri di atas konsep-konsep tersebut — memahami fondasinya membuat Anda dapat berpindah framework tanpa mengulang belajar dari nol. Perhentian pertama kita adalah protokol yang menjadi bahasa semua lapisan: HTTP.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
PetaEkosistem.java
Unduh berkasimport java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class PetaEkosistem {
record Teknologi(String nama, String lapisan, String peran) {}
record Keputusan(String situasi, String pilihan, String alasan) {}
public static void main(String[] args) {
List<Teknologi> peta = List.of(
new Teknologi("Jakarta Servlet", "Spesifikasi", "kontrak pemroses permintaan web"),
new Teknologi("Jakarta RESTful WS", "Spesifikasi", "anotasi REST di atas Servlet"),
new Teknologi("Jakarta CDI", "Spesifikasi", "dependency injection dan scope bean"),
new Teknologi("Apache Tomcat", "Wadah web", "implementasi Jakarta Servlet"),
new Teknologi("Eclipse Jetty", "Wadah web", "implementasi Jakarta Servlet"),
new Teknologi("WildFly", "Platform", "implementasi profil Jakarta EE"),
new Teknologi("Open Liberty", "Platform", "implementasi profil Jakarta EE"),
new Teknologi("Spring Boot", "Framework aplikasi", "wadah tertanam + ekosistem starter"),
new Teknologi("Quarkus", "Framework aplikasi", "dioptimalkan untuk kontainer"),
new Teknologi("Javalin", "Framework ringan", "pembungkus Jetty yang ringkas"));
System.out.println("== Jumlah teknologi per lapisan ==");
Map<String, List<Teknologi>> perLapisan = peta.stream()
.collect(Collectors.groupingBy(
Teknologi::lapisan, LinkedHashMap::new, Collectors.toList()));
perLapisan.forEach((lapisan, daftar) ->
System.out.printf("%-20s %d%n", lapisan, daftar.size()));
System.out.println();
System.out.println("== Isi setiap lapisan ==");
perLapisan.forEach((lapisan, daftar) -> {
System.out.println("[" + lapisan + "]");
for (Teknologi t : daftar) {
System.out.printf(" %-16s - %s%n", t.nama(), t.peran());
}
});
System.out.println();
System.out.println("== Saran pilihan per situasi ==");
List<Keputusan> keputusan = List.of(
new Keputusan("API kecil untuk tugas kuliah", "Javalin",
"satu dependensi, langsung berjalan"),
new Keputusan("Monolith aplikasi perusahaan", "Spring Boot",
"ekosistem matang, banyak integrasi siap pakai"),
new Keputusan("Layanan mikro hemat memori", "Quarkus",
"startup cepat dan jejak RAM kecil"),
new Keputusan("Aplikasi yang harus portabel antar vendor", "Jakarta EE di WildFly",
"kode hanya bergantung pada spesifikasi"));
for (Keputusan k : keputusan) {
System.out.printf("%-45s -> %-22s (%s)%n", k.situasi(), k.pilihan(), k.alasan());
}
}
}