คลาสพร็อกซีแบบไดนามิก Java สามารถแบ่งออกเป็นสองประเภท
พร็อกซีแบบคงที่: สร้างโดยโปรแกรมเมอร์หรือสร้างซอร์สโค้ดโดยอัตโนมัติด้วยเครื่องมือเฉพาะและรวบรวม ก่อนที่โปรแกรมจะทำงานไฟล์. class ของคลาสพร็อกซีจะมีอยู่แล้ว
พร็อกซีแบบไดนามิก: มันถูกสร้างขึ้นแบบไดนามิกโดยใช้กลไกการสะท้อนเมื่อโปรแกรมทำงาน
1. ก่อนอื่นเราจะแสดงให้เห็นถึงพร็อกซีแบบไดนามิก Java
ตอนนี้เรามีอินเทอร์เฟซธุรกิจที่เรียบง่ายพูดดังต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
แพ็คเกจ Testaop;
อินเทอร์เฟซสาธารณะพูด {
โมฆะสาธารณะ Sayshello (ชื่อสตริง);
โมฆะสาธารณะพูดคุย (ชื่อสตริง);
-
คลาสการใช้งานง่าย ๆ ที่พูดว่าเป็นดังต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
แพ็คเกจ Testaop;
ระดับสาธารณะที่พูดว่า implements พูด {
@Override
โมฆะสาธารณะ Sayshello (ชื่อสตริง) {
// todo วิธีการที่สร้างขึ้นอัตโนมัติสตับ
System.out.println (ชื่อ + ": สวัสดีทุกคน!");
-
@Override
โมฆะสาธารณะพูดคุย (ชื่อสตริง) {
// todo วิธีการที่สร้างขึ้นอัตโนมัติสตับ
System.out.println (ชื่อ + ": ฉันหมายความว่าเราต้องทำงานอย่างหนักเพื่อสร้างสังคมที่กลมกลืนกัน!");
-
-
สิ่งที่เราต้องการบรรลุคือการปลูกฝังการประมวลผลก่อนและหลังการพูดและการพูดคุย
JDK Dynamic Proxy ส่วนใหญ่ใช้สองคลาสในแพ็คเกจ java.lang.reflect: พร็อกซีและ InvocationHandler
InvocationHandler เป็นอินเทอร์เฟซที่กำหนดตรรกะการตัดข้ามโดยใช้อินเทอร์เฟซนี้และเรียกรหัสของคลาสเป้าหมายผ่านกลไกการสะท้อนกลับทอตรรกะการตัดข้ามแบบไดนามิกและตรรกะทางธุรกิจร่วมกัน
พร็อกซีใช้ InvocationHandler เพื่อสร้างอินสแตนซ์แบบไดนามิกที่สอดคล้องกับอินเทอร์เฟซบางอย่างและสร้างวัตถุพร็อกซีของคลาสเป้าหมาย
ดังต่อไปนี้เราสร้างอินสแตนซ์ InvocationHandler:
การคัดลอกรหัสมีดังนี้:
แพ็คเกจ Testaop;
นำเข้า java.lang.reflect.invocationhandler;
นำเข้า java.lang.reflect.method;
คลาสสาธารณะ MyInvocationHandler ใช้ InvocationHandler {
เป้าหมายวัตถุส่วนตัว
myinvocationhandler (เป้าหมายวัตถุ) {
this.target = เป้าหมาย;
-
@Override
วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุวิธีวิธีการวัตถุ [] args)
โยนได้ {
// ดำเนินการก่อนวิธีการเป้าหมาย
System.out.println (" - - - - - - - - - - - - - - - - - - - - - - - -"
System.out.println ("โปรดพูดบนเวทีคนถัดไป!");
// วิธีการโทรเป้าหมาย
Object obj = method.invoke (เป้าหมาย, args);
// ดำเนินการวิธีเป้าหมายหลังจากนั้น
System.out.println ("ทุกคนปรบมือและให้กำลังใจ!");
คืน OBJ;
-
-
นี่คือการทดสอบ:
การคัดลอกรหัสมีดังนี้:
แพ็คเกจ Testaop;
นำเข้า java.lang.reflect.proxy;
คลาสสาธารณะ JDKProxyTest {
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {
// หมวดหมู่ธุรกิจเป้าหมายที่คุณต้องการเป็นผู้ถือครอง
บอกว่าเป้าหมาย = คำพูดใหม่ impl ();
// สานคลาสเป้าหมายและชั้นเรียนข้ามเข้าด้วยกัน
myinvocationhandler handler = ใหม่ myinvocationhandler (เป้าหมาย);
// สร้างพร็อกซีอินสแตนซ์
การพูดพร็อกซี = (พูด) proxy.newproxyinstance (
target.getClass (). getClassLoader (), // ตัวโหลดคลาสของคลาสเป้าหมาย
target.getClass (). getInterfaces (), // อินเตอร์เฟสของคลาสเป้าหมาย
Handler); // cross-cut class
Proxy.sayhello ("Xiao Ming");
Proxy.talking ("Xiaoli");
-
-
การดำเนินการมีดังนี้:
การคัดลอกรหัสมีดังนี้:
-
กรุณาพูดบนเวทีคนต่อไป!
Xiao Ming: สวัสดีทุกคน!
ทุกคนปรบมือและให้กำลังใจ!
-
กรุณาพูดบนเวทีคนต่อไป!
Xiaoli: ฉันหมายความว่าเราต้องทำงานอย่างหนักเพื่อสร้างสังคมที่กลมกลืนกัน!
ทุกคนปรบมือและให้กำลังใจ!
มีข้อ จำกัด อย่างมากในการใช้พร็อกซีไดนามิก JDK ซึ่งก็คือว่าต้องใช้คลาสเป้าหมายจะต้องใช้อินเทอร์เฟซของวิธีการที่สอดคล้องกันและสามารถสร้างอินสแตนซ์พร็อกซีสำหรับอินเทอร์เฟซเท่านั้น เราสามารถเห็นได้ในวิธีการใหม่ของพร็อกซีในคลาสทดสอบด้านบนว่าพารามิเตอร์ที่สองของวิธีนี้คืออินเทอร์เฟซของคลาสเป้าหมาย หากคลาสนี้ไม่ได้ใช้อินเทอร์เฟซก็ขึ้นอยู่กับพร็อกซีแบบไดนามิก CGLIB
CGLIB ใช้เทคโนโลยี bytecode พื้นฐานมากซึ่งสามารถสร้างคลาสย่อยสำหรับคลาสและใช้เทคนิคการสกัดกั้นวิธีการในคลาสย่อยเพื่อสกัดกั้นวิธีการคลาสแม่ทั้งหมดและการปลูกฝังตรรกะการตัดข้ามในสถานการณ์
2. ถัดไปเราจะแสดงให้เห็นถึงพร็อกซีแบบไดนามิก CGLIB
ก่อนอื่นเราต้องให้คำแนะนำแพ็คเกจ
ก่อนอื่นเราสร้างพร็อกซีผู้สร้าง cglibproxy:
การคัดลอกรหัสมีดังนี้:
แพ็คเกจ testaop.cglib;
นำเข้า java.lang.reflect.method;
นำเข้า net.sf.cglib.proxy.enhancer;
นำเข้า net.sf.cglib.proxy.methodinterceptor;
นำเข้า net.sf.cglib.proxy.methodproxy;
คลาสสาธารณะ cglibproxy ใช้ MethodInterceptor {
Enhancer Enhancer = New Enhancer ();
วัตถุสาธารณะ getProxy (คลาส Clazz) {
// ตั้งค่าคลาสย่อยที่จะสร้าง
เพิ่มประสิทธิภาพ. setsuperclass (clazz);
enhancer.setCallback (นี่);
// สร้างอินสแตนซ์ subclass แบบไดนามิกผ่านเทคโนโลยี bytecode
return enhancer.create ();
-
@Override
การสกัดกั้นวัตถุสาธารณะ (Object OBJ, วิธีการ, วัตถุ [] args,
MethodProxy Proxy) โยนได้ {
// todo วิธีการที่สร้างขึ้นอัตโนมัติสตับ
System.out.println (" - - - - - - - - - - - - - - - - - - - - - - - -"
System.out.println ("โปรดพูดบนเวทีคนถัดไป!");
// วิธีการโทรเป้าหมาย
ผลลัพธ์ของวัตถุ = proxy.invokesuper (obj, args);
// ดำเนินการวิธีเป้าหมายหลังจากนั้น
System.out.println ("ทุกคนปรบมือและให้กำลังใจ!");
ผลการกลับมา;
-
-
จากนั้นทดสอบ:
การคัดลอกรหัสมีดังนี้:
แพ็คเกจ testaop.cglib;
นำเข้า testaop.saying;
นำเข้า testaop.sayingimpl;
คลาสสาธารณะ cglibproxytest {
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {
cglibproxy proxy = new cgLibProxy ();
// สร้างคลาสพร็อกซีโดยการสร้างคลาสย่อยแบบไดนามิก
บอกว่า target = (พูด) proxy.getproxy (พูดว่า impl.class);
Target.sayhello ("Xiao Ming");
Target.talking ("Xiaoli");
-
-
ผลลัพธ์ไม่แตกต่างจากพร็อกซีไดนามิก JDK
ทั้งพร็อกซี Dynamic Dynamic และ CGLIB Dynamic Proxy เป็นการปรับปรุงรันไทม์ซึ่งได้รับการปรับปรุงโดยการปลูกฝังรหัสข้ามลงในคลาสพร็อกซี ซึ่งแตกต่างจากสิ่งนี้ AspectJ ซึ่งสามารถปลูกฝังรหัสข้ามในช่วงเวลาการรวบรวมผ่านคอมไพเลอร์พิเศษ