مفهوم AOP
AOP: البرمجة الموجهة نحو الجانب (البرمجة الموجهة نحو المقطعين) ، تشرح ويكيبيديا على النحو التالي: الجانب هي آلية معيارية جديدة تستخدم لوصف المخاوف المستعرضة المنتشرة في الكائنات أو الفئات أو الوظائف. إن فصل المخاوف المستعرضة عن المخاوف هو المفهوم الأساسي للبرمجة الموجهة نحو الظل. إن فصل التركيز يجعل الرمز الذي يحل مشاكل المجال المحددة بشكل مستقل عن منطق العمل. لا يحتوي رمز منطق العمل على مكالمات إلى رمز لمشاكل المجال المحددة. يتم تغليف العلاقة بين منطق العمل ومشاكل المجال المحددة والصيانة من خلال الأقسام ، بحيث يمكن إدارة التغييرات التي كانت منتشرة في الأصل في جميع أنحاء التطبيق. من منظور AOP ، يمكن تقسيم التطبيقات إلى مخاوف مستعرضة ورمز منطق الأعمال. في التطوير الفعلي ، غالبًا ما يتم تضمين هذه المخاوف المستعرضة بشكل مباشر في رمز منطق الأعمال. البرمجة الموجهة نحو الوجه هي حل مشكلة فصل المخاوف المستعرضة عن منطق العمل.
طريقة التنفيذ:
يستخدم Spring Proxy JDK Dynamic Proxy كوكيل AOP افتراضيًا. العيب هو أن الفئة المستهدفة يجب أن تنفذ واجهة ، وإلا لا يمكن استخدام الوكيل الديناميكي JDK. إذا كان الفصل فئة بدلاً من واجهة ، فسيستخدم Spring Proxy CGLIB افتراضيًا. فيما يتعلق بالفرق بين الاثنين: يتم تنفيذ الوكيل الديناميكي JDK من خلال آلية انعكاس Java ، يجب على الطبقة المستهدفة تنفيذ واجهات ، ويقوم CGLIB بتنفيذ الوكيل للفئات. يتمثل مبدأها في إنشاء فئة فرعية للفئة المستهدفة بشكل ديناميكي وتجاوز تعزيز تنفيذ الطريقة ، ولكن نظرًا لاستخدام الميراث ، لا يمكن أن يكون الفئة المعدلة النهائية وكيلًا.
الوكيل الديناميكي JDK
تقوم شركة JDK Dynamic Proxy بإنشاء ملفات فئة من فئات الوكيل بناءً على الواجهة التي تنفذها الفئة المستهدفة أثناء عملية البرنامج. يتضمن الاستخدام بشكل أساسي فئتين:
واجهة InvocationHandler: يوفر طريقة invoke(Object obj,Method method, Object[] args) للمنافسين لتوفير تنفيذ منطق الوكيل المقابل. يمكن إجراء بعض المعالجة الخاصة على التنفيذ الفعلي ، والمعلمات هي
كائن OBJ: الفئة المستهدفة التي تم وكيلها
الطريقة: طريقة الفئة المستهدفة التي يجب تنفيذها
كائن [] args: معلمات طريقة الهدف
فئة الوكيل: قدم طريقة newProxyInstance (ClassLoader loader, Class[] interfaces, InvocationHandler h) للحصول على فئة الوكيل الديناميكي
نموذج الرمز:
واجهة عامة OrderService {public void createDorder () ؛ } الطبقة العامة OrderServiceImpl تنفذ OrderService {Override public void createDorder () {system.out.println ("إنشاء الطلب") ؛ }} الفئة العامة orderlogger {public void beforecreatorder () {system.out.println ("قبل إنشاء الطلب") ؛ } public void aftercreateDord () {system.out.println ("بعد إنشاء أمر") ؛ }} package com.sl.aop ؛ import java.lang.reflect.invocationHandler ؛ import java.lang.reflect.method ؛ import java.lang.reflect.proxy ؛ public class serviceproxy تنفس invocationHandler {private objectclass ؛ orderlogger orderlogger الخاص ؛ Public ServiceProxy (Object TargetClass ، orderlogger orderlogger) {this.targetClass = TargetClass ؛ this.orderLogger = orderlogger ؛ }. . نتيجة الكائن = method.invoke (TargetClass ، args) ؛ this.orderlogger.afterCreateDorder () ؛ نتيجة العودة }}فئة الاختبار:
package com.sl.aop ؛ import org.junit.test ؛ public class aoptest {test public void testdynamicproxy () {orderServiceImpl ServiceImpl = new orderserviceImpl () ؛ orderlogger logger = new OrderLogger () ؛ Service Service = (OrderService) New ServiceProxy (ServiceImpl ، Logger) .getDynamicproxy () ؛ service.CreateRorder () ؛ }}نتائج التشغيل:
أنا في الواقع مرتبك قليلاً عندما أصل إلى هذه النقطة. ماذا يعود Proxy.newProxyInstance() ؟ أين تسمى طريقة الاستدعاء؟ دعونا نلقي نظرة على رمز مصدر JDK: انظر كيف تبدو عملية الوكيل الديناميكي DK:
استدعاء Proxy.newProxyInstance()->Proxy.getProxyClass0()->WeakCache.get() وفقًا للوظيفة داخل الكود المصدري ، وقم أولاً بتحديد موقعه
peanscache.class:
public v get (k key ، p parameter) {objects.requirenonnull (parameter) ؛ expungestaleentries () ؛ كائن cachekey = cachekey.valueof (المفتاح ، refqueue) ؛ // بتكاسل قم بتثبيت قيم المستوى الثاني من أجل Cachekey ConcurrentMap <Object ، المورد <v>> valuesmap = map.get (cachekey) ؛ if (dordermap == null) {concurrentMap <object ، المورد <v >> oldvaluesmap = map.putifabsent (cachekey ، valuesmap = concurrenthashmap <> ()) ؛ if (oldvaluesmap! = null) {valuesmap = oldvaluesmap ؛ }} // إنشاء مفتاح subkey واسترداد المورد المحتمل <V> المخزّن بواسطة ذلك // subkey from valuesmap object subkey = objects.requirenonnull (subkeyfactory.apply (مفتاح ، المعلمة)) ؛ المورد <v> المورد = قيم map.get (مفتاح subkey) ؛ مصنع المصنع = فارغ ؛ بينما (صحيح) {if (المورد! = null) {// قد يكون المورد مصنعًا أو cachevalue <v> مثيل v value = supplier.get () ؛ if (value! = null) {return value ؛ }} // آخر لا يوجد مورد في ذاكرة التخزين المؤقت // أو المورد الذي تم إرجاعه (يمكن أن يكون cachevalue / / مصنع لم يكن ناجحًا في تثبيت cachevalue) // بنسى مصنع إذا (المصنع == null) {factory = مفتاح ، معلمة ، subkey ، القيم) ؛ } if (المورد == null) {المورد = valuesmap.putifabsent (المفتاح الفرعي ، المصنع) ؛ if (المورد == null) {// تم تثبيت مصنع المورد بنجاح = المصنع ؛ }. } else {// Retry مع مورد المورد الحالي للموردين = valuesmap.get (مفتاح subkey) ؛ }}}} يمكنك رؤية قيمة إرجاع الوظيفة ؛ و V value = supplier.get(); استمر في قراءته وابحث عن أن العشاء = المصنع هو في الواقع كائن مصنع ، لذا استمر في عرض طريقة Factory.get()
Synchronized V GET () {// Serialize Access // إعادة تحديد المورد <V> المورد = valuesmap.get (subkey) ؛ إذا كان (المورد! = هذا) {// شيء تم تغييره أثناء انتظارنا: // } // آخر لا يزال لنا (المورد == هذا) // إنشاء قيمة v جديدة = null ؛ حاول {value = objects.requirenonnull (valuefactory.apply (المفتاح ، المعلمة)) ؛ } أخيرًا {if (value == null) {// أزلنا على قيم الفشل map.remove (مفتاح subke ، هذا) ؛ }} // المسار الوحيد للوصول هنا هو مع قيمة تأكيد القيمة غير الفنية! = null ؛ // ref value مع cachevalue (PremReference) cachevalue <v> cachevalue = new cachevalue <> (value) ؛ // حاول استبدالنا بـ cachevalue (يجب أن ينجح هذا دائمًا) إذا كان (dordermap.replace (مفتاح subke ، هذا ، cachevalue)) {// وضع أيضًا في ReseverseMap Resplyap.put (cachevalue ، boolean.true) ؛ } آخر {رمي تأكيد جديد ("يجب ألا تصل إلى هنا") ؛ } // استبدلنا بنجاح بـ cachevalue -> إرجاع القيمة // ملفوفة من قيمة الإرجاع ؛ } قيمة الإرجاع ثم عرض مباشرة عبارة التعيين: value = Objects.requireNonNull(valueFactory.apply(key, parameter));
ماذا بحق الجحيم هو ValueFactory؟
Public DepicCache (bifunction <k ، p ،؟> subkeyfactory ، bifunction <k ، p ، v> valuefactory) {this.subKeyfactory = Objects.requirenonnull (subkeyfactory) ؛ this.valuefactory = objects.requirenonnull (valueFactory) ؛ } private static final premcache <classloader ، class <؟> [] ، class <؟ >> proxyclasscache = new DefenCache <> (new KeyFactory () ، proxyclassfactory ()) ؛ يمكنك معرفة أن ValueFactory هو كائن نوع proxyclassfactory ، وعرض مباشرة ProxyClassFactory. Apply() طريقة
الطبقة العامة <؟> تطبيق (loader classloader ، فئة <؟> [] واجهات) {map <class <؟> ، boolean> interfaceset = new IdentityHashMap <> (interfaces.length) ؛ لـ (class <؟> intf: interfaces) { / * * حدد أن تحميل الفئة يحل اسم الواجهة * إلى نفس كائن الفئة. */ class <؟> interfaceClass = null ؛ حاول {interfaceClass = class.forname (intf.getName () ، false ، loader) ؛ } catch (classnotfoundException e) {} if (interfaceClass! = intf) {throw new alficalArgumentException (intf + "غير مرئي من loader class") ؛ } / * * تحقق من أن كائن الفئة يمثل بالفعل واجهة *. */ if (! interfaceClass.isInterface ()) {رمي new alficalArgumentException (interfaceClass.getName () + "ليست واجهة") ؛ } / * * تحقق من أن هذه الواجهة ليست مكررة. */ if (interfaceset.put (interfaceClass ، boolean.true)! = null) {رمي new alfictalargumentException ("الواجهة المتكررة:" + interfaceClass.getName ()) ؛ }} سلسلة proxypkg = null ؛ // حزمة لتحديد فئة الوكيل في int accessflags = modifier.public | modifier.final ؛ / * * سجل حزمة واجهة الوكيل غير الحكومية بحيث يتم تعريف فئة * الوكيل في نفس الحزمة. تحقق من أن * جميع واجهات الوكيل غير العامة موجودة في نفس الحزمة. */ for (class <؟> intf: interfaces) {int flags = intf.getModifiers () ؛ if (! modifier.ispublic (flags)) {accessflags = modifier.final ؛ اسم السلسلة = intf.getName () ؛ int n = name.lastindexof ('.') ؛ String pkg = ((n == -1)؟ "": name.subString (0 ، n + 1)) ؛ if (proxypkg == null) {proxypkg = pkg ؛ } if if (! pkg.equals (proxypkg)) {رمي جديد alficalArgumentException ("واجهات غير عامة من حزم مختلفة") ؛ }}}} if (proxypkg == null) {// إذا لم يكن هناك واجهات الوكيل غير الحكومية ، استخدم proxypkg proxypkg com.sun.proxy com.sun.proxy proxypkg = respectutil.proxy_package + "." ؛ } / * * اختر اسمًا لفئة الوكيل لإنشاء. */ long num = nextUniquenumber.getandincrement () ؛ سلسلة proxyname = proxypkg + proxyclassnamePrefix + num ؛ / * * إنشاء فئة الوكيل المحددة. */ byte [] proxyclassfile = proxygenerator.generateproxyclass (proxyname ، interfaces ، accessflags) ؛ حاول {return defedeclass0 (loader ، proxyname ، proxyclassfile ، 0 ، proxyclassfile.length) ؛ } catch (classFormaterror e) { / * * A classformaterror هنا يعني (منع الحشرات في رمز توليد فئة البروكسي *) كان هناك بعض الجوانب غير الصالحة للوسائط المقدمة لإنشاء فئة الوكيل (مثل قيود الجهاز الظاهري * تجاوزت). */ رمي جديد غير unalfalArgumentException (E.ToString ()) ؛ }}}ارسم النقاط الرئيسية مباشرة:
byte [] proxyclassfile = proxygenerator.generateproxyclass (proxyname ، واجهات ، accessflags) ؛ return defedeclass0 (loader ، proxyname ، proxyclassfile ، 0 ، proxyclassfile.length) ؛
استدعاء ProxyGenerator.generateProxyClass يولد أخيرًا فئة وكيل ، ولكن يبدو أنه لا يوجد أي مكان يسمى Invoke ؛ ارجع إلى المقالة CSDN: //www.vevb.com/article/118935.htm ، حاول إخراج رمز ثنائي ثنائي تم إنشاؤه محليًا وتفكيكه لمعرفة ما هو عليه. رمز الاختبار كما يلي:
الفئة العامة aoptest {test public void testDynamicProxy () {orderserviceImpl ServiceImpl = new orderserviceImpl () ؛ orderlogger logger = new OrderLogger () ؛ Service Service = (OrderService) New ServiceProxy (ServiceImpl ، Logger) .getDynamicproxy () ؛ service.CreateRorder () ؛ // إخراج فئة الوكيل الديناميكي bytecode createproxyclassfile () ؛ } private static void createproxyclassfile () {string name = "proxyObject" ؛ byte [] data = proxygenerator.generateproxyclass (الاسم ، فئة جديدة [] {orderservice.class}) ؛ fileOutputStream Out = null ؛ حاول {Out = new FileOutputStream (name+". class") ؛ System.out.println ((ملف جديد ("Hello")). getabsolutepath ()) ؛ out.write (البيانات) ؛ } catch (fileNotFoundException e) {e.printStackTrace () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ } أخيرًا {if (null! = out) حاول {out.close () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ }}}}}}استخدم أداة java decompiler لإلغاء توحيد ملف الفئة الثنائي هذا:
ProxyObject.java ديناميكي محدد: Java:
استيراد com.sl.aop.orderservice ؛ import java.lang.reflect.invocationHandler ؛ import java.lang.reflect.method ؛ import java.lang.reflect.proxy ؛ استيراد m1 java.lang.reflect.undeclaredthrowable ؛ الطريقة الثابتة الخاصة M2 ؛ الطريقة الثابتة الخاصة M3 ؛ الطريقة الثابتة الخاصة M0 ؛ proxyobject (InvocationHandler ParamInvocationHandler) {super (paraminvocationHandler) ؛ } public final boolean equals (Object paramObject) {try {return ((boolean) this.h.invoke (this ، m1 ، comple new [] {paramobject})). booleanvalue () ؛ } catch (error | runTimeException localerror) {throw localerror ؛ } catch (throwable localThrowable) {رمي جديد غير محدد غير قابل للمعاناة (localThrowable) ؛ }} السلسلة النهائية العامة toString () {try {return (string) this.h.invoke (this ، m2 ، null) ؛ } catch (error | runTimeException localerror) {throw localerror ؛ } catch (throwable localThrowable) {رمي جديد غير محدد غير قابل للمعاناة (localThrowable) ؛ }} public final void createDord () {try {this.h.invoke (this ، m3 ، null) ؛ يعود؛ } catch (error | runTimeException localerror) {throw localerror ؛ } catch (throwable localThrowable) {رمي جديد غير محدد غير قابل للمعاناة (localThrowable) ؛ }} public final int hashcode () {try {return ((integer) this.h.invoke (this ، m0 ، null)). Intvalue () ؛ } catch (error | runTimeException localerror) {throw localerror ؛ } catch (throwable localThrowable) {رمي جديد غير محدد غير قابل للمعاناة (localThrowable) ؛ }} static {try {m1 = class.forname ("java.lang.object"). getMethod ("equals" ، class [] {class.forname ("java.lang.object")}) ؛ m2 = class.forname ("java.lang.object"). getMethod ("toString" ، فئة جديدة [0]) ؛ m3 = class.forname ("com.sl.aop.orderservice"). getMethod ("createRorder" ، فئة جديدة [0]) ؛ m0 = class.forname ("java.lang.object"). getMethod ("hashcode" ، فئة جديدة [0]) ؛ يعود؛ } catch (nosuchmethodexception localnosuchmethodexception) {رمي nosuchmethoderror جديد (localnosuchmethodexception.getMessage ()) ؛ } catch (classNotFoundException localClassNotFoundException) {رمي noclassDeffounderror (localclassnotfoundException.getMessage ()) ؛ }}رأى أخيرًا الجزء المتعلق بالاستدعاء:
public final void createRorder () {try {this.h.invoke (this ، m3 ، null) ؛ يعود؛ } catch (error | runTimeException localerror) {throw localerror ؛ } catch (throwable localThrowable) {رمي جديد غير محدد غير قابل للمعاناة (localThrowable) ؛ }}في الواقع ، ترث فئة الوكيل الديناميكي من الوكيل وتنفذ الواجهة الموروثة بواسطة الفئة المستهدفة. يتم استدعاء طريقة Invoke في طريقة CreateRorder ، والتي تنفذ زرع المنطق المقطع. نحن هنا أيضًا نجيب على سؤال ، لماذا يجب أن تنفذ الفئة المستهدفة من الوكيل الديناميكي JDK الواجهة ، لأن فئة الوكيل تهدف فعليًا إلى وكيل الواجهة ، وليس الفصل. يرث فئة الوكيل الديناميكية نفسها من الوكيل ، ولا تسمح Java براالة متعددة. تنفذ فئة الوكيل الديناميكي والفئة المستهدفة في الواقع الواجهات على التوالي. تدرك فئة الوكيل الدعوة إلى طريقة الفئة الهدف من خلال invocationHandler.invoke.
CGLIB الوكيل الديناميكي
يستخدم وكيل CGLIB إطارًا لـ Bytecode Processing ASM لتحويل Bytecode وإنشاء فئات جديدة ، ويستخدم تقنيات اعتراض الطرق في الفئات الفرعية لاعتراض جميع أساليب الفئة الأصل لتنفيذ منطق التقاطع المتقاطع ، وهو أكثر كفاءة من وكيل JDK الديناميكي باستخدام تقنية الانعكاس. ومع ذلك ، نظرًا لأن مبدأ CGLIB هو إنشاء فئات وكيل فئة فرعية للفئة الفرعية للطبقة المستهدفة ، فلا يمكن أن يتم إعلانها للطرق التي تم الإعلان عنها على أنها نهائية. استخدامه ينطوي بشكل أساسي على فئتين:
واجهة MethodInterceptor: توفر هذه الواجهة intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) المستخدمة بشكل رئيسي لاعتراض Call of Target Class.
كائن Arg0 ،: الفئة المستهدفة التي يجري أن يتم تعزيزها
الطريقة Arg1 ، طريقة تفويض
كائن [] arg2 ، معلمات الطريقة
methodproxy arg3: methodproxy كائن طريقة الوكيل
فئة المحسن: تستخدم لإنشاء فئة وكيل
مثال:
تنفيذ واجهة methodInterceptor. عندما تستدعي فئة الوكيل طريقة ، ستقوم CGLIB بإعادة تشغيل طريقة اعتراض واجهة MethodInterceptor ، وبالتالي نسج منطق السطح.
حزمة com.sl.aop ؛ استيراد java.lang.reflect.method ؛ استيراد org.springframework.cglib.proxy.enhancer cglibserviceproxy تنفذ methodInterceptor {private Object TargetClass ؛ orderlogger orderlogger الخاص ؛ public cglibserviceproxy (Object TargetClass ، orderlogger orderlogger) {this.targetClass = targetClass ؛ this.orderLogger = orderlogger ؛ } / *** إنشاء كائن وكيل** / كائن عام getInstance () {endancer ensancer = new ensancer () ؛ // قم بتعيين الفئة المستهدفة (الفئة التي يجب أن تكون محسّنة). // طريقة رد الاتصال المحسّن. // إنشاء عودة كائن الوكيل endance.create () ؛ } / *** اعتراض جميع أساليب الفئة المستهدفة** / Override اعتراض الكائن العام (الكائن Arg0 ، الطريقة Arg1 ، Object [] Arg2 ، methodproxy arg3) رمي {orderlogger.beforecreatorder () ؛ الكائن O1 = arg3.invokesuper (arg0 ، arg2) ؛ orderlogger.afterCreateRorder () ؛ إرجاع O1 ؛ }}طريقة الاختبار:
public void testDynamicProxy () {system.setProperty (debuggingClassWriter.debug_location_property ، "d: // class") ؛ orderServiceImpl ServiceImpl = new orderserviceImpl () ؛ orderlogger logger = new OrderLogger () ؛ cglibserviceproxy proxy = cglibserviceproxy جديد (serviceImpl ، logger) ؛ // إنشاء فئة وكيل عن طريق إنشاء فئات فرعية proxyimp = (orderServiceImpl) proxy.getInstance () ؛ proxyimp.createorder () ؛ }نتيجة:
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://class"); إخراج فئة الوكيل الديناميكي CGLIB إلى الدليل المحدد ، فك تشفير الوجه الحقيقي لفئة الوكيل:
package com.sl.aop ؛ import com.sl.aop.orderserviceimpl ؛ import java.lang.reflect.method ؛ import org.springframework.cglib.core.reflectutils org.springframework.cglib.proxy.factory ؛ استيراد org.springframework.cglib.proxy.methodinterceptor Factory {private boolean cglib $ bound ؛ كائن ثابت عام cglib $ factory_data ؛ private Static Final Threadlocal cglib $ thread_callbacks ؛ رد الاتصال النهائي الثابت الخاص [] cglib $ static_callbacks ؛ طريقة خاصة cglib $ callback_0 ؛ كائن ثابت خاص cglib $ callback_filter ؛ الطريقة النهائية الثابتة الخاصة cglib $ createDord $ 0 $ طريقة ؛ الطريقة الثابتة الخاصة الطريقة النهائية الوكيل cglib $ createDorder $ 0 $ proxy ؛ كائن نهائي ثابت خاص [] cglib $ فارغ ؛ الطريقة النهائية الثابتة الخاصة cglib $ تساوي طريقة $ 1 $ ؛ static static final methodproxy cglib $ يساوي 1 دولار $ الوكيل ؛ الطريقة النهائية الثابتة الخاصة cglib $ toString $ 2 $ طريقة ؛ Private Static Final Methodproxy cglib $ tostring $ 2 $ proxy ؛ الطريقة النهائية الثابتة الخاصة cglib $ hashdode $ 3 $ طريقة ؛ static static final methodproxy cglib $ hashcode $ 3 $ proxy ؛ استطاعة ثابتة خاصة MethodCglib $ clone 4 دولارات ؛ Private Static Final Methodproxy cglib $ clone $ 4 $ proxy ؛ static void cglib $ statichook1 () {cglib $ thread_callbacks = new threadlocal () ؛ cglib $ فارغ = كائن جديد [0] ؛ class var0 = class.forname ("com.sl.aop.orderserviceImpl $$ ensancerbycglib $$ 177779aa4") ؛ فئة var1 ؛ الطريقة [] var10000 = strenseUtils.findMethods (سلسلة جديدة [] {"متساوية" ، "(ljava/lang/object ؛) z" ، "tostring" ، "() ljava/lang/string ؛" ، "،" hashcode "،" () i "،" ، "() ljava/lang ؛" class.forname ("java.lang.object"). getDeclaredMethods ()) ؛ cglib $ يساوي 1 $ $ method = var10000 [0] ؛ cglib $ يساوي $ 1 $ proxy = methodproxy.create (var1 ، var0 ، "(ljava/lang/object ؛) z" ، "equals" ، "cglib $ يساوي $ 1") ؛ cglib $ toString $ 2 $ method = var10000 [1] ؛ cglib $ toString $ 2 $ proxy = methodproxy.create (var1 ، var0 ، "() ljava/lang/string ؛" ، "toString" ، "cglib $ toString $ 2") ؛ cglib $ hashcode $ 3 $ method = var10000 [2] ؛ cglib $ hashcode $ 3 $ proxy = methodproxy.create (var1 ، var0 ، "() i" ، "hashcode" ، "cglib $ hashcode $ 3") ؛ cglib $ clone $ 4 $ method = var10000 [3] ؛ cglib $ clone $ 4 $ proxy = methodproxy.create (var1 ، var0 ، "() ljava/lang/object ؛" ، "clone" ، "cglib $ clone $ 4") ؛ cglib $ createRorder $ 0 $ method = reflerMoutIls.FindMethods (سلسلة جديدة [] {"createRorder" ، "() v"} ، (var1 = class.forname ("com.sl.aop.orderserviceimpl")). getDeclaredMethods ()) [0] ؛ cglib $ createDorder $ 0 $ proxy = methodproxy.create (var1 ، var0 ، "() v" ، "createRorder" ، "cglib $ createDorder $ 0") ؛ } النهائي void cglib $ createDord $ 0 () {super.createorder () ؛ } public final void createDorder () {methodInterceptor var10000 = this.cglib $ callback_0 ؛ if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this) ؛ var10000 = this.cglib $ callback_0 ؛ } if (var10000! = null) {var10000.Intercept (this ، cglib $ createDord $ 0 $ method ، cglib $ fmareargs ، cglib $ createDorder $ 0 $ proxy) ؛ } آخر {super.createorder () ؛ }} النهائي boolean cglib $ يساوي $ 1 (الكائن var1) {return super.equals (var1) ؛ } public boolean equals (Object var1) {methodInterceptor var10000 = this.cglib $ callback_0 ؛ if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this) ؛ var10000 = this.cglib $ callback_0 ؛ } if (var10000! = null) {object var2 = var10000.Intercept (this ، cglib $ يساوي $ 1 $ ، كائن جديد [] {var1} ، cglib $ يساوي 1 $ $ proxy) ؛ return var2 == null؟ false: ((boolean) var2) .booleanvalue () ؛ } آخر {return super.equals (var1) ؛ }} سلسلة نهائية cglib $ toString $ 2 () {return super.toString () ؛ } السلسلة النهائية العامة toString () {methodInterceptor var10000 = this.cglib $ callback_0 ؛ if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this) ؛ var10000 = this.cglib $ callback_0 ؛ } return var10000! = null؟ (سلسلة) var10000.Intercept (هذا ، cglib $ toString $ 2 $ ، cglib $ فارغة ، cglib $ toString $ 2 $ proxy): super.toString () ؛ } Final int cglib $ hashcode $ 3 () {return super.hashCode () ؛ } hashcode النهائي العام () {methodInterceptor var10000 = this.cglib $ callback_0 ؛ if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this) ؛ var10000 = this.cglib $ callback_0 ؛ } if (var10000! = null) {object var1 = var10000.Intercept (هذا ، cglib $ hashcode $ 3 $ method ، cglib $ fmareargs ، cglib $ hashcode $ 3 $ proxy) ؛ return var1 == null؟ 0: ((number) var1) .IntValue () ؛ } آخر {return super.hashcode () ؛ }} الكائن النهائي cglib $ clone $ 4 () يلقي clonenotsupportedException {return super.clone () ؛ } الكائن النهائي المحمي Clone () يلقي clonenotsupportedException {methodInterceptor var10000 = this.cglib $ callback_0 ؛ if (this.cglib $ callback_0 == null) {cglib $ bind_callbacks (this) ؛ var10000 = this.cglib $ callback_0 ؛ } return var10000! = null؟ var10000.Intercept (هذا ، cglib $ clone $ 4 $ method ، cglib $ فارغة ، cglib $ clone $ 4 $ proxy): super.clone () ؛ } public static methodproxy cglib $ findMethodProxy (signature var0) {String var10000 = var0.toString () ؛ Switch (var10000.hashcode ()) {case -2138148221: if (var10000.equals ("createRorder () v")) } استراحة؛ الحالة -508378822: إذا (var10000.equals ("clone () ljava/lang/object ؛")) {return cglib $ clone $ 4 $ proxy ؛ } استراحة؛ Case 1826985398: if (var10000.equals ("equals (ljava/lang/object ؛) z")) {return cglib $ يساوي 1 دولار $ ؛ } استراحة؛ الحالة 1913648695: if (var10000.equals ("toString () ljava/lang/string ؛"))) {return cglib $ toString $ 2 $ proxy ؛ } استراحة؛ Case 1984935277: if (var10000.equals ("hashcode () i")) {return cglib $ hashdode $ 3 $ proxy ؛ }} الإرجاع null ؛ } OrderServiceImpl $$ ensancerbycglib $$ 17779aa4 () {cglib $ bind_callbacks (this) ؛ } public static void cglib $ set_thread_callbacks (callback [] var0) {cglib $ thread_callbacks.set (var0) ؛ } public static void cglib $ set_static_callbacks (callback [] var0) {cglib $ static_callbacks = var0 ؛ ) if (! var1.cglib $ bound) {var1.cglib $ bound = true ؛ كائن var10000 = cglib $ thread_callbacks.get () ؛ if (var10000 == null) {var10000 = cglib $ static_callbacks ؛ if (cglib $ static_callbacks == null) {return ؛ }} var1.cglib $ callback_0 = (methodInterceptor) ((callback []) var10000) [0] ؛ }} الكائن العام newinstance (callback [] var1) {cglib $ set_thread_callbacks (var1) ؛ OrderServiceImpl $$ ensancerbycglib $ $ 17779aa4 var10000 = new orderServiceImpl $$ ensancerbycglib $$ 17779aa4 () ؛ cglib $ set_thread_callbacks ((callback []) null) ؛ إرجاع var10000 ؛ } الكائن العام newInstance (Callback var1) {cglib $ set_thread_callbacks (رد اتصال جديد [] {var1}) ؛ OrderServiceImpl $$ ensancerbycglib $ $ 17779aa4 var10000 = new orderServiceImpl $$ ensancerbycglib $$ 17779aa4 () ؛ cglib $ set_thread_callbacks ((callback []) null) ؛ إرجاع var10000 ؛ } الكائن العام newinstance (class [] var1 ، object [] var2 ، callback [] var3) {cglib $ set_thread_callbacks (var3) ؛ OrderServiceImpl $$ ensancerbycglib $ $ 17779aa4 var10000 = new orderServiceImpl $$ ensancerbycglib $$ 17779aa4 ؛ Switch (var1.length) {case 0: var10000. <Ing> () ؛ cglib $ set_thread_callbacks ((callback []) null) ؛ إرجاع var10000 ؛ الافتراضي: رمي جديد غير unalfalArgumentException ("مُنشئ غير موجود") ؛ }} رد الاتصال العام getCallback (int var1) {cglib $ bind_callbacks (this) ؛ MethodInterceptor var10000 ؛ Switch (var1) {case 0: var10000 = this.cglib $ callback_0 ؛ استراحة؛ الافتراضي: var10000 = null ؛ } إرجاع var10000 ؛ } public void setCallback (int var1 ، callback var2) {switch (var1) {case 0: this.cglib $ callback_0 = (methodInterceptor) var2 ؛ الافتراضي:}} رد الاتصال العام [] getCallbacks () {cglib $ bind_callbacks (this) ؛ إرجاع رد الاتصال الجديد [] {this.cglib $ callback_0} ؛ } public void setCallbacks (callback [] var1) {this.cglib $ callback_0 = (methodInterceptor) var1 [0] ؛ } static {cglib $ statichook1 () ؛ }}في الكود أعلاه ، يمكنك أن ترى أن OrderServiceImpl $ $$ $$ $ $ $ $ $ $ 17779AA4 يرث OrderServiceImpl من الفئة المستهدفة ويؤسس مصنع الواجهة. في فئة الوكيل ، يتم إنشاء طريقتين cglib $ createDorder $ 0 و CreateRorder:
طريقة CGLIB $ CREATERORDER $ 0 تستدعي مباشرة supper.createOrder الفئة الهدف.
تحسب طريقة CreateRorder أولاً ما إذا كان رد اتصال واجهة MethodInterceptor قد تم تنفيذه. إذا كانت موجودة ، يتم استدعاء طريقة اعتراض واجهة MethodInterceptor. وفقًا للتنفيذ السابق ، يتم تنفيذ الدعوة إلى الطريقة المستهدفة. يتم تنفيذ Object o1 = arg3.invokeSuper(arg0, arg2) . Invokesuper هي في الواقع طريقة CGLIB$createOrder$0() لفئة الوكيل التي تسمى مباشرة ، ويتم استدعاء CREATERDRY الفئة الهدف أخيرًا.
مقارنة بين اثنين من العوامل
الوكيل الديناميكي JDK:
تنفذ فئة الوكيل وفئة المندوب نفس الواجهة. إنه ينفذ بشكل أساسي من خلال فئة الوكيل ويعيد كتابة طريقة الاستدعاء لأداء البرامج الديناميكية. سيتم تعزيز الطريقة في طريقة الاستدعاء. مزايا الطريقة: لا يلزم وجود واجهة مرمزة ، ومعدل إعادة استخدام الكود مرتفع. العيوب: فقط فئة المندوب التي يمكن تنفيذها بواسطة الواجهة
الوكيل الديناميكي CGLIB:
يأخذ فئة الوكيل فئة المندوب كطبقة الأم وتنشئ طريقتين لطرق المفوضية غير النهائية فيه. إحداها هي نفس طريقة توقيع طريقة المندوب ، والتي ستسمي طريقة المندوب من خلال Super في الطريقة ؛ والآخر هو الطريقة الفريدة لفئة الوكيل. في طريقة الوكيل ، سيحدد ما إذا كان هناك كائن يقوم بتنفيذ واجهة MethodInterceptor. إذا كانت موجودة ، فسيتم استدعاء طريقة التقاطع لتكييف طريقة المندوب. المزايا: يمكن أن يعزز تشغيل الفصل أو الواجهة في وقت التشغيل ، ولا يحتاج فئة المندوب إلى تنفيذ الواجهة. العيوب: لا يمكن أن يكون وكيل الطبقة النهائية والطريقة النهائية.
لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.