Byte Buddy adalah perpustakaan pembuatan kode dan manipulasi untuk membuat dan memodifikasi kelas Java selama runtime aplikasi Java dan tanpa bantuan kompiler. Selain utilitas pembuatan kode yang dikirimkan dengan Perpustakaan Kelas Java, Byte Buddy memungkinkan penciptaan kelas sewenang -wenang dan tidak terbatas pada implementasi antarmuka untuk pembuatan proxy runtime. Selain itu, Byte Buddy menawarkan API yang nyaman untuk mengubah kelas baik secara manual, menggunakan agen Java atau selama build.
Untuk menggunakan Byte Buddy, seseorang tidak memerlukan pemahaman tentang kode byte java atau format file kelas. Sebaliknya, API Byte Buddy bertujuan untuk kode yang ringkas dan mudah dimengerti untuk semua orang. Namun demikian, Byte Buddy tetap sepenuhnya dapat disesuaikan dengan kemungkinan mendefinisikan kode byte khusus. Selain itu, API dirancang agar tidak mengganggu mungkin dan sebagai hasilnya, Byte Buddy tidak meninggalkan jejak di kelas yang dibuat olehnya. Untuk alasan ini, kelas yang dihasilkan dapat ada tanpa memerlukan byte sobat di jalur kelas. Karena fitur ini, maskot Byte Buddy dipilih untuk menjadi hantu.
Byte Buddy ditulis dalam Java 5 tetapi mendukung generasi kelas untuk versi Java apa pun. Byte Buddy adalah perpustakaan ringan dan hanya tergantung pada API pengunjung dari pustaka Parser kode byte java yang tidak memerlukan dependensi lebih lanjut.
Pada pandangan pertama, pembuatan kode runtime dapat tampak seperti semacam sihir hitam yang harus dihindari dan hanya sedikit pengembang yang menulis aplikasi yang secara eksplisit menghasilkan kode selama runtime mereka. Namun, gambar ini berubah saat membuat perpustakaan yang perlu berinteraksi dengan kode dan jenis sewenang -wenang yang tidak diketahui pada waktu kompilasi. Dalam konteks ini, pelaksana perpustakaan harus sering memilih antara yang mengharuskan pengguna untuk mengimplementasikan antarmuka perpustakaan-kepemilikan atau untuk menghasilkan kode saat runtime ketika jenis pengguna menjadi pertama diketahui oleh perpustakaan. Banyak perpustakaan yang diketahui seperti misalnya Spring atau Hibernate memilih pendekatan terakhir yang populer di antara penggunanya di bawah istilah menggunakan objek java tua biasa . Akibatnya, pembuatan kode telah menjadi konsep di mana -mana di ruang Java. Byte Buddy adalah upaya untuk berinovasi dalam penciptaan runtime tipe Java untuk memberikan alat yang lebih baik yang diatur kepada mereka yang mengandalkan pembuatan kode.
Pada Oktober 2015, Byte Buddy dibedakan dengan Duke's Choice Award oleh Oracle. Penghargaan ini menghargai Byte Buddy untuk " jumlah inovasi yang luar biasa dalam teknologi Java ". Kami merasa sangat terhormat karena telah menerima penghargaan ini dan ingin mengucapkan terima kasih kepada semua pengguna dan semua orang yang membantu menjadikan Byte Buddy sebagai keberhasilannya. Kami sangat menghargainya!
Byte Buddy menawarkan kinerja yang sangat baik pada kualitas produksi. Ini stabil dan digunakan oleh kerangka kerja dan alat yang dibedakan seperti mockito, hibernate, jackson, sistem build Bazel Google dan banyak lainnya. Byte Buddy juga digunakan oleh sejumlah besar produk komersial untuk hasil yang bagus. Saat ini diunduh lebih dari 75 juta kali setahun.
Menyapa Dunia dengan Byte Buddy semudah yang bisa didapat. Setiap penciptaan kelas Java dimulai dengan instance dari kelas ByteBuddy
yang mewakili konfigurasi untuk membuat tipe baru:
Class <?> dynamicType = new ByteBuddy ()
. subclass ( Object . class )
. method ( ElementMatchers . named ( "toString" ))
. intercept ( FixedValue . value ( "Hello World!" ))
. make ()
. load ( getClass (). getClassLoader ())
. getLoaded ();
assertThat ( dynamicType . newInstance (). toString (), is ( "Hello World!" ));
Konfigurasi ByteBuddy
default yang digunakan dalam contoh di atas menciptakan kelas Java dalam versi terbaru dari format file kelas yang dipahami oleh pemrosesan mesin virtual Java. Seperti semoga jelas dari kode contoh, tipe yang dibuat akan memperluas kelas Object
dan mengesampingkan metode toString
yang seharusnya mengembalikan nilai tetap dari Hello World!
. Metode yang akan ditimpa diidentifikasi oleh apa yang disebut ElementMatcher
. Dalam contoh di atas, pencocokan elemen yang telah ditentukan named(String)
digunakan yang mengidentifikasi metode dengan nama yang tepat. Byte Buddy hadir dengan banyak pencocokan yang telah ditentukan dan diuji dengan baik yang dikumpulkan di kelas ElementMatchers
dan yang dapat dengan mudah disusun. Penciptaan pencocokan kustom lebih sederhana seperti mengimplementasikan antarmuka ElementMatcher
(fungsional).
Untuk mengimplementasikan metode toString
, kelas FixedValue
mendefinisikan nilai pengembalian konstan untuk metode yang ditimpa. Mendefinisikan nilai konstan hanyalah satu contoh dari banyak pencegat metode yang dikirimkan dengan byte sobat. Dengan mengimplementasikan antarmuka Implementation
, suatu metode bahkan dapat ditentukan oleh kode byte khusus.
Akhirnya, kelas Java yang dijelaskan dibuat dan kemudian dimuat ke mesin virtual Java. Untuk tujuan ini, diperlukan loader kelas target. Akhirnya, kita dapat meyakinkan diri kita tentang hasilnya dengan memanggil metode toString
pada contoh kelas yang dibuat dan menemukan nilai pengembalian untuk mewakili nilai konstan yang kita harapkan.
Tentu saja, contoh Hello World adalah kasus penggunaan yang terlalu sederhana untuk mengevaluasi kualitas perpustakaan pembuatan kode. Pada kenyataannya, pengguna perpustakaan semacam itu ingin melakukan manipulasi yang lebih kompleks, misalnya dengan memperkenalkan kait ke jalur eksekusi program Java. Menggunakan Byte Buddy, melakukan hal itu sama -sama sederhana. Contoh berikut memberikan rasa bagaimana metode panggilan dapat dicegat.
Byte Buddy mengekspresikan implementasi metode yang didefinisikan secara dinamis oleh contoh antarmuka Implementation
. Dalam contoh sebelumnya, FixedValue
yang mengimplementasikan antarmuka ini sudah ditunjukkan. Dengan mengimplementasikan antarmuka ini, pengguna Byte Buddy dapat pergi ke panjang mendefinisikan kode byte khusus untuk suatu metode. Namun, bagaimanapun, lebih mudah untuk menggunakan implementasi Byte Buddy yang telah ditentukan seperti MethodDelegation
yang memungkinkan untuk mengimplementasikan metode apa pun di Java biasa. Menggunakan implementasi ini lurus ke depan karena beroperasi dengan mendelegasikan aliran kontrol ke POJO. Sebagai contoh pojo seperti itu, Byte Buddy dapat mengarahkan kembali panggilan ke satu -satunya metode kelas berikut:
public class GreetingInterceptor {
public Object greet ( Object argument ) {
return "Hello from " + argument ;
}
}
Perhatikan bahwa GreetingInterceptor
di atas tidak bergantung pada tipe teman byte apa pun. Ini adalah kabar baik karena tidak ada kelas yang dihasilkan oleh Byte Buddy memerlukan Byte Buddy di jalur kelas! Mengingat GreetingInterceptor
di atas, kita dapat menggunakan Byte Buddy untuk mengimplementasikan Java 8 java.util.function.Function
Interface dan Metode apply
Abstraknya:
Class <? extends java . util . function . Function > dynamicType = new ByteBuddy ()
. subclass ( java . util . function . Function . class )
. method ( ElementMatchers . named ( "apply" ))
. intercept ( MethodDelegation . to ( new GreetingInterceptor ()))
. make ()
. load ( getClass (). getClassLoader ())
. getLoaded ();
assertThat (( String ) dynamicType . newInstance (). apply ( "Byte Buddy" ), is ( "Hello from Byte Buddy" ));
Melaksanakan kode di atas, Byte Buddy mengimplementasikan antarmuka Function
Java dan mengimplementasikan metode apply
sebagai delegasi ke instance pojo GreetingInterceptor
yang kami tentukan sebelumnya. Sekarang, setiap kali Function::apply
dipanggil, aliran kontrol dikirim ke GreetingInterceptor::greet
dan nilai pengembalian metode yang terakhir dikembalikan dari metode antarmuka.
Pencegatan dapat didefinisikan untuk mengambil dengan lebih banyak input dan output yang lebih umum dengan menganotasi parameter pencegat. Ketika Byte Buddy menemukan anotasi, perpustakaan menyuntikkan ketergantungan yang dibutuhkan parameter interseptor. Contoh untuk pencegat yang lebih umum adalah kelas berikut:
public class GeneralInterceptor {
@ RuntimeType
public Object intercept ( @ AllArguments Object [] allArguments ,
@ Origin Method method ) {
// intercept any method of any signature
}
}
Dengan interseptor di atas, metode apa pun dapat dicocokkan dan diproses. Misalnya, saat mencocokkan Function::apply
, argumen metode akan dilewati sebagai elemen tunggal dari suatu array. Juga, referensi Method
ke Fuction::apply
akan disahkan sebagai argumen kedua interseptor karena anotasi @Origin
. Dengan mendeklarasikan anotasi @RuntimeType
pada metode ini, Byte Buddy akhirnya melemparkan nilai yang dikembalikan ke nilai pengembalian metode yang dicegat jika diperlukan. Dengan melakukan itu, Byte Buddy juga menerapkan tinju dan unboxing otomatis.
Selain anotasi yang telah disebutkan ada banyak anotasi yang telah ditentukan sebelumnya. Misalnya, saat menggunakan anotasi @SuperCall
pada tipe Runnable
atau Callable
, Byte Buddy menyuntikkan instance proxy yang memungkinkan untuk doa metode super non-abstrak jika metode seperti itu ada. Dan bahkan jika Byte Buddy tidak mencakup kasus penggunaan, Byte Buddy menawarkan mekanisme ekstensi untuk mendefinisikan anotasi khusus.
Anda mungkin berharap bahwa menggunakan anotasi ini mengikat kode Anda dengan Byte Buddy. Namun, Java mengabaikan anotasi jika mereka tidak terlihat oleh loader kelas. Dengan cara ini, kode yang dihasilkan masih bisa ada tanpa Byte Buddy! Anda dapat menemukan informasi lebih lanjut tentang MethodDelegation
dan tentang semua anotasi yang telah ditentukan dalam tutorial Javadoc dan dalam Byte Buddy.
Byte Buddy tidak terbatas untuk membuat subkelas tetapi juga mampu mendefinisikan kembali kode yang ada. Untuk melakukannya, Byte Buddy menawarkan API yang nyaman untuk mendefinisikan apa yang disebut agen Java. Agen Java adalah program Java lama yang dapat digunakan untuk mengubah kode aplikasi Java yang ada selama runtime. Sebagai contoh, kita dapat menggunakan Byte Buddy untuk mengubah metode untuk mencetak waktu eksekusi mereka. Untuk ini, pertama -tama kami mendefinisikan interseptor yang mirip dengan pencegat dalam contoh sebelumnya:
public class TimingInterceptor {
@ RuntimeType
public static Object intercept ( @ Origin Method method ,
@ SuperCall Callable <?> callable ) {
long start = System . currentTimeMillis ();
try {
return callable . call ();
} finally {
System . out . println ( method + " took " + ( System . currentTimeMillis () - start ));
}
}
}
Menggunakan agen Java, kita sekarang dapat menerapkan pencegat ini untuk semua jenis yang cocok dengan ElementMatcher
untuk TypeDescription
. Sebagai contoh, kami memilih untuk menambahkan pencegat di atas ke semua jenis dengan nama yang berakhir dengan Timed
. Ini dilakukan demi kesederhanaan sedangkan anotasi mungkin akan menjadi alternatif yang lebih tepat untuk menandai kelas tersebut untuk agen produksi. Menggunakan API AgentBuilder
Byte Buddy, membuat agen java semudah mendefinisikan kelas agen berikut:
public class TimerAgent {
public static void premain ( String arguments ,
Instrumentation instrumentation ) {
new AgentBuilder . Default ()
. type ( ElementMatchers . nameEndsWith ( "Timed" ))
. transform (( builder , type , classLoader , module , protectionDomain ) ->
builder . method ( ElementMatchers . any ())
. intercept ( MethodDelegation . to ( TimingInterceptor . class ))
). installOn ( instrumentation );
}
}
Mirip dengan metode main
Java, metode premain
adalah titik masuk ke agen Java dari mana kami menerapkan redefinisi. Sebagai salah satu argumen, agen Java menerima instance dari antarmuka Instrumentation
yang memungkinkan Byte Buddy untuk menghubungkan ke API standar JVM untuk redefinisi kelas runtime.
Program ini dikemas bersama dengan file manifes dengan atribut Premain-Class
yang menunjuk ke TimerAgent
. File JAR yang dihasilkan sekarang dapat ditambahkan ke aplikasi Java apa pun dengan mengatur -javaagent:timingagent.jar
mirip dengan menambahkan toples ke jalur kelas. Dengan agen aktif, semua kelas yang berakhir pada Timed
sekarang mencetak waktu eksekusi mereka ke konsol.
Byte Buddy juga mampu menerapkan apa yang disebut lampiran runtime dengan menonaktifkan perubahan format file kelas dan menggunakan instrumentasi Advice
. Silakan merujuk ke Javadoc dari Advice
dan kelas AgentBuilder
untuk informasi lebih lanjut. Byte Buddy juga menawarkan perubahan eksplisit dari kelas Java melalui instance ByteBuddy
atau dengan menggunakan Byte Buddy Maven dan Gradle plugin.
Byte Buddy adalah perpustakaan yang komprehensif dan kami hanya menggaruk permukaan kemampuan Byte Buddy. Namun, Byte Buddy bertujuan untuk mudah digunakan dengan memberikan bahasa khusus domain untuk membuat kelas. Sebagian besar pembuatan kode runtime dapat dilakukan dengan menulis kode yang dapat dibaca dan tanpa pengetahuan tentang format file kelas Java. Jika Anda ingin mempelajari lebih lanjut tentang Byte Buddy, Anda dapat menemukan tutorial tentang halaman web Byte Buddy (ada juga terjemahan bahasa Mandarin yang tersedia).
Selain itu, Byte Buddy hadir dengan dokumentasi dalam kode terperinci dan cakupan kasus uji yang luas yang juga dapat berfungsi sebagai kode contoh. Akhirnya, Anda dapat menemukan daftar artikel dan presentasi terkini tentang Byte Buddy di wiki. Saat menggunakan Byte Buddy, pastikan juga untuk membaca informasi berikut tentang menjaga ketergantungan proyek.
Penggunaan Byte Buddy gratis dan tidak memerlukan pembelian lisensi. Untuk mendapatkan hasil maksimal dari perpustakaan atau untuk mendapatkan awal yang mudah, namun mungkin untuk membeli pelatihan, jam pengembangan atau rencana dukungan. Tarif tergantung pada ruang lingkup dan durasi keterlibatan. Harap hubungi dengan [email protected] untuk informasi lebih lanjut.
Byte Buddy terdaftar di Tidelift. Jika Anda tidak menggunakan Byte Buddy sampai batas tertentu di mana Anda ingin membeli dukungan eksplisit dan ingin mendukung komunitas open source secara umum, silakan pertimbangkan langganan.
Anda dapat mendukung pekerjaan saya melalui sponsor GitHub. Perhatikan bahwa opsi ini hanya dimaksudkan untuk aktor komersial yang mencari saluran pembayaran sederhana dan yang tidak mengharapkan dukungan sebagai imbalan. Dukungan melalui sponsor GitHub tidak mungkin untuk mempertahankan kepatuhan PPN. Harap hubungi perjanjian dukungan langsung sebagai gantinya.
Pertanyaan umum dapat ditanyakan pada stack overflow atau di milis Byte Buddy yang juga berfungsi sebagai arsip untuk pertanyaan. Tentu saja, laporan bug akan dipertimbangkan juga di luar rencana komersial. Untuk proyek open source, kadang -kadang dimungkinkan untuk menerima bantuan yang diperluas untuk menggunakan Byte Buddy untuk digunakan.
Byte Buddy ditulis di atas ASM, perpustakaan yang matang dan teruji untuk membaca dan menulis kelas java yang dikompilasi. Untuk memungkinkan manipulasi tipe lanjut, Byte Buddy sengaja mengekspos API ASM kepada penggunanya. Tentu saja, penggunaan langsung ASM tetap sepenuhnya opsional dan sebagian besar pengguna kemungkinan besar tidak akan pernah membutuhkannya. Pilihan ini dibuat sedemikian rupa sehingga pengguna Byte Buddy tidak terkendali ke fungsionalitas tingkat yang lebih tinggi tetapi dapat menerapkan implementasi khusus tanpa keributan saat diperlukan.
ASM sebelumnya telah mengubah API publik tetapi menambahkan mekanisme untuk kompatibilitas API yang dimulai dengan versi 4 perpustakaan. Untuk menghindari konflik versi dengan versi yang lebih lama seperti itu, Byte Buddy mengemas ulang ketergantungan ASM ke namespace sendiri. Jika Anda ingin menggunakan ASM secara langsung, artefak byte-buddy-dep
menawarkan versi Byte Buddy dengan ketergantungan eksplisit ke ASM. Saat melakukannya, Anda harus mengemas ulang Byte Buddy dan ASM ke namespace Anda untuk menghindari konflik versi.
Harap perhatikan kebijakan keamanan proyek ini.
Byte Buddy mendukung eksekusi pada semua versi JVM dari versi lima dan dan seterusnya dalam satu toples. Ini dilakukan untuk memudahkan pengembangan agen Java yang sering dibutuhkan untuk mendukung aplikasi yang lebih tua, atau tidak diketahui, yang tidak diperbarui secara aktif. Untuk memungkinkan ini sementara juga mendukung Java modern dan fitur-fitur seperti CD atau validasi kelas dengan bingkai peta stack, stoples utama untuk byte sobat kapal sebagai stoples multi-rilis yang berisi file kelas dalam versi lima dan delapan. Akibatnya, ukuran toples Byte Buddy lebih tinggi seperti yang diharapkan. Ukuran file jar biasanya tidak menjadi masalah, karena mayoritas kelas Byte Buddy tidak akan pernah dimuat. Namun, ukuran file mungkin menjadi masalah saat mendistribusikan agen Java. Karena agen-agen sudah perlu dibundel sebagai toples tunggal, oleh karena itu disarankan untuk menghapus versi Java Five dasar, atau versi java delapan-rilis dari file kelas yang terkandung, untuk mengurangi masalah ini. Ini didukung oleh sebagian besar plugin build untuk tujuan ini, seperti plugin Maven Shade.
Byte Buddy dilisensikan di bawah lisensi Apache yang liberal dan ramah bisnis, versi 2.0 dan tersedia secara bebas di GitHub. Selain itu, bundel byte-buddy bundel ASM yang dirilis di bawah lisensi BSD 3-klausa.
Byte Buddy Binaries diterbitkan ke repositori Maven Central dan di JCenter. Tanda tangan artefak dapat divalidasi terhadap kunci publik PGP ini dimulai dengan Byte Buddy 1.10.3. Versi yang lebih lama dapat divalidasi terhadap sertifikat yang lebih tua dan lebih lemah ini.
Proyek ini dibangun menggunakan Maven. Dari cangkang Anda, mengkloning dan membangun proyek akan berjalan seperti ini:
git clone https://github.com/raphw/byte-buddy.git
cd byte-buddy
mvn package
Pada perintah -perintah ini, Byte Buddy dikloning dari Github dan dibangun di atas mesin Anda. Opsi pembuatan lebih lanjut tercantum dalam file root pom. Byte Buddy dapat dibangun dengan JDK setidaknya versi 6. Namun disarankan untuk menggunakan JDK setidaknya versi 8 sebagai build untuk versi 6 dan 7 memerlukan penggunaan HTTP yang tidak terenkripsi. Dukungannya hanya dimaksudkan untuk menjalankan tes terhadap versi JDK ini dan dapat membuat Anda terpapar pada serangan man-in-the-middle. Karena itu, bangunan ini harus dihindari. Byte Buddy saat ini diuji untuk versi 6 dan ke atas JDK di server CI.
Silakan gunakan pelacak masalah GitHub untuk melaporkan bug. Saat melakukan kode, berikan kasus uji yang membuktikan fungsionalitas fitur Anda atau yang menunjukkan perbaikan bug. Selain itu, pastikan Anda tidak melanggar kasus uji yang ada. Jika memungkinkan, silakan luangkan waktu untuk menulis beberapa dokumentasi. Untuk permintaan fitur atau umpan balik umum, Anda juga dapat menggunakan pelacak masalah atau hubungi kami di milis kami.
Pekerjaan pada Byte Buddy juga dimungkinkan berkat deretan pendukung yang telah mendedikasikan sumber daya reguler dan perhatian pada proyek. Harap luangkan waktu Anda untuk melihat para pendukung dan penawaran mereka.