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:

LapisanContohPeran
SpesifikasiJakarta Servlet, Jakarta REST, Jakarta CDIKontrak API resmi
Wadah web (servlet container)Apache Tomcat, Eclipse JettyMenjalankan servlet, mengelola koneksi HTTP
Platform lengkapWildFly, Open LibertyImplementasi profil Jakarta EE utuh
Framework aplikasiSpring Boot, QuarkusWadah tertanam, konfigurasi otomatis, integrasi siap pakai
Framework ringanJavalinAPI 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:

xml
<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:

text
== 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:

  1. Baris 13-23 (List<Teknologi> peta = List.of(...)): data peta disimpan sebagai daftar immutable berisi record. List.of menjamin urutan sisip tetap sehingga output program tidak berubah antar eksekusi.
  2. Baris 26-28 (Collectors.groupingBy(...)): stream dikelompokkan berdasarkan lapisan(). Factory LinkedHashMap::new dipakai sebagai penampung hasil agar urutan grup mengikuti urutan kemunculan pertama — bila memakai HashMap biasa, urutan grup tetap stabil di Java, namun LinkedHashMap membuat niat kita eksplisit.
  3. Baris 34-39 (perLapisan.forEach(...)): setiap lapisan dicetak bersama anggotanya. Format %-16s meratakan kolom nama agar tabel mudah dibaca.
  4. Baris 43-51 (List<Keputusan> keputusan): tabel keputusan memodelkan pemilihan teknologi sebagai data, bukan sebagai aturan hard-coded di dalam if-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 berkas
java
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());
        }
    }
}