Ringkasan Artikel ini akan membahas dengan Anda bagaimana menggabungkan kekuatan anotasi dan aspek untuk memberikan layanan deklaratif kepada perusahaan dengan cara yang kompatibel dengan EJB 3.0 sambil tetap memberikan independensi kontainer.
1. Pendahuluan
Dalam upaya bersama kami untuk lebih meningkatkan kinerja produksi pengembangan perangkat lunak, kami - sebagai anggota komunitas Java - umumnya beralih ke J2EE untuk memberikan masalah teknis yang lebih menantang dalam pengembangan perusahaan seperti manajemen transaksi terdistribusi, solusi distribusi konkurensi dan objek. Ideologi pemandu di baliknya - layanan perusahaan yang kompleks ini dapat diimplementasikan oleh vendor server aplikasi dan diimbangi oleh pengembang komersial - memang merupakan ide yang bagus. J2EE, khususnya EJB, telah berhasil menyediakan platform di mana aplikasi Java perusahaan dibangun.
Bagian dari keberhasilan ini adalah karena kemampuan untuk melakukan pemrograman deklaratif - cara untuk mengembangkan program - di mana Anda dapat mendeklarasikan layanan infrastruktur alih -alih secara eksplisit dikodekan dengan logika bisnis sehingga kode tersebut tersebar di mana -mana. EJB telah membuktikan nilai dari pendekatan pemrograman ini - dengan memungkinkan masalah perusahaan seperti transaksi dan keamanan untuk dinyatakan dengan deskriptor publikasi dan ditangani oleh wadah.
Namun, selama beberapa tahun terakhir, semakin banyak pengembang telah menyadari bahwa EJB membawa banyak tantangan baru dalam produktivitas tim - masing -masing EJB harus disertai dengan banyak antarmuka, dengan deskripsi deskriptor yang dipublikasikan, diakses melalui JNDI, dll. Pengujian unit pada EJB di luar wadah juga membawa kesulitan tambahan.
Harap dicatat bahwa untuk membaca artikel ini, Anda harus memiliki alat berikut:
· Java 2 SDK 1.5
· Maven 2.0 Beta 2
Tujuan EJB 3.0 adalah untuk membuat pengembangan perusahaan lebih mudah dalam aspek -aspek berikut:
· Menerapkan permintaan deklaratif untuk layanan perusahaan dengan memperkenalkan anotasi metadata
· Menerapkan Injeksi Ketergantungan/Sumber Daya melalui Anotasi
· Menerapkan decoupling kacang perusahaan dan antarmuka spesifik EJB
· Penyederhanaan penyimpanan kontinu melalui pemetaan objek-relasional yang ringan
Ini seperti angin musim semi untuk pengembang EJB - mereka telah bekerja keras untuk mengembangkan, menguji dan memelihara EJB. Sekarang mudah untuk menulis kacang perusahaan menggunakan EJB 3.0, seperti membuat POJO (objek Java tradisional) dengan anotasi spesifik untuk menandainya sebagai EJB dan meminta layanan perusahaan. Berikut adalah contoh dari EJB di EJB 3.0 Public Draft:
@Stateful
Cartbean kelas publik mengimplementasikan ShoppingCart
{
total float pribadi;
kode produk vektor pribadi;
publik int someshoppingmethod () {...};
...
}
Pernyataan EJB 3.0 pada dasarnya menyatakan bahwa apa yang dibutuhkan pengembang bukanlah kelas berat, "satu rilis yang memuaskan segalanya", tetapi solusi yang ringan dan mudah digunakan-memberikan pengembang dengan berbagai layanan perusahaan. Untuk tujuan ini, salah satu metode terpenting yang disediakan oleh EJB 3.0 adalah memisahkan kacang perusahaan dan API EJB. Dan solusi ini juga membawa turunan yang menarik - EJB sekarang dapat berjalan tidak hanya pada wadah EJB yang berbeda, tetapi juga di dalam kerangka kerja aplikasi apa pun - kerangka kerja ini harus dapat mengenali EJB 3.0 (JSR 220) dan anotasi normal untuk menyatakan layanan perusahaan (JSR 250) .
Artikel ini tidak memberikan eksplorasi mendalam tentang pemrograman deklaratif, EJBS, aspek atau anotasi. Sebaliknya, cukup analisis hubungan timbal balik antara teknologi ini dan bahas bagaimana menggabungkannya dengan cara baru untuk menyederhanakan pengembangan aplikasi.
Dalam artikel ini, Anda akan belajar cara menulis kacang yang kompatibel dengan EJB 3.0 dan membuat beberapa aspek sederhana untuk membuatnya menjadi manajemen transaksi deklaratif, keamanan, dan injeksi sumber daya. Saya harap Anda dapat memperoleh manfaat dari latihan ini:
· Tiga aplikasi praktis dalam pembelajaran (injeksi ketergantungan, keamanan dan transaksi).
· Akrab dengan EJB 3.0 dan ide -ide di baliknya.
Kenali cara mengimplementasikan decoupling EJB dari API tertentu untuk memungkinkan layanan yang kompatibel dengan EJB 3.0 untuk diimplementasikan dengan ringan daripada disediakan oleh EJB saja.
2. Contoh Pemesanan Penerbangan Aplikasi
Sepanjang diskusi, Anda akan belajar tentang implementasi sistem pemesanan penerbangan - yang menggunakan aspek dan anotasi untuk menerapkan injeksi ketergantungan, keamanan, dan manajemen transaksi. Aplikasi ini hanya melakukan dua fungsi: memungkinkan pengguna untuk mencari penerbangan (Gambar 1) dan kemudian memesan perjalanan (Gambar 2). Kedua operasi akan diproses dengan aman untuk memungkinkan hanya pengguna yang diidentifikasi untuk melakukannya. Selain itu, karena operasi "pesanan perjalanan" melibatkan pemesanan dua penerbangan (keluar dan kembali penerbangan), operasi perlu dibuat sebagai transaksional - misalnya, kedua pesanan akan berhasil atau gagal sebagai satuan pekerjaan.
Gambar 1. Permintaan Penerbangan: Pertama, pengguna mencari penerbangan yang memenuhi kriteria yang ditentukan.
Gambar 2. Pemesanan Penerbangan: Selanjutnya, pengguna memesan penerbangan keluar dan penerbangan kembali. Kedua pesanan berhasil atau gagal.
Aplikasi web sederhana ini berisi beberapa servlet, penampilan layanan dan lapisan DAO (lihat Gambar 3).
Kekhawatiran silang seperti konfigurasi sumber daya, keamanan dan manajemen transaksi akan disediakan oleh aspek (diimplementasikan dengan aspek 1,5 m3) untuk mengimplementasikan perilaku injeksi yang dinyatakan dalam anotasi Java 5.
Gambar 3. Arsitektur Sistem Pemesanan Penerbangan: Sistem pemesanan penerbangan ini terdiri dari tiga komponen utama - mereka bergabung bersama untuk menyelesaikan permintaan pengguna. 3. Suntikan Sumber Daya
Deklarasi draft EJB 3.0 memungkinkan sumber daya untuk dinyatakan melalui anotasi @Resource (keputusan ini didefinisikan dalam rancangan deklarasi anotasi biasa) dan disuntikkan ke dalam EJB Anda oleh wadah. Injeksi ketergantungan adalah teknik - menggunakan teknik ini, entitas di luar objek daripada entitas yang dibuat secara eksplisit untuk objek tersebut dapat memberikan (menyuntikkan) ketergantungan objek. Kadang -kadang digambarkan sebagai prinsip Hollywood - lelucon yang seperti "Jangan menelepon kami, kami akan menelepon Anda."
Ambil kelas TravelAgencyServiceImpl sebagai contoh - untuk terus menyimpan beberapa data, kelas ini perlu menemukan implementasi antarmuka IFLIGHTDAO. Secara tradisional, ini dicapai melalui pabrik, singleton, pelacak layanan atau solusi khusus lainnya. Di antara mereka, satu solusi yang mungkin terlihat seperti ini:
Public Class TravelagencyServiceImpl mengimplementasikan ittravelagencyService
{
Publik Iflightdao Flightdao;
Public TravelagencyServiceImpl ()
{flightdao = flightdaofactory.getInstance (). getFlightDao ();
booktrip public void (Long OutboundFlightId, ReturnflightID, kursi int)
melempar InvalidSeatSException
{
cadangan (outboundflightId, kursi);
cadangan (returnFlightId, kursi);
}
}
Anda telah melihat bahwa implementasi ini melibatkan pembuatan kelas pabrik tertentu - kemungkinan akan membaca informasi konfigurasi yang disimpan di suatu tempat untuk memahami bagaimana implementasi untuk membuat IFLIGHTDAO akan dibuat. Jika layanan tidak secara eksplisit membuat dependensi yang disuntikkan oleh wadah, detail konfigurasi dan pembuatan objek akan diproksi ke wadah. Ini memungkinkan komponen dalam suatu aplikasi untuk mudah dihubungkan bersama - dengan konfigurasi yang berbeda dan menghilangkan banyak kode singleton dan pabrik kuno.
Implementasi kelas - yang bergantung pada implementasi IFLIGHTDAO yang dinyatakan dengan anotasi sumber daya JSR 250 - mungkin terlihat seperti ini:
Public Class TravelagencyServiceImpl mengimplementasikan ittravelagencyService
{
@resource (name = "flightdao")
Publik Iflightdao Flightdao;
booktrip public void (Long OutboundFlightId, ReturnflightID, kursi int)
melempar InvalidSeatSException
{
cadangan (outboundflightId, kursi);
cadangan (returnFlightId, kursi);
}
}
Dalam hal ini, wadah akan memberikan implementasi sumber daya yang benar bernama "Flightdao" ke kelas layanan. Tetapi bagaimana jika Anda ingin memanfaatkan injeksi sumber daya sekarang daripada menunggu rilis EJB 3.0? Oke, Anda dapat mengambil wadah ringan - dapat memberikan suntikan ketergantungan seperti wadah pegas atau pico. Namun, saya tidak mengerti bahwa ada wadah ringan - ia dapat menggunakan anotasi sumber daya JSR 250 untuk menentukan persyaratan injeksi (walaupun saya sangat menantikan beberapa dalam hal ini).
Salah satu solusi adalah menggunakan aspek untuk mengimplementasikan injeksi ketergantungan. Jika Anda menggunakan anotasi @Resource untuk ini, implementasi Anda akan konsisten dengan jalan EJB 3.0 dan maju kompatibel dengan implementasi EJB 3.0 - dan itu bukan hal yang sangat sulit untuk diimplementasikan. Daftar berikut menunjukkan aspek yang dibuat dengan aspekj - itu menyuntikkan bidang yang dijelaskan dengan anotasi @Resource:
@aspek
Injeksi Kelas Publik
{
Private DependencyManager Manager = New DependencyManager ();
@Before ("dapatkan (@resource * *. *)")
public void befefieldAccesss (gabungan hoinpointPoint)
Melempar IllegalargumentException, IllegalArAccessException
{
FieldSignature Signature = (FieldSignature) thisjoinpoint.getSignature ();
injectannotation sumber daya = Signature.getField (). GetAnnotation (Resource.class);
ketergantungan objek = manajer.Resolve dependency (Signature.getFieldType (), injectannotation.name ());
Signature.getField (). Set (thisjoinpoint.getThis (), ketergantungan);
}
}
Semua aspek sederhana ini adalah menanyakan kelas implementasi dari file properti (logika ini dienkapsulasi dalam objek DependencyManager) dan menyuntikkannya ke bidang yang dijelaskan dengan anotasi @Resource sebelum mengakses bidang. Jelas, implementasi ini tidak lengkap, tetapi menggambarkan bagaimana Anda dapat memberikan suntikan sumber daya dengan cara yang kompatibel dengan JSR 250 tanpa EJB.
4. Keselamatan
Selain injeksi sumber daya, JSR 250 dan EJB 3.0 juga memberikan representasi aman metadata melalui anotasi. Paket Javax.Annotation.security mendefinisikan lima anotasi - runas, roles allowed, imbinall, denyall dan rolesreferenced - yang semuanya dapat diterapkan pada metode untuk menentukan persyaratan keamanan. Misalnya, jika Anda ingin menyatakan bahwa metode BookFlight yang tercantum di atas hanya dapat dieksekusi oleh penelepon dengan peran "pengguna", Anda dapat memberi anotasi metode ini dengan batasan keamanan berikut:
Public Class TravelagencyServiceImpl mengimplementasikan ittravelagencyService
{
@resource (name = "flightdao")
Publik Iflightdao Flightdao;
@RolesAllowed ("pengguna")
booktrip public void (Long OutboundFlightId, ReturnflightID, kursi int)
melempar InvalidSeatSException
{
cadangan (outboundflightId, kursi);
cadangan (returnFlightId, kursi);
}
}
Anotasi ini akan menyatakan bahwa wadah bertanggung jawab untuk memastikan bahwa hanya penelepon dari peran yang ditentukan yang dapat menjalankan metode ini. Jadi sekarang saya akan menunjukkan aspek sederhana lainnya - itu akan semakin memperkuat kendala keamanan pada aplikasi:
@aspek
Keamanan Kelas Publik
{
@Around ("Eksekusi (@javax.annotation.security.RolesAllowed * *. *(..))")
Objek publik di sekitar Metode yang diterapkan (Prosidingjoinpoint ini menunjuk)
melempar yang bisa dilempar
{
boolean callerauthorized = false;
Roles allalallowed roles allowed = roles allowed forjoinPoint (thisjoinpoint);
untuk (peran string: roles allowed.value ())
{
if (callerinrole (peran))
{callArhorized = true;
}
if (callAraThorized)
{return thisjooinpoint.proed ();}
kalau tidak
{
Lempar RuntimeException baru ("Penelepon tidak berwenang untuk melakukan fungsi yang ditentukan");
}
}
Peran pribadi yang dialokasikan peran AlallowedForjoinpoint (Prosidingjoinpoint inijoinpoint)
{
MethodyIchature MethodyIGature = (MethodyIgnature) thisjoinpoint.getSignature ();
Metode targetMethod = Methodygnature.getMethod ();
return targetmethod.getannotation (roles allowed.class);
}
Private Boolean Callerinrole (Peran String)
{...}
}
Aspek ini mencakup pelaksanaan semua metode - dengan memverifikasi bahwa penelepon adalah salah satu peran yang ditentukan dalam anotasi, anotasi dengan anotasi @RolesAllowed dan memastikan bahwa penelepon berwenang untuk memanggil metode tersebut. Tentu saja Anda juga dapat menggunakan algoritma apa pun yang Anda sukai untuk mengotorisasi pengguna dan mengambil perannya, seperti JAAS atau solusi yang disesuaikan. Dalam contoh ini program, untuk kenyamanan, saya memilih untuk proxy ke wadah servlet.
V. Urusan
Transaksi menjadi bagian penting dari pengembangan perusahaan - karena mereka memfasilitasi integrasi data dalam lingkungan bersamaan. Dari tingkat tinggi, transaksi dapat memastikan ini melalui beberapa operasi atau lengkap atau tidak lengkap.
Berbeda dengan anotasi untuk injeksi dan keamanan sumber daya, anotasi untuk transaksi khusus untuk EJB 3.0 dan tidak didefinisikan dalam anotasi normal JSR 250. EJB 3.0 mendefinisikan dua anotasi yang terkait dengan transaksi: Manajemen Transaksi dan TransactionAttribute. Anotasi TransactionManager menentukan apakah transaksi dikelola oleh wadah atau oleh kacang. Dalam EJB 3, jika anotasi ini tidak ditentukan, transaksi yang dikelola oleh wadah akan digunakan. Anotasi TransactionAttribute digunakan untuk menentukan tingkat perambatan transaksi dari metode ini. Nilai yang valid - termasuk wajib, yang diperlukan, yang diperlukan, didukung, tidak didukung, dan tidak pernah didukung - digunakan untuk menentukan apakah transaksi yang ada diperlukan atau transaksi baru dimulai, dll.
Karena operasi BookFlight terdiri dari dua langkah - memesan penerbangan keluar dan penerbangan kembali, dengan mengemasnya ke dalam transaksi, Anda dapat memastikan konsistensi operasi. Dengan menggunakan anotasi transaksi EJB 3.0, ini akan terlihat seperti ini:
Public Class TravelagencyServiceImpl mengimplementasikan ittravelagencyService
{
@resource (name = "flightdao")
Publik Iflightdao Flightdao;
@RolesAllowed ("pengguna")
@transactionAttribute (transactionAttributeType.required)
booktrip public void (Long OutboundFlightId, ReturnflightID, kursi int)
melempar InvalidSeatSException
{
cadangan (outboundflightId, kursi);
cadangan (returnFlightId, kursi);
}
}
Dan Anda dapat menerapkan aspek sederhana untuk secara otomatis mendefinisikan batas transaksi:
@aspek
Transaksi Kelas Publik
{
@pointcut ("Eksekusi (@javax.ejb.transactionattribute * *. *(..))")
public void transactionalmethods () {}
@Before ("TransactionMethods ()")
public void beForetransactionalmethods ()
{hibernateutil.begintransaction ();
@AfterReturning ("TransactionAlmethods ()")
public void afterreturningtransactionalmethods ()
{hibernateutil.committransaction ();
@AfterThrowing ("TransactionAlmethods ()")
kekosongan publik setelah throwingtransactionalmethods ()
{hibernateutil.rollbackTransaction ();
}
Implementasi ini didasarkan pada asumsi bahwa pola thread-lokal yang hibernasi dan di mana-mana digunakan untuk mengelola sesi hibernasi dan objek transaksi;
6. Ringkasan
Dengan menggunakan set anotasi EJB 3.0 dan JSR 250, artikel ini telah menunjukkan bagaimana keprihatinan lintas-pemotongan seperti manajemen sumber daya, keamanan, dan transaksi diimplementasikan sebagai aspek. Tentu saja, ada banyak konten lain yang perlu kita pelajari lebih lanjut. Hal pertama yang harus dipelajari adalah cetak biru yang disediakan oleh masalah lintas-pemotongan modular dengan mengimplementasikan contoh-contoh aspek ini menggunakan AspectJ. Kedua, kami telah melihat beberapa ide dan konsep baru di balik pernyataan EJB 3.0 yang sekarang muncul. Akhirnya, kita juga melihat secara dramatis kebebasan yang harus disediakan untuk memisahkan objek bisnis kita dari API EJB. Pada titik ini, yang ingin Anda lakukan untuk membuat TravelagencyServiceImpl adalah sesi tanpa kewarganegaraan hanyalah menambahkan catatan terakhir:
@Stateful
Public Class TravelagencyServiceImpl mengimplementasikan ittravelagencyService
{...}
Akhirnya, saya sangat berharap bahwa pendekatan gratis ini untuk menyediakan layanan perusahaan akan membawa persaingan dan inovasi dalam industri kerangka/kontainer.