يمكن تقسيم فئات الوكيل الديناميكي Java إلى نوعين.
الوكيل الثابت: تم إنشاؤه بواسطة المبرمجين أو يقومون تلقائيًا بإنشاء التعليمات البرمجية المصدرية عن طريق أدوات محددة وتجمعها. قبل تشغيل البرنامج ، يوجد ملف .class لفئة الوكيل بالفعل.
الوكيل الديناميكي: يتم إنشاؤه ديناميكيًا باستخدام آلية الانعكاس عند تشغيل البرنامج.
1. أولاً ، سوف نوضح الوكيل الديناميكي Java.
الآن لدينا واجهة عمل بسيطة تقول ، على النحو التالي:
نسخة الكود كما يلي:
حزمة testaop ؛
الواجهة العامة تقول {
الفراغ العام sealhello (اسم السلسلة) ؛
الحديث الفراغ العام (اسم السلسلة) ؛
}
فئة تنفيذ بسيطة تقول ، على النحو التالي:
نسخة الكود كما يلي:
حزمة testaop ؛
الطبقة العامة التي تقولها تنفذ قول {
@تجاوز
void public sayhello (اسم السلسلة) {
// TODO METHOTION METTOD COBS
System.out.println (name + ": مرحبًا بالجميع!") ؛
}
@تجاوز
الحديث الفراغ العام (اسم السلسلة) {
// TODO METHOTION METTOD COBS
System.out.println (name + ": أعني ، يجب أن نعمل بجد لبناء مجتمع متناغم!") ؛
}
}
ما نريد تحقيقه هو زراعة المعالجة بشكل ديناميكي قبل وبعد قوله هيلو والتحدث.
يستخدم JDK Dynamic Proxy بشكل أساسي فئتين في حزمة java.lang.reflect: الوكيل و InvocationHandler.
InvocationHandler هي واجهة تحدد المنطق المتقاطع من خلال تنفيذ هذه الواجهة ويدعو رمز الفئة المستهدفة من خلال آلية الانعكاس ، وينسج بشكل ديناميكي منطق القطع المتقاطعة ومنطق الأعمال معًا.
يستخدم Proxy InvOcketHandler لإنشاء مثيل ديناميكي يتوافق مع واجهة معينة ويقوم بإنشاء كائن وكيل للفئة الهدف.
على النحو التالي ، نقوم بإنشاء مثيل InvocationHandler:
نسخة الكود كما يلي:
حزمة testaop ؛
استيراد java.lang.reflect.invocationHandler ؛
استيراد java.lang.reflect.method ؛
الطبقة العامة myinvocationHandler تنفذ invocationHandler {
هدف الهدف الخاص ؛
myinvocationHandler (هدف الكائن) {
this.target = الهدف ؛
}
@تجاوز
استدعاء الكائن العام (وكيل الكائن ، طريقة الطريقة ، الكائن [] args)
رميات قابلة للتطبيق {
// تنفيذ قبل طريقة الهدف
System.out.println ("― - ― - ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ؛
System.out.println ("الرجاء التحدث على المسرح الشخص التالي!") ؛
// استدعاء طريقة الهدف
Object obj = method.invoke (الهدف ، args) ؛
// تنفيذ طريقة الهدف بعد
System.out.println ("كل شخص تصفيق وتشجيع!") ؛
إرجاع OBJ ؛
}
}
ها هو الاختبار:
نسخة الكود كما يلي:
حزمة testaop ؛
استيراد java.lang.reflect.proxy ؛
الطبقة العامة jdkproxytest {
الفراغ الثابت العام الرئيسي (سلسلة [] args) {
// فئة الأعمال المستهدفة التي تريد أن تكون مضغوطًا
قول الهدف = new mayerimpl () ؛
// نسج الفئة المستهدفة والفئة المتقاطعة معًا
myinvocationHandler Handler = جديد myinvocationHandler (الهدف) ؛
// إنشاء مثيل وكيل
قول الوكيل = (قول) proxy.newproxyinstance (
Target.getClass ().
target.getClass (). getInterfaces () ، // واجهات الفئة المستهدفة
معالج) ؛ // فئة متقاطعة
proxy.sayhello ("Xiao Ming") ؛
proxy.talking ("xiaoli") ؛
}
}
العملية كما يلي:
نسخة الكود كما يلي:
― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― -
الرجاء التحدث على المسرح الشخص التالي!
شياو مينغ: مرحبا بالجميع!
كل شخص صفق وشجع!
― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― -
الرجاء التحدث على المسرح الشخص التالي!
Xiaoli: أعني ، يجب أن نعمل بجد لبناء مجتمع متناغم!
كل شخص صفق وشجع!
هناك قيود كبيرة على استخدام الوكيل الديناميكي JDK ، وهو أنه يتطلب أن يكون الفئة المستهدفة تنفيذ واجهة الطريقة المقابلة ، ويمكنها فقط إنشاء مثيلات وكيل للواجهة. يمكننا أن نرى في طريقة NewProxyInstance للوكالة في فئة الاختبار أعلاه أن المعلمة الثانية لهذه الطريقة هي واجهة الفئة الهدف. إذا لم تنفذ هذه الفئة واجهة ، فإن ذلك يعتمد على الوكيل الديناميكي CGLIB.
تتبنى CGLIB تقنية Bytecode الكامنة للغاية ، والتي يمكن أن تنشئ فئة فرعية لفئة ، وتستخدم تقنيات اعتراض الطريقة في الفئة الفرعية لاعتراض جميع مكالمات طرق الفئة الأصل ، وزرع منطق تقاطع الموقف.
2. بعد ذلك ، سوف نوضح الوكيل الديناميكي CGLIB.
بادئ ذي بدء ، نحن بحاجة إلى توجيه الحزمة.
نقوم أولاً بإنشاء منشئ وكيل Cglibproxy:
نسخة الكود كما يلي:
حزمة testaop.cglib ؛
استيراد java.lang.reflect.method ؛
استيراد net.sf.cglib.proxy.enhancer ؛
استيراد net.sf.cglib.proxy.methodinterceptor ؛
استيراد net.sf.cglib.proxy.methodproxy ؛
الطبقة العامة cglibproxy تنفذ methodInterceptor {
Enhancer Enhancer = New Enhancer () ؛
الكائن العام getProxy (class clazz) {
// قم بتعيين الفئة الفرعية المراد إنشاؤها
endance.SetSuperClass (clazz) ؛
ensancer.setCallback (هذا) ؛
// قم بإنشاء حالات فئة فرعية ديناميكيًا من خلال تقنية Bytecode
إرجاع ensancer.create () ؛
}
@تجاوز
اعتراض الكائن العام (كائن OBJ ، طريقة الطريقة ، الكائن [] args ،
MethodProxy Proxy) رمي رمي {
// TODO METHOTION METTOD COBS
System.out.println ("― - ― - ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ― ؛
System.out.println ("الرجاء التحدث على المسرح الشخص التالي!") ؛
// استدعاء طريقة الهدف
نتيجة الكائن = proxy.invokesuper (OBJ ، args) ؛
// تنفيذ طريقة الهدف بعد
System.out.println ("كل شخص تصفيق وتشجيع!") ؛
نتيجة العودة
}
}
ثم الاختبار:
نسخة الكود كما يلي:
حزمة testaop.cglib ؛
استيراد testaop.saying ؛
استيراد testaop.sayingimpl ؛
الفئة العامة cglibproxytest {
الفراغ الثابت العام الرئيسي (سلسلة [] args) {
cglibproxy proxy = new Cglibproxy () ؛
// قم بإنشاء فئات وكيل عن طريق إنشاء فئات فرعية ديناميكيًا
قول الهدف = (قول) proxy.getProxy (shoteImpl.Class) ؛
Target.Sayhello ("Xiao Ming") ؛
Target.Talking ("Xiaoli") ؛
}
}
والنتيجة لا تختلف عن الوكيل الديناميكي JDK.
كل من الوكيل الديناميكي JDK والوكالة الديناميكية CGLIB هما تحسينات وقت التشغيل ، والتي يتم تعزيزها عن طريق زرع الكود المتقاطع في فئات وكيل. على عكس هذا ، فإن الجوانب التي يمكنها زرع الكود المتقاطع في فترة التجميع من خلال برنامج التحويل البرمجي الخاص.