บทความนี้เกี่ยวกับปัญหาที่ยากใน Java โดยใช้ไลบรารี Java Core เพื่อใช้วิธี AOP อย่างง่ายและวิเคราะห์และเปรียบเทียบรหัสอินสแตนซ์ ต่อไปนี้เป็นเนื้อหาทั้งหมด:
ฤดูใบไม้ผลิเป็นเฟรมเวิร์กโอเพ่นซอร์สที่ได้รับความนิยมอย่างมากและ AOP (การเขียนโปรแกรมส่วน) เป็นหนึ่งในแนวคิดที่สำคัญที่สุดของฤดูใบไม้ผลิ เพื่อให้เข้าใจและเรียนรู้แนวคิดของ AOP ได้ดีขึ้นการใช้ห้องสมุดหลักเพื่อให้บรรลุในเวลานั้นเป็นวิธีที่ดี
ก่อนอื่นมาแนะนำแนวคิดของ AOP AOP (การเขียนโปรแกรมที่มุ่งเน้นด้าน) นั่นคือการเขียนโปรแกรมที่มุ่งเน้นวงสัมผัส การเขียนโปรแกรมที่เรียกว่าเป็นวงสัมผัสเป็นแนวคิดในการออกแบบรหัสจากมุมมองของพื้นที่หน้าตัด แนวคิด OOP แบบดั้งเดิมคือการใช้การสืบทอดการห่อหุ้มและความหลากหลายเพื่อสร้างความสัมพันธ์แบบลำดับชั้นในแนวตั้ง แต่ไม่เหมาะที่จะกำหนดความสัมพันธ์ในแนวนอน AOP Idea ให้อาหารเสริมที่ดีสำหรับเรื่องนี้
ตัวอย่างเช่นรหัสการจัดการบันทึกมักจะกระจัดกระจายในแนวนอนในหลายระดับวัตถุ แต่มันไม่มีส่วนเกี่ยวข้องกับฟังก์ชั่นหลักของวัตถุที่เกี่ยวข้อง นอกจากนี้ยังมีรหัสที่คล้ายกันมากมายเช่นการตรวจสอบการอนุญาต, เอาต์พุตดีบัก, การประมวลผลธุรกรรม ฯลฯ ซึ่งก็เหมือนกัน สิ่งนี้ไม่เอื้อต่อการใช้รหัสและการจัดการซ้ำ
ในเวลานี้เทคโนโลยี AOP เข้ามา มันใช้เทคโนโลยี "crosscutting" เพื่อเจาะลึกเข้าไปในวัตถุห่อหุ้ม, ห่อหุ้มพฤติกรรมทั่วไปที่ส่งผลกระทบต่อหลายคลาสลงในโมดูลที่นำกลับมาใช้ใหม่ได้และตั้งชื่อมันว่า "แง่มุม" นั่นคือการหั่น ส่วนที่เรียกว่า "ส่วน" นั้นถูกห่อหุ้มด้วยตรรกะหรือความรับผิดชอบที่ไม่เกี่ยวข้องกับธุรกิจ แต่เรียกว่าร่วมกันโดยโมดูลธุรกิจซึ่งสะดวกสำหรับการลดรหัสที่ซ้ำกันของระบบลดการมีเพศสัมพันธ์ระหว่างโมดูลและเอื้อต่อการดำเนินงานที่ตามมาและการบำรุงรักษา
AOP ถูกนำไปใช้อย่างไร?
คำตอบคือพร็อกซีแบบไดนามิก (จะมีอีกบทหนึ่งเกี่ยวกับพร็อกซีสำหรับรายละเอียดดังนั้นฉันจะไม่เข้าไปดูรายละเอียดที่นี่) มีสองวิธีในการใช้งานพร็อกซีแบบไดนามิกหนึ่งคือ JDK Dynamic Proxy และอีกวิธีหนึ่งคือ CGLIB Dynamic Proxy
จากนั้นใช้สองวิธีในการทำเกาลัดอย่างง่าย
มาออกแบบสถานการณ์ก่อนสมมติว่าเรามีอินเทอร์เฟซการคำนวณ icalculator และเครื่องคิดเลขคลาส CalculatorImpl ที่ใช้อินเทอร์เฟซนี้
อินเทอร์เฟซสาธารณะ icalculator {// การดำเนินการเพิ่มเติมสาธารณะ int เพิ่ม (int a, int b); // การลบสาธารณะ int ลบ (int a, int b); // หลาย int สาธารณะหลายตัว (int a, int b); // Dividation Public Int กำหนด (int a, int b);} Public Class CalculatorImpl ใช้ icalculator {@Override สาธารณะ int เพิ่ม (int a, int b) {return a + b; } @Override สาธารณะ int ลบ (int a, int b) {return a - b; } @Override Public Int Multiply (int a, int b) {return a * b; } @Override public int define (int a, int b) {return a / b; -วิธีการบันทึกจำนวนครั้งทั้งหมดที่ใช้วิธีเครื่องคิดเลขโดยไม่ต้องเปลี่ยนรหัสภายในของคลาสเครื่องคิดเลขเดิม
ด้วยพร็อกซีแบบไดนามิกมันง่ายมาก ก่อนสร้างคลาสและใช้อินเทอร์เฟซ InvocationHandler แทนที่เมธอด Invoke
Public Class TestHandler ดำเนินการ InvocationHandler {วัตถุส่วนตัว targetObject; usetimes int ส่วนตัว; // ผูกวัตถุผู้รับมอบสิทธิ์และส่งคืนพร็อกซีคลาสสาธารณะวัตถุผูกพัน (วัตถุเป้าหมาย) {this.targetObject = targetObject; ส่งคืน proxy.newproxyinstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), สิ่งนี้); } @Override วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุวิธีวิธีการวัตถุ [] args) พ่นที่โยนได้ {// ทำอะไรก่อน (); Object result = method.invoke (targetObject, args); หลังจาก(); ผลการกลับมา; } โมฆะส่วนตัวก่อน () {system.out.println ("เราสามารถทำอะไรบางอย่างก่อนคำนวณ"); } โมฆะส่วนตัวหลังจาก () {usetimes ++; System.out.println ("ใช้:"+usetimes+"Times"); -แม้ว่าดูเหมือนว่าจะมีรหัสมากเกินไป แต่วิธีการหลักคือวิธีการเรียกใช้ วัตถุผลลัพธ์ = method.invoke (targetObject, args); มันเทียบเท่ากับการใช้พารามิเตอร์ดั้งเดิมอย่างต่อเนื่องเพื่อดำเนินการวิธีดั้งเดิม ก่อนและหลังที่นี่เป็นฟังก์ชั่นที่กำหนดเองซึ่งสามารถทำบางสิ่งที่เราต้องการทำก่อนและหลังรหัสวัตถุถูกดำเนินการเช่นการนับการใช้งานที่นี่
ในวิธีการผูกวัตถุพร็อกซีเป้าหมายจะถูกส่งผ่านและอินสแตนซ์ของคลาสพร็อกซีจะถูกส่งคืน ต่อไปมาดูวิธีการใช้:
Public Class TestProxy {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {testhandler proxy = new testHandler (); icalculator คำนวณ = (icalculator) proxy.bind (ใหม่ calculatorimpl ()); int result = congulate.add (1,2); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); result = calculate.subtract (3,2); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); ผลลัพธ์ = calculater.multiply (4,6); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); ผลลัพธ์ = calculater.devide (6,2); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); -ก่อนอื่นเรากำหนด testhandler จากนั้นรับอินสแตนซ์พร็อกซีผ่านวิธีการผูกและจากนั้นเราสามารถใช้อินสแตนซ์นี้ได้โดยตรง ผลการดำเนินการมีดังนี้:
เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 1 ผลลัพธ์คือ: 3 เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 2 ผลลัพธ์คือ: 1 เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 3 ผลลัพธ์คือ: 24 เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 4 ผลลัพธ์คือ: 3
ด้วยวิธีนี้เราใช้ส่วนขยายรหัสโดยไม่ต้องแก้ไขรหัสภายในของ CalculatorImpl
ถัดไปใช้ CGLIB เพื่อนำไปใช้ครั้งเดียว
ก่อนอื่นสร้างคลาสเพื่อใช้งานอินเตอร์เฟส MethodInterceptor และแทนที่วิธีการสกัดกั้น รหัสอื่น ๆ คล้ายกับการใช้พร็อกซี JDK แต่กระบวนการรับวัตถุพร็อกซีนั้นแตกต่างกัน
คลาสสาธารณะ cglibproxy ใช้ methodInterceptor {private int usetimes; เป้าหมายวัตถุส่วนตัว วัตถุสาธารณะ getInstance (เป้าหมายวัตถุ) {this.target = เป้าหมาย; Enhancer Enhancer = New Enhancer (); enhancer.setsuperclass (this.target.getClass ()); enhancer.setCallback (นี่); return enhancer.create (); } @Override การสกัดกั้นวัตถุสาธารณะ (Object O, วิธีวิธี, วัตถุ [] วัตถุ, methodproxy methodproxy) พ่นที่ throwable {ก่อน (); ผลลัพธ์ของวัตถุ = methodProxy.invokesuper (o, วัตถุ); หลังจาก(); ผลการกลับมา; } โมฆะส่วนตัวก่อน () {system.out.println ("เราสามารถทำอะไรบางอย่างก่อนคำนวณ"); } โมฆะส่วนตัวหลังจาก () {usetimes ++; System.out.println ("ใช้:"+usetimes+"Times"); -ทดสอบออก:
Public Class TestCglibProxy {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {cglibproxy cglibproxy = new cglibproxy (); icalculator คำนวณ = (icalculator) cglibproxy.getInstance (ใหม่ calculatorImpl ()); int result = congulate.add (1,2); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); result = calculate.subtract (3,2); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); ผลลัพธ์ = คำนวณจำนวนมาก (4,6); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); result = คำนวณ devide (6,2); System.out.println ("ผลลัพธ์คือ:"+ผลลัพธ์); -ผลการดำเนินการมีดังนี้:
เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 1 ผลลัพธ์คือ: 3 เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 2 ผลลัพธ์คือ: 1 เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 3 ผลลัพธ์คือ: 24 เราสามารถทำอะไรบางอย่างก่อนคำนวณ ใช้: 4 ผลลัพธ์คือ: 3
ตอนนี้เราได้รับผลลัพธ์เดียวกัน (จำเป็นต้องมีแพ็คเกจสองแพ็คเกจ CGLIB-2.2.2.JAR ASM-3.3.JAR)
ทั้งสองวิธีมีจุดแข็งของตัวเอง พร็อกซี JDK จำเป็นต้องตั้งค่าอินเทอร์เฟซก่อนที่จะใช้พร็อกซี นี่คือข้อเสียและข้อได้เปรียบ ข้อเสียคือว่าสิ่งนี้จะลำบากขึ้นเล็กน้อยและมันไม่สามารถพร็อกซีที่ห่อหุ้มอยู่แล้วและไม่ได้ใช้อินเทอร์เฟซ วิธีการพร็อกซี CGLIB ไม่จำเป็นต้องใช้อินเทอร์เฟซ แต่มันก็เป็นเพราะสิ่งนี้ว่าพร็อกซี JDK จะสกัดกั้นวิธีการที่เขียนทับอินเตอร์เฟสในคลาสเท่านั้น ทั้งสองมีข้อดีและข้อเสียของพวกเขาดังนั้นสถานการณ์เฉพาะจำเป็นต้องวิเคราะห์ ในฤดูใบไม้ผลิมีการใช้โหมดพร็อกซีสองโหมด