Belajar Spring Boot - Modular Architecture & Patterns
Episode 18 of 24

Belajar Spring Boot - Modular Architecture & Patterns

Episode ini membahas struktur aplikasi yang sehat: arsitektur clean, hexagonal, dan onion; struktur modul fitur dan package- by-feature; design patterns populer seperti service layer dan repository; serta event-driven architecture dengan Spring Events dan Kafka.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Aplikasi yang berumur panjang tidak mati karena teknologi — ia mati karena struktur yang buruk membuat setiap perubahan semakin sulit. Episode 18 membahas modular architecture dan design patterns yang menjaga aplikasi Spring Boot tetap bisa dirawat.

Kalian akan mempelajari arsitektur clean, hexagonal, dan onion; struktur modul berbasis fitur; design patterns yang umum dipakai Spring; serta event-driven architecture dengan Spring Events dan Kafka untuk memisahkan komponen secara lebih jauh.

Arsitektur Clean, Hexagonal, dan Onion

Konsep Bersama: Dependency Menuju Dalam

Tiga arsitektur ini berbagi prinsip yang sama: logika bisnis berada di pusat, dan dependency selalu mengarah ke dalam — domain tidak bergantung pada detail teknis seperti framework atau database.

Lapisan arsitektur clean
Domain / Use Case
  -> Application Services
  -> Adapters (controller, repository, external API)

Clean Architecture memisahkan entities dan use cases dari controllers dan gateways. Hexagonal (Ports and Adapters) mengekspos domain melalui ports (interface) yang diimplementasi adapters (implementasi teknis). Onion Architecture adalah konsep serupa dengan lapisan berpusat pada domain.

Menerapkan di Spring Boot

Dalam Spring Boot, prinsipnya berarti: domain layer tidak boleh mengimpor Spring MVC atau JPA. Controller dan repository menjadi adapter yang berada di lapisan luar:

Port domain sebagai interface
public interface ItemRepositoryPort {
    Optional<Item> findById(Long id);
    Item save(Item item);
}

Domain hanya bergantung pada ItemRepositoryPort. Implementasi JPA — JpaItemRepositoryAdapter — memenuhi port tersebut dan bisa diganti tanpa mengubah domain. Inilah inti hexagonal architecture.

Modul Fitur dan Package-by-Feature

Package-by-Feature

Daripada memecah package berdasarkan teknologi (controller, service, repository), kelompokkan berdasarkan fitur:

Struktur package-by-feature
com.example/
├── item/
│   ├── ItemController.java
│   ├── ItemService.java
│   ├── ItemRepository.java
│   └── Item.java
├── order/
│   ├── OrderController.java
│   ├── OrderService.java
│   └── OrderRepository.java
└── shared/
    └── ApiError.java

Dengan struktur ini, semua file yang berkaitan dengan satu fitur berada dalam satu package — perubahan fitur hanya menyentuh satu area. Package-by-feature membuat aplikasi besar jauh lebih mudah dinavigasi daripada package-by-layer.

Modul Multi-Module

Untuk codebase yang sangat besar, pisahkan menjadi modul Maven/Gradle terpisah — misalnya domain, application, infrastructure, dan web. Detailnya akan dibahas di episode 19 tentang build automation.

Design Patterns Populer

Service Layer dan Repository

  • Service Layer — memisahkan logika bisnis dari controller dan repository; berisi use case aplikasi dan transaksi.
  • Repository — memisahkan akses data dari domain; menyediakan interface yang abstrak.
Service layer membungkus repository
@Service
@Transactional
public class ItemService {
 
    private final ItemRepository repository;
 
    public ItemService(ItemRepository repository) {
        this.repository = repository;
    }
 
    public Item create(Item item) {
        return repository.save(item);
    }
}

Kedua pattern ini sudah menjadi idiom Spring — kalian memakainya sejak episode 4 dan 6. Transaction di taruh di service layer karena di situlah batas unit kerja aplikasi.

Decorator dan Template Method

  • Decorator — membungkus object untuk menambah perilaku tanpa mengubah class asli; di Spring sering lewat @Primary bean atau proxy.
  • Template Method — mendefinisikan kerangka algoritma di base class; JdbcTemplate dan RestTemplate adalah contoh Spring yang memakai pola ini.

Spring sendiri sangat bergantung pada pola proxy: transaction, security, dan caching bekerja lewat proxy yang membungkus bean asli. Memahami ini membantu kalian menebak perilaku annotation seperti @Transactional.

Event-Driven Architecture

Spring Events untuk Komunikasi Internal

Untuk memisahkan komponen di dalam satu aplikasi, gunakan Spring Events. Publisher melempar event tanpa tahu siapa konsumennya:

Publish event
@Service
public class OrderService {
 
    private final ApplicationEventPublisher publisher;
 
    public OrderService(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }
 
    public Order placeOrder(Order order) {
        Order saved = repository.save(order);
        publisher.publishEvent(new OrderPlacedEvent(saved));
        return saved;
    }
}

Konsumen menangkap event dengan @EventListener:

Listen event
@Component
public class EmailNotifier {
 
    @EventListener
    public void onOrderPlaced(OrderPlacedEvent event) {
        // kirim email, tanpa bergantung pada OrderService
    }
}

OrderService tidak perlu tahu tentang EmailNotifier — komunikasi terbalik lewat event. Ini memecah ketergantungan langsung antar komponen. Untuk melihatnya bekerja, jalankan aplikasi dengan ./mvnw spring-boot:run lalu pemicu pembuatan order akan memunculkan log dari listener.

Spring Events vs Message Broker

Spring Events berjalan dalam satu proses — cocok untuk decoupling internal. Untuk komunikasi antar service atau yang butuh reliability, gunakan message broker seperti Kafka atau RabbitMQ:

Konfigurasi consumer Kafka
spring:
  kafka:
    bootstrap-servers: localhost:9092
    consumer:
      group-id: order-consumer
      auto-offset-reset: earliest

Kafka menyediakan persistensi event, replay, dan skala horizontal — pola yang tepat untuk arsitektur microservices event-driven yang dibahas di episode 14.

Penutup

Episode 18 membekali kalian dengan arsitektur dan pola yang menjaga aplikasi tetap sehat: clean, hexagonal, dan onion architecture; package-by-feature dan modul; design patterns service layer, repository, dan decorator; serta event-driven architecture dengan Spring Events dan Kafka.

Inti yang harus dibawa pulang:

  • Logika bisnis di pusat; dependency selalu mengarah ke dalam.
  • Ports and adapters membuat domain tidak bergantung pada framework dan database.
  • Package-by-feature lebih mudah dirawat daripada package-by-layer.
  • Service layer dan repository adalah pola dasar yang dipakai di seluruh Spring.
  • Spring Events memisahkan komponen dalam satu proses.
  • Kafka dan RabbitMQ menangani komunikasi antar service dengan reliability tinggi.

Di episode 19 selanjutnya kita akan membahas tooling modern dan build automation — perbandingan Maven vs Gradle Kotlin DSL, Spring Boot plugin dan dependency management BOM, live reload dengan Spring DevTools, serta reproducible builds dan multi-module project.