Bagaimana cara memanggil metode setelah inisialisasi kacang selesai?

237

Saya memiliki kasus penggunaan di mana saya perlu memanggil metode (non-statis) di kacang hanya sekali di ApplicationContext memuat. Apakah boleh, jika saya menggunakan MethodInvokingFactoryBean untuk ini? Atau kita punya solusi yang lebih baik?

Sebagai catatan, saya menggunakan ConfigContextLoaderListener untuk memuat Konteks Aplikasi dalam aplikasi web. Dan ingin, bahwa jika kacang 'A' dipakai hanya panggil methodA () sekali.

Bagaimana ini bisa dilakukan dengan baik?

peakit
sumber

Jawaban:

196

Anda dapat menggunakan sesuatu seperti:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

Ini akan memanggil metode "init" ketika kacang di-instantiated.

Mercer Traieste
sumber
15
postConstruct seharusnya lebih baik dalam banyak kasus, karena kami tidak ingin mengacaukan inisialisasi kacang hijau.
lwpro2
4
@ lwpro2 Apa yang Anda maksud dengan "tidak ingin mengacaukan inisialisasi kacang hijau" di sini?
Yngve Sneen Lindal
@Mercer Traieste apa yang harus saya berikan untuk atribut class di sini? Bisakah saya memberikan kelas controller di sini?
KJEjava48
314

Untuk memperluas saran @PostConstruct di jawaban lain, ini benar-benar solusi terbaik, menurut saya.

  • Itu membuat kode Anda dipisahkan dari API Spring (@PostConstruct dalam javax. *)
  • Ini secara eksplisit menjelaskan metode init Anda sebagai sesuatu yang perlu dipanggil untuk menginisialisasi kacang
  • Anda tidak perlu ingat untuk menambahkan atribut init-method ke definisi spring bean Anda, spring akan secara otomatis memanggil metode tersebut (dengan asumsi Anda mendaftarkan opsi anotasi-konfigurasi di tempat lain dalam konteksnya).
skaffman
sumber
9
Terima kasih, ini berhasil. Catatan jika Anda ingin menggunakan dengan Spring Anda harus memasukkan "<context: annotation-config />" untuk mendaftarkan kacang CommonAnnotationBeanPostProcessor (seperti yang disebutkan di atas)
khylo
2
Yang cocok <context:component-scan>juga berfungsi, dan dapat berguna untuk mengurangi waktu startup jika Anda memiliki pustaka non-Spring yang besar di classpath Anda.
Donal Fellows
5
JavaDoc untuk PostConstruct mengatakan bahwa hanya satu metode yang dapat dijelaskan dengan itu per kelas: docs.oracle.com/javaee/5/api/javax/annotation/…
Andrew Swan
@PostConstruct tidak berfungsi dengan manajer transaksional, lihat: forum.spring.io/forum/spring-projects/data/…
mmm
2
@PostConstruct juga tidak akan banyak berguna bagi Anda ketika kacang yang Anda instantiating bukan kelas Anda sendiri tetapi beberapa kelas pihak ketiga
John Rix
102

Ada tiga pendekatan yang berbeda untuk dipertimbangkan, seperti yang dijelaskan dalam referensi

Gunakan atribut init-metode

Pro:

  • Tidak memerlukan kacang untuk mengimplementasikan antarmuka.

Cons:

  • Tidak ada indikasi segera metode ini diperlukan setelah konstruksi untuk memastikan kacang dikonfigurasi dengan benar.

Terapkan InisialisasiBean

Pro:

  • Tidak perlu menentukan init-metode, atau mengaktifkan pemindaian komponen / proses anotasi.
  • Sesuai untuk kacang yang disuplai dengan perpustakaan, di mana kami tidak ingin aplikasi menggunakan perpustakaan ini berkaitan dengan siklus hidup kacang.

Cons:

  • Lebih invasif daripada pendekatan init-metode.

Gunakan JSR-250 @PostConstruct anotasi gaya hidup

Pro:

  • Berguna saat menggunakan pemindaian komponen untuk mendeteksi kacang secara otomatis.
  • Jelaskan bahwa metode spesifik akan digunakan untuk inisialisasi. Maksud lebih dekat ke kode.

Cons:

  • Inisialisasi tidak lagi ditentukan secara terpusat dalam konfigurasi.
  • Anda harus ingat untuk mengaktifkan pemrosesan anotasi (yang terkadang dapat dilupakan)
toolkit
sumber
4
Saya pikir itu sebenarnya hal yang baik untuk digunakan secara @PostConstructtepat karena ini adalah bagian dari kelas yang membutuhkan metode memanggil pada akhir pemrosesan inisialisasi.
Donal Fellows
Jika kelas itu BENAR-BENAR membutuhkannya dan Anda tidak dapat melakukannya di konstruktor, daripada saya anggap itu sebagai kode bau.
user482745
39

Sudahkah Anda mencoba implementasi InitializingBean? Kedengarannya persis seperti apa yang Anda cari.

Kelemahannya adalah kacang Anda menjadi Spring-aware, tetapi di sebagian besar aplikasi itu tidak terlalu buruk.

Jon Skeet
sumber
2
Apakah ada alasan Anda memilih mengimplementasikan antarmuka daripada menentukan init-metode dalam XML?
Markus
4
Itu masalah selera. Antarmuka adalah bagian dari model komponen Spring dan melayani tujuan itu dan hanya sementara untuk metode kustom bernama itu mungkin tidak benar-benar jelas bahwa itu harus dipanggil untuk menyelesaikan siklus hidup komponen. Jadi ini terutama melayani komunikasi. Tentu saja dengan kelemahan dari ketergantungan yang diperkenalkan ke kerangka Spring. Cara yang baik di antara adalah penggunaan @PostConstruct, karena memiliki semantik yang jelas namun tidak memperkenalkan ketergantungan ...
Oliver Drotbohm
7
Oliver memberi saya beberapa alasan yang bagus, tetapi sebenarnya saya baru saja lupa tentang metode init :) Salah satu alasan lainnya adalah bahwa tipe itu sendiri tahu bahwa itu perlu "selesai" setelah semua properti telah ditetapkan - tidak pada dasarnya sesuatu yang harus di konfigurasi.
Jon Skeet
8

Anda bisa menggunakan BeanPostProcessor kustom dalam konteks aplikasi Anda untuk melakukannya. Atau jika Anda tidak keberatan menerapkan antarmuka Spring di kacang Anda, Anda bisa menggunakan antarmuka InitializingBean atau direktif "init-metode" (tautan yang sama).

Rob H
sumber
Adakah yang punya perincian tentang cara menulis BeanPostProcessor. Kedengarannya persis seperti yang saya butuhkan. Cheers :)
peakit
Kapal pegas dengan banyak contoh. Lihat saja JavaDoc API untuk BeanPostProcessor dan Anda akan menemukan tautan ke banyak kelas implementasi. Kemudian lihat kode sumber untuk mereka.
Rob H
-7

Untuk lebih jauh menghilangkan kebingungan tentang dua pendekatan yaitu penggunaan

  1. @PostConstruct dan
  2. init-method="init"

Dari pengalaman pribadi, saya menyadari bahwa menggunakan (1) hanya berfungsi dalam wadah servlet, sementara (2) bekerja di lingkungan apa pun, bahkan dalam aplikasi desktop. Jadi, jika Anda akan menggunakan Spring dalam aplikasi mandiri, Anda harus menggunakan (2) untuk melakukan "panggil metode ini setelah inisialisasi.

Ayorinde
sumber
4
Secara teknis, @PostConstruct(ketika digunakan dalam aplikasi berbasis Musim Semi) terkait dengan umur konteks Musim Semi yang dimiliki. Konteks semacam itu dapat digunakan dalam semua jenis aplikasi.
Donal Fellows
Itu adalah perilaku yang saya harapkan tetapi tidak berhasil untuk saya.
Ayorinde