กลไกการไตร่ตรอง Java และพร็อกซีแบบไดนามิกทำให้ Java มีพลังมากขึ้น แนวคิดหลักของฤดูใบไม้ผลิ IOC และ AOP ถูกนำไปใช้ผ่านกลไกการสะท้อนและพร็อกซีแบบไดนามิก
1 Java Reflection
ตัวอย่าง:
ผู้ใช้ผู้ใช้ = ผู้ใช้ใหม่ (); user.settime5flag ("ทดสอบ"); คลาส <s?> cls = class.forname ("com.test.user"); // อินเทอร์เฟซต้องเป็นสาธารณะโดยไม่คำนึงว่ามันจะใช้ภายในในชั้นเรียนนี้! ใช้ cls.getDeclaredMethod () หรือ Traverse เพื่อแก้ไขวิธีการเข้าถึงวิธีการเข้าถึง = cls.getMethod ("getTime5Flag"); String res1 = (string) method.invoke (ผู้ใช้); System.out.println (res1); // หากคุณเกี่ยวข้องกับประเภทพื้นฐานเช่น int ให้ใช้ int.class! Integer.class! = int.class! method = cls.getMethod ("settime5flag", string.class); method.invoke (ผู้ใช้ "Rollen"); วิธี = cls.getMethod ("getTime5Flag"); String res2 = (string) method.invoke (ผู้ใช้); system.out.println (res2);รับแพ็คเกจที่สมบูรณ์และชื่อคลาสผ่านวัตถุ:
user.getClass (). getName (); // ชื่อคลาสพา ธ เต็มชื่อ user.getClass (). getSimplename (); // ชื่อคลาสที่ไม่มีชื่อแพ็คเกจ
รับชั้นเรียน:
class.forName ("com.test.user"); com.test.user.class; user.getClass (); ยกตัวอย่างวัตถุผ่านชั้นเรียนผู้ใช้ user = (ผู้ใช้) cls.newinstance (); // จะต้องมีตัวสร้างพารามิเตอร์รับตัวสร้างทั้งหมด
ตัวสร้าง <?> cons [] = cls.getConstructors (); // return cons [0] .newinstance () ในคำสั่งประกาศ; // ไม่มีการประกาศการแสดงผลจากนั้นมีตัวสร้างเริ่มต้นรับส่วนต่อประสานทั้งหมดที่ใช้โดยคลาส
คลาส <?> intes [] = cls.getInterfaces ();รับคลาสหลัก
cls.getsuperclass ();รับตัวดัดแปลง
int mo = cls.getModifiers (); int mo = cons [0] .getModifiers (); int mo = method.getModifiers (); modifier.toString (MO);รับพารามิเตอร์วิธีการ
method.getParameters (); ข้อเสีย [0] .getParameters ();รับประเภทพารามิเตอร์วิธี
method.getParametortypes (); ข้อเสีย [0] .getParametortypes ();รับทุกประเภทข้อยกเว้นที่ถูกโยนโดยการประกาศวิธีการ
Method.getExceptionTypes ();รับคุณสมบัติทั้งหมดที่ประกาศในชั้นเรียนนี้
ฟิลด์ [] ฟิลด์ = cls.getdeclaredfields (); // รวม PrivateField [0] .getModifiers (); ฟิลด์ [0] .getType ();
รับคุณลักษณะสาธารณะทั้งหมดของคลาสนี้รวมถึงการประกาศคลาสแม่การประกาศอินเทอร์เฟซและคุณลักษณะสาธารณะทั้งหมดของการประกาศคลาสนี้
Cls.GetFields ();
ตั้งค่าแอตทริบิวต์ที่ระบุเพื่อเข้าถึง
field.setAccessible (true); field.set (obj, 'ces'); field.get (obj);
* ความแตกต่างระหว่าง getFields () และ getDeclaredFields (): getFields () สามารถเข้าถึงฟิลด์ที่ประกาศว่าเป็นสาธารณะในชั้นเรียนเท่านั้น ไม่สามารถเข้าถึงฟิลด์ส่วนตัวและสามารถเข้าถึงเขตข้อมูลสาธารณะที่สืบทอดมาจากชั้นเรียนอื่น ๆ GetDeclaredFields () สามารถเข้าถึงฟิลด์ทั้งหมดในชั้นเรียนซึ่งไม่มีส่วนเกี่ยวข้องกับสาธารณะส่วนตัวและป้องกัน แต่ไม่สามารถเข้าถึงฟิลด์ที่สืบทอดมาจากชั้นเรียนอื่น ๆ
* ความแตกต่างระหว่าง getMethods () และ getDeclaredMethods (): getMethods () สามารถเข้าถึงวิธีการที่ประกาศว่าเป็นสาธารณะในชั้นเรียนและวิธีการส่วนตัวไม่สามารถเข้าถึงได้และสามารถเข้าถึงวิธีการสาธารณะที่สืบทอดมาจากชั้นเรียนอื่น ๆ getDeclaredMethods () สามารถเข้าถึงทุกฟิลด์ในชั้นเรียนซึ่งไม่มีส่วนเกี่ยวข้องกับสาธารณะส่วนตัวและปกป้องและไม่สามารถเข้าถึงวิธีการที่สืบทอดมาจากชั้นเรียนอื่น ๆ
* ความแตกต่างระหว่าง getConstructors () และ getDeclaredConstructors (): getConstructors () สามารถเข้าถึงตัวสร้างที่ประกาศเป็นสาธารณะในชั้นเรียน; getDeclaredConstructors () สามารถเข้าถึงตัวสร้างทั้งหมดในชั้นเรียนและไม่มีส่วนเกี่ยวข้องกับสาธารณะส่วนตัวและการปกป้อง
รับและแก้ไขข้อมูลของอาร์เรย์ผ่านการสะท้อนกลับ
int [] temp = {1,2,3,4,5}; คลาส <?> demo = temp.getClass (). getComponentYpe (); system.out.println ("ประเภทอาร์เรย์:"+demo.getName ()); // intsystem.out.out.println ( "+array.getLength (temp)); // 5System.out.println (" องค์ประกอบแรกของอาร์เรย์: "+array.get (temp, 0)); // 1Array.set (temp, 0, 100); system.out.println (" องค์ประกอบแรกของการปรับเปลี่ยน รับประเภทอาร์เรย์cls.getComponentType ();ตรวจสอบว่าเป็นประเภทอาร์เรย์หรือไม่
cls.isarray ();
2 ตัวแทนชวา
โมเดลพร็อกซีเป็นรูปแบบการออกแบบ Java ที่ใช้กันทั่วไป ลักษณะของมันคือคลาสพร็อกซีและคลาสตัวแทนมีอินเทอร์เฟซเดียวกัน คลาสพร็อกซีส่วนใหญ่มีหน้าที่รับผิดชอบในการประมวลผลข้อความล่วงหน้าการกรองข้อความการส่งต่อข้อความไปยังคลาสผู้ได้รับมอบหมายและการประมวลผลข้อความหลังจากเหตุการณ์ มักจะมีความสัมพันธ์ระหว่างคลาสพร็อกซีและคลาสผู้แทน เป้าหมายของคลาสพร็อกซีเกี่ยวข้องกับวัตถุของคลาสตัวแทน วัตถุประสงค์ของคลาสพร็อกซีนั้นไม่ได้ใช้บริการอย่างแท้จริง แต่ให้บริการเฉพาะโดยเรียกใช้วิธีการที่เกี่ยวข้องของวัตถุคลาสตัวแทน
ตามระยะเวลาของการสร้างเอเจนต์คลาสตัวแทนสามารถแบ่งออกเป็นสองประเภท
•พร็อกซีแบบคงที่: สร้างโดยโปรแกรมเมอร์หรือสร้างซอร์สโค้ดโดยอัตโนมัติด้วยเครื่องมือเฉพาะจากนั้นรวบรวมมัน ก่อนที่โปรแกรมจะทำงานไฟล์. class ของคลาสพร็อกซีจะมีอยู่แล้ว
•พร็อกซีแบบไดนามิก: เมื่อโปรแกรมกำลังทำงานไบต์จะถูกสร้างขึ้นแบบไดนามิกโดยกลไกการสะท้อน Java
2.1 พร็อกซีคงที่
การนับอินเทอร์เฟซสาธารณะ {โมฆะสาธารณะ queryCount ();} countimpl คลาสสาธารณะใช้การนับจำนวน {โมฆะสาธารณะ queryCount () {system.out.println ("ดูวิธีบัญชี ... "); }} // Proxy Class Public Class CountProxy ใช้การนับจำนวน {countImpl ส่วนตัว countimpl; Public CountProxy (CountImpl CountImpl) {this.countimpl = countimpl; } @Override โมฆะสาธารณะ QueryCount () {System.out.println ("ก่อนการประมวลผลธุรกรรม"); CountImpl.QueryCount (); // เรียกวิธีการเรียนผู้แทน; System.out.println ("หลังการประมวลผลธุรกรรม"); }} // การทดสอบคลาสสาธารณะคลาสทดสอบ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {countimpl countimpl = ใหม่ countimpl (); CountProxy CountProxy = ใหม่ CountProxy (CountImpl); CountProxy.queryCount (); -สังเกตรหัสและพบว่าแต่ละคลาสพร็อกซีสามารถให้บริการเพียงหนึ่งอินเตอร์เฟสเท่านั้นดังนั้นพร็อกซีจำนวนมากเกินไปจะเกิดขึ้นอย่างหลีกเลี่ยงไม่ได้ในการพัฒนาโปรแกรม ยิ่งไปกว่านั้นการดำเนินการพร็อกซีทั้งหมดยกเว้นวิธีการโทรที่แตกต่างกันการดำเนินการอื่น ๆ ทั้งหมดจะเหมือนกันดังนั้นรหัสจะต้องทำซ้ำในเวลานี้ วิธีที่ดีที่สุดในการแก้ปัญหานี้คือการทำฟังก์ชั่นพร็อกซีทั้งหมดผ่านคลาสพร็อกซีดังนั้นจึงต้องทำโดยใช้พร็อกซีแบบไดนามิกในเวลานี้
2.2 Dynamic Agent
bytecode ของคลาสพร็อกซีแบบไดนามิกถูกสร้างขึ้นแบบไดนามิกโดยกลไกการสะท้อน Java เมื่อโปรแกรมทำงานโดยไม่จำเป็นต้องให้โปรแกรมเมอร์เขียนซอร์สโค้ดด้วยตนเอง คลาสพร็อกซีแบบไดนามิกไม่เพียง แต่ทำให้การเขียนโปรแกรมง่ายขึ้น แต่ยังช่วยปรับปรุงความสามารถในการปรับขนาดของระบบซอฟต์แวร์เนื่องจากกลไกการสะท้อน Java สามารถสร้างคลาสพร็อกซีแบบไดนามิกทุกประเภท
2.2.1 JDK Dynamic Proxy
พร็อกซีคลาสและอินเทอร์เฟซ InvocationHandler ในแพ็คเกจ java.lang.reflect ให้ความสามารถในการสร้างคลาสพร็อกซีแบบไดนามิก
อินเทอร์เฟซ InchectionHandler:
อินเทอร์เฟซ Public InvocationHandler {
วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุวิธีวิธีการวัตถุ [] args) โยนได้
-
คำอธิบายพารามิเตอร์:
พร็อกซีวัตถุ: หมายถึงวัตถุที่เป็นพร็อกซี
วิธีการ: วิธีที่จะเรียก
Object [] args: พารามิเตอร์ที่ต้องการเมื่อเรียกเมธอด
คุณสามารถนึกถึงคลาสย่อยของอินเทอร์เฟซ InvocationHandler เป็นคลาสการดำเนินการสุดท้ายของพร็อกซีแทนที่ proxysubject
พร็อกซีคลาส:
พร็อกซีคลาสเป็นคลาสปฏิบัติการที่เชี่ยวชาญในพร็อกซี มันสามารถสร้างคลาสการใช้งานแบบไดนามิกสำหรับอินเทอร์เฟซอย่างน้อยหนึ่งรายการผ่านคลาสนี้ คลาสนี้มีวิธีการดำเนินการต่อไปนี้:
วัตถุสแตติกสาธารณะ newproxyinstance (classloader loader, คลาส <?> [] อินเตอร์เฟส, rainticationhandler h) พ่น unledalargumentException
คำอธิบายพารามิเตอร์:
classloader loader: class loader
คลาส <?> [] อินเทอร์เฟซ: รับอินเทอร์เฟซทั้งหมด
InvocationHandler H: รับอินสแตนซ์ย่อยของอินเตอร์เฟส InvocationHandler
หากคุณต้องการทำพร็อกซีแบบไดนามิกให้เสร็จสิ้นคุณต้องกำหนดคลาสย่อยของอินเตอร์เฟส InvocationHandler เพื่อให้การดำเนินการเฉพาะของพร็อกซีเสร็จสมบูรณ์
หัวเรื่องอินเตอร์เฟส {สตริงสาธารณะบอกว่า (ชื่อสตริงอายุ int);} คลาส realsubject ใช้หัวเรื่อง {@Override สตริงสาธารณะบอกว่า (ชื่อสตริงอายุ int) {ชื่อคืน + "" + อายุ; }} // JDK Proxy Class MyInVocationHandler ใช้ indearCocationHandler {เป้าหมายวัตถุส่วนตัว = null; // ผูกวัตถุตัวแทนและส่งคืนพร็อกซีคลาสสาธารณะการผูกวัตถุ (เป้าหมายวัตถุ) {สิ่งนี้ เป้าหมาย = เป้าหมาย; ส่งคืน proxy.newproxyinstance (target.getClass (). getClassLoader (), target.getClass (). getInterfaces (), สิ่งนี้); // ผูกอินเตอร์เฟส (cglib ประกอบขึ้นสำหรับสิ่งนี้)} @Override วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุวิธีวิธีวัตถุ [] args) พ่น throwable {system.out.println ("ก่อนวิธี!"); อุณหภูมิอุณหภูมิ = method.invoke (เป้าหมาย, args); System.out.println ("After Method!"); กลับอุณหภูมิ; }} คลาสสวัสดี {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myinvocationhandhand demo = new MyinVocationHandler (); subs sub = (หัวเรื่อง) demo.bind (ใหม่ realsubject ()); String info = sub.say ("Rollen", 20); System.out.println (ข้อมูล); - อย่างไรก็ตามพร็อกซีแบบไดนามิกของ JDK อาศัยการใช้งานอินเตอร์เฟส หากบางคลาสไม่ใช้อินเทอร์เฟซพวกเขาไม่สามารถใช้พร็อกซี JDK ดังนั้นพวกเขาจึงจำเป็นต้องใช้พร็อกซีแบบไดนามิก CGLIB
2.2.2 CGLIB Dynamic Proxy
กลไกพร็อกซีแบบไดนามิกของ JDK สามารถใช้คลาสพร็อกซีที่ใช้อินเทอร์เฟซในขณะที่คลาสที่ไม่ใช้อินเตอร์เฟสไม่สามารถใช้พร็อกซีแบบไดนามิกของ JDK ได้
CGLIB ใช้พร็อกซีสำหรับชั้นเรียน หลักการของมันคือ การสร้างคลาสย่อยสำหรับคลาสเป้าหมายที่ระบุและแทนที่การปรับปรุงการใช้งานวิธีการ อย่างไรก็ตามเนื่องจากมีการใช้มรดกมาจึงไม่สามารถแก้ไขคลาสสุดท้ายได้
อินเตอร์เฟสสาธารณะ BookFacade {โมฆะสาธารณะ addbook (); } ชั้นเรียนสาธารณะ BookFacadeImpl1 {โมฆะสาธารณะ addbook () {system.out.println ("วิธีธรรมดาในการเพิ่มหนังสือ ... "); }} นำเข้า java.lang.reflect.method; นำเข้า net.sf.cglib.proxy.enhancer; นำเข้า net.sf.cglib.proxy.methodinterceptor; นำเข้า net.sf.cglib.proxy.methodproxy; // CGLIB Dynamic Proxy Class Public Class BookFacadecglib ใช้ MethodInterceptor {เป้าหมายวัตถุส่วนตัว; // ผูกวัตถุตัวแทนและส่งคืนพร็อกซีคลาสสาธารณะวัตถุ getInstance (เป้าหมายวัตถุ) {this.target = เป้าหมาย; Enhancer Enhancer = New Enhancer (); enhancer.setsuperclass (this.target.getClass ()); // วิธีการโทรกลับ Method.setCallback (นี่); // สร้างพร็อกซีออบเจ็กต์ return enhancer.create (); } @Override // วิธีการโทรกลับวัตถุสาธารณะการสกัดกั้น (วัตถุ obj, วิธีการ, วัตถุ [] args, methodproxy proxy) โยน throwable {system.out.println ("ฟังก์ชั่นเริ่มต้น"); อุณหภูมิวัตถุ = proxy.invokesuper (obj, args); System.out.println ("ฟังก์ชันสิ้นสุด"); กลับอุณหภูมิ; }} ระดับสาธารณะ testcglib {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {bookfacadecglib cglib = ใหม่ bookfacadecglib (); BookFacadeImpl1 BookCglib = (BookFacadeImpl1) cglib.getInstance (ใหม่ BookFacadeImpl1 ()); bookcglib.addbook (); -การสนทนาสั้น ๆ ข้างต้นเกี่ยวกับ Java Reflection และ Proxy เป็นเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่าคุณจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น