AOP คืออะไร
AOP (การเขียนโปรแกรมที่มุ่งเน้นด้านการเขียนโปรแกรมเชิงภาพ) สามารถกล่าวได้ว่าเป็นอาหารเสริมและการปรับปรุง OOP (การเขียนโปรแกรมเชิงวัตถุ) OOP แนะนำแนวคิดเช่นการห่อหุ้มมรดกและความหลากหลายเพื่อสร้างลำดับชั้นของวัตถุเพื่อจำลองการรวบรวมพฤติกรรมสาธารณะ เมื่อเราจำเป็นต้องแนะนำพฤติกรรมสาธารณะกับวัตถุที่กระจัดกระจาย OOP ดูเหมือนจะไร้อำนาจ นั่นคือ OOP ช่วยให้คุณกำหนดความสัมพันธ์จากบนลงล่าง แต่ไม่เหมาะสำหรับการกำหนดความสัมพันธ์จากซ้ายไปขวา ตัวอย่างเช่นฟังก์ชั่นการบันทึก รหัสบันทึกมักจะกระจัดกระจายในแนวนอนในทุกระดับวัตถุโดยไม่มีความสัมพันธ์ใด ๆ กับฟังก์ชันการทำงานหลักของวัตถุที่มันกระจัดกระจาย เช่นเดียวกับรหัสประเภทอื่น ๆ เช่นความปลอดภัยการจัดการข้อยกเว้นและความโปร่งใส รหัสที่ไม่เกี่ยวข้องประเภทนี้กระจัดกระจายไปทุกหนทุกแห่งเรียกว่ารหัสตัดข้าม ในการออกแบบ OOP มันทำให้เกิดการทำซ้ำรหัสจำนวนมากซึ่งไม่เอื้อต่อการใช้ซ้ำของแต่ละโมดูล
การแนะนำ
รูปแบบการออกแบบ Java ที่ฉันเขียนเมื่อไม่นานมานี้ - รูปแบบพร็อกซี เมื่อเร็ว ๆ นี้เมื่อฉันดูที่ฤดูใบไม้ผลิ AOP ฉันรู้สึกว่าควรมีการเชื่อมต่ออย่างใกล้ชิดในรูปแบบพร็อกซีดังนั้นฉันจึงตัดสินใจที่จะเข้าใจหลักการดำเนินการของฤดูใบไม้ผลิ AOP
เมื่อพูดถึง AOP เราต้องพูดถึง OOP แนวคิดของการห่อหุ้มมรดกและความหลากหลายได้รับการแนะนำใน OOP เพื่อสร้างลำดับชั้นของวัตถุเพื่อจำลองการรวบรวมพฤติกรรมสาธารณะ อย่างไรก็ตามหากเราจำเป็นต้องแนะนำชิ้นส่วนทั่วไปสำหรับวัตถุบางอย่าง OOP จะแนะนำรหัสที่ซ้ำกันจำนวนมาก ตัวอย่างเช่น: ฟังก์ชั่นการบันทึก
เทคโนโลยี AOP ใช้เทคนิคที่เรียกว่า "crosscutting" เพื่อผ่าด้านในของวัตถุที่ห่อหุ้มและห่อหุ้มพฤติกรรมทั่วไปที่ส่งผลกระทบต่อหลายคลาสลงในโมดูลที่นำมาใช้ซ้ำได้ซึ่งสามารถลดการทำซ้ำรหัสของระบบลดการมีเพศสัมพันธ์ระหว่างโมดูลและอำนวยความสะดวกในการดำเนินงานในอนาคตและการบำรุงรักษา AOP แบ่งระบบซอฟต์แวร์ออกเป็นสองส่วน: ความกังวลหลักและความสนใจข้าม กระบวนการหลักของการประมวลผลทางธุรกิจคือการมุ่งเน้นหลักและส่วนที่มีส่วนเกี่ยวข้องเพียงเล็กน้อยคือการโฟกัสแบบตัดขวาง ลักษณะหนึ่งของความกังวลเกี่ยวกับการตัดข้ามคือพวกเขามักจะเกิดขึ้นในความกังวลหลักหลายประการและมีความคล้ายคลึงกันทุกที่ ตัวอย่างเช่นการตรวจสอบสิทธิ์การอนุญาตการบันทึกและการประมวลผลธุรกรรม
หลักการดำเนินการ
เมื่อฉันเรียนรู้โหมดพร็อกซีฉันได้เรียนรู้ว่าโหมดพร็อกซีแบ่งออกเป็นพร็อกซีแบบไดนามิกและพร็อกซีแบบคงที่ ตอนนี้เราจะใช้เฟรมเวิร์ก AOP ของเราเองก่อนตามรูปแบบพร็อกซีจากนั้นศึกษาหลักการดำเนินการของ AOP ของฤดูใบไม้ผลิ
ครั้งแรกมันถูกนำไปใช้กับพร็อกซีแบบคงที่ กุญแจสำคัญในการพร็อกซีแบบคงที่คือการใช้อินเทอร์เฟซทั่วไประหว่างวัตถุพร็อกซีและวัตถุเป้าหมายและวัตถุพร็อกซีเก็บข้อมูลอ้างอิงไปยังวัตถุเป้าหมาย
รหัสอินเตอร์เฟสสาธารณะ:
อินเทอร์เฟซสาธารณะ ihello {/*** วิธีการทางธุรกิจ*@param str*/void sayhello (string str);} รหัสคลาสเป้าหมาย: คลาสสาธารณะคลาสสวัสดีนำ ihello {@overridepublic void sayhello (str str) {system.out.println ("hello"+str); สำหรับรหัสคลาสพร็อกซีเราเพิ่มฟังก์ชั่นการบันทึกลงในนั้นและดำเนินการวิธีการเฉพาะก่อนและหลังวิธีการเริ่มต้น มันไม่คล้ายกับ AOP หรือไม่
Proxyhello คลาสสาธารณะใช้ ihello {ส่วนตัว ihello สวัสดี; Proxyhello สาธารณะ (Ihello Hello) {super (); this.hello = hello;}@overridepublic void sayshello (string str) {logger.start (); // เพิ่มวิธีการเฉพาะ hello.sayhello (str); logger.end ();}}} รหัสคลาสบันทึก:
Logger คลาสสาธารณะ {โมฆะคงที่สาธารณะเริ่มต้น () {system.out.println (วันที่ใหม่ ()+ "ทักทายเริ่มต้น ... ");} โมฆะคงที่สาธารณะคง รหัสทดสอบ:
การทดสอบระดับสาธารณะ {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ihello hello = new proxyhello (hello ใหม่ ()); // ถ้าเราต้องการฟังก์ชั่นการบันทึกให้ใช้พร็อกซีคลาส // ihello สวัสดี = hello new (); // ถ้าเราไม่ต้องการฟังก์ชั่นการบันทึก -ด้วยวิธีนี้เราใช้ AOP ที่ง่ายที่สุด แต่จะมีปัญหา: ถ้าเรามีชั้นเรียนมากมายเช่นสวัสดีเราควรเขียนชั้นเรียนมากมายเช่น HelloFroxy หรือไม่? ในความเป็นจริงมันเป็นสิ่งที่ลำบากมาก หลังจาก JDK1.3 แล้ว JDK ให้เราด้วยคลาส API java.lang.reflect.invocationhandler คลาสนี้ช่วยให้เราสามารถทำบางสิ่งบางอย่างสำหรับบางวิธีเมื่อ JVM เรียกวิธีการของคลาสที่แน่นอน มาใช้การใช้งานพร็อกซีแบบไดนามิกกันเถอะ
การใช้งานพร็อกซีแบบไดนามิกส่วนใหญ่ใช้ InvocationHandler และฉีดวัตถุเป้าหมายลงในวัตถุพร็อกซีโดยใช้กลไกการสะท้อนกลับเพื่อดำเนินการวิธีการวัตถุเป้าหมาย
การใช้งานอินเตอร์เฟสนั้นเหมือนกับพร็อกซีแบบคงที่รหัสพร็อกซีคลาส:
คลาสสาธารณะ Dynaproxyhello ใช้ InvocationHandler {เป้าหมายวัตถุส่วนตัว; // วัตถุเป้าหมาย/*** อินสแตนซ์วัตถุเป้าหมายผ่านการสะท้อนกลับ* @param Object* @return*/วัตถุสาธารณะผูก (วัตถุวัตถุ) {this.target = object; return proxy.newproxyinstance สิ่งนี้);}@overridepublic object revoke (พร็อกซีวัตถุ, วิธีวิธี, วัตถุ [] args) โยน {object result = null; logger.start (); // เพิ่มวิธีการเพิ่มเติม // วิธีการเรียกใช้วัตถุเป้าหมายผ่านผลการสะท้อนกลับ รหัสชั้นเรียนทดสอบ:
ชั้นเรียนสาธารณะ Dynatest {โมฆะสาธารณะคงที่หลัก (String [] args) {ihello hello = (ihello) ใหม่ dynaproxyhello (). ผูก (hello ใหม่ ()); // ถ้าเราต้องการฟังก์ชั่นการบันทึกให้ใช้ proxy class // ihello hello = hello new หลังจากอ่านรหัสข้างต้นอาจมีปัญหาเมื่อเทียบกับฤดูใบไม้ผลิ AOP คลาสบันทึกสามารถพิมพ์ได้ก่อนและหลังวิธีการเท่านั้น แต่ AOP ควรจะสามารถดำเนินการได้เมื่อตรงตามเงื่อนไข วัตถุ Dynapoxyhello ทั้งหมดและวัตถุการดำเนินการบันทึก (logger) ทั้งหมดสามารถถอดรหัสได้หรือไม่?
เมื่อดูการใช้งานรหัสต่อไปนี้มันจะแยกวัตถุ Dynapoxyhello และวัตถุดำเนินการบันทึก (logger):
เราจำเป็นต้องเพิ่มรหัสการดำเนินการบันทึก (หรือรหัสการดำเนินการอื่น ๆ ) ก่อนหรือหลังวิธีการของวัตถุพร็อกซี จากนั้นเราสามารถนามธรรมอินเตอร์เฟสซึ่งมีเพียงสองวิธีเท่านั้น: วิธีหนึ่งคือวิธีการที่ดำเนินการก่อนที่วัตถุพร็อกซีต้องการดำเนินการวิธีการ เราตั้งชื่อมันเริ่มต้นและวิธีที่สองคือวิธีการที่ดำเนินการหลังจากวัตถุพร็อกซีดำเนินการวิธีการและเราตั้งชื่อมันสิ้นสุด
อินเทอร์เฟซของ Logger:
อินเทอร์เฟซสาธารณะ ilogger {เป็นโมฆะเริ่มต้น (วิธีการ); void end (วิธีการ);} การใช้งานอินเทอร์เฟซ Logger:
คลาสสาธารณะ Dlogger ใช้ ilogger {@overridepublic เป็นโมฆะเริ่มต้น (วิธีการ) {system.out.println (วันที่ใหม่ () + method.getName () + "ทักทายเริ่ม ... ");}@methodname) พร็อกซีคลาสไดนามิก:
ชั้นเรียนสาธารณะ Dynaproxyhello ใช้ InvocationHandler {// Call Object Object Object Proxy; // เป้าหมายวัตถุเป้าหมายวัตถุส่วนตัว; การผูกวัตถุสาธารณะ (เป้าหมายวัตถุ, พร็อกซีวัตถุ) {this.target = target; this.proxy = proxy; ส่งคืน proxy.newproxyinstance (this.target.target. this.target.getClass (). getInterfaces (), this);}@overridepublic Object เรียกใช้ (พร็อกซีวัตถุวิธีการวิธีการวัตถุ [] args) โยน {object result = null; // การสะท้อนได้รับการเริ่มต้นของผู้ประกอบการ คลาส [] {method.class}); // reflection ดำเนินการวิธีการเริ่มต้น start.invoke (this.proxy, วัตถุใหม่ [] {this.proxy.getClass ()}); // ดำเนินการวิธีดั้งเดิมเพื่อประมวลผลวิธีการของวัตถุ คลาส [] {method.class}); // reflection ดำเนินการวิธีการสิ้นสุด end.invoke (this.proxy, วัตถุใหม่ [] {method}); return result;}} รหัสทดสอบ:
Dynatest ระดับสาธารณะ {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {ihello hello = (ihello) ใหม่ dynaproxyhello () ผูก (hello ใหม่ (), dlogger ใหม่ ()); // ถ้าเราต้องการฟังก์ชั่นการบันทึก สวัสดี Sayhello ("พรุ่งนี้");}} จากตัวอย่างข้างต้นเราสามารถพบได้ว่าผ่านเทคโนโลยีพร็อกซิงและการส่งสัญญาณแบบไดนามิกฟังก์ชั่นของ AOP ได้ถูกนำไปใช้โดยทั่วไป หากเราต้องการพิมพ์บันทึกก่อนที่จะดำเนินการวิธีการเราไม่สามารถใช้วิธีการสิ้นสุด () เพื่อให้เราสามารถควบคุมเวลาการพิมพ์ หากเราต้องการให้วิธีการที่ระบุในการพิมพ์บันทึกเราจะต้องเพิ่มการตัดสินในชื่อวิธีการลงในวิธีการเรียกใช้ () ชื่อวิธีสามารถเขียนในไฟล์ XML เพื่อให้เราสามารถแยกมันด้วยไฟล์การกำหนดค่าเพื่อให้เราใช้เฟรมเวิร์กสปริงแบบง่าย
เนื้อหาข้างต้นคือหลักการใช้งาน Spring AOP ที่แนะนำโดยบรรณาธิการ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ!