1. Ikhtisar <BR /> Agen adalah pola desain, yang tujuannya adalah untuk memberikan objek lain dengan proxy untuk mengontrol akses ke objek tertentu. Kelas proxy bertanggung jawab untuk preprocessing pesan untuk kelas delegasi, memfilter pesan dan meneruskan pesan, dan melakukan pemrosesan selanjutnya setelah pesan dieksekusi oleh kelas delegasi. Untuk mempertahankan konsistensi dalam perilaku, kelas proxy dan kelas delegasi biasanya menerapkan antarmuka yang sama.
Menurut periode penciptaan agen, kelas agen dapat dibagi menjadi dua jenis:
Proxy Static: Programmer membuat kelas proxy atau alat tertentu untuk secara otomatis menghasilkan kode sumber dan kemudian mengkompilasinya. Artinya, file .class dari kelas proxy sudah ada sebelum program berjalan.
Proxy Dynamic: Gunakan mekanisme refleksi untuk membuat dan menghasilkan secara dinamis saat program berjalan.
Mari kita perkenalkan secara singkat proxy statis sebelum menerapkan mekanisme proxy dinamis.
2. Proxy Static <BR /> Seperti yang disebutkan di atas, baik kelas proxy dan kelas delegasi umumnya perlu menerapkan antarmuka yang sama. Berikut ini adalah mendefinisikan antarmuka ini terlebih dahulu:
Layanan Antarmuka Publik {public void add ();}Kelas delegasi adalah implementasi antarmuka, didefinisikan sebagai berikut:
layanan kelas publik mengimplementasikan layanan {public void add () {System.out.println ("Tambahkan pengguna!"); }}Jika kami ingin menambahkan beberapa log ke kelas delegasi, kelas proxy dapat didefinisikan sebagai berikut:
ServiceProxy kelas publik mengimplementasikan Layanan {Layanan Layanan Privat; Public ServiceProxy (Layanan Layanan) {super (); this.service = layanan; } public void add () {System.out.println ("Layanan Mulai"); service.add (); System.out.println ("Layanan Akhir"); }}Tulis kelas tes:
kelas publik testmain {public static void main (string [] args) {service serviceImpl = new serviceImpl (); Proxy layanan = serviceProxy baru (serviceImpl); proxy.add (); }}Jalankan program pengujian, hasilnya adalah sebagai berikut:
Dari kode di atas, kita dapat melihat bahwa kelas proxy statis hanya dapat melayani antarmuka tertentu. Jika Anda ingin melayani beberapa jenis objek, Anda harus proksi setiap objek. Kami akan memikirkan apakah semua fungsi proxy dapat diselesaikan melalui kelas proxy, jadi kami memperkenalkan konsep proxy dinamis.
3. Dinamis Proxy Java's Dynamic Proxy terutama melibatkan dua kelas, proxy dan InvocationHandler.
Proxy: Menyediakan satu set metode statis untuk secara dinamis menghasilkan kelas proxy dan objeknya untuk satu set antarmuka.
// Metode 1: Metode ini digunakan untuk mendapatkan prosesor panggilan yang terkait dengan objek proxy yang ditentukan. Static InvocationHandler GetInvocationHandler (Proxy Objek) // Metode 2: Metode ini digunakan untuk mendapatkan objek kelas dari kelas proxy dinamis yang terkait dengan loader kelas yang ditentukan dan satu set antarmuka. kelas statis getproxyclass (classloader loader, class [] antarmuka) // Metode 3: Metode ini digunakan untuk menentukan apakah objek kelas yang ditentukan adalah kelas proxy dinamis statis boolean isproxyclass (kelas cl) // metode interfaces dan satu set interfaces dan satu set interfaces. Objek Statis NewProxyInstance (ClassLoader Loader, Class [] Antarmuka, InvocationHandler H)
InvocationHandler: Ini adalah antarmuka prosesor pemanggilan, menyesuaikan metode Invok, yang digunakan untuk menangani metode panggilan yang terpusat pada objek kelas proxy dinamis, biasanya di mana akses proxy ke kelas delegasi diimplementasikan
// Metode ini bertanggung jawab untuk menangani semua panggilan metode secara terpusat pada kelas proxy dinamis. Parameter pertama adalah contoh dari kelas proxy, dan parameter kedua adalah objek metode yang disebut // metode ketiga adalah parameter panggilan. Prosesor Prosesor Panggilan Preproses atau pengiriman ke instance kelas delegasi untuk mengirimkan objek eksekusi.
Untuk mengimplementasikan proxy dinamis untuk Java, ada empat langkah spesifik:
1. Buat prosesor panggilan Anda sendiri dengan mengimplementasikan antarmuka InvocationHandler
2. Buat kelas proxy dinamis dengan menentukan objek ClassLoader dan satu set antarmuka untuk kelas proxy
3. Dapatkan konstruktor kelas proxy dinamis melalui mekanisme refleksi, dan satu -satunya jenis parameternya adalah tipe antarmuka kelas prosesor panggilan
4. Buat instance kelas proxy dinamis melalui konstruktor. Selama konstruksi, objek prosesor disebut sebagai parameter dan dilewati.
Berikut ini adalah contoh menerapkan proxy dinamis Anda sendiri berdasarkan pada empat langkah di atas:
Kelas implementasi antarmuka dan antarmuka (mis. Kelas delegasi) sama dengan kode proxy statis di atas. Di sini kami akan menerapkan antarmuka InvocationHandler untuk membuat prosesor panggilan kami sendiri.
Layanan Public Class Handle mengimplementasikan InvocationHandler {Private Object S; Public ServiceHandle (Objek S) {this.s = s; } Invoke Objek Publik (Proxy Objek, Metode Metode, Objek [] args) melempar Throwable {System.out.println ("Layanan Mulai"); // Invoke berarti memanggil metode yang mendasari yang diwakili oleh objek metode ini pada objek yang ditentukan dengan parameter yang ditentukan hasil objek = metode.invoke (s, args); System.out.println ("Layanan Akhir"); hasil pengembalian; }}Tulis kelas tes:
testmain kelas publik {public static void main (string [] args) {service service = new serviceImpl (); Penangan InvocationHandler = layanan baru (layanan); Service s = (service) proxy.newproxyInstance (service.getClass (). GetClassLoader (), service.getClass (). GetInterfaces (), handler); s.add (); }}Jalankan program pengujian, dan hasilnya sama dengan proxy statis. Kita dapat melihat bahwa kode di atas tidak memiliki langkah 2 dan 3 yang kita sebutkan sebelumnya, karena metode statis Prox newProxyInstance telah merangkum kedua langkah ini untuk kita. Implementasi internal spesifik adalah sebagai berikut:
// Buat objek kelas secara dinamis dari kelas proxy untuk serangkaian antarmuka termasuk antarmuka antarmuka melalui kelas proxy clazz = proxy.getProxyclass (classloader, kelas baru [] {interface.class, ...}); // dapatkan objek konstruktor dari objek class konstruktor claze.class (clazz. Instance kelas proxy dinamis melalui proxy antarmuka objek konstruktor = (antarmuka) constructor.newinstance (objek baru [] {handler});Implementasi internal fungsi NewProxyInstance adalah:
Objek statis publik newProxyInstance (classloader loader, class <?> [] Antarmuka, InvocationHandler h) melempar ilegalargumentException {// periksa h tidak kosong, jika tidak melempar objek pengecualian.requirenonnull (h); // Dapatkan objek tipe kelas proxy yang terkait dengan merumuskan class loader dan satu set antarmuka kelas akhir <?> [] Intfs = antarmuka.clone (); // Periksa apakah objek kelas antarmuka terlihat oleh class loader dan persis sama dengan objek kelas antarmuka yang dikenali oleh class loader final securityManager sm = system.getSecurityManager (); if (sm! = null) {checkProxyAccess (reflection.getCallerClass (), loader, intfs); } // Dapatkan objek tipe kelas proxy yang terkait untuk merumuskan loader kelas dan satu set kelas antarmuka <?> Cl = getProxyClass0 (loader, intfs); coba {if (sm! = null) {checkNewProxyPermission (reflection.getCallerClass (), cl); } // Dapatkan objek konstruktor melalui refleksi dan hasilkan konstruktor final instance kelas proxy <?> Cons = cl.getConstructor (constructorparams); Final InvocationHandler IH = H; if (! Modifier.ispublic (cl.getModifiers ())) {AccessController.Doprivileged (new PrivilegedAction <void> () {public void run () {Cons.setAccessible (true); return null;}}); } return cons.newInstance (objek baru [] {h}); } Catch (IllegalAccessException | InstantiationException e) {lempar internalError baru (e.tostring (), e); } catch (InvocateTargetException e) {Throwable t = e.getCause (); if (t instanceof runtimeException) {throw (runtimeException) t; } else {lempar internalError baru (t.toString (), t); }} catch (nosuchmethodeException e) {lempar internalError baru (e.tostring (), e); }} 4. Simulasi dan implementasikan kelas proxy
Menurut prinsip di atas, kita dapat mensimulasikan dan mengimplementasikan kelas proxy sendiri:
Public Class Proxy {Public Static Object NewProxyInstance (Class Inface, InvocationHandle H) melempar Exception {String rt = "/r/n"; String methodstr = ""; Metode [] metode = inface.getMethods (); untuk (metode m: metode) {methodstr+= "@override"+rt+"public void"+m.getname ()+"()"+rt+"{"+rt+"coba {"+rt+"Metode md ="+inface.getname ()+".") (") (") () () ". "h.invoke (ini, md);"+ rt+ "} catch (exception e) {e.printstacktrace ();}"+ rt+ "}"; } String src = "test paket;"+ rt+ "impor java.lang.reflect.method;"+ rt+ "Layanan kelas publik ImplementsImpl2 mengimplementasikan"+ inface.getName ()+ rt+ "{"+ rt+ "publiconImpl2 (dongeng h)"+ rt+ "{"+ rt+ "rt" tht+ "rt+" rt+ "rt+" "rt+" "rt+" {"+" test.invocationHandle h; "+ rt+ Methodstr+"} "; String filename = "d: /src/test/serviceImpl2.java"; // Compile Compile (SRC, FileName); // Muat ke dalam memori dan buat objek instan m = loadMemory (h); kembali m; } private static void compile (string src, string fileName) melempar ioException {file f = file baru (fileName); FileWriter FileWriter = FileWriter baru (f); FileWriter.write (SRC); FileWriter.Flush (); filewriter.close (); // Dapatkan kompiler java yang disediakan oleh platform ini, javacompiler compiler = toolprovider.getsystemjavacompiler (); // Dapatkan instance baru yang diimplementasikan oleh manajer file standar StandardJavaFileManager filemanager = compiler.getstandardFileManager (null, null, null); // Dapatkan objek file yang mewakili file iterable unit yang diberikan = filemanager.getjavafileObjects (nama file); // Buat CompilationTask T = Compiler.getask (NULL, FileManager, NULL, NULL, NULL, NULL); // jalankan tugas kompilasi ini t.call (); filemanager.close (); } Private Static Object LoadMemory (InvocationHandle H) melempar Malformedurlexception, ClassNotFoundException, NosuchMethodeException, InstantiationException, IllegalAccessException, InvocationTargetException {URL [] URLS = URL baru [] {URL baru (" // Muat kelas dan sumber daya urlclassloader UL = URLClassLoader baru (URLS); Kelas C = UL.LoadClass ("test.serviceImpl2"); // Mengembalikan konstruktor publik yang ditentukan dari kelas yang diwakili oleh objek kelas. Konstruktor CTR = C.GetConstructor (InvocationHandle.class); // Gunakan metode konstruktor yang diwakili oleh objek konstruktor ini CTR untuk membuat instance baru dari kelas deklarasi dari metode konstruktor, dan menginisialisasi instance dengan objek parameter inisialisasi yang ditentukan m = ctr.newinstance (h); kembali m; }}5. Ringkasan 1. Proxy dinamis yang disebut adalah kelas seperti itu. Ini adalah kelas yang dihasilkan saat runtime. Saat menghasilkannya, Anda harus menyediakan satu set antarmuka untuk itu, dan kemudian mengubah kelas untuk mengklaim bahwa ia mengimplementasikan antarmuka ini. Namun, itu tidak akan melakukan pekerjaan yang substansial untuk Anda, tetapi akan mengambil alih pekerjaan yang sebenarnya berdasarkan pawang parameter (yaitu, kelas implementasi antarmuka InvocationHandler) yang disediakan ketika Anda menghasilkan instance.
2. Desain Proxy membuatnya hanya mendukung proxy antarmuka. Mekanisme warisan Java yang ditakdirkan bahwa kelas proksi dinamis tidak dapat mengimplementasikan proksi dinamis untuk kelas, karena warisan berganda pada dasarnya tidak layak di Java.
Di atas adalah semua tentang artikel ini, saya harap ini akan membantu untuk pembelajaran semua orang.