1. Definisi mode proxy
Berikan objek dengan objek proxy, dan objek proxy mengontrol akses ke objek asli, yaitu, klien tidak secara langsung memanipulasi objek asli, tetapi secara tidak langsung memanipulasi objek asli melalui objek proxy.
Contoh pola proxy yang terkenal adalah penghitungan referensi: Ketika beberapa salinan objek kompleks diperlukan, pola proxy dapat dikombinasikan dengan mode meta untuk mengurangi jumlah memori. Pendekatan yang khas adalah membuat objek yang kompleks dan proxy ganda, setiap proxy mengacu pada objek asli. Operasi yang bertindak pada agen akan diteruskan ke objek asli. Setelah semua agen tidak ada, objek kompleks dihapus.
Sederhana untuk memahami model proxy, tetapi sebenarnya ada model proxy dalam kehidupan:
Kami dapat membeli tiket kereta di stasiun kereta, tetapi kami juga dapat membelinya di kantor penjualan tiket kereta. Kantor Penjualan Tiket Kereta di sini adalah agen untuk pembelian tiket di stasiun kereta. Artinya, kami mengeluarkan permintaan pembelian tiket di outlet penjualan. Outlet penjualan akan mengirim permintaan ke stasiun kereta api, dan stasiun kereta akan mengirimkan tanggapan yang berhasil untuk pembelian ke outlet penjualan, dan outlet penjualan akan memberi tahu Anda lagi.
Namun, tiket hanya dapat dibeli di outlet penjualan, tetapi tidak pengembalian uang, sementara tiket dapat dibeli di stasiun kereta, sehingga operasi yang didukung oleh agen mungkin berbeda dari objek yang ditugaskan.
Izinkan saya memberi Anda contoh lain yang akan Anda temui saat menulis program:
Jika ada proyek yang ada (Anda tidak memiliki kode sumber, Anda hanya dapat menyebutnya) yang dapat menghubungi int komputasi (string exp1) untuk mengimplementasikan perhitungan ekspresi akhiran. Jika Anda ingin menggunakan proyek ini untuk mengimplementasikan perhitungan ekspresi infix, maka Anda dapat menulis kelas proxy dan menentukan komputasi (string exp2). Parameter Exp2 ini adalah ekspresi infix. Oleh karena itu, Anda perlu mengubah ekspresi infix menjadi ekspresi akhiran (preprocess) sebelum memanggil komputasi () dari proyek yang ada, dan kemudian memanggil komputasi () dari proyek yang ada. Tentu saja, Anda juga dapat menerima nilai pengembalian dan melakukan operasi lain, seperti menyimpan file (postprocess). Proses ini menggunakan mode proxy.
Saat menggunakan komputer, Anda juga akan menemukan aplikasi mode proxy:
Proxy Jarak Jauh: Kami tidak dapat mengakses Facebook karena GFW di Cina. Kami dapat mengaksesnya dengan menjelajahi dinding (menyiapkan proxy). Proses aksesnya adalah:
(1) Pengguna mengirimkan permintaan HTTP ke proxy
(2) Proxy mengirimkan permintaan HTTP ke server web
(3) Server Web mengirimkan respons HTTP ke proxy
(4) Proxy mengirimkan respons HTTP kembali ke pengguna
2. Proxy statis
Yang disebut proxy statis berarti bahwa kelas proxy dihasilkan selama tahap kompilasi untuk menyelesaikan serangkaian operasi pada objek proxy. Berikut ini adalah diagram kelas struktur dari pola proxy:
1. Peserta dalam model proxy
Ada empat peran dalam mode proxy:
Antarmuka Topik: Artinya, antarmuka perilaku yang diimplementasikan oleh kelas proxy.
Objek Target: Artinya, objek yang diproksi.
Objek proxy: Klien proxy yang digunakan untuk merangkum kelas topik nyata adalah berikut ini adalah struktur diagram kelas dari pola proxy:
2. Gagasan untuk Model Agen Menerapkan
Baik objek proxy dan objek target mengimplementasikan antarmuka perilaku yang sama.
Kelas proxy dan kelas target mengimplementasikan logika antarmuka secara terpisah.
Instantiate objek target dalam konstruktor kelas proxy.
Memanggil antarmuka perilaku objek target di kelas proxy.
Jika klien ingin memanggil antarmuka perilaku dari objek target, itu hanya dapat beroperasi melalui kelas proxy.
3. Contoh proxy statis
Berikut ini adalah contoh pemuatan malas untuk menggambarkan proxy statis. Ketika kami memulai sistem layanan, mungkin perlu waktu lama untuk memuat kelas tertentu. Untuk mendapatkan kinerja yang lebih baik, saat memulai sistem, kami sering tidak menginisialisasi kelas kompleks ini, tetapi sebaliknya menginisialisasi kelas proxy -nya. Ini akan memisahkan metode yang memakan sumber daya menggunakan proxy untuk pemisahan, yang dapat mempercepat kecepatan startup sistem dan mengurangi waktu tunggu pengguna.
Tentukan antarmuka topik
subjek antarmuka publik {public void wayshello (); public void Saygoodbye ();} Tentukan kelas target dan terapkan antarmuka topik
Public Class RealSubject mengimplementasikan subjek {public void sayshello () {System.out.println ("Hello World"); } public void wordgoodbye () {System.out.println ("Goodbye World"); }} Tentukan kelas proksi untuk proxy objek target.
Public Class StaticProxy mengimplementasikan subjek {private realsubject realsubject = null; public staticproxy () {} public void wayshello () {// dimuat pada waktu itu, malas memuat if (realsubject == null) {realsubject = new realsubject (); } realsubject.sayhello (); } // Metode Saygoodbye adalah sama ...} Tentukan klien
klien kelas publik {public static void main (string [] args) {staticproxy sp = new staticproxy (); sp.sayhello (); sp.saygoodbye (); }}Di atas adalah contoh uji sederhana dari proxy statis. Itu mungkin tidak terasa praktis. Namun, ini bukan masalahnya. Menggunakan proxy, kami juga dapat mengubah metode objek target. Misalnya, serangkaian koneksi dibuat di kumpulan koneksi database. Untuk memastikan bahwa koneksi jarang dibuka, koneksi ini hampir tidak pernah ditutup. Namun, kami selalu memiliki kebiasaan menutup koneksi terbuka. Dengan cara ini, kita dapat menggunakan mode proxy untuk mencabut metode tutup di antarmuka koneksi, dan mengubahnya untuk mendaur ulang ke kumpulan koneksi database alih -alih benar -benar menjalankan metode koneksi#tutup. Ada banyak contoh lain, dan Anda perlu mengalaminya sendiri.
3. Agen Dinamis
Proksi dinamis mengacu pada kelas proxy yang menghasilkan secara dinamis saat runtime. Artinya, bytecode kelas proxy akan dihasilkan dan dimuat saat runtime ke classloader proxy saat ini. Dibandingkan dengan kelas pemrosesan statis, kelas dinamis memiliki banyak manfaat.
Tidak perlu menulis kelas enkapsulasi yang sepenuhnya identik untuk topik nyata. Jika ada banyak metode dalam antarmuka topik, juga merepotkan untuk menulis metode proxy untuk setiap antarmuka. Jika antarmuka berubah, tema nyata dan kelas proxy harus dimodifikasi, yang tidak kondusif untuk pemeliharaan sistem;
Menggunakan beberapa metode pembuatan proxy dinamis bahkan dapat merumuskan logika eksekusi kelas proxy saat runtime, sehingga sangat meningkatkan fleksibilitas sistem.
Ada banyak cara untuk menghasilkan proxy dinamis: JDK hadir dengan proxy dinamis, CGLIB, Javassist, dll. Metode ini memiliki kelebihan dan kekurangannya sendiri. Artikel ini terutama mengeksplorasi penggunaan proxy dinamis dan analisis kode sumber di JDK.
Berikut adalah contoh untuk menjelaskan penggunaan proxy dinamis di JDK:
DynamicProxy kelas publik mengimplementasikan InvocationHandler {private realsubject = null; Invoke Objek Publik (Proxy Objek, Metode Metode, Objek [] args) {if (realsubject == null) {realsubject = new realsubject (); } method.invoke (realsubject, args); Return RealSubject; }}Contoh Kode Klien
Klien kelas publik {public static void main (string [] args) {subjek subjek = (subjek) proxy.newinstance (classloader.getsystemloader (), realsubject.class.getInterfaces (), new dinamicproxy ()); Subjek.sayhello (); Subjek.saygoodbye (); }}Seperti yang dapat dilihat dari kode di atas, kita perlu menggunakan proxy dinamis di JDK. Gunakan metode statis proxy.newinstance (classloader, antarmuka [], Invokehandler) untuk membuat kelas proxy dinamis. Metode NewInstance memiliki tiga parameter, yang mewakili class loader, daftar antarmuka yang Anda ingin kelas proxy diimplementasikan, dan instance yang mengimplementasikan antarmuka Invokhandler. Proksi dinamis menyerahkan proses eksekusi masing -masing metode ke metode Invoke untuk diproses.
JDK Dynamic Proxy mensyaratkan bahwa proxy harus berupa antarmuka, tetapi kelas sederhana tidak bisa. Kelas proxy yang dihasilkan oleh JDK Dynamic Proxy akan mewarisi kelas proxy, dan kelas proxy akan mengimplementasikan semua daftar antarmuka yang Anda lewati. Oleh karena itu, jenisnya dapat dilemparkan ke jenis antarmuka. Di bawah ini adalah diagram struktur proxy.
Dapat dilihat bahwa proxy adalah semua metode statis, jadi jika kelas proxy tidak mengimplementasikan antarmuka apa pun, maka itu adalah tipe proxy dan tidak memiliki metode instance.
Tentu saja, jika Anda bergabung, Anda harus proksi kelas yang tidak menerapkan antarmuka tertentu, dan metode kelas ini sama dengan yang ditentukan oleh antarmuka lain, dan dapat dengan mudah diimplementasikan menggunakan refleksi.
Kelas Publik DynamicProxy mengimplementasikan Invokehandler {// kelas yang ingin Anda proxy proxy target classclass private = null; // inisialisasi kelas ini DynamicProxy (TargetClass TargetClass) {this.targetClass = TargetClass; } Invoke Objek Publik (Proksi Objek, Metode Metode, Objek [] args) {// Gunakan refleksi untuk mendapatkan kelas yang ingin Anda proksi Metode myMethod = targetClass.getClass (). GetDeclaredMethod (method.getName (), Method.getParametertypes ()); mymethod.setAccessible (true); return mymethod.invoke (targetClass, args); }}4. JDK Analisis Kode Sumber Proksi Dinamis (JDK7)
Setelah melihat contoh di atas, kita hanya tahu cara menggunakan proxy dinamis. Namun, masih berkabut tentang bagaimana kelas proxy dibuat, yang memanggil metode Invoke, dll. Analisis berikut
1. Bagaimana objek proxy dibuat?
Pertama -tama lihat kode sumber dari metode proxy.newinstance:
Objek statis publik newProxyInstance (classloader loader, class <?> [] antarmuka, InvocationHandler h) melempar IllegalArgumentException {} // Dapatkan Informasi Antarmuka Kelas Akhir <?> [] intfs = antarmuka.clone (); Final SecurityManager SM = System.GetSecurityManager (); if (sm! = null) {checkProxyAccess (reflection.getCallerClass (), loader, intfs); } // Hasilkan kelas kelas proxy <?> Cl = getProxyClass0 (loader, intfs); // ... ok mari kita lihat babak pertama pertama}Dari kode sumber, dapat dilihat bahwa generasi kelas proxy tergantung pada metode getProxyClass0. Selanjutnya, mari kita lihat kode sumber GetProxyClass0:
Private Static Class <?> getProxyClass0 (classloader loader, class <?> ... antarmuka) {// Jumlah daftar antarmuka tidak dapat melebihi 0xFFFF if (interfaces.length> 65535) {lempar baru ilegalArgumentException ("batas antarmuka yang dilampaui"); } // Catatan di sini, penjelasan berikut diberikan secara rinci untuk mengembalikan proxyclasscache.get (loader, antarmuka); } Penjelasan ProxyClassCache.get adalah: Jika kelas proxy yang mengimplementasikan daftar antarmuka sudah ada, maka ambil langsung dari cache. Jika tidak ada, seseorang dihasilkan melalui proxyclassFactory.
Sebelum melihat kode sumber ProxyClassCache.get, mari kita pahami secara singkat ProxyClassCache:
private static final weastcache <classloader, class <?> [], class <? >> ProxyClassCache = New Weakcache <> (KeyFactory baru (), proxyclassFactory baru ());
ProxyClassCache adalah cache tipe lemah. Konstruktornya memiliki dua parameter. Salah satunya adalah proxyclassFactory yang digunakan untuk menghasilkan kelas proxy. Berikut ini adalah kode sumber proxyclasscache.get:
Kelas Akhir Weakcache <k, p, v> {... public v get (K key, parameter p) {}}Di sini k mewakili kunci, P mewakili parameter, V mewakili nilai
public v get (K key, parameter p) {// Java7 Metode penilaian nullobject, jika parameter kosong, pengecualian dengan pesan yang ditentukan akan dilemparkan. Jika tidak kosong, kembali. Objeks.requirenonnull (parameter); // Bersihkan struktur data dari lemah yang melemah yang memiliki referensi lemah, yang umumnya digunakan untuk cache expungestaleentries (); // Dapatkan CacheKey dari objek antrian CacheKey = CacheKey.VALUEOF (kunci, refqueue); // Isi pemasok dengan pemuatan malas. Concurrent adalah peta yang aman-utas concurrentMap <objek, pemasok <v>> valuesmap = map.get (cacheKey); if (valuesmap == null) {concurrentMap <objek, pemasok <v>> oldvaluesmap = map.putifabsent (cacheKey, valuesmap = concurrenthashmap baru <> ()); if (oldValuesMap! = null) {valuesmap = oldValuesMap; }} // Buat subkey dan ambil kemungkinan pemasok <v> yang disimpan oleh // subkey dari valuesmap objek subkey = objects.requirenonnull (subkeyfactory.apply (key, parameter)); Pemasok <v> pemasok = valuesmap.get (subkey); Pabrik Pabrik = NULL; while (true) {if (pemasok! = null) {// Dapatkan nilai dari pemasok. Nilai ini mungkin realisasi pabrik atau cache. // Tiga kalimat berikut adalah kode inti, yang mengembalikan kelas yang mengimplementasikan Invokhandler dan berisi informasi yang diperlukan. V Value = Supplier.get (); if (value! = null) {nilai kembali; }} // lain tidak ada pemasok dalam cache // atau pemasok yang mengembalikan null (bisa menjadi cachevalue yang dibersihkan // atau pabrik yang tidak berhasil dalam memasang cachevalue) // proses berikut adalah proses pengisian} {factory == null) {// buat pabrik} jika pemasok (factory == null) {// buat pabrik} jika pemasok (pemasok == null) {// buat {factory == null) {// buat factory} jika pemasok (pemasok == null) {// buat {factory == null) {// buat factory} jika pemasok (pemasok == null = Fungsi while loop adalah untuk terus mendapatkan kelas yang mengimplementasikan Invokehandler. Kelas ini dapat diperoleh dari cache atau dihasilkan dari ProxyFactoryClass.
Pabrik adalah kelas internal yang mengimplementasikan antarmuka pemasok <V>. Kelas ini mengesampingkan metode GET, dan metode instance tipe ProxyFactoryClass dipanggil dalam metode GET. Metode ini adalah cara nyata untuk membuat kelas proxy. Mari kita lihat kode sumber dari Metode ProxyFactoryCoryClass#Apply:
kelas publik <?> Terapkan (classloader loader, class <?> [] antarmuka) {peta <class <?>, boolean> antarmuka = identityHashMap baru <> (antarmuka.length); untuk (class <?> intf: antarmuka) { /* Pastikan bahwa class loader menyelesaikan nama antarmuka ini ke objek kelas yang sama.* / class <?> InterfaceClass = null; coba {// Muat informasi tentang setiap antarmukaclass = class.forname (intf.getName (), false, loader); } catch (classNotFoundException e) {} // Jika kelas dimuat dengan classload Anda sendiri tidak sama dengan kelas yang Anda lewati, lempar pengecualian jika (antarmukaclass! = intf) {lempar baru ilegalargumentException (intf + "tidak terlihat dari class loader"); } // Jika masuk bukan tipe antarmuka if (! InterfaceClass.isInterface ()) {lempar baru ilegalargumentException (antarmaceclass.getName () + "bukan antarmuka"); } // Verifikasi apakah antarmuka diulangi if (antarmaceset.put (antarmuka, boolean.true)! = Null) {lempar IllegalArgumentException baru ("Antarmuka berulang:" + interfaceClass.getName ()); }} String proxypkg = null; // Paket untuk mendefinisikan kelas proxy di /* Rekam paket antarmuka proxy non-publik sehingga kelas proxy akan didefinisikan dalam paket yang sama. * Pastikan bahwa semua antarmuka proxy non-publik berada dalam paket yang sama. */// Paragraf ini tergantung pada apakah ada antarmuka yang tidak publik dalam antarmuka yang Anda lewati. Jika demikian, semua antarmuka ini harus ditentukan dalam satu paket. Jika tidak, lempar pengecualian untuk (kelas <?> Intf: antarmuka) {int flags = intf.getModifiers (); if (! Modifier.ispublic (flags)) {string name = intf.getName (); int n = name.LastIndexOf ('.'); String pkg = ((n == -1)? "": Name.substring (0, n + 1)); if (proxypkg == null) {proxypkg = pkg; } lain jika (! pkg.equals (proxypkg)) {lempar baru ilegalargumentException ("antarmuka non-publik dari paket yang berbeda"); }}}} if (proxypkg == null) {// Jika tidak ada antarmuka proxy non-publik, gunakan paket com.sun.proxy proxypkg = reflectutil.proxy_package + "."; } / * * Pilih nama untuk dihasilkan oleh kelas proxy. */ long num = nextUliquenumber.getAndIncrement (); // Hasilkan nama kelas kelas proxy acak, $ proxy + num string proxyname = proxypkg + proxyclassnameprefix + num; /** Hasilkan file kelas kelas proxy, kembalikan aliran byte*/ byte [] proxyclassFile = proxygenerator.generateProxyClass (proxyname, antarmuka); coba {return Defineclass0 (loader, proxyname, proxyclassfile, 0, proxyclassfile.length); } catch (classFormaterRor e) {// end lempar baru ilegalargumentException (e.toString ()); }}}ProxyFactoryClass#Apply yang disebutkan di atas adalah metode untuk benar -benar menghasilkan kelas proxy, yang sebenarnya tidak akurat. Setelah membaca kode sumber di sini, kami akan menemukan bahwa ProxyGenerator#GenerateProxyClass adalah metode untuk benar -benar menghasilkan kelas proxy. Hasilkan file kelas yang sesuai sesuai dengan komposisi bytecode kelas Java (lihat artikel saya yang lain Java Bytecode Learning Notes). Kode sumber spesifik ProxyGenerator#GenerateProxyClass adalah sebagai berikut:
byte pribadi [] generateClassFile () { / * * Langkah 1: Merakit objek proxymethod untuk semua metode untuk * menghasilkan kode pengiriman proxy untuk. */ // Metode addProxyMethod adalah menambahkan semua metode ke daftar dan sesuai dengan kelas yang sesuai // Berikut adalah tiga metode yang sesuai dengan objek, Tostring dan sama addProxyMethod (HashCodemethod, Object.class); addProxyMethod (EqualsMethod, Object.class); addproxymethod (TostringMethod, Object.class); // Bandingkan antarmuka dalam daftar antarmuka dengan metode di bawah antarmuka untuk (int i = 0; i <antarmuka. untuk (int j = 0; j <methods.length; j ++) {addProxyMethod (Metode [j], antarmuka [i]); }} / * * Untuk setiap set metode proxy dengan tanda tangan yang sama, * Verifikasi bahwa tipe pengembalian metode kompatibel. */ for (Daftar <RoxyMethod> tanda Methods: proxymethods.values ()) {checkReturnTypes (sigmethods); } / * * Langkah 2: Rakitan fieldInfo dan MethodInfo struct untuk semua * bidang dan metode di kelas yang kami hasilkan. */// Tambahkan metode konstruktor ke metode ini, yang hanya satu konstruktor, yang merupakan konstruktor dengan antarmuka InvocationHandler.//tipis adalah metode nyata untuk menambahkan metode ke file kelas, yaitu, kelas proxy. Namun, itu belum diproses. Ini baru saja ditambahkan terlebih dahulu dan tunggu loop. Deskripsi Nama Konstruktor dalam File Kelas adalah <init> coba {Methods.add (GenerAteConstructor ()); untuk (daftar <droxymethod> SignMethods: proxymethods.values ()) {for (ProxyMethod PM: SignMethods) {// Tambahkan Atribut Jenis Metode ke setiap metode proxy. Angka 10 adalah pengidentifikasi file kelas, yang berarti bahwa atribut ini adalah fields.add (fieldInfo baru (pm.methodfieldname, "ljava/lang/reflect/method;", acc_private | acc_static)); // Tambahkan setiap metode proxy ke metode metode kelas proxy. }} // Tambahkan blok inisialisasi statis dan inisialisasi setiap atribut. Di sini, blok kode statis juga disebut konstruktor kelas. Ini sebenarnya adalah metode dengan nama <linit>, jadi tambahkan ke metode daftar metode. } catch (ioException e) {lempar internalError baru ("Pengecualian I/O yang tidak terduga"); } // Jumlah metode dan atribut tidak dapat melebihi 65535, termasuk jumlah antarmuka sebelumnya. // Ini karena dalam file kelas, angka -angka ini diwakili dalam hexadecimal 4 -bit, sehingga nilai maksimum adalah 2 dengan kekuatan 16 -1 if (methods.size ()> 65535) {melempar IllegalArargumentException baru ("batas metode terlampaui"); } if (fields.size ()> 65535) {lempar baru ilegalargumentException ("batas lapangan terlampaui"); } // Langkah selanjutnya adalah menulis file kelas, termasuk angka ajaib, nama kelas, kumpulan konstan dan serangkaian bytecode lainnya. Saya tidak akan membahas detailnya. Jika Anda membutuhkannya, Anda dapat merujuk pada pengetahuan yang relevan dari bytecode mesin virtual JVM. cp.getClass (dottoslash (classname)); cp.getClass (SuperClassName); untuk (int i = 0; i <antarmuka. } cp.setreadonly (); BytearrayoutputStream bout = new bytearrayoutputStream (); DataOutputStream dout = DataOutputStream baru (Bout); coba {// u4 sihir; dout.writeint (0xCafeBabe); // u2 minor_version; dout.writeshort (classfile_minor_version); // u2 mayor_version; dout.writeshort (classfile_major_version); cp.write (dout); // (tulis kumpulan konstan) // u2 access_flags; dout.writeshort (acc_public | acc_final | acc_super); // u2 this_class; dout.writeshort (cp.getClass (dottoslash (classname))); // u2 super_class; dout.writeshort (cp.getClass (superclassName)); // u2 antarmuka_count; dout.writeshort (antarmuka.length); // antarmuka u2 [antarmuka_count]; untuk (int i = 0; i <antarmuka. } // u2 fields_count; dout.writeshort (fields.size ()); // bidang field_info [fields_count]; untuk (fieldInfo f: fields) {f.write (dout); } // u2 method_count; dout.writeshort (methods.size ()); // Method_info Metode [Methods_Count]; untuk (MethodInfo m: Metode) {m.write (dout); } // u2 atribute_count; dout.writeshort (0); // (tidak ada atribut ClassFile untuk kelas proxy)} catch (ioException e) {lempar internalError baru ("Pengecualian I/O yang tidak terduga"); } return bout.tobyteArray (); }Setelah lapisan panggilan, kelas proxy akhirnya dihasilkan.
2. Siapa yang menelepon Invoke?
Kami mensimulasikan JDK untuk menghasilkan kelas proxy dengan sendirinya, dengan nama kelas TestProxygen:
Public Class TestGeneratorProxy {public static void main (string [] args) melempar ioException {byte [] classFile = proxygenerator.generateProxyClass ("testproxygen", subjek.class.getInterfaces ()); File file = file baru ("/user/yadoao/desktop/testproxygen.class"); FileOutputStream fos = baru fileOutputStream (file); fos.write (classfile); fos.flush (); fos.close (); }}Mendekompilasi file kelas dengan JD-GUI, dan hasilnya adalah sebagai berikut:
Impor com.su.dynamicproxy.isubject; impor java.lang.reflect.invocationHandler; impor java.lang.reflect.method; impor java.lang.reflect.proxy; impor public. M3; Metode Statis Pribadi M1; Metode Statis Pribadi M0; metode statis pribadi M4; metode statis pribadi m2; TestProxyGen publik (InvocationHandler ParamInvocationHandler) melempar {super (paramInvocationHandler); } public final void sayshello () melempar {coba {this.h.invoke (ini, m3, null); kembali; } catch (error | runimeException localError) {throw localError; } Catch (Throwable LocalThrowable) {lempar New UndeclaredthrowableException (Localthrowable); }} public final boolean setara (objek paramObject) melempar {coba {return ((boolean) this.h.invoke (ini, m1, objek baru [] {paramoBject})). booleanValue (); } catch (error | runimeException localError) {throw localError; } Catch (Throwable LocalThrowable) {lempar New UndeclaredthrowableException (Localthrowable); }} public final int hashCode () melempar {coba {return ((integer) this.h.invoke (this, m0, null)). intvalue (); } catch (error | runimeException localError) {throw localError; } Catch (Throwable LocalThrowable) {lempar New UndeclaredthrowableException (Localthrowable); }} public final void Saysgoodbye () melempar {coba {this.h.invoke (ini, m4, null); kembali; } catch (error | runimeException localError) {throw localError; } Catch (Throwable LocalThrowable) {lempar New UndeclaredthrowableException (Localthrowable); }} public final string toString () melempar {coba {return (string) this.h.invoke (ini, m2, null); } catch (error | runimeException localError) {throw localError; } Catch (Throwable LocalThrowable) {lempar New UndeclaredthrowableException (Localthrowable); }} static {coba {m3 = class.forname ("com.su.dynamicproxy.isubject"). getMethod ("sayhello", kelas baru [0]); m1 = class.forname ("java.lang.object"). getMethod ("equals", kelas baru [] {class.forname ("java.lang.object")}); m0 = class.forname ("java.lang.object"). getMethod ("hashCode", kelas baru [0]); m4 = class.forname ("com.su.dynamicproxy.isubject"). getMethod ("Saygoodbye", kelas baru [0]); m2 = class.forname ("java.lang.object"). getMethod ("tostring", kelas baru [0]); kembali; } catch (nosuchmethodException localNoSuchMethodeException) {lempar nosuchmethoderror baru (localnoSuchmethodeException.getMessage ()); } catch (ClassNotFoundException LocalClassNotFoundException) {Throw NoClassDeffoundError baru (LocalClassNotFoundException.getMessage ()); }}} Pertama, saya perhatikan bahwa konstruktor kelas proxy yang dihasilkan dilewatkan di kelas yang mengimplementasikan antarmuka Invokhandler sebagai parameter, dan disebut konstruktor proxy kelas induk, yang menginisialisasi variabel anggota yang dilindungi invokehander h di proxy.
Saya melihat beberapa blok inisialisasi statis lagi. Blok inisialisasi statis di sini adalah untuk menginisialisasi daftar antarmuka proxy dan kode hashcode, tostring, dan sama dengan metode.
Akhirnya, ada proses panggilan dari metode ini, yang semuanya adalah panggilan balik ke metode Invoke.
Ini berakhir dengan analisis pola proxy ini.