1. คำนำ
ในโครงการก่อนหน้านี้ฉันไม่ค่อยให้ความสนใจกับการดำเนินการเฉพาะและทฤษฎีของฤดูใบไม้ผลิ AOP ฉันเพิ่งเข้าใจสั้น ๆ ว่า AOP คืออะไรและจะใช้มันอย่างไร ฉันเห็นโพสต์บล็อกที่เขียนได้ดีดังนั้นฉันจึงมาเรียนรู้
AOP
AOP (การเขียนโปรแกรมที่มุ่งเน้นด้าน) นั่นคือการเขียนโปรแกรมเชิงภาพสามารถกล่าวได้ว่าเป็นอาหารเสริมและการปรับปรุง OOP (การเขียนโปรแกรมเชิงวัตถุ) OOP แนะนำแนวคิดเช่นการห่อหุ้มมรดกและความหลากหลายเพื่อสร้างลำดับชั้นของวัตถุที่ใช้ในการจำลองการรวบรวมพฤติกรรมสาธารณะ อย่างไรก็ตาม OOP อนุญาตให้นักพัฒนากำหนดความสัมพันธ์ในแนวตั้ง แต่ไม่เหมาะสำหรับการกำหนดความสัมพันธ์ในแนวนอนเช่นฟังก์ชั่นการบันทึก รหัสบันทึกมักจะกระจัดกระจายในแนวนอนในทุกระดับวัตถุและไม่มีส่วนเกี่ยวข้องกับฟังก์ชั่นหลักของวัตถุที่เกี่ยวข้อง รหัสที่ไม่เกี่ยวข้องประเภทนี้กระจัดกระจายไปทุกหนทุกแห่งเรียกว่า Cross Cutting ในการออกแบบ OOP มันทำให้เกิดการทำซ้ำรหัสจำนวนมากซึ่งไม่เอื้อต่อการใช้ซ้ำของแต่ละโมดูล
ในทางตรงกันข้ามเทคโนโลยี AOP ใช้เทคนิคที่เรียกว่า "crosscutting" เพื่อผ่าด้านในของวัตถุที่ห่อหุ้มและห่อหุ้มพฤติกรรมทั่วไปเหล่านั้นที่ส่งผลกระทบต่อคลาสหลายคลาสลงในโมดูลที่นำมาใช้ซ้ำได้และตั้งชื่อ "แง่มุม" ซึ่งเป็นแง่มุม ส่วนที่เรียกว่า "ส่วน" นั้นถูกห่อหุ้มด้วยตรรกะหรือความรับผิดชอบที่ไม่เกี่ยวข้องกับธุรกิจ แต่เรียกว่าร่วมกันโดยโมดูลธุรกิจซึ่งสะดวกสำหรับการลดรหัสที่ซ้ำกันของระบบลดการมีเพศสัมพันธ์ระหว่างโมดูลและเอื้อต่อการดำเนินงานในอนาคตและการบำรุงรักษา
ด้วยการใช้เทคโนโลยี "crosscutting" AOP แบ่งระบบซอฟต์แวร์ออกเป็นสองส่วน: ความกังวลหลักและความกังวลข้ามการตัดข้าม กระบวนการหลักของการประมวลผลทางธุรกิจคือการมุ่งเน้นหลักและส่วนที่มีส่วนเกี่ยวข้องเพียงเล็กน้อยคือโฟกัสแบบตัดขวาง คุณลักษณะหนึ่งของข้อกังวลข้ามการตัดคือพวกเขามักจะเกิดขึ้นในความกังวลหลักหลายประการและมีความคล้ายคลึงกันในสถานที่ต่าง ๆ เช่นการรับรองความถูกต้องการอนุญาตบันทึกและสิ่งต่าง ๆ บทบาทของ AOP คือการแยกข้อกังวลต่าง ๆ ในระบบและแยกข้อกังวลหลักออกจากข้อกังวลข้ามการตัด
แนวคิดหลักของ AOP
1. จุดสนใจข้ามตัด
วิธีใดในการสกัดกั้นและวิธีจัดการกับวิธีการหลังจากการสกัดกั้น ข้อกังวลเหล่านี้เรียกว่าข้อกังวลข้ามการตัด
2. ส่วน (แง่มุม)
ชั้นเรียนเป็นนามธรรมของคุณสมบัติของวัตถุและส่วนต่าง ๆ เป็นนามธรรมของข้อกังวลข้ามการตัดข้าม
3. จุด Joinpoint
จุดที่สกัดกั้นเนื่องจากสปริงรองรับจุดเชื่อมต่อประเภทวิธีการเท่านั้นดังนั้นจุดเชื่อมต่อในสปริงหมายถึงวิธีการที่สกัดกั้น ในความเป็นจริงจุดเชื่อมต่ออาจเป็นฟิลด์หรือตัวสร้าง
4. Pointcut
คำจำกัดความของจุดเชื่อมต่อที่สกัดกั้น
5. การแจ้งเตือน (คำแนะนำ)
การแจ้งเตือนที่เรียกว่าหมายถึงรหัสที่จะดำเนินการหลังจากสกัดกั้นจุดเชื่อมต่อ การแจ้งเตือนแบ่งออกเป็นห้าหมวดหมู่: การตั้งค่าไว้ล่วงหน้า, โพสต์ชุด, ข้อยกเว้น, ขั้นสุดท้ายและการแจ้งเตือนโดยรอบ
6. วัตถุเป้าหมาย
วัตถุเป้าหมายของพร็อกซี
7. สาน
กระบวนการใช้ร่องกับวัตถุเป้าหมายและทำให้เกิดการสร้างวัตถุพร็อกซี
8. บทนำ
โดยไม่ต้องแก้ไขรหัสการแนะนำสามารถเพิ่มวิธีการหรือฟิลด์บางอย่างแบบไดนามิกในชั้นเรียนในช่วงเวลารันไทม์
การสนับสนุนของฤดูใบไม้ผลิสำหรับ AOP
ตัวแทน AOP ในฤดูใบไม้ผลิมีหน้าที่ในการสร้างและการจัดการคอนเทนเนอร์ IOC ของฤดูใบไม้ผลิและการอ้างอิงของมันยังได้รับการจัดการโดยคอนเทนเนอร์ IOC ดังนั้นพร็อกซี AOP สามารถกำหนดเป้าหมายอินสแตนซ์ถั่วอื่น ๆ โดยตรงในคอนเทนเนอร์และความสัมพันธ์นี้สามารถให้ได้โดยการฉีดพึ่งพาของคอนเทนเนอร์ IOC กฎสำหรับการสร้างพร็อกซีในฤดูใบไม้ผลิคือ:
1. โดยค่าเริ่มต้น Java Dynamic Proxy ใช้เพื่อสร้างพร็อกซี AOP เพื่อให้คุณสามารถสร้างพร็อกซีสำหรับอินเทอร์เฟซใด ๆ
2. เมื่อคลาสที่ต้องการพร็อกซีไม่ใช่อินเทอร์เฟซพร็อกซีสปริงจะเปลี่ยนไปใช้พร็อกซี CGLIB และยังสามารถบังคับ CGLIB ให้ใช้
การเขียนโปรแกรม AOP เป็นเรื่องง่ายมาก เมื่อมองไปที่การเขียนโปรแกรม AOP โปรแกรมเมอร์ต้องเข้าร่วมในสามส่วนเท่านั้น:
1. กำหนดองค์ประกอบธุรกิจทั่วไป
2. กำหนดจุดเข้าจุดเริ่มต้นหนึ่งจุดอาจตัดส่วนประกอบธุรกิจหลายรายการ
3. กำหนดการประมวลผลที่ปรับปรุงแล้ว การประมวลผลขั้นสูงคือการดำเนินการประมวลผลที่ทอเป็นส่วนประกอบทางธุรกิจทั่วไปในกรอบ AOP
ดังนั้นกุญแจสำคัญในการเขียนโปรแกรม AOP คือการกำหนดจุดเริ่มต้นและกำหนดการประมวลผลการปรับปรุง เมื่อกำหนดจุดเข้าและการประมวลผลการปรับปรุงที่เหมาะสมเฟรมเวิร์ก AOP จะสร้างพร็อกซี AOP โดยอัตโนมัตินั่นคือวิธีการของพร็อกซีอ็อบเจ็กต์ = การประมวลผลการปรับปรุง + วิธีการของวัตถุพร็อกซี
นี่คือเทมเพลตไฟล์ Spring AOP .xml ชื่อ AOP.XML และเนื้อหาที่ตามมาจะถูกขยายใน AOP.XML:
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://ww.w3.org/2001/xml xmlns: aop = "http://www.springframework.org/schema/aop" xmlns: tx = "http://www.springframework.org/schema/tx" xsi: schemalocation = "http:/ http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://ww.springframework http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> </ beans>
การใช้ AOP อย่างง่ายขึ้นอยู่กับฤดูใบไม้ผลิ
โปรดทราบว่าก่อนที่จะอธิบายให้ฉันอธิบาย: เพื่อเรียกใช้รหัสสำเร็จไม่เพียงพอที่จะใช้แพ็คเกจ JAR ที่จัดทำโดย Spring ให้กับนักพัฒนา กรุณาดาวน์โหลดแพ็คเกจสองขวดออนไลน์:
1. aopalliance.jar
2. appectjweaver.jar
เริ่มอธิบายวิธีการใช้งาน XML ของ Spring AOP ก่อนอื่นให้กำหนดอินเทอร์เฟซ:
อินเทอร์เฟซสาธารณะ helloWorld {void printhelloworld (); เป็นโมฆะ doprint ();} กำหนดคลาสการใช้งานอินเตอร์เฟสสองคลาส:
ชั้นเรียนสาธารณะ HelloWorldimpl1 ใช้ helloWorld {โมฆะสาธารณะ Printhelloworld () {System.out.println ("ป้อน HelloWorldimpl1.printhelloworld ()"); } โมฆะสาธารณะ doprint () {system.out.println ("ป้อน helloWorldimpl1.doprint ()"); กลับ ; - ชั้นเรียนสาธารณะ HelloWorldimpl2 ใช้ helloWorld {โมฆะสาธารณะ Printhelloworld () {System.out.println ("ป้อน HelloWorldimpl2.printhelloworld ()"); } โมฆะสาธารณะ doprint () {system.out.println ("ป้อน helloWorldimpl2.doprint ()"); กลับ ; - โฟกัสข้ามการตัดนี่คือเวลาการพิมพ์:
Public Class TimeHandler {Public Void Printtime () {System.out.println ("currenttime =" + system.currentTimeMillis ()); - ด้วยคลาสทั้งสามนี้คุณสามารถใช้ AOP Spring Simple ได้ ดูการกำหนดค่าของ aop.xml:
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://ww.w3.org/2001/xml xmlns: aop = "http://www.springframework.org/schema/aop" xmlns: tx = "http://www.springframework.org/schema/tx" xsi: schemalocation = "http:/ http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://ww.springframework http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> <bean id =" HelloWorldimpl1 "/> <bean id =" HelloWorldimpl2 "/> <bean id =" TimeHandler " <aop: pointcut id = "addallmethod" expression = "การดำเนินการ (* com.xrq.aop.helloworld.* (.. ))" /> <aop: ก่อนวิธี = "printtime" pointcut-ref = "addallmethod" />
เขียนฟังก์ชั่นหลักเพื่อเรียกมันว่า:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {applicationcontext ctx = ใหม่ classpathxmlapplicationContext ("aop.xml"); HelloWorld HW1 = (HelloWorld) ctx.getBean ("HelloWorldimpl1"); HelloWorld HW2 = (HelloWorld) ctx.getBean ("HelloWorldimpl2"); hw1.printhelloworld (); System.out.println (); hw1.doprint (); System.out.println (); System.out.println (); hw2.printhelloworld (); System.out.println (); hw2.doprint ();} ผลการทำงานคือ:
CurrentTime = 1446129611993ENTER HELLOWORLDIMPL1.PRINTHOLLOWORLD () CurrentTime = 1446129611993CurrentTime = 1446129611994ENTER HELLOWORLDIMPL1.DOPRINT () HelloWorldimpl2.printhelloworld () currenttime = 1446129611994currenttime = 14461296119944ENTER HELLOWORLDIMPL2.DOPRINT () CurrentTime = 14461296119944
ฉันเห็นว่าวิธีการทั้งหมดของทั้งสองคลาสการใช้งานของอินเทอร์เฟซ HelloWorld ได้ถูกเพิ่มเข้าไปในพร็อกซีและเนื้อหาพร็อกซีเป็นเวลาการพิมพ์
รายละเอียดเพิ่มเติมเกี่ยวกับการใช้ AOP ที่ใช้สปริง
1. เพิ่มข้อกังวลข้ามการตัดและพิมพ์บันทึก คลาส Java คือ:
ชั้นเรียนสาธารณะ LOGHANDLER {โมฆะสาธารณะ logBeFore () {system.out.println ("บันทึกก่อนวิธีการ"); } โมฆะสาธารณะ logafter () {system.out.println ("บันทึกหลังจากวิธีการ"); -<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://ww.w3.org/2001/xml xmlns: aop = "http://www.springframework.org/schema/aop" xmlns: tx = "http://www.springframework.org/schema/tx" xsi: schemalocation = "http:/ http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://ww.springframework http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> <bean id =" helloWorldimpl1 "/> <bean id =" helloWorldimpl2 "/> <bean id =" timehandler "/> ref = "timehandler" order = "1"> <aop: pointcut id = "addtime" expression = "การดำเนินการ (* com.xrq.aop.helloworld.* (.. ))" /> <aop: before method = "pointcut-ref-ref =" addtime " /> <aop: id = "log" ref = "loghandler" order = "2"> <aop: pointcut id = "printlog" expression = "การดำเนินการ (* com.xrq.aop.helloworld.* (.. ))" /> <aop: method = "logbefore" pointcut-ref = "printlog </aop: แง่มุม> </aop: config> </ beans>
คลาสทดสอบยังคงไม่เปลี่ยนแปลงและผลการพิมพ์คือ:
currenttime = 1446130273734log ก่อนเมธอเรนเดอร์ helloWorldimpl1.printhelloworld () บันทึกหลังจากวิธีการเวลา = 1446130273735CurrentTime = 1446130273736LOG 1446130273736log ก่อนเมธอเดนเตอร์ HelloWorldimpl2.printhelloworld () บันทึกหลังจาก MethodCurrentTime = 1446130273736CurrentTime = 1446130273737log
มีสองวิธีในการใช้ Loghandler ก่อนเวลา TimeHandler:
(1) มีแอตทริบิวต์คำสั่งซื้อในด้านและจำนวนแอตทริบิวต์คำสั่งซื้อคือลำดับของการตัดข้ามจุดโฟกัส
(2) กำหนด loghandler ก่อนเวลา timehandler ฤดูใบไม้ผลิใช้คำจำกัดความของการจัดลำดับเป็นลำดับการทอโดยค่าเริ่มต้น
2. ฉันแค่ต้องการสานบางวิธีลงในอินเทอร์เฟซ
เพียงปรับเปลี่ยนนิพจน์ pointcut:
<? xml version = "1.0" การเข้ารหัส = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://ww.w3.org/2001/xml xmlns: aop = "http://www.springframework.org/schema/aop" xmlns: tx = "http://www.springframework.org/schema/tx" xsi: schemalocation = "http:/ http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://ww.springframework http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> <bean id =" helloWorldimpl1 "/> <bean id =" helloWorldimpl2 "/> <bean id =" timehandler "/> ref = "timehandler" order = "1"> <aop: pointcut id = "addtime" expression = "การดำเนินการ (* com.xrq.aop.helloworld.print* (.. ))" /> <aop: method = "pintcut-red-ref =" Addtime " id = "log" ref = "loghandler" order = "2"> <aop: pointcut id = "printlog" expression = "การดำเนินการ (* com.xrq.aop.helloworld.do* (.. ))" /> <aop: ก่อนวิธี = </aop: แง่มุม> </aop: config> </ beans>
หมายความว่า TimeHandler จะสานวิธีที่เริ่มต้นที่จุดเริ่มต้นของการพิมพ์อินเตอร์เฟส HelloWorld เท่านั้น Loghandler จะสานวิธีที่เริ่มต้นที่จุดเริ่มต้นของอินเตอร์เฟส HelloWorld เท่านั้น
3. บังคับ cglib เพื่อสร้างพร็อกซี
ดังที่ได้กล่าวไว้ก่อนหน้านี้สปริงใช้พร็อกซีแบบไดนามิกหรือ cglib เพื่อสร้างพร็อกซี สปริงรุ่นที่สูงขึ้นจะเลือกโดยอัตโนมัติว่าจะใช้พร็อกซีแบบไดนามิกหรือ CGLIB เพื่อสร้างเนื้อหาพร็อกซี แน่นอนว่าเรายังสามารถบังคับให้ CGLIB สร้างพร็อกซีนั่นคือมีแอตทริบิวต์ "พร็อกซี-เป้าหมาย-คลาส" ใน <AOP: config> หากค่าแอตทริบิวต์นี้ถูกตั้งค่าเป็นจริงพร็อกซีที่ใช้คลาสจะทำงาน หากการตั้งค่า proxy-target-class ถูกตั้งค่าเป็นเท็จหรือแอตทริบิวต์นี้จะถูกละเว้นพร็อกซีที่ใช้อินเตอร์เฟสจะใช้งานได้
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น