Penjelasan terperinci tentang proxy dinamis JDK
Artikel ini terutama memperkenalkan prinsip -prinsip dasar proxy dinamis JDK, sehingga semua orang dapat memahami proxy JDK lebih dalam, tahu apa itu. Memahami prinsip sebenarnya dari proxy dinamis JDK dan proses pembuatannya. Mari kita ambil demo sederhana.
JDK Proxy HelloWorld
Paket com.yao.proxy;/** * Dibuat oleh Robin */Antarmuka publik HelloWorld {void Sayshello ();} Paket com.yao.proxy; import com.yao.helloworld;/** * Dibuat oleh Robin */kelas publik HelloWorldImpl mengimplementasikan HelloWorld {public void sayhello () {System.out.print ("Hello World"); Paket com.yao.proxy; impor java.lang.reflect.invocationHandler; impor java.lang.reflect.method;/** * Dibuat oleh robin */public class myInvocationHandler, target public; { System.out.println ("Metode:"+ Method.getName ()+ "dipanggil!"); Paket com.yao.proxy; impor com.yao.hellorld; impor java.lang.reflect.constructor; impor java.lang.reflect.invocationHandler; Impor Java.Reflect atic void main (string [] args) melempar nosuchmethodexception, ilegalaccessException, InvocationTargetException, InstantiationException {// Ada dua cara untuk menulis di sini. Class <?> ProxyClass = Proxy.getProxyClass (jdkproxytest.class.getClassLoader (), HelloWorld.class); .newinstance (IH); // Berikut ini adalah cara penulisan yang lebih sederhana, pada dasarnya sama seperti di atas/ * HelloWorld HelloWorld = (HelloWorld) Proxy. }}Jalankan kode di atas dan proxy JDK yang sederhana akan diimplementasikan.
Proses pembuatan agen
Alasan mengapa kami menyebut JDK Dynamic Proxy setiap hari adalah bahwa kelas proksi ini dihasilkan secara dinamis oleh JDK untuk kami saat runtime. Sebelum menjelaskan proses pembuatan proksi, pertama -tama kami menambahkan parameter -dsun.misc.proxygenerator.SaveGeneratedFiles = Tata ke parameter startup JVM. Saya menggunakan ide intellij, dan setelah kelas proxy dihasilkan, ditempatkan langsung di direktori root proyek , dengan nama paket spesifik sebagai struktur direktori.
Proses menghasilkan kelas proxy terutama mencakup dua bagian:
Entri metode getproxyclass dari kelas proxy: Anda harus lulus di class loader dan antarmuka
Kemudian panggil metode GetProxyClass0, dan anotasi di dalamnya sangat jelas. Dapat dilihat dengan jelas di sini bahwa ada batasan jumlah antarmuka antarmuka, yang tidak dapat melebihi 65535. Informasi inisialisasi spesifik ProxyClassCache adalah sebagai berikut:
ProxyClassCache = New Weakcache <> (KeyFactory baru (), New ProxyClassFactory ());
Logika spesifik untuk membuat kelas proxy dibuat melalui metode Apply dari proxyclassFactory.
Logika di ProxyClassFactory mencakup logika pembuatan nama paket, panggilan proxygenerator.
1. Logika pembuatan nama paket default adalah com.sun.proxy.
2. Nama paket siap, bytecode proxy dibuat sesuai dengan antarmuka masuk tertentu melalui proxygenerator. Di kelas proxy, semua logika metode proxy adalah sama untuk memanggil metode Invocation Handander.
3. Muat bytecode ke dalam JVM melalui loader kelas yang diteruskan: Defineclass0 (loader, proxyname, proxyclassfile, 0, proxyclassfile.length);.
Proxy Final ProxyClassFactory mengimplementasikan bifunction <classloader, class <?> [], class <? >> {// awalan untuk semua nama kelas proxy proxy string final proxyclassnameprefix proxy @classion @proxy @ ER Loader, Class <?> [] Antarmuka) {Peta <class <?>, Boolean> antarmuka = identityhashmap baru <> (antarmuka. false, loader);} catch (classnotfoundException e) {} (Interfaceclass! = Intf) {Melempar IllegalArgumentException baru (Intf + "tidak terlihat dari class loader"); ACE bukan duplikat (Interfaceset.put (InterfaceClass, Boolean.True)! = NULL) {Melempar IllegalArgumentException baru ("Antarmuka berulang:" + Paket. Antarmuka sehingga kelas proxy akan didefinisikan dalam paket yang sama * Antarmuka proxy non-publik berada dalam paket yang sama = ((n == -1)? "": name.substring (0, n + 1)); Proxypkg = pkg;} lain jika (! . ";} / * * Pilih nama untuk kelas proxy untuk menghasilkan. * / Long num = nextUnoMeNumber.getAndIncrement (); (proxyname, antarmuka, AccessFlags); proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } } }Kami dapat mendekompilasi berdasarkan bytecode kelas proxy, dan kami bisa mendapatkan hasil berikut.
Struktur kasar agen mencakup 4 bagian:
Paket com.sun.proxy; impor com.yao.hellorld; impor java.lang.reflect.invocationhandler; impor java.lang.reflect.method; impor java.langercrorexy (lefleckscepy procion; M1 Metode Statis Privat M3; PUBLIK $ Proxy0 (InvocationHandler Var1) melempar {super (var1); UndeclaredthrowableException (var4); lemparan {coba {super.h.invoke (ini, m3, (objek []) null); Ull); var3) {Throw New UndeclaredthrowableException (var3); ception (var3);}} static {coba {m1 = Class.forname ("java.lang.object"). GetMethod ("Equals", kelas baru [] {class.forname ("java.lang.object")}); Etod ("Tostring", kelas baru [0]); Kelas [0]);FAQ:
1. ToString () HashCode () Equal () Metode Calling Logic: Jika metode pada ketiga objek ini dipanggil, mereka akan melewati logika InvocationHandler seperti metode dan metode antarmuka lainnya. Metode lain pada objek tidak akan mengikuti logika pemrosesan proxy, tetapi akan langsung mengikuti logika metode pada objek yang diwarisi oleh proxy.
2. Ketika antarmuka berisi metode kode hash yang setara dan tostring, itu akan mengikuti logika penangan doa seperti menangani metode antarmuka biasa, dan memicu logika metode berdasarkan penulisan ulang objek target;
3. Antarmuka berisi tanda tangan metode duplikat, yang tunduk pada urutan antarmuka dilewati.
Terima kasih telah membaca, saya harap ini dapat membantu Anda.