@Transactional @async และคำอธิบายประกอบอื่น ๆ ไม่ทำงาน
ก่อนหน้านี้หลายคนได้พบกับสถานการณ์บางอย่างที่คำอธิบายประกอบไม่ทำงานเมื่อใช้ @Transactional, @async และคำอธิบายประกอบอื่น ๆ ในฤดูใบไม้ผลิ
ทำไมสถานการณ์เหล่านี้ถึงเกิดขึ้น? เนื่องจากฟังก์ชั่นของคำอธิบายประกอบเหล่านี้ถูกนำมาใช้จริงโดย Spring AOP และหลักการดำเนินการของพวกเขาจะถูกนำไปใช้ผ่านพร็อกซี
พร็อกซีไดนามิก JDK
มาทำความเข้าใจกับหลักการพื้นฐานของพร็อกซีไดนามิก JDK ด้วยตัวอย่างง่ายๆ:
// Target Class Interface Public Interface JDKPROXYTESTService {Void Run ();} // คลาส Public Class Public Class JDKPROXYTESTServiceImpl ใช้ JDKPROXYTESTService {โมฆะสาธารณะ }} // พร็อกซีคลาสสาธารณะคลาส Public Testjdkproxy ใช้ InvocationHandler {วัตถุส่วนตัว TargetObject; // พร็อกซีเป้าหมายวัตถุ // สร้างวัตถุพร็อกซีวัตถุสาธารณะวัตถุ newproxy (วัตถุเป้าหมาย) {this.targetObject = targetObject; ส่งคืน proxy.newproxyinstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), สิ่งนี้); } // ใช้การสะท้อนกลับเพื่อดำเนินการเพิ่มประสิทธิภาพเชิงตรรกะบนวัตถุสาธารณะลอจิกดั้งเดิมเรียกใช้ (พร็อกซีวัตถุวิธีวิธีการวัตถุ [] args) โยนได้ที่ throwable {// จำลองการทำธุรกรรมเริ่มต้น umpebeginTransaction (); // วัตถุการดำเนินการดั้งเดิม ret = method.invoke (targetObject, args); // การส่งธุรกรรมการทำธุรกรรม MOCK ASSUMECOMMITRANSACTIONACTION (); ผลตอบแทนผลตอบแทน; } โมฆะส่วนตัว iseBegInTransaction () {system.out.println ("การทำธุรกรรมการเยาะเย้ยเริ่มต้น ... "); } โมฆะส่วนตัว AssumeCommitTransaction () {System.out.println ("การส่งธุรกรรมจำลอง ... "); }} // ทดสอบการทดสอบระดับสาธารณะ {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {testjdkproxy jdkproxy = ใหม่ testjdkproxy (); jdkproxytestservice proxy = (jdkproxytestservice) jdkproxy.newproxy (ใหม่ jdkproxytestserviceimpl ()); proxy.run (); -ตัวอย่างข้างต้นควรจะสามารถอธิบายหลักการของพร็อกซีไดนามิก JDK ได้อย่างชัดเจน มันใช้กลไกการสะท้อนกลับเพื่อสร้างคลาสที่ไม่ระบุชื่อซึ่งใช้อินเทอร์เฟซพร็อกซีและเรียกใช้ InvokeHandler เพื่อจัดการก่อนที่จะเรียกวิธีการเฉพาะ เมื่อเราเรียกวิธีการผ่านวัตถุพร็อกซีคลาสเราจะเรียกวิธีการเรียกใช้ก่อนแล้วเรียกใช้วิธีดั้งเดิม ด้วยวิธีนี้เราสามารถเพิ่มตรรกะการประมวลผลได้อย่างสม่ำเสมอก่อนและหลังตรรกะวิธีการดั้งเดิม
ฤดูใบไม้ผลิยังมีวิธีพร็อกซีแบบไดนามิกที่เป็นพร็อกซีแบบไดนามิก CGLIB มันโหลดไฟล์คลาสของคลาสพร็อกซีวัตถุและประมวลผลโดยการแก้ไข bytecode เพื่อสร้างคลาสย่อย แม้ว่าวิธีการจัดการจะแตกต่างกัน แต่ความคิดของเอเจนซี่นั้นสอดคล้องกัน
หากวัตถุเป้าหมายที่เป็นพร็อกซีใช้อินเทอร์เฟซสปริงจะใช้พร็อกซีไดนามิก JDK โดยค่าเริ่มต้น อินเทอร์เฟซทั้งหมดที่นำมาใช้โดยประเภทเป้าหมายนี้จะถูกพร็อกซี หากวัตถุเป้าหมายไม่ได้ใช้อินเทอร์เฟซใด ๆ จะสร้างพร็อกซี CGLIB
สปริง AOP คำอธิบายประกอบความล้มเหลวและความละเอียด
จากการวิเคราะห์ด้านบนของหลักการพร็อกซีแบบไดนามิกให้ดูที่ปัญหาทั่วไปสองประการต่อไปนี้:
ในคลาสเดียวกันเมธอด A วิธีการ B (หมายเหตุประกอบกับวิธี B) และคำอธิบายประกอบไม่ถูกต้อง
สำหรับคำอธิบายประกอบ AOP ในฤดูใบไม้ผลิทั้งหมดหากฤดูใบไม้ผลิพบคำอธิบายประกอบดังกล่าวเมื่อสแกนถั่วมันจะสร้างวัตถุพร็อกซีแบบไดนามิก
คำอธิบายประกอบนี้ใช้ได้หากคุณต้องการเรียกวิธี A A ด้วยคำอธิบายประกอบโดยตรงผ่านวัตถุของคลาส X เนื่องจากในเวลานี้ฤดูใบไม้ผลิจะกำหนดว่ามีคำอธิบายประกอบ AOP เกี่ยวกับวิธีการที่คุณกำลังจะโทรหาและจากนั้นจะใช้วัตถุพร็อกซีของคลาส X เพื่อโทร
แต่สมมติว่าวิธี A ในคลาส X จะเรียกวิธี B ด้วยคำอธิบายประกอบและคุณยังต้องการเรียกวิธีการผ่านวัตถุของคลาส X จากนั้นคำอธิบายประกอบบนวิธี B นั้นไม่ถูกต้อง เนื่องจากฤดูใบไม้ผลิกำหนดว่า A You Call ไม่มีคำอธิบายประกอบวัตถุต้นฉบับจึงยังคงใช้มากกว่าวัตถุพร็อกซี เมื่อการโทร B ถัดไปคำอธิบายประกอบของวิธี B ในวัตถุดั้งเดิมนั้นไม่ถูกต้องแน่นอน
สารละลาย:
วิธีที่ง่ายที่สุดคือการสร้างวิธีการ A และ B ไม่มีการพึ่งพาและสามารถเรียกใช้วิธี B โดยตรงผ่านวัตถุของคลาส X
แต่หลายครั้งตรรกะของเราอาจไม่ได้เขียนด้วยวิธีนี้ดังนั้นจึงมีวิธีอื่น: หาวิธีที่จะรับวัตถุพร็อกซีด้วยตนเอง
คลาส AOPContext มีวิธีการ CurrentProxy () ที่สามารถรับวัตถุพร็อกซีโดยตรงของคลาสปัจจุบัน จากนั้นตัวอย่างข้างต้นสามารถแก้ไขได้เช่นนี้:
// วิธีการโทร B วิธีการภายใน A // 1 โทร B โดยตรงคำอธิบายประกอบไม่ถูกต้อง B () // 2. รับวัตถุพร็อกซีคลาสและโทร B. ((x) aopcontext.currentProxy ()). B ()
วัตถุ @autowired เป็นโมฆะในวิธี AOP Annotation
ในการใช้งานก่อนหน้านี้ในวิธีการอธิบายประกอบเมื่อใช้วัตถุที่ฉีดอื่น ๆ พบว่าวัตถุนั้นไม่ได้ถูกฉีดและมันเป็นโมฆะ
ในที่สุดก็พบว่าเหตุผลนี้เป็นเพราะวิธีการเป็นส่วนตัว เนื่องจากสปริงใช้พร็อกซีแบบไดนามิก JDK หรือ CGLIB แบบไดนามิกพร็อกซีหนึ่งจึงเป็นคลาสที่ใช้อินเทอร์เฟซและอีกอันหนึ่งถูกนำไปใช้ผ่านคลาสย่อย ไม่ว่าจะเป็นอินเทอร์เฟซและคลาสแม่วิธีการส่วนตัวไม่เช่นนั้นไม่เช่นนั้นไม่ว่าจะเป็นคลาสย่อยหรือคลาสการใช้งานที่สามารถแทนที่ได้
หากวิธีการเป็นส่วนตัววิธีนี้ไม่สามารถพบได้ในกระบวนการพร็อกซีทำให้เกิดปัญหาในการสร้างวัตถุพร็อกซีและทำให้วัตถุบางอย่างไม่ถูกฉีด
ดังนั้นหากวิธีการจำเป็นต้องใช้คำอธิบายประกอบ AOP ให้ตั้งค่าเป็นวิธีที่ไม่ได้อยู่ในรายการ
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น