Dalam hal Pola Desain Proxy , Apa perbedaan antara Dynamic Proxy JDK dan API pembuatan kode dinamis pihak ketiga seperti CGLib ?
Apa perbedaan antara menggunakan kedua pendekatan tersebut dan kapan satu harus memilih satu dari yang lain?
Dalam hal Pola Desain Proxy , Apa perbedaan antara Dynamic Proxy JDK dan API pembuatan kode dinamis pihak ketiga seperti CGLib ?
Apa perbedaan antara menggunakan kedua pendekatan tersebut dan kapan satu harus memilih satu dari yang lain?
Jawaban:
JDK Dynamic proxy hanya dapat proxy dengan antarmuka (sehingga kelas target Anda perlu mengimplementasikan antarmuka, yang kemudian juga diimplementasikan oleh kelas proxy).
CGLIB (dan javassist) dapat membuat proxy dengan mensubclassing. Dalam skenario ini proksi menjadi subkelas dari kelas target. Tidak perlu antarmuka.
Jadi proksi Java Dynamic dapat proksi: public class Foo implements iFoo
tempat CGLIB dapat proksi:public class Foo
EDIT:
Saya harus menyebutkan bahwa karena javassist dan CGLIB menggunakan proxy dengan mensubclassing, bahwa ini adalah alasan Anda tidak dapat mendeklarasikan metode final atau membuat kelas final saat menggunakan kerangka kerja yang mengandalkan ini. Itu akan menghentikan perpustakaan ini dari memungkinkan untuk subkelas kelas Anda dan menimpa metode Anda.
Perbedaan fungsionalitas
Proxy JDK memungkinkan untuk mengimplementasikan set antarmuka apa pun saat subkelas Object
. Metode antarmuka apa pun, plus Object::hashCode
, Object::equals
dan Object::toString
kemudian diteruskan ke InvocationHandler
. Selain itu, antarmuka perpustakaan standar java.lang.reflect.Proxy
diterapkan.
cglib memungkinkan Anda untuk mengimplementasikan set antarmuka apa pun saat subkelas kelas non-final. Juga, metode dapat diganti secara opsional, yaitu tidak semua metode non-abstrak perlu dicegat. Selain itu, ada berbagai cara menerapkan metode. Ia juga menawarkan InvocationHandler
kelas (dalam paket yang berbeda), tetapi juga memungkinkan untuk memanggil metode super dengan menggunakan pencegat yang lebih canggih seperti misalnya a MethodInterceptor
. Selain itu, cglib dapat meningkatkan kinerja dengan intersepsi khusus seperti FixedValue
. Saya pernah menulis ringkasan pencegat berbeda untuk cglib .
Perbedaan kinerja
Proxy JDK diimplementasikan agak naif dengan hanya satu operator intersepsi, yang InvocationHandler
. Ini membutuhkan pengiriman metode virtual ke implementasi yang tidak selalu dapat disatukan. Cglib memungkinkan untuk membuat kode byte khusus yang terkadang dapat meningkatkan kinerja. Berikut adalah beberapa perbandingan untuk mengimplementasikan antarmuka dengan metode 18 rintisan:
cglib JDK proxy
creation 804.000 (1.899) 973.650 (1.624)
invocation 0.002 (0.000) 0.005 (0.000)
Waktu dicatat dalam nanodetik dengan standar deviasi dalam kawat gigi. Anda dapat menemukan rincian lebih lanjut tentang tolok ukur dalam tutorial Byte Buddy, di mana Byte Buddy adalah alternatif yang lebih modern untuk cglib. Juga, perhatikan bahwa cglib tidak lagi dalam pengembangan aktif.
Dynamic proxy: Implementasi dinamis dari antarmuka saat runtime menggunakan JDK Reflection API .
Contoh: Spring menggunakan proksi dinamis untuk transaksi sebagai berikut:
Proxy yang dihasilkan berada di atas kacang. Ini menambahkan perilaku transnasional pada kacang. Di sini proksi menghasilkan secara dinamis saat runtime menggunakan JDK Reflection API.
Ketika aplikasi dihentikan, proksi akan dihancurkan dan kami hanya akan memiliki antarmuka dan kacang pada sistem file.
Pada contoh di atas kita memiliki antarmuka. Tetapi dalam sebagian besar implementasi antarmuka tidak terbaik. Jadi bean tidak mengimplementasikan antarmuka, dalam hal ini kami menggunakan warisan:
Untuk menghasilkan proxy seperti itu, Spring menggunakan perpustakaan pihak ketiga yang disebut CGLib .
CGLib ( C ode G eneration Lib rary) dibangun di atas ASM , ini terutama digunakan menghasilkan proxy yang memperpanjang kacang dan menambahkan perilaku kacang dalam metode proxy.
Spring AOP menggunakan proxy dinamis JDK atau CGLIB untuk membuat proxy untuk objek target yang diberikan. (JDK proxy dinamis lebih disukai setiap kali Anda punya pilihan).
Jika objek target yang akan diimplementasikan mengimplementasikan setidaknya satu antarmuka maka proxy dinamis JDK akan digunakan. Semua antarmuka yang diimplementasikan oleh tipe target akan diproksi. Jika objek target tidak mengimplementasikan antarmuka apa pun maka proksi CGLIB akan dibuat.
Jika Anda ingin memaksakan penggunaan proksi CGLIB (misalnya, untuk memproksi setiap metode yang ditentukan untuk objek target, bukan hanya yang diimplementasikan oleh antarmuka-nya) Anda dapat melakukannya. Namun, ada beberapa masalah yang perlu dipertimbangkan:
metode terakhir tidak dapat disarankan, karena mereka tidak dapat diganti.
Anda akan membutuhkan binari CGLIB 2 di classpath Anda, sedangkan proksi dinamis tersedia dengan JDK. Spring akan secara otomatis memperingatkan Anda ketika membutuhkan CGLIB dan kelas-kelas perpustakaan CGLIB tidak ditemukan di classpath.
Konstruktor objek proksi Anda akan dipanggil dua kali. Ini adalah konsekuensi alami dari model proksi CGLIB di mana subkelas dihasilkan untuk setiap objek yang diproksi. Untuk setiap instance proksi, dua objek dibuat: objek proksi aktual dan sebuah instance dari subkelas yang mengimplementasikan saran. Perilaku ini tidak diperagakan saat menggunakan proksi JDK. Biasanya, memanggil konstruktor tipe proksi dua kali, tidak menjadi masalah, karena biasanya hanya ada tugas yang terjadi dan tidak ada logika nyata yang diterapkan dalam konstruktor.