Belajar Spring Boot - Dependency Injection & Bean Management
Episode 4 of 24

Belajar Spring Boot - Dependency Injection & Bean Management

Episode ini membedah jantung Spring: bean dan dependency injection. Kalian mempelajari annotation @Component, @Service, @Repository, dan @Controller, perbandingan constructor vs field vs setter injection, scope bean standar, serta lifecycle callbacks.

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

Pendahuluan

Di episode 2 kalian sudah melihat application context menyimpan semua bean. Sekarang kita membuka detailnya: bagaimana sebuah class menjadi bean, bagaimana Spring menyuntikkan dependency, dan bagaimana mengontrol siklus hidup serta scope-nya.

Dependency Injection adalah alasan utama orang memilih Spring. Kalian akan menulis kode yang lebih mudah diuji, lebih bersih, dan terpisah dari konfigurasi. Episode 4 ini adalah fondasi yang akan kalian pakai di seluruh sisa series.

Konsep Bean dan Stereotype Annotation

Apa itu Bean?

Bean adalah object yang dibuat, dikelola, dan di-inject oleh Spring container. Kalian tidak memanggil new sendiri — Spring yang melakukannya, menyimpan instance-nya di application context, dan menyuntikkannya ke class lain yang membutuhkan.

Spring menemukan bean melalui component scan — pemindaian otomatis pada package dan sub-package dari kelas utama. Untuk menandai sebuah class sebagai bean, gunakan salah satu annotation berikut:

  • @Component — komponen generik.
  • @Service — kelas dengan logika bisnis.
  • @Repository — kelas akses data, dengan terjemahan exception database otomatis.
  • @Controller / @RestController — kelas yang menangani request HTTP.
Lapisan bean di aplikasi Spring
@Service
public class ItemService {
    // logika bisnis
}
 
@Repository
public class ItemRepository {
    // akses database
}
 
@RestController
public class ItemController {
    // endpoint HTTP
}

Secara teknis @Service, @Repository, dan @Controller adalah meta-annotation dari @Component. Namun memakai annotation yang spesifik memperjelas peran setiap class dan memicu perilaku tambahan — misalnya @Repository mengubah exception database menjadi DataAccessException Spring.

Constructor vs Field vs Setter Injection

Constructor Injection (Rekomendasi)

Cara terbaik dan direkomendasikan Spring adalah constructor injection: dependency dideklarasikan sebagai parameter constructor final:

Constructor injection
@Service
public class ItemService {
 
    private final ItemRepository repository;
 
    public ItemService(ItemRepository repository) {
        this.repository = repository;
    }
}

Karena class hanya punya satu constructor, Spring bisa menyuntikkan dependency tanpa annotation tambahan. Field yang final memastikan dependency tidak bisa berubah setelah dibuat, sehingga test menjadi mudah — kalian cukup mengoper mock lewat constructor.

Field dan Setter Injection

Field injection memakai @Autowired langsung di field — ringkas tapi menyembunyikan dependency dan menyulitkan testing. Setter injection memakai setter — berguna untuk dependency yang opsional. Keduanya dibolehkan, tapi untuk kode baru, konsistensi constructor injection lebih diutamakan.

Scope Bean Standar

Scope menentukan berapa lama dan bagaimana sebuah bean hidup:

  • singleton (default) — satu instance per application context; semua injection berbagi instance yang sama.
  • prototype — instance baru setiap kali di-inject atau diminta.
  • request — satu instance per request HTTP.
  • session — satu instance per session HTTP.
  • application — satu instance per ServletContext.
Mengatur scope bean
@Service
@Scope("prototype")
public class AuditLogger {
    // instance baru setiap dipakai
}

Singleton adalah default yang tepat untuk bean tanpa state, seperti service dan repository. Gunakan prototype hanya untuk object yang menyimpan state per pemakaian.

Custom Bean dan Lifecycle Callbacks

Mendefinisikan Bean dengan @Bean

Ketika bean berasal dari library pihak ketiga — misalnya RestClient atau PasswordEncoder — kalian tidak bisa menandainya dengan @Component. Solusinya: deklarasikan lewat method @Bean di dalam class @Configuration:

Custom bean dengan @Bean
@Configuration
public class AppConfig {
 
    @Bean
    public RestClient restClient() {
        return RestClient.builder()
                .baseUrl("https://api.example.com")
                .build();
    }
}

Method @Bean dipanggil oleh container saat aplikasi start, dan hasilnya disimpan sebagai bean dengan nama sesuai nama method. Cara ini juga berguna untuk men-setup bean dengan konfigurasi awal yang kompleks.

Lifecycle Callbacks

Bean bisa menjalankan logika saat dibuat dan saat dihancurkan. Spring menyediakan dua annotation: @PostConstruct untuk inisialisasi setelah dependency ter-inject, dan @PreDestroy untuk pembersihan sebelum container menutup bean.

Lifecycle callback
@Component
public class CacheWarmer {
 
    @PostConstruct
    public void init() {
        // siapkan cache saat aplikasi start
    }
 
    @PreDestroy
    public void cleanup() {
        // bersihkan resource saat aplikasi berhenti
    }
}

Annotation ini penting untuk menaruh logika inisialisasi yang butuh dependency sudah terpasang — sesuatu yang tidak bisa dilakukan di constructor.

Masalah Umum: Circular Dependency dan Bean yang Gagal

Dua masalah yang paling sering ditemui: circular dependency, ketika bean A membutuhkan B dan B membutuhkan A sehingga container tidak bisa menyelesaikan keduanya, dan NoSuchBeanDefinitionException, ketika tidak ada bean yang cocok dengan tipe yang diminta. Solusi untuk circular dependency: refactor agar satu arah, atau gunakan @Lazy pada salah satu sisi. Untuk bean yang hilang, periksa package scan — pastikan class berada di dalam package kelas utama atau sub-package-nya. Untuk melihat daftar bean yang berhasil ter-registrasi, jalankan aplikasi dengan ./mvnw spring-boot:run lalu periksa endpoint actuator beans.

Pola penanganan masalah bean
Circular dependency -> refactor ke satu arah
Bean tidak ditemukan -> periksa component scan

Jika kedua kasus muncul, bacalah stack trace lengkapnya — Spring biasanya memberi tahu persis bean mana yang bermasalah.

Penutup

Episode 4 membekali kalian dengan pemahaman inti Spring: bean sebagai object yang dikelola container, stereotype annotation untuk menandai peran class, perbandingan tiga gaya injection dengan constructor sebagai pilihan utama, scope singleton dan prototype, custom bean dengan @Bean, serta lifecycle callbacks.

Inti yang harus dibawa pulang:

  • Bean dibuat dan dikelola oleh Spring container, bukan oleh new manual.
  • @Service, @Repository, dan @Controller memperjelas peran setiap class.
  • Constructor injection dengan field final adalah gaya yang direkomendasikan.
  • Scope singleton adalah default; prototype dipakai untuk state per pemakaian.
  • Library pihak ketiga di-deklarasikan sebagai bean lewat @Bean di class @Configuration.
  • @PostConstruct dan @PreDestroy mengelola inisialisasi serta pembersihan bean.

Di episode 5 selanjutnya kita akan membangun web MVC dan REST API dasar@RestController dan @RequestMapping, path variable, request param, request body, headers, hingga ResponseEntity dengan status code dan serialisasi JSON. Kalian akan mulai menghasilkan API yang benar-benar berguna.

Belajar Spring Boot - Dependency Injection & Bean Management | Belajar Spring Boot