Model proxy adalah model desain Java yang umum digunakan. Karakteristiknya adalah bahwa kelas proxy dan kelas delegasi memiliki antarmuka yang sama. Kelas proxy terutama bertanggung jawab untuk preprocessing pesan, memfilter pesan, meneruskan pesan ke kelas delegasi, dan memproses pesan setelah acara. Biasanya ada hubungan antara kelas proxy dan kelas delegasi. Objek kelas proxy dikaitkan dengan objek kelas delegasi. Objek kelas proxy itu sendiri tidak benar -benar menerapkan layanan, tetapi menyediakan layanan spesifik dengan memanggil metode yang relevan dari objek kelas delegasi.
Perbandingan berbagai implementasi proxy dinamis Java
antarmuka
antarmuka addInterface {int add (int a, int b);} subinterface antarmuka {int sub (int a, int b);} Kelas Implementasi
kelas aritmatika mengimplementasikan addInterface, subinterface {@Override public int sub (int a, int b) {return ab; } @Override public int add (int a, int b) {return a+b; }}Metode 1: Proxy Dinamis Dibangun ke dalam JDK
1. Metode Implementasi
Mekanisme proxy dinamis yang diperkenalkan oleh Java setelah JDK1.3 memungkinkan kita untuk secara dinamis membuat kelas proxy selama runtime. Menerapkan AOP menggunakan proxy dinamis memerlukan empat peran: kelas proxy, antarmuka kelas proxy, perangkat tenun, dan AvocationHandler. Perangkat tenun menggunakan mekanisme refleksi antarmuka untuk menghasilkan kelas proxy, dan kemudian menenun kode ke dalam kelas proxy ini. Kelas proxy adalah target yang disebutkan dalam AOP. InvocationHandler adalah bagian, yang berisi saran dan pointcut.
2. Implementasi antarmuka VinVocationHandler
kelas jdkdpqueryhandler mengimplementasikan InvocationHandler {private arithmetic real; public JDKDPqueryHandler (Arithmetic Real) {this.real = real; } @Override Public Object Invoke (objek proxy, metode metode, objek [] args) melempar lempar {string methodName = method.getName (); System.out.println (Metode); System.out.println ("Metode:" + MethodName + "Mulai, Parameter:" + arrays.aslist (args)); Hasil objek = metode.invoke (nyata, args); System.out.println ("Metode:"+MethodName+"Berakhir, Hasil:"+Hasil); hasil pengembalian; }}3. Buat kelas proxy dan hubungi kelas proxy
kelas publik utama {private static int a = 4, b = 2; Objek statis publik createJDKproxy (aritmetic real) {objek proxyarithmetic = proxy.newproxyInstance (real.getClass (). getClassLoader (), real.getClass (). getInterfaces (), jdkdpQueryHandler (real)); return proxyarithmetic; } public static void main (string [] args) {aritmetic real = aritmatika baru (); Objek proxyarithmetic = createJDkproxy (nyata); ((AddInterface) proxyarithmetic) .add (a, b); ((Subinterface) Proxyaritmetic) .sub (A, B); }}Metode 2: Dynamic Bytecode Generation (CGLIB)
1. Metode Implementasi
Penambah dan MethodInterceptor. Penambah dapat digunakan untuk secara dinamis menghasilkan kelas, yang dapat mewarisi kelas yang ditentukan dan mengimplementasikan beberapa antarmuka yang ditentukan. Pada saat yang sama, penambah perlu menentukan panggilan balik sebelum menghasilkan kelas. Ketika metode kelas dipanggil, pelaksanaan metode ini ditetapkan untuk panggilan balik ini. MethodInterceptor adalah antarmuka yang lebih banyak digunakan yang diwarisi dari panggilan balik, dan hanya memiliki satu deklarasi metode.
2. Perbandingan Antarmuka InvocationHandler (dalam JDK) dan Methodace Interface (dalam CGLIB)
Metode antarmuka publik MethodInterceptor memperluas callback {Public Object Intercept (Object Obj, java.lang.reflect.method Method, objek [] args, MethodProxy Proxy) melempar Throwable; } Invocation Handller {public Object Invoke (Proxy Object, Metode Metode, Object [] args) melempar yang dapat dilempar; } Dalam hal komposisi parameter, parameter input MethodInterceptor adalah 1 lebih dari InvocationHandler. Faktanya, arti dari tiga objek parameter pertama sama dengan yang dari InvocationHandler.
Parameter pertama menunjukkan objek dari mana metode panggilan berasal;
Parameter kedua mewakili objek metode yang memanggil metode;
Parameter ketiga mewakili daftar parameter input untuk panggilan ini;
Parameter tambahan adalah tipe MethodProxy, yang harus menjadi objek yang dihasilkan oleh CGLIB untuk menggantikan objek Metode. Menggunakan MethodProxy akan meningkatkan efisiensi daripada memanggil metode metode JDK sendiri secara langsung.
3. Sadarilah 1
Implementasi Antarmuka MethodInterceptor
kelas cglibdpQueryinteptor mengimplementasikan MethodInterceptor {private arithmetic real; Publik CGlibDPqueryInterceptor (Arithmetic Real) {this.real = real; } @Override Public Object Intercept (Target Objek, Metode Metode, Object [] args, MethodProxy Proxy) melempar Throwable {String MethodName = Method.getName (); System.out.println (Metode); System.out.println ("Metode:" + MethodName + "Mulai, Parameter:" + arrays.aslist (args)); // hasil objek = Method.invoke (nyata, args); // Kedua metode bisa mendapatkan hasil objek = proxy.invoke (nyata, args); System.out.println ("Metode:"+ MethodName+ "Berakhir, Hasil:"+ Hasil); hasil pengembalian; }}Buat kelas proxy dan hubungi kelas proxy
kelas publik utama {private static int a = 4, b = 2; Objek statis public createCglibproxy (arithmetic real) {Enhancer Enhancer = new Enhancer (); Enhancer.setCallback (CGLIBDPQueryPereptor baru (nyata)); Enhancer.setInterfaces (real.getClass (). getInterfaces ()); return enhancer.create (); } public static void main (string [] args) {aritmetic real = aritmatika baru (); Objek proxyarithmetic = createCglibproxy (nyata); ((AddInterface) proxyarithmetic) .add (a, b); ((Subinterface) Proxyaritmetic) .sub (A, B); }}Perhatikan bahwa MethodProxy menyediakan 2 metode saat mengeksekusi fungsi.
Obyek publik Invoke (objek obj, objek [] args) melempar objek publik yang dapat dilempar InvokeSuper (objek obj, objek [] args) melempar yang dapat dilempar
Di antara mereka, Javadoc mengatakan bahwa metode Invoke () ini dapat digunakan untuk pelaksanaan objek lain di kelas yang sama, yaitu, OBJ dalam metode ini perlu masuk ke objek lain dari kelas yang sama (metode di atas adalah untuk meneruskan objek yang berbeda dari kelas aritmatika), jika tidak, ia akan memasuki tes yang tak terbatas (stackoverflowerrower yang benar -benar muncul). Jika Anda memikirkannya dengan cermat, Anda akan menemukan bahwa target dalam intersep objek publik (target objek, metode metode, objek [] args, proxy methodproxy) adalah objek proxy yang diimplementasikan. Ketika metode add () dipanggil melalui target, metode intersep () akan dipicu untuk dipanggil. Jika metode.invoke (target, args) dipanggil dalam metode intersep (), itu setara dengan memanggil metode add () lagi, menghasilkan loop rekursif yang tak terbatas. Tetapi jika Anda mengeksekusi metode.invoke (nyata, args) itu tidak akan, karena nyata dan target adalah objek yang berbeda di kelas yang sama, nyata adalah topik logis nyata, dan target adalah proksi untuk topik nyata nyata.
Berikut adalah contoh untuk mensimulasikan:
antarmuka solveInterface {void solve ();} kelas implement real solveInterface {public void solve () {System.out.println ("Real Solve!"); }} Target kelas memperluas objek nyata {private objek obj; public void setObject (objek obj) {this.obj = obj; } private void Invoke () {try {Method Method = solveInterface.class.getMethod ("solve", class baru [] {}); method.invoke (obj, kelas baru [] {}); } catch (Exception e) {E.PrintStackTrace (); }} public void solve () {System.out.println ("Target Solve!"); memohon(); }} kelas publik {public static void main (string [] args) melempar Exception {target target = new new target (); target.setObject (new real ()); // benar // target.setObject (target); // panggilan siklik terjadi target.solve (); }}Bahkan, metode Metode Invoke () akan memanggil metode penyelesaian () yang sesuai sesuai dengan tipe OBJ, yaitu, polimorfisme.
4. Sadarilah 2
Implementasi Antarmuka MethodInterceptor
kelas cglibdpqueryinterceptor mengimplementasikan MethodInterceptor {@Override Public Object Intercept (Target Objek, Metode Metode, Objek [] Args, MethodProxy Proxy) melempar Throwable {String MethodName = Method.getName (); System.out.println (Metode); System.out.println (Metode); System.out.println ("Metode:" + MethodName + "Mulai, Parameter:" + arrays.aslist (args)); // Cetak informasi kelas: target.getClass (); hilangkan hasil objek = proxy.invokeSuper (target, args); System.out.println ("Metode:"+MethodName+"Berakhir, Hasil:"+Hasil); hasil pengembalian; }}Buat kelas proxy dan hubungi kelas proxy
kelas publik utama {private static int a = 4, b = 2; public static objek createCglibproxy () {Enhancer Enhancer = new Enhancer (); Enhancer.setCallback (CGLIBDPQueryPerCeptor () baru ()); Enhancer.setsuperclass (Arithmetic.class); return enhancer.create (); } public static void main (string [] args) {aritmetic real = aritmatika baru (); Objek proxyarithmetic = createCglibproxy (); ((AddInterface) proxyarithmetic) .add (a, b); ((Subinterface) Proxyaritmetic) .sub (A, B); }}Perhatikan bahwa penambah tidak mengatur antarmuka dalam implementasi 2, karena superclass diatur (yaitu, kelas induk dari kelas proxy adalah aritmatika), kelas proxy kami akan mewarisi itu, dan aritmatika telah menerapkan antarmuka kami. Untuk membuktikan ini, Anda dapat mencetak informasi kelas target.getClass () dalam metode intersep MethodInterceptor. Anda akan menemukan bahwa kelas induk kelas proxy CGLIB berbeda. sebagai berikut:
Implementasi 1:
kelas publik com.test.aritmetic $$ Enhancerbycglib $$ 4FA786EB Memperluas java.lang.Object
Implementasi 2:
kelas publik com.test.aritmetic $$ Enhancerbycglib $$ 4FA786EB Extends com.test.aritmetic
Metode 3: Javassist menghasilkan proxy dinamis (pembuatan agen pabrik atau pembuatan kode dinamis)
Javassist adalah kerangka kerja untuk mengedit bytecode, yang memungkinkan Anda untuk mengoperasikan bytecode dengan sangat sederhana. Ini dapat mendefinisikan atau memodifikasi kelas selama runtime. Prinsip penerapan AOP menggunakan javassist adalah untuk secara langsung memodifikasi metode yang perlu dipotong sebelum bytecode dimuat. Ini lebih efisien daripada menggunakan CGLIB untuk mengimplementasikan AOP, dan tidak ada banyak batasan. Prinsip implementasi adalah sebagai berikut:
Implementasi 1:
Implementasi Antarmuka
kelas javassistDpqueryHandler mengimplementasikan MethodHandler {@Override Objek Publik Invoke (Target Objek, Metode Metode, Metode Proxy, Object [] args) melempar Throwable {String MethodName = Method.getName (); System.out.println (Metode); System.out.println (Metode); System.out.println ("Metode:" + MethodName + "Mulai, Parameter:" + arrays.aslist (args)); Hasil objek = proxy.invoke (target, args); System.out.println ("Metode:"+MethodName+"Berakhir, Hasil:"+Hasil); hasil pengembalian; }}Buat kelas proxy dan hubungi kelas proxy
kelas publik utama {private static int a = 4, b = 2; objek statis publik createjavassistproxy () melempar pengecualian {factory proxyfactory = new proxyfactory (); factory.setsuperclass (arithmetic.class); factory.setHandler (javassistDpqueryHandler ()); return factory.createClass (). newInstance (); } public static void main (string [] args) melempar Exception {aritmatika nyata = aritmatika baru (); Objek proxyarithmetic = createJavassistProxy (); ((AddInterface) proxyarithmetic) .add (a, b); ((Subinterface) Proxyaritmetic) .sub (A, B); }}Catatan: Definisi metode Invoke di antarmuka MethodHandler adalah sebagai berikut:
Invoke Objek Publik (Target Objek, Metode Metode, Metode Proxy, Object [] args)
Metode mewakili objek metode yang memanggil metode, proxy adalah objek yang menghasilkan dan menggantikan metode dengan kelas proxy. Jika tidak, menggunakan metode.invoke (target, args) akan menghasilkan panggilan loop yang tak terbatas.
Implementasi 2:
Proses proksi umum menggunakan javassist dinamis sedikit berbeda dari metode sebelumnya. Di dalam javassist, kode java dinamis dapat dihasilkan untuk menghasilkan bytecode. Proksi dinamis yang dibuat dengan cara ini bisa sangat fleksibel dan bahkan dapat menghasilkan logika bisnis saat runtime.
// Interceptor InterceptorHandler Custom Interceptors { /*** Memanggil metode objek proxy dinamis akan mencerminkan metode ini. Anda dapat menambahkan operasi sebelum dan sesudah AOP ke implementasi metode ini. Hanya jika kode berikut ditambahkan ke Badan Metode ini* Metode proxy akan dieksekusi, dan nilai pengembalian akan dikembalikan ke proxy dan akhirnya dikembalikan ke program* @param obj objek proxy objek* @param metode metode objek proxy* @param args objek [] Parameter proxy objek proxy* @return objek Nilai pengembalian @param @param @Parameter Objek Proxy* Objek Proxy Object* @Return Object Nilai Pengembalian Nilai Pengembalian Eksekusi OBJ, metode metode, objek [] args) melempar yang dapat dilempar; } // Implementasi kelas interceptor InterceptorHandlerImpl mengimplementasikan IntercepTorHandler {@Override Objek Publik Invoke (Object Obj, Metode Metode, Object [] args) melempar Throwable {String MethodName = Method.getName (); System.out.println (Metode); System.out.println (Metode); System.out.println ("Metode:" + MethodName + "Mulai, Parameter:" + arrays.aslist (args)); Hasil Objek = Method.Invoke (OBJ, ARGS); System.out.println ("Metode:"+MethodName+"Berakhir, Hasil:"+Hasil); hasil pengembalian; }} class myproxyImpl { / ** Nama kelas sufiks kelas proxy dinamis* / private final static string proxy_class_name_suffix = "$ myproxy_"; / ** Interceptor Interface*/ Private Final Static String Interceptor_Handler_interface = "com.test.InterceptorHandler"; / ** Indeks nama kelas dari kelas proxy dinamis untuk mencegah duplikasi nama kelas*/ proxyclassIndex int statis private = 1; /*** Antarmuka proxy dinamis yang terpapar kepada pengguna, mengembalikan objek proxy dinamis dari antarmuka tertentu. Perhatikan bahwa implementasi proxy ini harus digunakan dengan com.cuishen.myaop.interceptorhandler Interceptor*, yaitu, jika pengguna ingin menggunakan proxy dinamis ini, ia harus pertama -tama mengimplementasikan com.cuishen.myaop. @param classToProxy String The class name of the implementation class of the interface to be dynamically proxyed, eg test.StudentInfoServiceImpl * @param interceptorHandlerImplClassName String The class name of the implementation class of the interceptor interface provided by the user* @return Object Returns the dynamic proxy object of a certain interface* @throws InstantiationException * @throws IllegalAccessException * @throws notfoundException * @throws cantcompileexception * @throws ClassNotFoundException * @LEE com.cuishen.myaop. IllegalAccessException, NotFoundException, CanTCompileException, ClassNotFoundException {class interfaceClass = class.forname (antarmaceclassname); Kelas intercepTorHandlImplClass = class.forname (interceptorHandlerImplClassName); return dynamicImplementInterFace (classtoproxy, interfaceClass, interceptorHandlerImplClass); } /** * Dynamic implementation of the interface to be proxyed* @param classToProxy String The class name of the implementation class of the interface to be dynamically proxyed, eg test.StudentInfoServiceImpl * @param interfaceClass Class Interface class to be dynamically proxyed, eg test.StudentInfoService * @param interceptorHandlerImplClass Class Kelas Implementasi yang Disediakan Pengguna Antarmuka Interceptor * @Return Obyek Mengembalikan objek proksi dinamis dari antarmuka tertentu * @throws notfoundException * @throws cantcompileException * @throws InstantiationException * @Throws IllegalAcception */ Private Static ObjectImplementsImplementsInclementsInclementsInclementsInclementsceplementsceplass) lemparan notfoundException, CanTompileException, InstantiationException, IllegalAccessException {classpool cp = classpool.getDefault (); String InterfacEname = InterfaceClass.GetName (); // Dinamis Tentukan nama kelas dari string kelas proxy proxyclassname = antarmuka + proxy_class_name_suffix + proxyclassIndex ++; // Nama paket antarmuka yang akan diimplementasikan + nama antarmuka String InterfacenamePath = Interfacename; Ctclass ctinterface = cp.getctclass (antarmukaenamepath); Ctclass cc = cp.makeClass (proxyclassname); cc.addinterface (ctinterface); Metode [] Metode = InterfaceClass.getMethods (); untuk (int i = 0; i <methods.length; i ++) {Method Method = Metode [i]; DynamicImplementsmethodsFromInterface (Classtoproxy, CC, Metode, IntercepTorHandLerImplClass, I); } return (objek) cc.toclass (). newInstance (); } /*** Metode dalam implementasi dinamis dari metode* @param classtoproxy string nama kelas dari kelas implementasi antarmuka yang akan dikruksis secara dinamis, misalnya test.StudentInfoserViceImpl* @param emplement clsclass kemasan interfaced dari dynamic proxy class proxy dynamic* @param Metode Metode THE METODEMI @Param Paket Kelas Dinamik. interceptorClass Class The interceptor implementation class provided by the user* @param methodIndex int Index of the method to be implemented* @throws CannotCompileException */ private static void dynamicImplementsMethodsFromInterface(String classToProxy, CtClass implementer, Method methodToImpl, Class interceptorClass, int methodIndex) throws CannotCompileException { String methodCode = generateMethodCode (classtoproxy, methodtoImpl, interceptorclass, methodIndex); Ctmethod cm = ctnewmethod.make (MethodCode, implementer); implementer.addmethod (CM); } /*** Secara dinamis merakit Badan Metode. Tentu saja, implementasi metode dalam proxy bukanlah salinan metode sederhana, tetapi mencerminkan metode Invoke dalam interceptor dan lulus parameter yang diterima* @param classtoproxy string nama kelas dari kelas implementasi dari interface yang disamarkan secara dinamis. @Param InterceptorClass Class Kelas implementasi interseptor yang disediakan pengguna* @param MethodIndex int Indeks dari metode yang akan diimplementasikan* @Return String string dari metode perakitan dinamis*/ private static string generatemethodcode (string classtoproxy, metode methodtoImpl, class interceptorclass, int MethodIndex) {Methodname. String methodReTurnType = MethodToImpl.getRetRoType (). GetName (); Class [] parameter = MethodToImpl.GetParameterTypes (); Class [] exceptionTypes = MethodToImpl.GetExceptionTypes (); StringBuffer ExceptionBuffer = StringBuffer baru (); // Pengecualian deklarasi metode perakitan jika (exceptiontypes.length> 0) exceptionBuffer.append ("lemparan"); untuk (int i = 0; i <exceptiontypes.length; i ++) {if (i! = exceptionTypes.length - 1) exceptionBuffer.append (exceptionTypes [i] .getName ()). append (","); lain ExceptionBuffer.Append (ExceptionTypes [i] .getName ()); } StringBuffer ParameterBuffer = New StringBuffer (); // Daftar parameter metode perakitan untuk (int i = 0; i <parameter.length; i ++) {class parameter = parameter [i]; String parameterType = parameter.getName (); // Dinamis Menentukan Nama Variabel dari Metode Parameter String RefName = "A" + I; if (i! = parameter.length - 1) parameterBuffer.append (parameterType) .append (" + refname) .append (", "); else parameterBuffer.append (parameTerType) .Append (" + RefName); } StringBuffer MethodDeclare = stringBuffer baru (); // Metode Deklarasi, karena ini adalah metode yang mengimplementasikan antarmuka, itu adalah MethodDeclare Public. String interceptorImplName = interceptorclass.getName (); // methodbody methodDeclare.append (interceptor_handler_interface) .Append ("Interceptor = new") .Append (InterceptorImplname) .Append ("();/n"); // Reflection Call Interceptor Interceptor Interceptor Methoddeclare.append ("Object Returnobj = Interceptor.Invoke (class.forname (/" " + classtoproxy +"/"). Newinstance (), class.forname (/" " + classtoproxy +"/"). if (parameter.length> 0) MethoneDeclare.append ("Objek baru [] {"); methodDeclare.append ("($ w) a" + i + ","); lain MethodDeclare.append ("null);/n"); // Bungkus nilai pengembalian call interceptor if (methodtoImpl.getReturnType (). IsPrimitive ()) {if (MethodToImpl.getReturnType (). Equals (boolean.type)) MethodDeclare.Append ("return ((boolean) returnobj) .boolaeanvalue ();/Noolean; lain if (methodtoImpl.getReturnType (). Equals (integer.type)) MethodDeclare.append ("return ((integer) returnObj) .IntValue ();/n"); lain jika (MethodToImpl.GetReturnType (). Equals (long.type)) MethodDeclare.append ("return ((long) returnobj) .longValue ();/n"); lain if (methodtoImpl.getReturnType (). Equals (float.type)) MethodDeclare.append ("return ((float) returnobj) .floatValue ();/n"); lain if (methodtoImpl.getReturnType (). Equals (double.type)) MethodDeclare.append ("return (" return ("return (" return ("return ();/n"); else if (methodtoImpl.getReturnType (kembali) ("return (" return ("(" ("return (" return ("(" ("(" return ("("; "return (" ("(" ever return ("("; "return (" (";" return ("("; "return (" (";" return ("" (";" return ("(" ever return ("" ("ever ("; "return (" ("ever ("; "return (" (";" return ("("; "return ("; "return (" (";" return (";" if (MethodToImpl.GetReturnType (). Equals (double.type)) MethodDeclare.append ("return (" return ("return (" return ("return (" return ("return (" MethodToImpl.getReturnType (). Equals (double.type))) MethodDeclare.append ("return (" return ("return (" return ("return (" methodToImpl.getReturnType (). Equals (double.type)) methodDeclare.append ("return (" return ("return (" return ("return (" MethodToImpl.getReturnType (). MethodDeclare.append ("return (" return ("return (" return ("MethodToImpl.getReturnType (). Equal ((double) returnobj) .doublevalue ();/n"); lain jika (methodtoImpl.getReturntype (). Equals (character.type)) methodDececececeCeceCeClare ("evand (" everjAj). if (methodtoImpl.getReturnType (). Equals (byte.type)) MethodDeclare.append ("return ((byte) returnobj) .bytevalue ();/n"); ((Byte) returnObj) .bytevalue ();/n "); lain jika (methodtoImpl.getReturnType (). Equals (short.type)) MethodDeclare.append (" return ((pendek) returnobj) .shortValue ();/n ");} else {MethodDeclare.paprappend (") ("");} else {MethodDeclare.applappend (") (" ");" METODHTEPLECET (""); " } MethoneDeclare.append ("}"); NAMA IMPLEKTASI PENGEMBALIAN PENGETAHUAN KELAS NAMA KELAS PROXYARARITHMETIK = MYPROXYIMPL.NEWPROXYINSTANCE ("com.test.arithmeticinterface", "com.test.arithmetic", "com.test.interceptorhandlerImpl"); ((Arithmeticinterface) Proxyarithmetic) .sub (a, b);Cetak kode untuk mengimplementasikan antarmuka secara dinamis sebagai berikut:
public int add (int a0, int a1) {com.test.interceptorhandler interceptor = com.test.intepteptorhandlerImpl baru (); objek returnobj = interceptor.invoke (class.forname ("com.test.arithmetic"). newinstance (), class.forname ("com.test. Objek [] {($ w) a0, ($ w) a1}); return ((integer) returnObj) .IntValue ();} public int sub (int a0, int a1) {com.test.interceptorhandler interceptor = new.test.interceptorHandImpl (); objek returnobj = interceptor.invoke (class.forname ("com.test.arithmetic"). newInstance (), class.forname ("com.test.arithmetic"). getMethods () [1], objek baru [] {($ w) a0, ($ w) A1}); return ((integer) {($ w) a0, ($ w) a1}); return ((integer) returner) {($ w) A0, ($ w) a1}); return ((integer) returner) Di atas adalah pengantar terperinci untuk mekanisme implementasi proxy dinamis di Java, dan saya harap ini akan membantu untuk pembelajaran semua orang.