‘Kebanyakan’ memakai context:component-scan di Spring MVC + Spring Core


Jika saya membuat proyek baru dengan memakai template Spring MVC dari STS, maka secara otomatis akan dibuatkan dua file konfigurasi Spring, yaitu:

  1. /src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
  2. /src/main/webapp/WEB-INF/spring/root-context.xml

Jika saya membuka definisi DispatcherServlet di web.xml, saya akan menemukan parameter seperti berikut ini:

<servlet>
  <servlet-name>appServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
  </init-param>
</servlet>

Terlihat bahwa file konfigurasi servlet-context.xml akan dipakai oleh DispatcherServlet.

Dengan pemikiran yang naif, saya awalnya menganggap bahwa root-context.xml akan dipanggil secara tidak langsung oleh servlet-context.xml sehingga isinya akan digabungkan ke dalam 1 context.  Tapi ternyata saya salah!!!

root-context.xml dan servlet-context.xml akan dipakai untuk membuat dua context yang berdiri sendiri!!  Masing-masing isi-nya berdiri sendiri..

Lalu, apa konsekuensinya?  Biasanya, pada servlet-context.xml, saya mendefinisikan hal-hal yang berhubungan dengan Spring Web MVC.  Sementara pada root-context.xml, saya akan menyertakan file konfigurasi lain yang berhubungan dengan JPA, Spring Security, dan sebagainya.

Pada servlet-context.xml yang naif, saya mengisyaratkan Spring Core agar membuat bean secara otomatis dengan mencari annotation di package yang saya tentukan:

<context:component-scan base-package="com.lena.aplikasi" />

Demikian juga, pada root-context.xml, saya perlu menentukan class-class yang akan di-scan, dengan konfigurasi seperti:

<context:component-scan base-package="com.lena.aplikasi" />

Secara naif, saya mengira setiap class yang memiliki annotation yang diturunkan dari @Component akan dibuat menjadi singleton dalam 1 context yang sama.  Tapi ternyata tidak!  Masing-masing class akan dibuat menjadi singleton dalam 2 context yang berbeda.  Untuk setiap class komponen, akan ada 1 singleton di context servlet-context.xml dan 1 singleton lagi di context root-context.xml.

Untuk membuktikannya, saya mencari di log console saat menjalankan aplikasi.  Saya akan melihat ada DUA baris terpisah yang mengandung nama bean kompoen saya, yaitu:

Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@80e8fe: ... [daftar bean]

dan

Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b6c585: ... [daftar bean]

Apakah ada masalah jika diteruskan seperti ini?  Tentu saja.  Membuat definisi bean dua kali berarti duplikasi penggunaan memori.  Selain itu, waktu startup akan menjadi lebih lama.  Dan, bisa jadi akan muncul bug-bug suatu hari nanti.   Saya  menemukan bug aneh seperti ini karena pada saat melakukan integration testing pada service layer dengan  JUnit, saya hanya memakai  root-context.xml saja.  Sementara ternyata, pada saat aplikasi dijalankan sepenuhnya (dengan servlet-context.xml dan root-context.xml), terdapat perilaku yang berbeda.

Lalu bagaimana solusinya?  Saya mulai membiasakan diri hanya menyertakan bean/komponen yang berhubungan dengan web di servlet-context.xml.  Karena biasanya class-class yang berhubungan dengan web berada di subpackage web, maka saya mendefinisikan ulang component-scan di servlet-context.xml menjadi:

<context:component-scan base-package="com.lena.aplikasi.web" />

Sementara itu, pada root-context.xml, saya akan menyertakan sisa-nya.  Tapi karena komponen-komponen lain tersebut bisa saja terpencar di berbagai subpackage yang berbeda-beda, maka  root-context.xml saya tetap mencari seluruh class yang ada, tetapi kali ini mengabaikan yang ada di subpackage web:

<context:component-scan base-package="com.lena.aplikasi">
   <context:exclude-filter type="regex" expression="com\.lena\.aplikasi\.web\..*" />
</context:component-scan>

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: