java.lang.instrument use use
تم تقديم حزمة java.lang.instrument في JDK5. يمكن للمبرمجين تعديل رمز الفئة ديناميكيًا عن طريق تعديل رمز Bytecode للطريقة. عادة ما يتم معالجتها مسبقًا قبل استدعاء الطريقة الرئيسية للفئة ، ويتم تنفيذها بواسطة Java لتحديد فئة الوكيل للفئة. قبل تحميل رمز الفئة من الفئة في JVM ، سيتم استدعاء طريقة تحويل ClassFiLetRansformer لتحقيق وظيفة تعديل طريقة الفئة الأصلية وتنفيذ AOP. تتمثل ميزة ذلك في أنه لن ينتج فئة جديدة مثل تقنية الوكيل الديناميكي أو CGLIB التي تنفذ AOP ، وليس هناك حاجة للفئة الأصلية للحصول على واجهة.
(1) الوكيل هو اعتراض قبل الطريقة الرئيسية ، أي الكود الذي ينفذ الوكيل قبل تنفيذ الطريقة الرئيسية. يتم تشغيل رمز الوكيل في نفس JVM مثل الطريقة الرئيسية الخاصة بك ، ويتم تحميله بواسطة نفس نظام System Classloader ، ويتم إدارته بواسطة نفس سياسة الأمن والسياق. وكيل الاسم مضللة بعض الشيء ، وليس نفس العامل الذي نفهمه عمومًا. وكيل Java بسيط نسبيا للاستخدام. كيف تكتب وكيل جافا؟ تحتاج فقط إلى تنفيذ طريقة Premain: Public Static Void Premain (String AgentArgs ، Insteration Inst) إذا كان لا يمكن العثور على التعريف أعلاه لـ Premain في JDK 6 ، فستحاول أيضًا استدعاء تعريف Premain التالي: Public Static Void Premain (String AgentArgs)
(2) يجب كتابة فئة الوكيل في حزمة JAR ، ثم يجب أن تحتوي META-INF/MAINIFEST.MF على السمة من فئة Premain. فيما يلي مثال على manesest.mf:
بيان البيان: 1.0 من الفئة المبكرة: Myagent1 تم إنشاؤه من خلال: 1.6.0_06
ثم أضف manceest.mf إلى حزمة الجرة الخاصة بك. فيما يلي سمات البيان المبينة لملف جرة الوكلاء: فئة Premain إذا تم تحديد وكيل عند بدء تشغيل JVM ، تحدد هذه السمة فئة الوكيل ، أي الفئة التي تحتوي على طريقة Premain. مطلوب هذه الخاصية إذا تم تحديد وكيل عند بدء تشغيل JVM. إذا لم يكن العقار موجودًا ، فسيقوم JVM بإجهاض. ملاحظة: هذه الخاصية هي اسم فئة ، وليس اسم ملف أو مسار. من فئة الوكيل إذا كان التنفيذ يدعم الآلية لبدء الوكيل في لحظة معينة بعد بدء تشغيل VM ، تحدد هذه الخاصية فئة الوكيل. وهذا هو ، الفئة التي تحتوي على طريقة الوكيل. هذه الخاصية مطلوبة ولن يتم بدء الوكيل إذا لم يكن موجودًا. ملاحظة: هذا هو اسم الفصل ، وليس اسم الملف أو المسار. يقوم مسار Boot-Class بتعيين قائمة المسار لعمليات البحث عن فئة التمهيد. تمثل المسارات الدلائل أو المكتبات (عادة ما يتم الرجوع إليها كمكتبات جرة أو مضغوطة على العديد من المنصات). بعد فشل آلية خاصة منصة لإيجاد فئة ، يبحث محمل فئة التمهيد عن هذه المسارات. ابحث في المسارات بالترتيب المدرج. يتم فصل المسارات في القائمة بواسطة مسافة واحدة أو أكثر. المسارات تستخدم بناء جملة مكون المسار من URI الهرمي. إذا بدأ المسار بحرف مائل ("/") ، فهو مسار مطلق ، وإلا فهو مسار نسبي. يتم تحليل المسار النسبي بناءً على المسار المطلق لملف جرة الوكيل. تجاهل المسارات بتنسيق غير صحيح ومسارات غير موجودة. إذا تم بدء الوكيل في لحظة معينة بعد بدء تشغيل VM ، يتم تجاهل المسار الذي لا يمثل ملف JAR. هذه الخاصية اختيارية. CAN-REDEDENS-CLASSES BOOLEAN (صواب أو خطأ ، غير ذي صلة بالحالة العلوية والسفلية). ما إذا كانت الفصول المطلوبة لهذا الوكيل يمكن إعادة تعريفها. تعتبر القيم الأخرى غير الحقيقية خاطئة. هذه الخاصية اختيارية والقيمة الافتراضية خاطئة. فئات Can-Ranversform Boolean (صحيحة أو خاطئة ، غير ذات صلة بالحالة العلوية والسفلية). ما إذا كانت الفصول الدراسية المطلوبة لهذا الوكيل يمكن إعادة بناءها. تعتبر القيم الأخرى غير الحقيقية خاطئة. هذه الخاصية اختيارية والقيمة الافتراضية خاطئة. CAN-Set-Method-Prefix Boolean Value (صحيحة أو خاطئة ، غير ذات صلة بالحالة العلوية والسفلية). ما إذا كان يمكن تعيين بادئة الطريقة الأصلية المطلوبة بواسطة هذا الوكيل. تعتبر القيم الأخرى غير الحقيقية خاطئة. هذه الخاصية اختيارية والقيمة الافتراضية خاطئة.
(3) سيتم إضافة كل حزم JAR هذه تلقائيًا إلى ClassPath للبرنامج. لذلك ليست هناك حاجة لإضافتها إلى classpath يدويًا. إلا إذا كنت ترغب في تحديد ترتيب ClassPaths.
(4) لا يوجد حد لعدد معلمات -javaagent في برنامج Java ، حتى تتمكن من إضافة أكبر عدد ممكن من وكلاء Java. سيتم تنفيذ جميع وكلاء Java بالترتيب الذي تحدده. على سبيل المثال:
Java -Javaagent: Myagent1.jar -javaagent: Myagent2.jar -jar myprogram.jar
لنفترض أن الوظيفة الرئيسية في myProgram.jar في برنامج MyProgram. Myagent1.jar ، myagent2.jar ، الفصول التي تنفذ Premain في هاتين الحزمتين اثنين من myagent1 ، وسيكون ترتيب تنفيذ برنامج Myagent2:
Myagent1.premain -> myagent2.premain -> myprogram.main
(5) بالإضافة إلى ذلك ، لن يتم تنفيذ Premain بعد الوظيفة الرئيسية ، على سبيل المثال:
Java -javaagent: Myagent1.Jar -jar myprogram.jar -javaagent: myagent2.jar
يتم وضع Myagent2 خلف myprogram.jar ، لذلك لن يتم تنفيذ Premain of Myagent2 ، وبالتالي ستكون نتيجة التنفيذ:
Myagent1.premain -> myprogram.main
(6) يمكن لكل وكيل Java الحصول على معلمة من نوع السلسلة ، أي AgentArgs في Premain. يتم تعريف هذا الوكيل في خيار Java. على سبيل المثال:
Java -javaagent: Myagent2.jar = thisisagentargs -jar myprogram.jar
ستكون قيمة AgentArgs التي تلقاها Premain في Myagent2 "thisisagentargs" (باستثناء عروض الأسعار المزدوجة).
(7) الأجهزة في المعلمة: أضف classFiLetRansformer المحددة بواسطة المعلمة لتغيير ملف الفئة. يقوم المحول المخصص هنا بتنفيذ طريقة التحويل ، والتي توفر تعديلًا إلى رمز الفئة المراد تنفيذه بالفعل ، ويمكنه حتى الوصول إلى نقطة تنفيذ طريقة فئة أخرى. على سبيل المثال: كتابة فئة الوكيل:
Package org.toy ؛ import java.lang.instrument.instrumentation ؛ import java.lang.instrument.classfiletransformer ؛ perfmonagent class perfmonagent {private static instatation inst = null ؛ /** * يتم استدعاء هذه الطريقة قبل أن تسمى الطراز الرئيسي للتطبيق ، * عندما يتم تحديد هذا الوكيل إلى Java VM. **/ public static void premain (String AgentArgs ، antractation _inst) {system.out.println ("perfmonagent.premain () تم استدعاء.") ؛ // تهيئة المتغيرات الثابتة التي نستخدمها لتتبع المعلومات. inst = _inst ؛ // قم بإعداد محول ملف الفصل. classFiLetRansformer trans = new perfmonxformer () ؛ System.out.println ("إضافة مثيل perfmonxformer إلى JVM.") ؛ Inst.AddTransformer (trans) ؛ }}اكتب فئة ClassFiLetRansformer:
package org.toy ؛ import java.lang.instrument.classfiletransformer ؛ import java.lang.instrument.illegalclassformatexception ؛ eSport java.security.protectiondomain javassist.notfoundException ؛ import javassist.expr.expreditor ؛ استيراد javassist.expr.methodcall ؛ الطبقة العامة perfmonxformer تنفذ classfiletransformer {public byte []] بايت [] تحولت = فارغة ؛ System.out.println ("Transforming" + className) ؛ pool classpool = classpool.getDefault () ؛ ctclass cl = null ؛ حاول {cl = pool.makeClass (new java.io.bytearrayinputstream (classFileBuffer)) ؛ if (cl.isinterface () == false) {ctbehavior [] methods = cl.getDeclaredBehaviors () ؛ لـ (int i = 0 ؛ i <methods.length ؛ i ++) {if (methods [i] .isempty () == false) {domethod (methods [i]) ؛ }} transfort = cl.tobytecode () ؛ }} catch (استثناء e) {system.err.println ("لا يمكن الأداة" + className + "، استثناء:" + e.getMessage ()) ؛ } أخيرًا {if (cl! = null) {cl.detach () ؛ }} تحولت ؛ } private void domethod (ctbehavior method) يلقي notfoundException ، لا يمكن compilexception {// method.insertbefore ("stime long = system.nanotime () ؛") ؛ // method.insertAfter ("system.out.println (/" LEEAD "+method.getName ()+" و time:/"+(system.nanotime ()-Stime)) ؛") ؛ method.instrument (new Expreditor () {public void edit (methodCall m) rems cantmotcomexception {m.replace ("{long stime = system.nanotime () ؛ $ _ = $ stop ($$) ؛ system.out.println (/" +m.getClassName () +". ":/"+(system.nanotime ()-Stime)) ؛} ") ؛}}) ؛ }}) ؛ }}الفئتان أعلاه هما جوهر الوكيل. عندما يبدأ JVM ، سيتم استدعاء perfmonagent.premain قبل تحميل التطبيق. بعد ذلك ، يتم إنشاء مثيل له في perfmonagent.premain ، ثم يتم إنشاء مثيل له في perfmonxformer ، ثم يتم إنشاء مثيل له في perfmonxformer ، ثم يتم إنشاء مثيل في perfmonxformer ، ثم يتم إنشاء مثيل لـ perfmonxformer إلى مثيل الأجهزة (المنقولة من JVM). هذا يجعل perfmonxformer.transform سيتم استدعاؤه عند تحميل الفصل في التطبيق. يمكنك تغيير الفئة المحملة في هذه الطريقة. إنه حقًا سحري. من أجل تغيير رمز الفئة ، استخدمت JBoss 'Javassist. على الرغم من أنك لست مضطرًا لاستخدامها مثل هذا ، إلا أن Jboss 'Javassist قوي حقًا ، مما يتيح لك تغيير رمز الفئة بسهولة.
في الطريقة المذكورة أعلاه ، قمت بتغيير رمز الفئة وأضفت stime طويلة = system.nanotime () ؛ إلى مدخل طريقة كل فئة ، وإضافة system.out.println ("methodClassName.MethodName:"+(system.nanotime ()-Stime)) ؛
شكرا لك على القراءة ، آمل أن تساعدك. شكرا لك على دعمك لهذا الموقع!