แนะนำ
อย่างที่เราทราบกันดีว่า AOP (การเขียนโปรแกรมที่มุ่งเน้นส่วน) เป็นหนึ่งในคุณสมบัติของกรอบฤดูใบไม้ผลิ AOP ให้ความยืดหยุ่นสูงมากโดยการตั้งค่าการตัดข้ามข้อกังวล AOP ทำงานอย่างไรในฤดูใบไม้ผลิ? เมื่อคุณสามารถใช้ Core Java ได้ แต่ต้องการเทคโนโลยี AOP คำตอบสำหรับคำถามนี้จะสำคัญอย่างยิ่ง ไม่เพียงแค่นั้นในการสัมภาษณ์ตำแหน่งทางเทคนิคขั้นสูงคำถามดังกล่าวมักจะปรากฏเป็นคำถามทดสอบ ดูสิเพื่อนของฉันเพิ่งเข้าร่วมการสัมภาษณ์และถูกถามคำถามที่ยากเช่นนี้ - วิธีใช้ AOP โดยไม่ต้องใช้ห้องสมุดฤดูใบไม้ผลิและห้องสมุดที่เกี่ยวข้องและมีเพียง Java Core ดังนั้นฉันจะจัดทำโครงร่างในบทความนี้เพื่อช่วยให้คุณเข้าใจวิธีการใช้ AOP โดยใช้ Core Java (แน่นอน AOP นี้มีข้อ จำกัด การทำงานบางอย่าง) โปรดทราบว่าบทความนี้ไม่ใช่การศึกษาเปรียบเทียบของ Spring AOP และ Java AOP แต่เป็นบทช่วยสอนเกี่ยวกับการใช้ AOP ด้วยความช่วยเหลือของรูปแบบการออกแบบโดยธรรมชาติใน Core Java
ฉันเชื่อว่าผู้อ่านรู้แล้วว่า AOP คืออะไรและจะใช้มันอย่างไรในกรอบฤดูใบไม้ผลิดังนั้นบทความนี้จึงมุ่งเน้นไปที่วิธีการใช้ AOP โดยไม่ต้องใช้ฤดูใบไม้ผลิ ก่อนอื่นเราต้องรู้ว่าฤดูใบไม้ผลิใช้สองเทคโนโลยี: พร็อกซี JDK และ CGLIB เพื่อใช้ AOP JDK Dynamic Proxy ให้วิธีที่ยืดหยุ่นในการเชื่อมต่อวิธีการและดำเนินการที่ระบุ แต่จะต้องมีข้อ จำกัด เมื่อดำเนินการ: อินเทอร์เฟซที่เกี่ยวข้องและคลาสการใช้งานของอินเตอร์เฟสจะต้องจัดเตรียมไว้ก่อน ฝึกฝนเพื่อสร้างความรู้ที่แท้จริงให้เราเข้าใจประโยคนี้ผ่านกรณี! ขณะนี้มีโปรแกรมเครื่องคิดเลขสำหรับการดำเนินการคณิตศาสตร์ ลองพิจารณาฟังก์ชั่นการแบ่ง คำถามในเวลานี้คือ: หากเฟรมเวิร์กหลักมีรหัสในการใช้งานอยู่แล้วเราสามารถจี้มันและทำการตรวจสอบเพิ่มเติมเมื่อมีการดำเนินการรหัสหรือไม่? คำตอบคือใช่และฉันจะพิสูจน์สิ่งนี้ด้วยตัวอย่างโค้ดที่ให้ไว้ด้านล่าง ก่อนอื่นมาดูรหัสของอินเทอร์เฟซพื้นฐาน:
เครื่องคิดเลขอินเตอร์เฟสสาธารณะ {INT สาธารณะคำนวณ (int a, int b);}รหัสของคลาสการใช้งานอินเตอร์เฟสนี้มีดังนี้:
Class CalculatorImpl ใช้เครื่องคิดเลข {@Override public int คำนวณ (int a, int b) {return a/b; -สมมติว่าเราไม่สามารถซ่อมแซมรหัสข้างต้นหรือทำการเปลี่ยนแปลงใด ๆ ในไลบรารีหลักเราจะใช้ฟังก์ชั่นการตรวจสอบได้อย่างสมบูรณ์แบบได้อย่างไร ทำไมไม่ลองฟังก์ชั่นพร็อกซีไดนามิก JDK
คลาสสาธารณะ SomeHandler ใช้ InvocationHandler {// รหัสที่ถูกละเว้นเพื่อความเรียบง่าย… .. @Override วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุวิธีวิธีการวัตถุ [] พารามิเตอร์) โยน {// การตรวจสอบความถูกต้องทางธุรกิจที่ซับซ้อนของคุณ ผลการกลับมา; -มาดูกันว่าฟังก์ชั่นการตรวจสอบโดย JDK Dynamic Proxy ทำงานอย่างไรผ่านคลาสทดสอบ
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {calculatoriMpl calcimpl = ใหม่ calculatoriMpl (); เครื่องคิดเลข proxied = (เครื่องคิดเลข) proxyfactory.getProxy (calculator.class, calcimpl, ใหม่ somehandler (calcimpl)); int result = proxied.calculate (20, 10); System.out.println ("ผลลัพธ์สุดท้าย :::" + ผลลัพธ์); -จากผลลัพธ์เราจะเห็นได้ว่าเพียงแค่ใช้อินเทอร์เฟซ InvocationHandler ที่ทรงพลังเราสามารถรับการใช้งานได้ ตามเอกสารของ JDK อินเตอร์เฟส IntriacationHandler ใช้อินสแตนซ์พร็อกซีเพื่อจัดการการเรียกใช้เมธอด
ตอนนี้เรารู้แล้วว่าวิธีการของ InvocationHandler สามารถช่วยเราแก้ปัญหาได้ ดังนั้นเรามาแก้ปัญหาใหม่ - เราจะดำเนินการก่อนและหลังการดำเนินการได้อย่างไร หากต้องการกล่าวโดยเฉพาะอย่างยิ่งเราสามารถขอวิธีการโดยการเพิ่ม AOPs หลายตัว (ก่อนหน้านี้) (หมายเหตุของนักแปล: ข้อความต้นฉบับเพิ่ม AOPs หลายตัว แต่ฉันคิดว่า Handler ทำหน้าที่เป็นแง่มุม)? คำตอบก็คือใช่ ทำตามขั้นตอนด้านล่างเพื่อสร้างเทมเพลตรหัสที่มีความคล่องตัวเพื่อตอบสนองความต้องการนี้:
สองวิธีในการใช้ AOP:
1. การใช้งานพร็อกซีแบบไดนามิกที่จัดทำโดย JDK
ส่วนต่อประสาน
ผู้ใช้ส่วนต่อประสานสาธารณะ {void getuser (); เป็นโมฆะ adduser (); Void UpdateUser (); เป็นโมฆะ deleteuser (); - คลาสการใช้งานดั้งเดิม
ผู้ใช้ระดับสาธารณะ UserBeanImpl ใช้ผู้ใช้ {Private String user = null; Public UserBeanImpl () {} Public UserBeanImpl (ผู้ใช้สตริง) {this.user = user; } สตริงสาธารณะ getUserName () {return user; } โมฆะสาธารณะ getUser () {system.out.println ("นี่คือวิธี getuser ()!"); } โมฆะสาธารณะ setUser (ผู้ใช้สตริง) {this.user = ผู้ใช้; System.out.println ("นี่คือวิธี setuser ()!"); } โมฆะสาธารณะ adduser () {system.out.println ("นี่คือวิธี adduser ()!"); } public void updateUser () {system.out.println ("นี่คือวิธี updateUser ()!"); } โมฆะสาธารณะ deleteUser () {system.out.println ("นี่คือวิธี deleteUser ()!"); - ชั้นเรียน
นำเข้า java.lang.reflect.invocationhandler; นำเข้า java.lang.reflect.method; นำเข้า java.lang.reflect.proxy; นำเข้า com.cignacmc.finance.bean.userbeanimpl; ระดับสาธารณะ UserBeanProxy ใช้ InvocationHandler {วัตถุส่วนตัว TargetObject; Public UserBeanProxy (Object TargetObject) {this.targetObject = targetObject; } วัตถุสาธารณะเรียกใช้ (พร็อกซีวัตถุ, วิธีการ, วัตถุ [] args) โยน throwable {userBeanImpl userBean = (userBeanImpl) targetObject; String username = userBean.getUserName (); ผลลัพธ์ของวัตถุ = null; // การตัดสินการอนุญาตถ้า (ชื่อผู้ใช้! = null &&! "". เท่ากับ (ชื่อผู้ใช้)) {result = method.invoke (TargetObject, args); } ผลตอบแทนผลลัพธ์; -
ชั้นเรียนทดสอบ
นำเข้า java.lang.reflect.proxy; นำเข้า com.cignacmc.finance.bean.userbean; นำเข้า com.cignacmc.finance.bean.userbeanimpl; นำเข้า com.cignacmc.finance.proxy.userbeanproxy; Proxyexe ระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {system.out.println ("พิสูจน์แล้ว ......... "); userBeanImpl targetObject = ใหม่ UserBeanImpl ("Bob Liang"); userBeanProxy proxy = ใหม่ userBeanProxy (TargetObject); // สร้างพร็อกซีอ็อบเจ็กต์วัตถุผู้ใช้เบียน = (userbean) proxy.newproxyinstance (targetobject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), พร็อกซี); Object.adduser (); System.out.println ("ไม่พิสูจน์ ............ "); targetObject = ใหม่ userbeanimpl (); proxy = ใหม่ userBeanProxy (targetObject); // สร้างพร็อกซีอ็อบเจ็กต์วัตถุ = (userbean) proxy.newproxyinstance (targetobject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), พร็อกซี); Object.adduser (); -
เอาท์พุท:
พิสูจน์แล้ว ............ นี่คือวิธี Adduser ()! ไม่พิสูจน์ ..........
จากตัวอย่างข้างต้นวิธีที่เรียกว่า Adduser () สามารถสกัดกั้นและประมวลผลได้สำเร็จ
2. สร้างคลาสพร็อกซีผ่าน CGLIB
ข้อได้เปรียบคือวัตถุเป้าหมายของเราไม่จำเป็นต้องใช้คลาสอินเตอร์เฟสดั้งเดิม
คลาสสาธารณะ clientBean {ชื่อสตริงส่วนตัว = null; Public ClientBean () {} Public ClientBean (ชื่อสตริง) {this.name = name; } โมฆะสาธารณะ addClient () {system.out.println ("นี่คือวิธี addClient ()!"); } โมฆะสาธารณะ deleteClient () {system.out.println ("นี่คือวิธี deleteClient ()!"); } โมฆะสาธารณะ getClient () {system.out.println ("นี่คือวิธี getClient ()!"); } โมฆะสาธารณะ getClient () {system.out.println ("นี่คือวิธี getClient ())!"); } โมฆะสาธารณะ updateClient () {system.out.println ("นี่คือ updateClient () วิธี!"); } สตริงสาธารณะ getClientName () {ชื่อคืน; } โมฆะสาธารณะ setClientName (ชื่อสตริง) {this.name = name; - ชั้นเรียน
นำเข้า java.lang.reflect.method; นำเข้า com.cignacmc.finance.bean.clientbean; นำเข้า net.sf.cglib.proxy.enhancer; นำเข้า net.sf.cglib.proxy.methodinterceptor; นำเข้า net.sf.cglib.proxy.methodinterceptor; นำเข้า net.sf.cglib.proxy.methodproxy; คลาสสาธารณะ cglibproxy ใช้ methodInterceptor {วัตถุส่วนตัว targetObject; วัตถุสาธารณะ createProxyObject (Object TargetObject) {this.targetObject = TargetObject; Enhancer Enhancer = New Enhancer (); enhancer.setsuperclass (this.targetobject.getClass ()); enhancer.setCallback (นี่); return enhancer.create (); } การสกัดกั้นวัตถุสาธารณะ (พร็อกซีวัตถุ, วิธีการ, วัตถุ [] args, methodproxy methodproxy) โยน {clientebean clientebean = (clientebean) targetObject; string username = clientBean.getClientName (); ผลลัพธ์ของวัตถุ = null; if (ชื่อผู้ใช้! = null &&! "". เท่ากับ (ชื่อผู้ใช้)) {result = method.invoke (TargetObject, args); } ผลตอบแทนผลลัพธ์; - ชั้นเรียนทดสอบ
นำเข้า java.lang.reflect.proxy; นำเข้า com.cignacmc.finance.bean.clientbean; นำเข้า com.cignacmc.finance.bean.userbean; นำเข้า com.cignacmc.finance.bean.userbeanimpl; นำเข้า com.cignacmc.finance.proxy.cglibproxy; นำเข้า com.cignacmc.finance.proxy.userbeanproxy; Proxyexe คลาสสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {system.out.println ("........ cglib พร็อกซี ............ "); System.out.println ("พิสูจน์แล้ว ............... "); CGLIBPROXY CPROXY = new CGLIBPROXY (); ClientBean ClientBean = (ClientBean) CPROXY.CreateProxYObject (ใหม่ ClientBean ("Bob Liang")); clientBean.addClient (); System.out.println ("ไม่พิสูจน์ ............... "); cproxy = new cglibproxy (); clientBean = (clientBean) cproxy.createProxyObject (ใหม่ clientBean ()); clientBean.addClient (); -
เอาท์พุท:
..... CGLIB PROXY .................. พิสูจน์แล้ว ............ นี่คือวิธี AddClient ()! ไม่พิสูจน์ ............