1. ภาพรวม <BR /> Agent เป็นรูปแบบการออกแบบซึ่งมีวัตถุประสงค์เพื่อให้วัตถุอื่นมีพร็อกซีเพื่อควบคุมการเข้าถึงวัตถุบางอย่าง คลาสพร็อกซีมีหน้าที่รับผิดชอบในการประมวลผลข้อความล่วงหน้าสำหรับคลาสผู้ได้รับมอบหมายการกรองข้อความและข้อความส่งต่อและดำเนินการประมวลผลที่ตามมาหลังจากที่ข้อความถูกดำเนินการโดยคลาสตัวแทน เพื่อรักษาความสอดคล้องในพฤติกรรมคลาสพร็อกซีและคลาสตัวแทนมักจะใช้อินเทอร์เฟซเดียวกัน
ตามระยะเวลาของการสร้างตัวแทนคลาสตัวแทนสามารถแบ่งออกเป็นสองประเภท:
พร็อกซีแบบคงที่: โปรแกรมเมอร์สร้างคลาสพร็อกซีหรือเครื่องมือเฉพาะเพื่อสร้างซอร์สโค้ดโดยอัตโนมัติแล้วรวบรวม กล่าวคือไฟล์. class ของคลาสพร็อกซีมีอยู่แล้วก่อนที่โปรแกรมจะทำงาน
พร็อกซีแบบไดนามิก: ใช้กลไกการสะท้อนเพื่อสร้างและสร้างแบบไดนามิกเมื่อโปรแกรมทำงาน
มาแนะนำพร็อกซีแบบคงที่ก่อนที่จะใช้กลไกพร็อกซีแบบไดนามิก
2. พร็อกซีคงที่ <br /> ดังที่ได้กล่าวไว้ข้างต้นทั้งคลาสพร็อกซีและคลาสตัวแทนโดยทั่วไปจำเป็นต้องใช้อินเทอร์เฟซเดียวกัน ต่อไปนี้คือการกำหนดอินเทอร์เฟซนี้ก่อน:
บริการส่วนต่อประสานสาธารณะ {โมฆะสาธารณะเพิ่ม ();}คลาสผู้แทนคือการใช้งานอินเทอร์เฟซที่กำหนดดังนี้:
ServiceImpl ระดับสาธารณะใช้บริการ {โมฆะสาธารณะเพิ่ม () {system.out.println ("เพิ่มผู้ใช้!"); -หากเราต้องการเพิ่มบันทึกบางอย่างในคลาสผู้ได้รับมอบหมายคลาสพร็อกซีสามารถกำหนดได้ดังนี้:
ServiceProxy ชั้นเรียนสาธารณะใช้บริการ {บริการส่วนตัว; Public ServiceProxy (บริการบริการ) {super (); this.service = บริการ; } โมฆะสาธารณะเพิ่ม () {system.out.println ("บริการเริ่มต้น"); Service.add (); System.out.println ("End Service End"); -เขียนคลาสทดสอบ:
Public Class Testmain {โมฆะคงที่สาธารณะหลัก (String [] args) {service serviceimpl = new ServiceImpl (); บริการพร็อกซี = ใหม่บริการ (ServiceImpl); Proxy.add (); -เรียกใช้โปรแกรมทดสอบผลลัพธ์มีดังนี้:
จากรหัสข้างต้นเราจะเห็นว่าคลาสพร็อกซีแบบคงที่สามารถให้บริการเฉพาะอินเตอร์เฟสเฉพาะ หากคุณต้องการให้บริการวัตถุหลายประเภทคุณต้องพร็อกซีแต่ละวัตถุ เราจะคิดว่าฟังก์ชั่นพร็อกซีทั้งหมดจะเสร็จสมบูรณ์ผ่านระดับพร็อกซีหรือไม่ดังนั้นเราจึงแนะนำแนวคิดของพร็อกซีแบบไดนามิกหรือไม่
3. พร็อกซีแบบไดนามิกของพร็อกซีพร็อกซี ไดนามิกส่วนใหญ่เกี่ยวข้องกับสองคลาสพร็อกซีและการเรียกร้อง
พร็อกซี: จัดเตรียมชุดของวิธีการคงที่เพื่อสร้างคลาสพร็อกซีแบบไดนามิกและวัตถุของพวกเขาสำหรับชุดของอินเทอร์เฟซ
// วิธีที่ 1: วิธีนี้ใช้เพื่อรับโปรเซสเซอร์การโทรที่เกี่ยวข้องกับวัตถุพร็อกซีที่ระบุ Static InvocationHandler getInvocationHandler (พร็อกซีวัตถุ) // วิธีที่ 2: วิธีนี้ใช้เพื่อรับวัตถุคลาสของคลาสพร็อกซีแบบไดนามิกที่เกี่ยวข้องกับตัวโหลดคลาสที่ระบุและชุดของอินเทอร์เฟซ คลาสคงที่ getProxyClass (classloader loader, คลาส [] อินเตอร์เฟส) // วิธีที่ 3: วิธีนี้ใช้เพื่อตรวจสอบว่าวัตถุคลาสที่ระบุหรือไม่เป็นพร็อกซีคลาสแบบไดนามิกบูลีนสแตติกบูลีน iSproxyclass (คลาส Cl) // เมธอด 4: วิธีการนี้ใช้เพื่อสร้างคลาสพร็อกซีแบบไดนามิก วัตถุแบบคงที่ newproxyinstance (classloader loader, คลาส [] อินเตอร์เฟส, InvocationHandler H)
InvocationHandler: มันเป็นอินเทอร์เฟซโปรเซสเซอร์การโทรปรับแต่งวิธีการของ INCK ซึ่งใช้ในการจัดการการเรียกใช้วิธีการในศูนย์กลางบนวัตถุพร็อกซีคลาสแบบไดนามิก
// วิธีนี้มีหน้าที่รับผิดชอบในการจัดการวิธีการทั้งหมดจากส่วนกลางในคลาสพร็อกซีแบบไดนามิก พารามิเตอร์แรกเป็นทั้งอินสแตนซ์ของคลาสพร็อกซีและพารามิเตอร์ที่สองคือวัตถุวิธีการที่เรียกว่า // วิธีที่สามคือพารามิเตอร์การโทร โปรเซสเซอร์การประมวลผลการประมวลผลล่วงหน้าหรือส่งไปยังอินสแตนซ์ของคลาสตัวแทนเพื่อส่งวัตถุการดำเนินการเรียกใช้ (พร็อกซีวัตถุวิธีวิธีการวัตถุ [] args)
ในการใช้งานพร็อกซีแบบไดนามิกสำหรับ Java มีสี่ขั้นตอนเฉพาะ:
1. สร้างโปรเซสเซอร์การโทรของคุณเองโดยใช้อินเตอร์เฟส InvocationHandler
2. สร้างคลาสพร็อกซีแบบไดนามิกโดยการระบุวัตถุ classloader และชุดของอินเทอร์เฟซสำหรับคลาสพร็อกซี
3. รับตัวสร้างของคลาสพร็อกซีแบบไดนามิกผ่านกลไกการสะท้อนกลับและประเภทพารามิเตอร์เดียวคือประเภทอินเตอร์เฟสคลาสโปรเซสเซอร์การโทร
4. สร้างอินสแตนซ์ระดับพร็อกซีแบบไดนามิกผ่านตัวสร้าง ในระหว่างการก่อสร้างวัตถุโปรเซสเซอร์ถูกเรียกว่าเป็นพารามิเตอร์และผ่านเข้ามา
ต่อไปนี้เป็นตัวอย่างของการใช้งานพร็อกซีแบบไดนามิกของคุณเองตามขั้นตอนสี่ขั้นตอนข้างต้น:
คลาสการใช้งานของอินเทอร์เฟซและอินเทอร์เฟซ (เช่นคลาสตัวแทน) นั้นเหมือนกับรหัสของพร็อกซีแบบคงที่ข้างต้น ที่นี่เราจะใช้อินเทอร์เฟซ InvocationHandler เพื่อสร้างโปรเซสเซอร์การโทรของเราเอง
Public Class ServiceHandle ใช้ InvocationHandler {วัตถุส่วนตัว s; Public ServiceHandle (Object S) {this.s = s; } วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุ, วิธีการ, วัตถุ [] args) โยน {system.out.println ("บริการเริ่มต้น"); // revoke หมายถึงการเรียกวิธีการพื้นฐานที่แสดงโดยวัตถุวิธีนี้บนวัตถุที่ระบุด้วยพารามิเตอร์ที่ระบุผลลัพธ์วัตถุผล = วิธีการ invoke (s, args); System.out.println ("End Service End"); ผลการกลับมา; -เขียนคลาสทดสอบ:
Public Class Testmain {โมฆะคงที่สาธารณะหลัก (String [] args) {บริการบริการ = new ServiceImpl (); InvocationHandler Handler = ใหม่ ServiceHandle (บริการ); บริการ s = (บริการ) proxy.newproxyinstance (service.getClass (). getClassLoader (), service.getClass (). getInterfaces (), handler); s.add (); -เรียกใช้โปรแกรมทดสอบและผลลัพธ์ก็เหมือนกับพร็อกซีแบบคงที่ เราจะเห็นได้ว่ารหัสข้างต้นไม่มีขั้นตอนที่ 2 และ 3 ที่เราพูดถึงก่อนหน้านี้เนื่องจากวิธีการคงที่ของ Prox Newproxyinstance ได้ห่อหุ้มสองขั้นตอนนี้สำหรับเรา การใช้งานภายในเฉพาะมีดังนี้:
// สร้างวัตถุคลาสแบบไดนามิกของคลาสพร็อกซีสำหรับชุดของอินเทอร์เฟซรวมถึงอินเตอร์เฟสอินเตอร์เฟสผ่านคลาสพร็อกซี clazz = proxy.getProxyclass (classloader, คลาสใหม่ [] {interface.class, ... }); }); // สร้างอินสแตนซ์ของคลาสพร็อกซีแบบไดนามิกผ่านตัวสร้างออบเจ็กต์อินเตอร์เฟส proxy = (อินเตอร์เฟส) constructor.newInstance (วัตถุใหม่ [] {handler});การใช้งานภายในของฟังก์ชัน newproxyinstance คือ:
วัตถุสแตติกสาธารณะ newproxyinstance (classloader loader, คลาส <?> [] อินเตอร์เฟส, rainticationhandler h) พ่น unledalargumentexception {// check h ไม่ว่างเปล่า // รับวัตถุประเภทคลาสพร็อกซีที่เกี่ยวข้องกับการกำหนดคลาสโหลดเดอร์และชุดของอินเตอร์เฟสคลาสสุดท้ายคลาส <?> [] intfs = interfaces.clone (); // ตรวจสอบว่าวัตถุคลาสอินเตอร์เฟสนั้นสามารถมองเห็นได้ในคลาสโหลดเดอร์หรือไม่และเหมือนกับวัตถุคลาสอินเตอร์เฟสที่ได้รับการยอมรับโดยคลาส Loader Final SecurityManager SM = System.getSecurityManager (); if (sm! = null) {checkproxyaccess (reftection.getCallerClass (), loader, intfs); } // รับวัตถุประเภทคลาสพร็อกซีที่เกี่ยวข้องกับการกำหนดคลาสโหลดเดอร์และชุดของคลาสอินเตอร์เฟส <?> cl = getProxyClass0 (โหลดเดอร์, intfs); ลอง {ถ้า (sm! = null) {checkNewProxypermission (reftection.getCallerClass (), cl); } // รับวัตถุคอนสตรัคเตอร์ผ่านการสะท้อนและสร้างอินสแตนซ์ระดับพร็อกซีคอนสตรัคเตอร์สุดท้าย <?> cons = cl.getConstructor (ConstructorParams); สุดท้าย InvocationHandler IH = H; if (! modifier.ispublic (cl.getModifiers ())) {AccessController.doprivileged (ใหม่ PrivilegedAction <Void> () {public void run () {cons.setAccessible (จริง); return null;}}); } return cons.newinstance (วัตถุใหม่ [] {h}); } catch (unglemalaccessexception | InstantiationException e) {โยน InternalError ใหม่ (e.toString (), e); } catch (InvocationTargetException e) {throwable t = e.getCause (); if (t อินสแตนซ์ของ runtimeException) {throw (runtimeException) t; } else {โยนใหม่ภายใน (t.toString (), t); }} catch (nosuchmethodexception e) {โยนใหม่ภายใน (e.toString (), e); - 4. จำลองและใช้งานระดับพร็อกซี
ตามการแนะนำหลักการข้างต้นเราสามารถจำลองและใช้ระดับพร็อกซีด้วยตนเอง:
พร็อกซีคลาสสาธารณะ {วัตถุสาธารณะคงที่ newproxyinstance (คลาส INFACE, InvocationHandle H) โยนข้อยกเว้น {String RT = "/R/N"; String Methodstr = ""; วิธีการ [] วิธีการ = inface.getMethods (); สำหรับ (เมธอด m: วิธีการ) {methodstr+= "@override"+rt+"โมฆะสาธารณะ"+m.getName ()+"()" "+rt+" {"+rt+" ลอง {"+rt+" md = "+inface.getName ()+" "H.invoke (นี่, md);"+ rt+ "} catch (Exception e) {E.printstackTrace ();}"+ rt+ "}"; } String src = "การทดสอบแพ็คเกจ;"+ rt+ "นำเข้า java.lang.reflect.method;"+ rt+ "การให้บริการระดับสาธารณะ usprements"+ inface.getName ()+ rt+ "{"+ rt+ "serviceImpl2 (การเรียกใช้ h)"+ "{"+ " test.invocationhandle h; "+ rt+ methodstr+"} "; string filename = "d: /src/test/serviceimpl2.java"; // Compile Compile (SRC, ชื่อไฟล์); // โหลดลงในหน่วยความจำและสร้างวัตถุอินสแตนซ์ m = loadMemory (h); กลับ M; } Void Compile ส่วนตัวแบบคงที่ (String Src, String filename) พ่น IOException {ไฟล์ f = ไฟล์ใหม่ (ชื่อไฟล์); fileWriter fileWriter = new FileWriter (F); FileWriter.Write (SRC); fileWriter.flush (); fileWriter.close (); // รับคอมไพเลอร์ Java ที่จัดทำโดยแพลตฟอร์มนี้ Javacompiler Compiler = ToolProvider.getSystemjavacompiler (); // รับอินสแตนซ์ใหม่ที่ใช้งานโดยตัวจัดการไฟล์มาตรฐาน StandardJavafileManager fileManager = Compiler.getStandardFileManager (NULL, NULL, NULL); // รับวัตถุไฟล์ที่แสดงไฟล์ที่กำหนด iterable units = fileManager.getJavafileObjects (ชื่อไฟล์); // สร้าง Future CompilationTask t = Compiler.getTask (NULL, FileManager, Null, NULL, NULL, หน่วย); // ดำเนินการรวบรวมงานนี้ t.call (); fileManager.close (); } LoadMemory Object ส่วนตัว (InvocationHandle H) พ่น Malformedurlexception, classnotfoundexception, nosuchmethodexception, instantiationexception, unledalAccessException, การเรียกใช้งาน EdargetException {url [] urls = url ใหม่ [] {url ใหม่ // โหลดคลาสและทรัพยากร urlclassloader ul = urlclassloader ใหม่ (URL); คลาส c = ul.loadclass ("test.serviceimpl2"); // ส่งคืนตัวสร้างสาธารณะที่ระบุของคลาสที่แสดงโดยวัตถุคลาส constructor ctr = c.getConstructor (InvocationHandle.class); // ใช้เมธอดคอนสตรัคเตอร์ที่แสดงโดยวัตถุสร้าง CTR นี้เพื่อสร้างอินสแตนซ์ใหม่ของคลาสการประกาศของวิธีการสร้างและเริ่มต้นอินสแตนซ์ด้วยพารามิเตอร์การเริ่มต้นที่ระบุวัตถุ m = ctr.newinstance (h); กลับ M; -5. สรุป 1. พร็อกซีแบบไดนามิกที่เรียกว่าเป็นคลาส มันเป็นคลาสที่สร้างขึ้นเมื่อรันไทม์ เมื่อสร้างมันขึ้นมาคุณต้องจัดเตรียมชุดอินเทอร์เฟซให้กับมันแล้วเปลี่ยนคลาสเพื่ออ้างว่าใช้อินเทอร์เฟซเหล่านี้ อย่างไรก็ตามมันจะไม่ทำงานที่สำคัญสำหรับคุณ แต่จะเข้าใช้งานจริงตามตัวจัดการพารามิเตอร์ (นั่นคือคลาสการใช้งานของอินเทอร์เฟซ InvocationHandler) ที่ให้ไว้เมื่อคุณสร้างอินสแตนซ์
2. การออกแบบของพร็อกซีทำให้การสนับสนุนพร็อกซีอินเทอร์เฟซเท่านั้น กลไกการสืบทอดของ Java กำหนดว่าคลาสพร็อกซีแบบไดนามิกไม่สามารถใช้พร็อกซีแบบไดนามิกสำหรับคลาสได้เนื่องจากการสืบทอดหลายครั้งนั้นไม่สามารถทำได้ใน Java
ข้างต้นเป็นเรื่องเกี่ยวกับบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน