Java EE 6 @ javax.annotation.ManagedBean vs. @ javax.inject.Named vs. @ javax.faces.ManagedBean

107

Saya merasa ada sedikit kekacauan di spek Java EE 6. Ada beberapa set anotasi.

Kami memiliki javax.ejbanotasi seperti @Statefuldan @Statelessuntuk membuat EJB.

Ada juga yang @javax.annotation.ManagedBeanmembuat kacang yang dikelola.

Ada anotasi dalam javax.enterprise.contextlike @SessionScopeddan @RequestScoped.

Terlebih lagi ada juga @ManagedBeandan @SessionScoped/ @RequestScopedketerangan dalam javax.faces.beanpaket.

Dan untuk membuat acara lebih rumit ada paket javax.injectdengan @Namedanotasi.

Bisakah seseorang menjelaskan bagaimana mereka terkait satu sama lain?

Di mana saya bisa menggunakan @EJB, @Injectatau @ManagedProperymenyuntikkan kacang lain?

Piotr Gwiazda
sumber
Lihat juga: stackoverflow.com/questions/4684112/…
Arjan Tijms

Jawaban:

194

Pertama-tama izinkan saya melakukan beberapa klarifikasi:

Definisi kacang yang dikelola : umumnya kacang yang dikelola adalah objek yang siklus hidupnya (konstruksi, penghancuran, dll) dikelola oleh sebuah wadah.

Di Java ee kami memiliki banyak container yang mengatur daur hidup objeknya, seperti container JSF, container EJB, container CDI, container Servlet, dll.

Semua kontainer ini bekerja secara independen, mereka boot dalam inisialisasi server aplikasi dan memindai kelas dari semua artefak termasuk jar, ejb-jar, file perang dan telinga dalam waktu penyebaran dan mengumpulkan dan menyimpan beberapa metadata tentang mereka, lalu ketika Anda membutuhkan objek dari kelas saat runtime mereka akan memberi Anda contoh dari kelas-kelas itu dan setelah menyelesaikan pekerjaan, mereka akan menghancurkannya.

Jadi kami dapat mengatakan bahwa kami memiliki:

  • Kacang yang dikelola JSF
  • Kacang yang dikelola CDI
  • Biji yang dikelola EJB
  • Dan bahkan Servlet adalah kacang yang dikelola karena dibuat instance-nya dan dihancurkan oleh wadah, yaitu wadah servlet.

Jadi ketika Anda melihat kata Managed Bean, Anda harus bertanya tentang konteks atau jenisnya. (JSF, CDI, EJB, dll.)

Kemudian Anda mungkin bertanya mengapa kami memiliki banyak kontainer ini: AFAIK, Java EE guys ingin memiliki kerangka kerja injeksi ketergantungan, tetapi mereka tidak dapat mengumpulkan semua persyaratan dalam satu spesifikasi karena mereka tidak dapat memprediksi persyaratan masa depan dan mereka membuat EJB 1.0 dan kemudian 2.0 dan kemudian 3.0 dan sekarang 3.1 tetapi target EJB hanya untuk beberapa persyaratan (transaksi, model komponen terdistribusi, dll).

Pada saat yang sama (secara paralel) mereka menyadari bahwa mereka perlu mendukung JSF juga, kemudian mereka membuat biji yang dikelola JSF dan wadah lain untuk biji JSF dan mereka menganggapnya sebagai wadah DI yang matang, tetapi tetap saja itu bukan wadah yang lengkap dan matang.

Setelah itu Gavin King dan beberapa orang baik lainnya;) membuat CDI yang merupakan wadah DI paling matang yang pernah saya lihat. CDI (terinspirasi oleh Seam2, Guice dan Spring) dibuat untuk mengisi celah antara JSF dan EJB dan banyak hal berguna lainnya seperti injeksi pojo, metode produser, interseptor, dekorator, integrasi SPI, sangat fleksibel, dll. Dan bahkan dapat dilakukan apa yang dilakukan biji terkelola EJB dan JSF maka kita hanya dapat memiliki satu wadah DI yang matang dan kuat. Tetapi untuk beberapa kompatibilitas mundur dan alasan politik Java EE guys ingin menyimpannya !!!

Di sini Anda dapat menemukan perbedaan dan kasus penggunaan untuk masing-masing jenis ini:

Kacang Terkelola JSF, Kacang CDI, dan EJB

JSF pada awalnya dikembangkan dengan kacang yang dikelola sendiri dan mekanisme injeksi ketergantungan yang ditingkatkan untuk JSF 2.0 untuk menyertakan kacang berbasis anotasi. Ketika CDI dirilis dengan Java EE 6, itu dianggap sebagai kerangka kerja kacang yang dikelola untuk platform itu dan tentu saja, EJB ketinggalan jaman semuanya telah ada selama lebih dari satu dekade.

Masalahnya tentu saja mengetahui mana yang akan digunakan dan kapan menggunakannya.

Mari kita mulai dengan kacang Terkelola JSF yang paling sederhana.

Kacang Terkelola JSF

Singkatnya, jangan gunakan jika Anda mengembangkan untuk Java EE 6 dan menggunakan CDI. Mereka menyediakan mekanisme sederhana untuk injeksi ketergantungan dan menentukan kacang pendukung untuk halaman web, tetapi mereka jauh lebih lemah daripada kacang CDI.

Mereka dapat ditentukan menggunakan @javax.faces.bean.ManagedBeananotasi yang mengambil parameter nama opsional. Nama ini dapat digunakan untuk mereferensikan kacang dari halaman JSF.

Cakupan dapat diterapkan ke bean menggunakan salah satu cakupan berbeda yang ditentukan dalam javax.faces.beanpaket yang mencakup cakupan permintaan, sesi, aplikasi, tampilan, dan kustom.

@ManagedBean(name="someBean")
@RequestScoped
public class SomeBean {
    ....
    ....
}

Kacang JSF tidak dapat dicampur dengan jenis biji lainnya tanpa kode manual.

Kacang CDI

CDI adalah kerangka kerja pengelolaan kacang dan injeksi ketergantungan yang dirilis sebagai bagian dari Java EE 6 dan ini mencakup fasilitas kacang terkelola yang lengkap dan lengkap. Biji CDI jauh lebih maju dan fleksibel daripada biji yang dikelola JSF sederhana. Mereka dapat menggunakan interseptor, ruang lingkup percakapan, Acara, jenis injeksi aman, dekorator, stereotip, dan metode produsen.

Untuk menyebarkan kacang CDI, Anda harus menempatkan file bernama beans.xml dalam folder META-INF di classpath. Setelah Anda melakukan ini, maka setiap kacang dalam paket menjadi kacang CDI. Ada banyak fitur di CDI, terlalu banyak untuk dibahas di sini, tetapi sebagai referensi cepat untuk fitur mirip JSF, Anda dapat menentukan cakupan kacang CDI menggunakan salah satu cakupan yang ditentukan dalam javax.enterprise.contextpaket (yaitu, permintaan, percakapan , cakupan sesi dan aplikasi). Jika Anda ingin menggunakan kacang CDI dari halaman JSF, Anda dapat memberinya nama menggunakan javax.inject.Namedanotasi. Untuk menyuntikkan kacang ke kacang lain, Anda menganotasi bidang tersebut dengan javax.inject.Injectanotasi.

@Named("someBean")
@RequestScoped
public class SomeBean {

    @Inject
    private SomeService someService;
}

Injeksi otomatis seperti yang dijelaskan di atas dapat dikontrol melalui penggunaan Kualifikasi yang dapat membantu mencocokkan kelas tertentu yang ingin Anda injeksi. Jika Anda memiliki beberapa jenis pembayaran, Anda dapat menambahkan kualifikasi apakah itu asinkron atau tidak. Meskipun Anda dapat menggunakan @Namedanotasi sebagai qualifier, Anda tidak boleh seperti yang disediakan untuk mengekspos kacang dalam EL.

CDI menangani injeksi biji dengan cakupan yang tidak cocok melalui penggunaan proxy. Oleh karena itu, Anda dapat memasukkan kacang cakupan permintaan ke dalam kacang cakupan sesi dan referensi akan tetap valid pada setiap permintaan karena untuk setiap permintaan, proxy akan terhubung kembali ke instance langsung dari kacang cakupan permintaan.

CDI juga memiliki dukungan untuk interseptor, acara, cakupan percakapan baru, dan banyak fitur lainnya yang menjadikannya pilihan yang jauh lebih baik daripada kacang yang dikelola JSF.

EJB

EJB mendahului biji CDI dan dalam beberapa hal mirip dengan biji CDI dan dalam hal lain sangat berbeda. Terutama, perbedaan antara kacang CDI dan EJB adalah bahwa EJB adalah:

  • Transaksional
  • Terpencil atau lokal
  • Mampu pasif kacang stateful membebaskan sumber daya
  • Mampu menggunakan timer
  • Bisa asynchronous

Kedua jenis EJB disebut stateless dan stateful. Stateless EJB dapat dianggap sebagai kacang sekali pakai yang aman untuk thread yang tidak mempertahankan status apa pun di antara dua permintaan web. EJB yang berstatus memiliki status tahan dan dapat dibuat serta diam selama dibutuhkan hingga dibuang.

Mendefinisikan EJB itu sederhana, Anda cukup menambahkan javax.ejb.Statelessatau javax.ejb.Statefulanotasi ke kelas.

@Stateless
public class BookingService {

  public String makeReservation(Item Item, Customer customer) {
    ...
    ...
  }
}

Kacang stateless harus memiliki cakupan dependen sementara kacang sesi stateful dapat memiliki cakupan apa pun. Secara default, transaksi bersifat transaksional, tetapi Anda dapat menggunakan anotasi atribut transaction.

Meskipun EJB dan biji CDI sangat berbeda dalam hal fitur, penulisan kode untuk mengintegrasikannya sangat mirip karena biji CDI dapat disuntikkan ke dalam EJB dan EJB dapat disuntikkan ke dalam biji CDI. Tidak perlu membuat perbedaan saat menyuntikkan satu sama lain. Sekali lagi, cakupan yang berbeda ditangani oleh CDI melalui penggunaan proxy. Satu pengecualian untuk ini adalah bahwa CDI tidak mendukung injeksi EJB jarak jauh tetapi dapat diimplementasikan dengan menulis metode produser sederhana untuknya.

The javax.inject.Namedpenjelasan serta setiap Kualifikasi dapat digunakan pada EJB untuk mencocokkannya dengan titik injeksi.

Kapan menggunakan kacang yang mana

Bagaimana Anda tahu kapan harus menggunakan kacang yang mana? Sederhana.

Jangan pernah menggunakan kacang yang dikelola JSF kecuali Anda bekerja dalam wadah servlet dan tidak ingin mencoba membuat CDI bekerja di Tomcat (walaupun ada beberapa arketipe Maven untuk itu sehingga tidak ada alasan).

Secara umum, Anda harus menggunakan kacang CDI kecuali Anda membutuhkan fungsionalitas lanjutan yang tersedia di EJB seperti fungsi transaksional. Anda dapat menulis interseptor Anda sendiri untuk membuat kacang CDI menjadi transaksional, tetapi untuk saat ini, lebih mudah menggunakan EJB sampai CDI mendapatkan kacang CDI transaksional yang berada di sekitar sudut. Jika Anda terjebak dalam wadah servlet dan menggunakan CDI, maka transaksi tulisan tangan atau interseptor transaksi Anda sendiri adalah satu-satunya pilihan tanpa EJB.

Jika Anda perlu menggunakan @ViewScopedCDI Anda harus

  • gunakan modul seam- face atau MyFaces CODI . cukup tambahkan salah satunya ke classpath Anda dan @ViewScopedakan berfungsi di CDI. MyFaces CODI memiliki dukungan @ViewScoped yang lebih solid
  • gunakan MyFaces CODI @ViewAccessScoped, ini adalah ekstensi yang ditulis di atas CDI oleh Apache, cukup unduh dan gunakan @ViewAccessScopedanotasi sebagai gantinya @ViewScoped.
  • Gunakan CDI @ConversationScopeddan buat itu berjalan lama. Lihat di sini untuk info lebih lanjut .
  • Gunakan anotasi Omnifaces @ViewScoped

Beberapa bagian dicuri dari sini .

Mehdi
sumber
3
Ini bagus! Terima kasih! Untuk lengkapnya, cukup beri tahu cara menginjeksi kacang CDI atau EJB ke kacang JSF. Apakah @ManagedProperty("#{someBean})"cara yang tepat?
Piotr Gwiazda
2
Nggak! itu tidak akan berhasil. cukup ubah kacang yang dikelola jsf Anda menjadi kacang yang dikelola CDI dengan memberi anotasi menggunakan @Nameddan @javax.enterprise.context.RequestScopeddan gunakan injeksi CDI menggunakan anotasi @Inject. jangan gunakan kacang yang dikelola jsf jika Anda tidak perlu;).
Mehdi
3
> JEE guys ingin menyimpannya !!! - Ini sedikit lebih halus dari itu. CDI selesai agak terlambat dalam siklus Java EE 6 dan JSF 2 & JAX-RS sudah selesai. Mereka telah meningkatkan resp. memperkenalkan fasilitas kacang yang dikelola sendiri. Jika CDI tersedia lebih awal, segalanya mungkin akan terlihat berbeda. Di Java EE 7, JSF akan mengadopsi CDI dan javax.faces.bean pada akhirnya akan ditinggalkan (deprecation adalah proses yang lambat di Java EE, yang baik dan buruk).
Arjan Tijms
3
Ketika Anda mengatakan: Untuk menyebarkan kacang CDI, Anda harus menempatkan file bernama beans.xml dalam folder META-INF di classpath. Setelah Anda melakukan ini, maka setiap kacang dalam paket menjadi kacang CDI. Apakah maksud Anda setiap biji juga menjadi biji CDI selain sebelumnya? Bagaimana jika saya memiliki JSF ManagedBeans dengan ManagedBean dan ViewScoped. Mereka masih Kacang Terkelola JSF, bukan?
Koray Tugay
3
Seseorang dapat melakukan pembaruan untuk Java EE 7 pada artikel hebat ini?
Martijn Burger
7

Ya, ini bisa membingungkan.

Untuk beberapa alasan historis ehm, JSF dan CDI menggunakan anotasi yang sama untuk cakupan, tetapi dari paket yang berbeda.

Seperti yang mungkin Anda tebak, itu berasal javax.faces.beandari spesifikasi JSF, dan tidak terkait dengan CDI. Jangan menggunakannya kecuali Anda memiliki alasan yang sangat kuat untuk melakukannya. Dan jangan pernah mencampurnya dengan penjelasan CDI dari javax.ejb. Ini akan menghasilkan daftar bug dan anomali halus yang tak ada habisnya.

Saya biasanya menyarankan Anda membaca sekilas beberapa halaman pertama (atau bahkan lebih) dari dokumentasi Weld yang sangat bagus . Ini akan menempatkan Anda pada jalur untuk Java EE 6.

Dan jangan ragu untuk memposting pertanyaan lebih lanjut di sini.

jan groth
sumber
Sebenarnya saya punya dua pertanyaan: 1. Saya sering menemukan view scope sangat berguna. Kalau begitu saya perlu menggunakan anotasi JSF? 2. Itu berarti @javax.annotation.ManagedBeantidak ada gunanya karena CDI memperlakukan semua kelas sebagai kacang yang dikelola, benar kan?
Piotr Gwiazda
Tidak terlalu. Anda perlu menjembatani cakupan JSF ke CDI dengan, misalnya, Seam Faces. Dan ya, @ManagedBeans tidak diperlukan jika Anda memiliki beans.xml di file jar yang relevan. Oh, dan jika Anda memiliki pertanyaan lebih lanjut, lebih baik memulai utas baru sebelum kami kehilangan diri di bagian komentar.
jan groth
3

Karena tidak ada balasan secara khusus tentang @javax.annotation.ManagedBean, berikut link ke jawaban dari pertanyaan serupa: Backing beans (@ManagedBean) atau CDI Beans (@Named)? . Spesifikasi dapat ditemukan di http://download.oracle.com/otndocs/jcp/managed_beans-1.0-fr-eval-oth-JSpec/ . Jadi menurut saya @javax.annotation.ManagedBeanitu dimaksudkan sebagai generalisasi @javax.faces.bean.ManagedBean.

Dari apa yang saya kumpulkan, Kacang Terkelola JSF dihapuskan demi Kacang CDI (mungkin sudah tidak digunakan lagi dari JSF 2.3?), Jadi saya rasa @javax.annotation.ManagedBeanitu semua semakin usang sekarang.

Hein Blöd
sumber
@Namedakan menggantikan @ManagedBeandi masa depan?
Thufir
1
Saya telah membaca beberapa pernyataan oleh pakar Java EE berbeda yang memperkirakan bahwa @Namedkacang CDI akan menggantikan JSF @ManagedBeans, misalnya di stackoverflow.com/questions/4347374/… , BalusC mengatakan "Harapannya adalah bahwa @ManagedBean dan kawan-kawan akan dihentikan sesuai dengan Java EE 8. ".
Hein Blöd