Byte Buddy هي مكتبة لتوليد الكود والتلاعب لإنشاء وتعديل فئات Java أثناء وقت تشغيل تطبيق Java وبدون مساعدة من برنامج التحويل البرمجي. بخلاف أدوات توليد الكود التي تشحن مع مكتبة فئة Java ، يسمح Byte Buddy بإنشاء فصول تعسفية ولا يقتصر على تنفيذ واجهات لإنشاء وكلاء وقت التشغيل. علاوة على ذلك ، يقدم Byte Buddy واجهة برمجة تطبيقات مريحة لتغيير الفصول يدويًا ، باستخدام وكيل Java أو أثناء البناء.
من أجل استخدام Byte Buddy ، لا يتطلب المرء فهمًا لرمز Byte Java أو تنسيق ملف الفئة. على النقيض من ذلك ، تهدف واجهة برمجة تطبيقات Byte Buddy's إلى رمز موجز وسهل الفهم للجميع. ومع ذلك ، يظل Byte Buddy قابلاً للتخصيص بالكامل إلى إمكانية تحديد رمز البايت المخصص. علاوة على ذلك ، تم تصميم واجهة برمجة التطبيقات لتكون غير تابعة للتقطيع قدر الإمكان ، ونتيجة لذلك ، لا يترك Byte Buddy أي أثر في الفصول التي تم إنشاؤها بواسطة ذلك. لهذا السبب ، يمكن أن توجد الفئات التي تم إنشاؤها دون الحاجة إلى زميل بايت على مسار الفصل. بسبب هذه الميزة ، تم اختيار التميمة Byte Buddy لتكون شبحًا.
Bitte Buddy مكتوب في Java 5 ولكنه يدعم توليد الفصول لأي إصدار Java. Byte Buddy هي مكتبة خفيفة الوزن وتعتمد فقط على واجهة برمجة تطبيقات الزوار في مكتبة Java Byte Code Library ASM التي لا تتطلب أي تبعيات أخرى.
للوهلة الأولى ، يمكن أن يكون توليد رمز وقت التشغيل نوعًا من السحر الأسود الذي يجب تجنبه وفقط عدد قليل من المطورين يكتبون التطبيقات التي تنشئ رمزًا بشكل صريح أثناء وقت التشغيل. ومع ذلك ، تتغير هذه الصورة عند إنشاء مكتبات تحتاج إلى التفاعل مع التعليمات البرمجية والأنواع غير المعروفة في وقت الترجمة. في هذا السياق ، يجب أن يختار تطبيق المكتبة في كثير من الأحيان بين مطالبة المستخدم بتنفيذ واجهات مكتبة أو لإنشاء رمز في وقت التشغيل عندما تصبح أنواع المستخدم معروفة أولاً للمكتبة. تختار العديد من المكتبات المعروفة مثل Spring أو Hibernate النهج الأخير الذي يحظى بشعبية بين مستخدميها تحت مصطلح استخدام كائنات Java القديمة . نتيجة لذلك ، أصبح توليد الكود مفهومًا في كل مكان في مساحة Java. Byte Buddy هي محاولة لابتكار إنشاء وقت التشغيل لأنواع Java من أجل توفير أداة أفضل للذين يعتمدون على توليد الكود.
في أكتوبر 2015 ، تميز Byte Buddy بجائزة اختيار Duke من Oracle. تقدر الجائزة Byte Buddy لـ " كمية هائلة من الابتكار في تقنية Java ". نشعر بالفخر الشديد لتلقي هذه الجائزة ونريد أن نشكر جميع المستخدمين وكل من ساعد في جعل Byte Buddy النجاح الذي أصبح عليه. نحن حقا نقدر ذلك!
يقدم Byte Buddy أداءً ممتازًا في جودة الإنتاج. إنه مستقر ويستخدم من خلال الأطر والأدوات المتميزة مثل Mockito و Hibernate و Jackson و Google Bazel Build System وغيرها. يتم استخدام Byte Buddy أيضًا من قبل عدد كبير من المنتجات التجارية لتحقيق نتيجة رائعة. يتم تنزيله حاليًا أكثر من 75 مليون مرة في السنة.
إن قول Hello World with Byte Buddy سهل قدر الإمكان. أي إنشاء فئة Java يبدأ بمثيل من فئة ByteBuddy
التي تمثل تكوينًا لإنشاء أنواع جديدة:
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!" ));
يقوم تكوين ByteBuddy
الافتراضي الذي يتم استخدامه في المثال أعلاه بإنشاء فئة Java في أحدث إصدار من تنسيق ملف الفئة الذي يفهمه جهاز المعالجة الافتراضي. كما نأمل أن يكون واضحًا من رمز المثال ، سيقوم النوع الذي تم إنشاؤه بتوسيع فئة Object
ويتجاوز طريقة toString
الخاصة به والتي يجب أن تُرجع قيمة ثابتة لـ Hello World!
. يتم تحديد طريقة التجاوز من قبل ما يسمى ElementMatcher
. في المثال أعلاه ، يتم استخدام مطابقة عنصر محدد مسبقًا named(String)
يحدد الطرق بأسمائها الدقيقة. يأتي Byte Buddy مع العديد من الممرات المحددة مسبقًا والمختبرة جيدًا والتي يتم جمعها في فئة ElementMatchers
والتي يمكن تأليفها بسهولة. ومع ذلك ، فإن إنشاء المطاعم المخصصة أمر بسيط مثل تطبيق واجهة ElementMatcher
(الوظيفية).
لتنفيذ طريقة toString
، تحدد فئة FixedValue
قيمة إرجاع ثابتة للطريقة المتجاوز. تحديد القيمة الثابتة هو مثال واحد فقط على العديد من أجهزة اعتراضات الطريقة التي تشحن مع Byte Buddy. من خلال تنفيذ واجهة Implementation
، يمكن تحديد طريقة مع ذلك بواسطة رمز البايت المخصص.
أخيرًا ، يتم إنشاء فئة Java الموصوفة ثم يتم تحميلها في جهاز Java Virtual. لهذا الغرض ، يلزم تحميل فئة الهدف. في النهاية ، يمكننا إقناع أنفسنا بالنتيجة من خلال استدعاء طريقة toString
على مثيل للفئة التي تم إنشاؤها وإيجاد قيمة الإرجاع لتمثيل القيمة الثابتة التي توقعناها.
بالطبع ، مثال Hello World هو حالة استخدام بسيطة للغاية لتقييم جودة مكتبة توليد الكود. في الواقع ، يريد مستخدم مثل هذه المكتبة إجراء معالجة أكثر تعقيدًا ، على سبيل المثال من خلال إدخال السنانير في مسار تنفيذ برنامج Java. باستخدام Byte Buddy ، فإن القيام بذلك أمر بسيط بنفس القدر. يعطي المثال التالي طعمًا لكيفية اعتراض مكالمات الطريقة.
Byte Buddy يعبر عن تطبيقات الطريقة المحددة ديناميكيًا بواسطة مثيلات واجهة Implementation
. في المثال السابق ، تم توضيح FixedValue
التي تنفذ هذه الواجهة بالفعل. من خلال تطبيق هذه الواجهة ، يمكن لمستخدم Byte Buddy الانتقال إلى طول رمز البايت المخصص للطريقة. عادةً ما يكون من الأسهل استخدام تطبيقات Byte Buddy المحددة مسبقًا مثل MethodDelegation
التي تسمح بتنفيذ أي طريقة في Java العادي. استخدام هذا التنفيذ مستقيم للأمام لأنه يعمل عن طريق تفويض تدفق التحكم إلى أي POJO. كمثال على مثل هذا Pojo ، يمكن لـ Byte Buddy على سبيل المثال إعادة توجيه مكالمة إلى الطريقة الوحيدة للفئة التالية:
public class GreetingInterceptor {
public Object greet ( Object argument ) {
return "Hello from " + argument ;
}
}
لاحظ أن GreetingInterceptor
المذكور أعلاه لا يعتمد على أي نوع من Byte Buddy. هذه أخبار جيدة لأن أيا من الفصول التي يولدها بايت بوددي تتطلب بايت بايت على مسار الفصل! بالنظر إلى GreetingInterceptor
أعلاه ، يمكننا استخدام Byte Buddy لتنفيذ Java 8 java.util.function.Function
واجهة وطريقة apply
التجريدية:
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" ));
بتنفيذ الكود أعلاه ، يقوم Byte Buddy بتنفيذ واجهة Function
Java وتنفذ طريقة apply
كفد إلى مثيل لـ GreetingInterceptor
Pojo الذي حددناه من قبل. الآن ، في كل مرة تسمى طريقة Function::apply
، يتم إرسال تدفق التحكم إلى GreetingInterceptor::greet
وإعادة قيمة إرجاع الطريقة الأخيرة من طريقة الواجهة.
يمكن تعريف المقاطعات على أخذ المزيد من المدخلات والمخرجات العامة عن طريق التعليق على معلمات التقاطع. عندما يكتشف Byte Buddy شرحًا توضيحيًا ، تقوم المكتبة بحقن التبعية التي تتطلبها المعلمة اعتراضية. مثال على اعتراض أكثر عمومية هو الفئة التالية:
public class GeneralInterceptor {
@ RuntimeType
public Object intercept ( @ AllArguments Object [] allArguments ,
@ Origin Method method ) {
// intercept any method of any signature
}
}
مع اعتراض أعلاه ، يمكن مطابقة أي طريقة اعتراضية ومعالجتها. على سبيل المثال ، عند مطابقة Function::apply
، سيتم تمرير وسيطات الطريقة كعنصر واحد من الصفيف. وأيضًا ، سيتم تمرير Method
إلى Fuction::apply
كوسيطة ثانية للاعتراض بسبب شرح @Origin
. من خلال إعلان التعليق @RuntimeType
على الطريقة ، يلقي Byte Buddy أخيرًا القيمة التي تم إرجاعها إلى قيمة الإرجاع للطريقة المعتادة إذا كان ذلك ضروريًا. في القيام بذلك ، يطبق Byte Buddy أيضًا الملاكمة التلقائية والملاكمة.
إلى جانب التعليقات التوضيحية التي سبق ذكرها ، يوجد الكثير من التعليقات التوضيحية الأخرى المحددة مسبقًا. على سبيل المثال ، عند استخدام التعليق التوضيحي @SuperCall
على نوع Runnable
أو Callable
، يقوم Byte Buddy بحقن مثيلات الوكيل التي تسمح باستدعاء طريقة فائقة غير متجانسة إذا كانت هذه الطريقة موجودة. وحتى إذا كان Byte Buddy لا يغطي حالة الاستخدام ، فإن Byte Buddy يوفر آلية تمديد لتحديد التعليقات التوضيحية المخصصة.
قد تتوقع أن يربط استخدام هذه التعليقات التوضيحية الكود الخاص بك إلى Byte Buddy. ومع ذلك ، تتجاهل Java التعليقات التوضيحية في حالة عدم مرئية لعملية تحميل الفصل. بهذه الطريقة ، لا يزال هناك رمز تم إنشاؤه بدون بايت بايت! يمكنك العثور على مزيد من المعلومات حول MethodDelegation
وعلى كل تعليقاتها المحددة مسبقًا في Javadoc وفي البرنامج التعليمي Byte Buddy.
لا يقتصر Byte Buddy على إنشاء فئات فرعية ولكنه قادر أيضًا على إعادة تعريف الكود الحالي. للقيام بذلك ، يقدم Byte Buddy واجهة برمجة تطبيقات مريحة لتحديد ما يسمى وكلاء Java. وكلاء Java هم برامج Java القديمة التي يمكن استخدامها لتغيير رمز تطبيق Java الحالي أثناء وقت التشغيل. على سبيل المثال ، يمكننا استخدام Byte Buddy لتغيير طرق طباعة وقت التنفيذ الخاص بهم. لهذا ، نحدد أولاً اعتراضًا مشابهًا للاعتراضات في الأمثلة السابقة:
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 ));
}
}
}
باستخدام وكيل Java ، يمكننا الآن تطبيق هذا التقاطع على جميع الأنواع التي تتطابق مع ElementMatcher
لمكتب TypeDescription
. على سبيل المثال ، نختار إضافة اعتراض أعلاه إلى جميع الأنواع مع اسم ينتهي في Timed
. يتم ذلك من أجل البساطة في حين أن التعليق التوضيحي قد يكون بديلاً أكثر ملاءمة لوضع هذه الفئات لعامل الإنتاج. باستخدام واجهة برمجة تطبيقات Byte Buddy's AgentBuilder
، فإن إنشاء وكيل Java سهل مثل تحديد فئة الوكيل التالية:
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 );
}
}
على غرار الطريقة main
لـ Java ، فإن طريقة premain
هي نقطة الدخول إلى أي وكيل Java الذي نطبق منه إعادة التعريف. كوسيطة واحدة ، يتلقى وكيل Java مثيلًا لواجهة Instrumentation
التي تسمح لـ Byte Buddy بالتوصيل في واجهة برمجة تطبيقات JVM القياسية لإعادة تعريف فئة وقت التشغيل.
يتم تعبئة هذا البرنامج جنبًا إلى جنب مع ملف واضح مع سمة Premain-Class
التي تشير إلى TimerAgent
. يمكن الآن إضافة ملف JAR الناتج إلى أي تطبيق Java عن طريق الإعداد -javaagent:timingagent.jar
مماثلة لإضافة جرة إلى مسار الفصل. مع Active Active ، تقوم جميع الفئات التي تنتهي في Timed
بطباعة وقت التنفيذ الخاص بهم إلى وحدة التحكم.
Bitte Buddy قادر أيضًا على تطبيق ما يسمى مرفقات وقت التشغيل عن طريق تعطيل تغييرات تنسيق ملف الفئة واستخدام أدوات Advice
. يرجى الرجوع إلى Javadoc من Advice
وفئة AgentBuilder
لمزيد من المعلومات. يقدم Byte Buddy أيضًا التغيير الصريح لفئات Java عبر مثيل ByteBuddy
أو باستخدام المكونات الإضافية Byte Buddy Maven و Gradle .
Byte Buddy هي مكتبة شاملة وقمنا بخدش فقط سطح Byte Buddy. ومع ذلك ، يهدف Byte Buddy إلى أن يكون سهلاً الاستخدام من خلال توفير لغة خاصة بالمجال لإنشاء فصول. يمكن إجراء معظم توليد رمز وقت التشغيل عن طريق كتابة رمز قابل للقراءة وبدون أي معرفة بتنسيق ملف فئة Java. إذا كنت ترغب في معرفة المزيد عن Byte Buddy ، فيمكنك العثور على مثل هذا البرنامج التعليمي على صفحة الويب الخاصة بـ Byte Buddy (تتوفر أيضًا ترجمة صينية).
علاوة على ذلك ، يأتي Byte Buddy مع وثائق مفصلة داخل الرمز وتغطية حالة الاختبار الواسعة التي يمكن أن تكون بمثابة رمز مثال. أخيرًا ، يمكنك العثور على قائمة حديثة من المقالات والعروض التقديمية على Byte Buddy في الويكي. عند استخدام Byte Buddy ، تأكد أيضًا من قراءة المعلومات التالية حول الحفاظ على تبعية المشروع.
استخدام Byte Buddy مجاني ولا يتطلب شراء ترخيص. للحصول على أقصى استفادة من المكتبة أو لتأمين بداية سهلة ، من الممكن شراء ساعات التدريب أو ساعات التطوير أو خطط الدعم. المعدلات تعتمد على نطاق ومدة المشاركة. يرجى التواصل مع [email protected] لمزيد من المعلومات.
يتم سرد Byte Buddy على Tidelift. إذا كنت لا تستخدم Byte Buddy إلى حد ما تريد شراء دعم صريح وترغب في دعم مجتمع المصدر المفتوح بشكل عام ، فيرجى مراعاة الاشتراك.
يمكنك دعم عملي عبر رعاة Github. لاحظ أن هذا الخيار مخصص فقط للجهات الفاعلة التجارية الذين يبحثون عن قناة دفع بسيطة ولا تتوقع الدعم في المقابل. الدعم عبر رعاة GitHub لا يمكن الحفاظ على امتثال ضريبة القيمة المضافة. يرجى التواصل لاتفاقية الدعم المباشر بدلاً من ذلك.
يمكن طرح الأسئلة العامة على سعة مكدس أو في القائمة البريدية لبايت بايت والتي بمثابة أرشيف للأسئلة. بالطبع ، سيتم النظر في تقارير الأخطاء أيضًا خارج خطة تجارية. بالنسبة للمشاريع المفتوحة المصدر ، من الممكن في بعض الأحيان تلقي مساعدة ممتدة لاستخدام Byte Buddy.
تتم كتابة Byte Buddy على رأس ASM ، وهي مكتبة ناضجة ومختبرة جيدًا لقراءة وكتابة فصول Java المترجمة. من أجل السماح بمعالجة من النوع المتقدم ، تقوم Byte Buddy بعرض ASM API عن عمد لمستخدميها. بالطبع ، لا يزال الاستخدام المباشر لـ ASM اختياريًا تمامًا ، وعلى الأرجح لن يتطلب ذلك أبدًا. تم إجراء هذا الاختيار بحيث لا يتم تقييد مستخدم Byte Buddy لوظائفه ذات المستوى الأعلى ولكن يمكنه تنفيذ تطبيقات مخصصة دون ضجة عندما يكون ذلك ضروريًا.
سبق أن قامت ASM بتغيير واجهة برمجة التطبيقات العامة الخاصة بها ، لكنها أضافت آلية توافق API بدءًا من الإصدار 4 من المكتبة. من أجل تجنب تعارض الإصدار مع مثل هذه الإصدارات القديمة ، يعيد Byte Buddy تعمية ASM في مساحة اسمها الخاصة. إذا كنت ترغب في استخدام ASM مباشرة ، فإن Art Artifact byte-buddy-dep
تقدم نسخة من Byte Buddy مع تبعية صريحة على ASM. عند القيام بذلك ، يجب عليك إعادة تعبئة كل من Byte Buddy و ASM في مساحة الاسم الخاصة بك لتجنب تعارضات الإصدار.
يرجى ملاحظة السياسة الأمنية لهذا المشروع.
يدعم Byte Buddy التنفيذ على جميع إصدارات JVM من الإصدار الخامس وما بعده في جرة واحدة. يتم ذلك لتخفيف تطوير وكلاء Java التي تتطلب في كثير من الأحيان دعم التطبيقات القديمة أو غير المعروفة التي لم يتم تحديثها بنشاط. للسماح بذلك مع دعم Java الحديثة وميزات مثل CDS أو التحقق من صحة الفصل مع إطارات خريطة المكدس ، فإن الجرار الرئيسية لشحن Byte Buddy كجرار متعددة الإصدار تحتوي على ملفات فئة في الإصدار الخامس والثامن. نتيجة لذلك ، يكون حجم جرة بايت بايت أعلى كما يتوقع المرء. لا يمثل حجم ملف JAR مشكلة عادة ، حيث لن يتم تحميل غالبية فصول Byte Buddy أبدًا. ومع ذلك ، قد يكون حجم الملف مشكلة عند توزيع وكلاء Java. نظرًا لأن الوكلاء يحتاجون بالفعل إلى تجميعه كجرة واحدة ، فمن المستحسن إما إزالة إما إصدار Java Five الأساسي ، أو إصدار Java Eight المتعدد من ملفات الفئة الموجودة ، لتقليل هذه المشكلة. يتم دعم هذا من خلال معظم الإضافات البناء لهذا الغرض ، مثل مكون Maven Shade.
Byte Buddy مرخصة بموجب ترخيص Apache الليبرالي والصديق للأعمال ، الإصدار 2.0 وهو متاح بحرية على Github. بالإضافة إلى ذلك ، فإن حزم التوزيع البايت بوددي ASM التي تم إصدارها بموجب ترخيص BSD من 3 أبناء.
يتم نشر ثنائيات Byte Buddy إلى مستودعات Maven Central و JCenter. يمكن التحقق من صحة توقيعات القطع الأثرية مقابل مفتاح PGP العام بدءًا من Byte Buddy 1.10.3. يمكن التحقق من صحة الإصدارات القديمة مقابل هذه الشهادة القديمة والأضعف.
تم بناء المشروع باستخدام Maven. من قذيتك ، فإن الاستنساخ وبناء المشروع سيذهب إلى شيء من هذا القبيل:
git clone https://github.com/raphw/byte-buddy.git
cd byte-buddy
mvn package
على هذه الأوامر ، يتم استنساخ Byte Buddy من Github وبنيت على جهازك. يتم سرد المزيد من خيارات الإنشاء في ملف POM الجذر. يمكن بناء Byte Buddy مع أي JDK على الأقل من الإصدار 6. ومع ذلك ، يوصى باستخدام JDK على الأقل من الإصدار 8 حيث يتطلب بناء الإصدار 6 و 7 استخدام HTTP غير المشفرة. يهدف دعمه فقط إلى إجراء اختبارات مقابل إصدار JDK هذا ويمكنه تعريضك لهجمات الرجل في الوسط. لذلك ، يجب تجنب هذه البناء. يتم اختبار Byte Buddy حاليًا للإصدارات 6 وما فوق من JDK على خوادم CI.
يرجى استخدام تعقب إصدار Github للإبلاغ عن الأخطاء. عند ارتكاب رمز ، يرجى تقديم حالات اختبار تثبت وظائف ميزاتك أو التي تظهر إصلاح الأخطاء. علاوة على ذلك ، تأكد من عدم كسر أي حالات اختبار موجودة. إذا كان ذلك ممكنًا ، يرجى أخذ الوقت الكافي لكتابة بعض الوثائق. لطلبات الميزات أو التعليقات العامة ، يمكنك أيضًا استخدام تعقب المشكلات أو الاتصال بنا على قائمتنا البريدية.
يعد العمل على Byte Buddy ممكنًا أيضًا بفضل صف من المؤيدين الذين خصصوا موارد منتظمة والاهتمام بالمشروع. يرجى أخذ وقتك لإلقاء نظرة على هؤلاء المؤيدين وعروضهم.