Spring系列篇--關于AOP【面向切面】的詳解

目錄

一.AOP是什么

二.案例演示?

1.前置通知1.1 先準備接口

1.2然后再準備好實現類

1.3對我們的目標對象進行JavaBean配置?

1.4 編寫前置系統日志通知

1.5配置系統通知XML中的JavaBean

1.6 配置代理XML中的JavaBean

1.7 測試代碼開始測試

注意這里有一個報錯問題!!!

2. 后置通知2.1 先準備好后置通知的系統日志

2.2 配置后置系統通知的XML的JavaBean

?2.3 測試結果

3.環繞通知

3.2 環繞通知的系統日志

3.3 配置環繞通知的XML的JavaBean與前置通知和后置通知一致

3.4 測試結果

4.異常通知4.1 異常通知的系統日志和其他系統日志不同的是,方法名為固定的afterThrowing,不能修改

5.過濾通知5.1 直接在XML中配置JavaBean

四.總結aop是面向切面編程,普通程序由上而下正常執行,aop的程序執行是先執行到目標對象的目標方法中,如果連接點上由前置通知,則先執行前置通知再執行目標方法,最后如果目標方法有后置通知則最后執行后置通知代碼,不管是前置通知,后置通知,環繞通知,異常通知,過濾通知,代碼都是非業務核心代碼,如日志、事務的管理(開啟、提交、回滾) ? ? ? ??


一.AOP是什么

簡介:
面向切面編程(Aspect-Oriented Programming)是一種編程范式,它的主要目的是通過預編譯和運行期動態代理實現程序功能的橫切(cross-cutting)特性,如日志記錄、性能統計、事務監控等。它可以幫助開發者將這些原本分散在各個方法或類中的業務邏輯抽象出來,提高代碼復用性,降低耦合度
AOP(Aspect-Oriented Programming)是Spring框架的一個重要特性,它通過將橫切關注點(cross-cutting concerns)從核心業務邏輯中分離出來,以模塊化的方式在整個應用程序中重復使用。以下是關于AOP的簡介及其特點:

AOP是一種編程范式,它通過將橫切關注點切割出來,將其模塊化,并將其應用于多個類和模塊,以提高代碼的重用性和可維護性。
橫切關注點是指與核心業務邏輯無關但存在于多個類或模塊中的非功能性需求,例如日志記錄、性能監控、事務管理等。
特點:

模塊化:AOP允許將橫切關注點從核心業務邏輯中提取出來,形成獨立的切面(Aspect),使得關注點的邏輯可以獨立于各個模塊。
解耦:AOP通過解耦橫切關注點與核心業務邏輯,使得它們可以獨立演化和變化,提高了模塊之間的松耦合程度。
重用性:AOP允許將切面應用于多個類和模塊,從而實現了關注點的重用,避免了代碼的重復編寫。
可維護性:將橫切關注點抽象為切面后,使得代碼結構更清晰,易于理解和維護。
動態性:AOP可以在運行時動態地將切面應用到目標對象上,而不需要修改目標對象的源代碼,增強了系統的靈活性和可擴展性。
多樣性:Spring框架支持不同類型的切面編程,包括基于代理的AOP和基于字節碼增強的AOP。這樣可以選擇最適合應用程序需求的AOP實現方式。
在Spring框架中,AOP的實現采用了代理模式和動態代理技術。Spring提供了多種AOP的實現方式,包括基于XML配置的AOP、基于注解的AOP和基于純Java配置的AOP(JavaConfig)等,開發者可以根據具體需求選擇適合的方式來配置和使用AOP。
?

面向切面:
1.專業術語
①目標對象:
專業解釋:被通知(被代理)的對象

通俗理解:在書店中,商品就是目標。每個商品都有自己的屬性(比如價格、名稱、庫存等)和行為(比如計算促銷價格、更新庫存等)。收銀員通過掃描商品的條形碼來與商品進行交互,調用商品的方法來獲取商品信息以及執行一些操作。商品本身即代表了目標

②連接點:
專業解釋:程序執行過程中明確的點,如方法的調用,或者異常的拋出

通俗理解:在書店中,我們可以將顧客結賬的行為看作一個連接點

③通知:
專業解釋:在某個特定的連接點上執行的動作,同時Advice也是程序代碼的具體實現,例如一個實現日志記錄的代碼(通知有些書上也稱為處理)

通俗理解:

前置通知(Before Advice):在切入點前執行的代碼,在讀者購買圖書之前,我們可以記錄讀者購買的圖書信息
后置通知(After Advice):在切入點后執行的代碼,在讀者購買圖書之后,我們可以更新圖書庫存
環繞通知(Around Advice):在切入點前后都執行的代碼,我們可以對讀者進行額外的安全檢查和記錄日志
異常通知(After-Throwing Advice):異常通知是在切入點發生異常時執行的額外功能代碼。假設當顧客購買商品的數量大于庫存數量時,就會發生異常。我們希望在顧客購買商品時檢查庫存,并在發生異常時執行異常通知,向顧客顯示錯誤信息并處理異常情況
過濾通知(After-Returning Advice):過濾通知是在切入點成功執行后執行的額外功能代碼。假設我們有一個特殊會員組,他們在購買商品時可以獲得額外的積分。我們可以使用過濾通知來篩選出這些特殊會員,并在成功購買后給他們添加積分
④代理:
專業解釋:將通知應用到目標對象后創建的對象(代理=目標+通知)

通俗理解:在書店中,收銀員是一個代理角色。他們既代表顧客與商品交互,又代表書店執行一些額外的任務。當顧客帶著商品到收銀臺時,收銀員會掃描每個商品的條形碼,獲取商品信息并計算總價。這里,收銀員即充當了顧客與商品之間的代理角色,也充當了超市執行計算總價等額外任務的代理角色

⑤切入點:
專業解釋:

多個連接點的集合,定義了通知應該應用到那些連接點 (也將Pointcut理解成一個條件 ,此條件決定了容器在什么情況下將通知和目標組合成代理返回給外部程序)

通俗理解:在書店場景中,我們可能希望在計算折扣方法之前或之后記錄日志和進行庫存管理。這些切入點決定了我們在代碼中操作的位置

⑥適配器:
專業解釋:適配器是一個中間組件,用于將面向切面編程框架與原始的業務邏輯代碼連接起來(適配器=通知(Advice)+切入點(Pointcut))

通俗理解:在書店場景中,適配器可以將代理對象與書店的購買圖書業務邏輯連接起來,使得代理對象能夠在購買圖書的過程中添加額外的功能

2.代碼演示
? ? ? ? 在上面場景模擬的代碼中,我們能夠發現記錄日志的代碼基本相同,那么有沒有可能將這部分的代碼抽取出來進行封裝,統一進行維護呢?同時也可以將日志代碼和業務代碼完全分離,解耦合

??那么我們便可以將業務方法中的非業務核心代碼(日志記錄)抽離出來形成一個橫切面,并且將這個橫切面封裝成一個對象,將所有的記錄日志的代碼寫到這個對象中,以實現與業務代碼的分離,這便是面向切面編程的思想

2.1將記錄日志的代碼進行封裝
?

三.案例演示?


1.前置通知
1.1 先準備接口

package com.lya.aop.biz;public interface IBookBiz {// 購書public boolean buy(String userName, String bookName, Double price);// 發表書評public void comment(String userName, String comments);
}

1.2然后再準備好實現類

package com.lya.aop.biz.impl;import com.YU.aop.biz.IBookBiz;
import com.YU.aop.exception.PriceException;public class BookBizImpl implements IBookBiz {public BookBizImpl() {super();}public boolean buy(String userName, String bookName, Double price) {// 通過控制臺的輸出方式模擬購書if (null == price || price <= 0) {throw new PriceException("book price exception");}System.out.println(userName + " buy " + bookName + ", spend " + price);return true;}public void comment(String userName, String comments) {// 通過控制臺的輸出方式模擬發表書評System.out.println(userName + " say:" + comments);}}

1.3對我們的目標對象進行JavaBean配置?

<!--目標對象-->
? ? <bean class="com.lya.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>

1.4 編寫前置系統日志通知

package com.lya.aop.advice;import java.lang.reflect.Method;
import java.util.Arrays;import org.springframework.aop.MethodBeforeAdvice;/*** 買書、評論前加系統日志* @author YU**/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//?? ??? ?在這里,可以獲取到目標類的全路徑及方法及方法參數,然后就可以將他們寫到日志表里去String target = arg2.getClass().getName();String methodName = arg0.getName();String args = Arrays.toString(arg1);System.out.println("【前置通知:系統日志】:"+target+"."+methodName+"("+args+")被調用了");}}

1.5配置系統通知XML中的JavaBean

<!--通知-->
? ? <bean class="com.lya.aop.advice.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"></bean>

1.6 配置代理XML中的JavaBean

<!-- 代理--><bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy"><!-- 配置目標對象 --><property name="target" ref="bookBiz"></property><!-- 配置代理接口,目標對象的接口 --><property name="proxyInterfaces"><value>com.YU.aop.biz.IBookBiz</value></property><property name="interceptorNames"><list><value>myMethodBeforeAdvice</value></list></property></bean>

1.7 測試代碼開始測試

package com.lya.util;import com.lya.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 豬八戒有限集團* @create 2023-08-17-15:34*/
public class Demo {public static void main(String[] args) {
//        今天所學:
//        1.AOP的介紹:專心做事//       2專業術語
//        1.連接點
//        2.通知:前,后,環繞
//        3.目標
//        4.代理
//        代理=目標+通知//        3配置xml初始化Spring容器IOCClassPathXmlApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");//        演示一:目標對象
//        BookBizImpl bookBiz = context.getBean("bookTarget",BookBizImpl.class);
//        bookBiz.buy("曉東","欠你一夜",2000d);
//        bookBiz.comment("曉東","不看虧了,看了真爽啊!");//        演示二:前置通知
//        錯誤:類型強轉,Object proxy1 = context.getBean("proxy");System.out.println(proxy1.getClass()+"代理的類型");
//      com.sun.proxy.$Proxy5代理的類型//      這里proxy==new bookbizimpl
//        BookBizImpl proxy = context.getBean("proxy",BookBizImpl.class);
//        proxy.buy("曉東","欠你一夜",2000d);
//        proxy.comment("曉東","不看虧了,看了真爽啊!");//        使用接口接收代理對象!!!因為代理對象實現了接口在xml中IBookBiz proxy = context.getBean("proxy",IBookBiz.class);proxy.buy("曉東","欠你一夜",2000d);proxy.comment("曉東","不看虧了,看了真爽啊!");}
}

注意這里有一個報錯問題!!!

因為proxy代理已經實現了接口可以看作為一個實現類

 使用接口接收代理對象!!!因為代理對象實現了接口在xml中

測試結果:

?由測試結果可得知,不僅獲取到了我們的參數,同時根據方法獲取到了我們的系統日志,也就是前置通知

2. 后置通知
2.1 先準備好后置通知的系統日志

package com.zking.aop.advice;import java.lang.reflect.Method;
import java.util.Arrays;import org.springframework.aop.AfterReturningAdvice;/*** 買書返利* @author Administrator**/
public class MyAfterReturningAdvice implements AfterReturningAdvice {@Overridepublic void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {String target = arg3.getClass().getName();String methodName = arg1.getName();String args = Arrays.toString(arg2);System.out.println("【后置通知:買書返利】:"+target+"."+methodName+"("+args+")被調用了,"+"該方法被調用后的返回值為:"+arg0);}}

2.2 配置后置系統通知的XML的JavaBean

<!--后置通知-->
? ? <bean class="com.YU.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
并在前面已經配置好的代理接口中添加一個value值

?2.3 測試結果

?由測試結果我們可以得知,后置通知永遠都在方法執行后才會顯示通知,與前置通知不同的是每次前面的方法調用后都會返回一個參數

3.環繞通知


3.1 環繞通知就是前置通知和后置通知的結合,在實際應用開發中,我們一般不會單獨編寫前置通知和后置通知,單獨使用前置通知或者后置通知時,我們會使用環繞通知,將里面前置(后置)通知的功能注釋,以達到單獨使用的目的

3.2 環繞通知的系統日志

package com.lya.advice;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;import java.util.Arrays;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 豬八戒有限集團* @create 2023-08-17-18:45** 環繞通知*/
public class AroundAdvice  implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {//獲取目標對象的執行方法String methodName=invocation.getMethod().getName();//獲取目標對象執行方法的參數Object[] params=invocation.getArguments();//獲取目標對象Object target = invocation.getThis();System.out.println("[環繞通知] "+target.getClass().getName()+"."+methodName+","+ "執行的參數:"+ Arrays.toString(params));Object returnValue = invocation.proceed(); //放行操作System.out.println("[環繞通知] 返回參數等于:"+returnValue);return returnValue;}
}

3.3 配置環繞通知的XML的JavaBean與前置通知和后置通知一致

3.4 測試結果

由測試結果得知,環繞通知就是前置通知和后置通知的結合,優點就是不需要再多次去進行配置及編碼,所以就像我們前面所說在實際開發應用中我們一般都會選擇使用環繞通知

4.異常通知
4.1 異常通知的系統日志和其他系統日志不同的是,方法名為固定的afterThrowing,不能修改

package com.lya.advice;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 豬八戒有限集團* @create 2023-08-17-18:56*/import org.springframework.aop.ThrowsAdvice;/*** 異常通知*/
public class ExceptionAdvice implements ThrowsAdvice {public void afterThrowing(PriceException e) {System.out.println("[異常通知] 價格異常,撤銷訂單!");}
}

價格異常

package com.lya.advice;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 豬八戒有限集團* @create 2023-08-17-19:04** 價格異常通知*/
public class PriceException  extends RuntimeException {public PriceException() {super();}public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}public PriceException(String message, Throwable cause) {super(message, cause);}public PriceException(String message) {super(message);}public PriceException(Throwable cause) {super(cause);}
}

4.2 在我們正常程序出問題沒有去配置異常通知時會出現報錯,并且不會執行后面的后置通知,如以下情況

4.3 異常處理配置和前面的配置相同

4.4 當我們配置好異常通知模塊時,程序出現異常時會上報日志進行提示

5.過濾通知
5.1 直接在XML中配置JavaBean

<!--過濾通知-->
? ? <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor">
? ? ? ? <property name="advice" ref="myAfterReturningAdvice"></property>
? ? ? ? <property name="pattern" value=".*buy"></property>
? ? </bean>


?

將圖中指出部分替換成過濾通知

?測試結果:

對比框中內容,在調用過buy方法后進行過濾,第二次調用時不再buy方法而是comment方法?

四.總結
aop是面向切面編程,普通程序由上而下正常執行,aop的程序執行是先執行到目標對象的目標方法中,如果連接點上由前置通知,則先執行前置通知再執行目標方法,最后如果目標方法有后置通知則最后執行后置通知代碼,不管是前置通知,后置通知,環繞通知,異常通知,過濾通知,代碼都是非業務核心代碼,如日志、事務的管理(開啟、提交、回滾) ? ? ? ??
?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41235.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41235.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41235.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM虛擬機:初始化的介紹

本文重點 我們前面學習了三個步驟: 裝載 連接 初始化 初始化 初始化的時候,會為靜態成員變量賦值初始值,它有兩種方式: ①聲明類變量是指定初始值 ②使用靜態代碼塊為類變量指定初始值 例子 最后輸出的結果為3,它的過程是這樣的: main方法中輸出T.count,由于count是…

自簽證書讓Chrome信任的方式

自簽證書讓Chrome信任的方式(域名情況) 網站是搭建在linux上的&#xff0c;內容大概是一個code-server;我要在windows的chrome中訪問&#xff0c;在Linux機器上自簽了一個證書&#xff0c;準備讓windows中的chrome信任。linux裝好openssl。首先買好域名&#xff0c;配置好解析…

tkinter+爬蟲+pygame實現音樂播放器

文章目錄 前文安裝模塊示意圖爬蟲完整代碼pygametkinter完整代碼結尾前文 本文將涉及爬蟲(數據的獲取),pygame(音樂播放器),tkinter(界面顯示),將他們匯聚到一起制造一個音樂播放器,歡迎大家的訂閱。 安裝模塊 pip install requests,parsel,lxpy,pygame 示意圖

Flask下載文件報錯304 NOT MODIFIED

文章目錄 問題描述解決方案參考文獻 問題描述 前端 Vue 下下來的文件無法正常打開&#xff0c;大小比正常的略大一點&#xff0c;通過 Postman 直接調用是正常的 解決方案 由前端解決 如果響應大小比文件略大一點&#xff0c;從 responses 中取出關鍵數據再組成文件如果響應…

open cv學習 (二)色彩空間和通道

色彩空間和通道 demo1 import cv2hsv_image cv2.imread("./img.png")cv2.imshow("img", hsv_image) hsv_image cv2.cvtColor(hsv_image, cv2.COLOR_BGR2HSV) h, s, v cv2.split(hsv_image) cv2.imshow("B", h) cv2.imshow("G", s…

文本圖片怎么轉Excel?分享一些好用的方法

在處理數據時&#xff0c;Excel 是一個非常強大的工具&#xff0c;但有時候需要將文本和圖片轉換為 Excel 格式&#xff0c;這可能會讓人感到困惑。在本文中&#xff0c;我們將介紹一些好用的方法&#xff0c;以便您能夠輕松地將文本和圖片轉換成 Excel 格式。 將文本圖片為Exc…

部署piwigo網頁 通過cpolar分享本地電腦上的圖片

通過cpolar分享本地電腦上有趣的照片&#xff1a;發布piwigo網頁 文章目錄 通過cpolar分享本地電腦上有趣的照片&#xff1a;發布piwigo網頁前言1. 設定一條內網穿透數據隧道2. 與piwigo網站綁定3. 在創建隧道界面填寫關鍵信息4. 隧道創建完成 總結 前言 首先在本地電腦上部署…

K8S核心組件etcd詳解(上)

1 介紹 https://etcd.io/docs/v3.5/ etcd是一個高可用的分布式鍵值存儲系統&#xff0c;是CoreOS&#xff08;現在隸屬于Red Hat&#xff09;公司開發的一個開源項目。它提供了一個簡單的接口來存儲和檢索鍵值對數據&#xff0c;并使用Raft協議實現了分布式一致性。etcd廣泛應用…

關于計數以及Index返回訂單號升級版002(控制字符長度,控制年月標記,拾取未使用編號)--使用兩個表來滿足操作

1實現步驟以及說明 1.根據參數獲取當前setNoIndex表里現在的No的index值&#xff0c;如果包含關鍵字當前對應數據&#xff0c;則現在SetIndexNoLeft 表中找到有無未使用并未占用的那條數據&#xff08;被占用的數據IsTaken1&#xff0c;生成后使用當前時間與updated時間進行比…

Django圖書商城系統實戰開發-實現訂單管理

Django圖書商城系統實戰開發-實現訂單管理 簡介 在本教程中&#xff0c;我們將繼續基于Django框架開發圖書商城系統&#xff0c;這次的重點是實現訂單管理功能。訂單管理是一個電子商務系統中非常重要的部分&#xff0c;它涉及到用戶下單、支付、發貨以及訂單狀態的管理等方面…

【hive】簡單介紹hive的幾種join

文章目錄 前言1. Common Join2. Map Join介紹&#xff1a;使用方法&#xff1a;限制&#xff1a; 3. Bucket Map Join介紹&#xff1a;好處&#xff1a;使用條件&#xff1a;使用方法&#xff1a; 4. Sort Merge Bucket Map Join介紹&#xff1a;如何使用&#xff1a; 5. Skew …

如何在控制臺查看excel內容

背景 最近發現打開電腦的excel很慢&#xff0c;而且使用到的場景很少&#xff0c;也因為mac自帶了預覽的功能。但是shigen就是閑不住&#xff0c;想自己搞一個excel預覽軟件&#xff0c;于是在一番技術選型之后&#xff0c;我決定使用python在控制臺顯示excel的內容。 具體的需…

Redis與MySQL的比較:什么情況下使用Redis更合適?什么情況下使用MySQL更合適?

Redis和MySQL是兩種不同類型的數據庫&#xff0c;各有自己的特點和適用場景。下面是Redis和MySQL的比較以及它們適合使用的情況&#xff1a; Redis適合的場景&#xff1a; 高性能讀寫&#xff1a;Redis是基于內存的快速Key-Value存儲&#xff0c;讀寫性能非常高。它適用于需要…

NodeJs導出PDF

&#xff08;優于別人&#xff0c;并不高貴&#xff0c;真正的高貴應該是優于過去的自己。——海明威&#xff09; 場景 根據訂單參數生成賬單PDF 結果 示例代碼 /* eslint-disable no-unused-vars */ /* eslint-disable no-undef */ /* eslint-disable complexity */ const…

【jquery實現動態給表格添加刪除行,合并指定單元格】

jquery實現動態給表格添加刪除行&#xff0c;合并指定單元格 前端技術 jspjquery 動態添加行 //新增行 $("#addRowBtn").click(function(){var rowEl$("<tr><td><input typecheckbox classcheckItem/></td><td><input nam…

NPOI 讀取和寫入Excel

在C#中使用NPOI庫讀取和寫入Excel文件&#xff0c;你需要先下載并安裝NPOI庫。你可以在NuGet管理器中搜索NPOI并進行安裝。 以下是一個使用NPOI庫進行Excel文件讀取和寫入的示例&#xff1a; 讀取Excel文件&#xff1a; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel…

【仿寫tomcat】二、掃描java文件,獲取帶有@WebServlet注解的類

tomcat仿寫 項目結構掃描文件servlet注解map容器servlet工具類啟動類調用 項目結構 掃描文件之前當然要確定一下項目結構了&#xff0c;我這里的方案是tomcat和項目同級 項目的話就仿照我們平時使用的結構就好了&#xff0c;我們規定所有的靜態資源文件都在webApp目錄下存放…

【數據庫】P1 數據庫基本常識

數據庫基本常識 數據庫 ≠ 數據庫管理系統表&#xff08;Table&#xff09;SQL是什么 數據庫 ≠ 數據庫管理系統 數據庫是保存有組織的數據的容器&#xff0c;數據庫稱為 DB&#xff08;DataBase&#xff09;&#xff1b;數據庫管理系統是創建和操縱數據庫的軟件&#xff0c;數…

充氣泵方案設計——便攜無線充氣泵方案

充氣泵方案的進化史是人類歷史上電子技術發展史中的一環。電子技術&#xff0c;特別是微電子技術是 20 世紀發展最為迅速、影響最為廣泛的技術成就。電子技術的核心是電子器件,電子器件的進步和換代&#xff0c;引起了電子電路極大的變化&#xff0c;出現了很多新的電路和應用。…