【推薦】深入淺出學習Spring框架【中】

目錄

1.AOP是什么???

2.案列:

3.spring的aop的專業術語

?4.代碼模擬

4.1 前置通知

??3.2.后置通知

??3.3.環繞通知

??3.4.異常通知

?3.5.過濾通知


1.AOP是什么???

  • 面向切面編程(Aspect-Oriented Programming)是一種編程范式,它的主要目的是通過預編譯和運行期動態代理實現程序功能的橫切(cross-cutting)特性,如日志記錄、性能統計、事務監控等。它可以幫助開發者將這些原本分散在各個方法或類中的業務邏輯抽象出來,提高代碼復用性,降低耦合度
  • 面向切面編程的核心思想是將程序分為兩個部分:切入點和切面切入點(entry point)是程序執行過程中需要被攔截的代碼段,而切面(weaving)則是實現橫切功能的代碼段。在運行時,通過動態代理技術,將切入點的代碼交由切面織入,實現橫切的效果
  • 面向切面編程是希望能夠將通用需求功能從不相關的類當中分離出來,能夠使得很多類共享一個行為,一旦發生變化,不必修改很多類,而只是修改這個行為即可
  • AOP通過提供另一種思考程序結構的方式來補充了面向對象編程(OOP)。OOP中模塊化的基本單元是類(class),而AOP中模塊化的基本單元是切面(aspect)。可以這么理解,OOP是解決了縱向的代碼復用問題,AOP是解決了橫向的代碼復用問題.

2.案列:

場景模擬:這里我模擬的場景為線上書城系統

首先進行一個沒有使用Aop的模擬代碼展示:

實體類:Book:其中是書籍的屬性,行為等
Dao類:BookDao:其中是有關于書籍操作的代碼
業務邏輯層:BookBiz:...,BookBizImpl:...
Web層:new 對象//增加
public int add(Book book) {
b.add()
}//修改
public int edit(Book book) {
b.edit()
}//刪除
public int del(Book book) {
b.del()
}//上架
public int up(Book book) {
b.up()
}//下架
public int down(Book book) {
b.down()
}

但是很多時候會出現這樣的情況:

①用戶購買了書籍,卻說自己沒有收到貨物...

②店家發出的貨物為空貨物,而其卻為了牟利,矢口否認...

針對這樣的情況,很多時候都沒有證據來證明到底是真是假,而在我們成熟的系統中,通常都會添加一個叫做‘日志記錄’的東西,它可以用來記錄和跟蹤系統、應用程序或事件的活動和狀態的過程,通俗來說就是使用這個系統的用戶的每一步操作都會被記錄下來,這樣就話就成為一個證據:那成熟的系統應該是怎么樣?

實體類:Book:其中是書籍的屬性,行為等
Dao類:BookDao:其中是有關于書籍操作的代碼
業務邏輯層:BookBiz:...,BookBizImpl:...
Web層:new對象//增加
public int add(Book book) {
b.add()
}//修改
public int edit(Book book) {
b.edit()
}//刪除
public int del(Book book) {
b.del()
}//上架
public int up(Book book) {
datetime=..//操作時的時間
username=...//操作的用戶名
args = ...//參數
logBiz.add(datetime,username,args);//將其都添加到日志中去b.up()
}//下架
public int down(Book book) {
datetime=..//操作時的時間
username=...//操作的用戶名
args = ...//參數
logBiz.add(datetime,username,args);//將其都添加到日志中去b.down()
}

現在是在上架和下架中添加了日志記錄,如果要在其他的方法操作中,也添加日志記錄的話,那就需要將這一段代碼再重復幾次,這樣就有點麻煩,而且還改變了原有代碼的結構,如果需求發生改變,需要對打印的日志內容作出修改,那就必須修改用到了日志記錄方法中的所有相關代碼,如果是1000個方法呢?每次就需要手動去修改1000個方法中的代碼,對項目的維護成本就會很高這也不利于我們的系統維護。然后我們可以用到AOP可以幫助開發者將將原本分散在各個方法或類中的業務邏輯抽象出來,提高代碼復用性,降低耦合度,接下怎么提高代碼的復用性:

3.spring的aop的專業術語

? ?項目代碼但是從上往下依次執行,而現在加入了面向切面的思想,當我們的代碼執行到目標對象是,查看連接點是否有前置通知,先執行前置通知,再執行目標方法,如果沒有前置通知,那么就直接執行目標方法,最后看連接點上是否有后置通知,如果有,就再執行后置通知,如果沒有就執行完了。

  • ?連接點(Joinpoint):程序執行過程中明確的點,如方法的調用,或者異常的拋出.
  • ?目標(Target):被通知(被代理)的對象,就是完成具體的業務邏輯 ,比如書籍的增刪改查
  • ?通知(Advice):在某個特定的連接點上執行的動作,同時Advice也是程序代碼的具體實現,例如一個實現日志記錄的代碼(通知有些書上也稱為處理) ?,完成切面編程,非業務核心代碼
  • ?代理(Proxy):將通知應用到目標對象后創建的對象(代理=目標+通知), ?例子:外科醫生+護士只有代理對象才有AOP功能,而AOP的代碼是寫在通知的方法里面的
  • 切入點(Pointcut):多個連接點的集合,定義了通知應該應用到那些連接點 , (也將Pointcut理解成一個條件 ,此條件決定了容器在什么情況下將通知和目標組合成代理返回給外部程序),比如給新增方法添加日志功能
  • ?適配器(Advisor):適配器=通知(Advice)+切入點(Pointcut)

? ? ?注:目標對象只負責業務邏輯代碼

???? ? ? ? ? ?通知對象負責AOP代碼,這二個對象都沒有AOP的功能,只有代理對象才有。

?4.代碼模擬

4.1 前置通知

????????首先,我們先寫service接口和實現類進行模擬,在里面寫兩個方法

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

? ? ?然后,寫實現類,重新這兩個方法,并且做了一個價格的判斷

package com.sy.aop.biz.impl;import com.sy.aop.biz.IBookBiz;
import com.sy.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);}}

?接下來要寫上面價格判斷的異常?

package com.sy.aop.exception;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);}}

然后,我們先創建一個類,將類名.方法名,攜帶的參數,作為日志存儲到數據庫。

package com.sy.aop.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;
import java.util.Arrays;/*** 買書、評論前加系統日志* @author shenyan**/
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+")被調用了");}}

?最后,進行一個配置

!--aop-->
<!-- 目標對象 -->
<bean class="com.sy.aop.biz.impl.BookBizImpl" id="bookBiz"></bean><!-- 通知 -->
<bean class="com.sy.aop.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean><!-- 代理=目標+通知 --><bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy"><property name="target" ref="bookBiz"></property><property name="proxyInterfaces"><list><value>com.sy.aop.biz.IBookBiz</value></list></property><property name="interceptorNames"><list><value>myMethodBeforeAdvice</value></list></property></bean>

前臺的一個驗證:

package com.sy.aop.demo;import com.sy.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 諶艷* @site www.shenyan.com* @create 2023-08-17 21:13*/
public class demo1 {public static void main (String [] args){ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring-context.xml");IBookBiz bookBiz=(IBookBiz) context.getBean("bookBiz");bookBiz.buy("花花","天下掉下一個林妹妹",18.88);bookBiz.comment("嘿嘿","嘿嘿嘿真好看");}
}

結果為展示:

??3.2.后置通知

????????有了前面的鋪墊,直接再創建一個后置通知的類,比起前置通知,多了一個參數,就是返回參數

package com.sy.aop.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;
import java.util.Arrays;/*** 買書、評論前加系統日志* @author shenyan**/
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+")被調用了");}}
接著,配置文件即可

?然后前臺看結果;

package com.sy.aop.demo;import com.sy.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 諶艷* @site www.shenyan.com* @create 2023-08-17 21:13*/
public class demo1 {public static void main (String [] args){ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/spring-context.xml");
//        IBookBiz bookBiz=(IBookBiz) context.getBean("bookBiz");IBookBiz bookBiz=(IBookBiz) context.getBean("bookProxy");bookBiz.buy("花花","天下掉下一個林妹妹",18.88);bookBiz.comment("嘿嘿","嘿嘿嘿真好看");}
}

??3.3.環繞通知

? ? ? ??結合了前置通知和后置通知,它兩個都有所以一般常用這個,

????????它只有一個參數,但是這一個參數相當于上面前置通知和后置通知的3,4個參數

package com.sy.aop.advice;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;import java.util.Arrays;/*** 環繞通知* 	包含了前置和后置通知* * @author shenyan**/
public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation arg0) throws Throwable {String target = arg0.getThis().getClass().getName();String methodName = arg0.getMethod().getName();String args = Arrays.toString(arg0.getArguments());System.out.println("【環繞通知調用前:】:"+target+"."+methodName+"("+args+")被調用了");
//		arg0.proceed()就是目標對象的方法Object proceed = arg0.proceed();System.out.println("【環繞通知調用后:】:該方法被調用后的返回值為:"+proceed);return proceed;}}

? 接著就是配置文件

?然后前臺測試:

?結果展示:

??3.4.異常通知

? ??? ? 先建一個類,但是注意,這個異常通知的類,重寫的話,方法名字只能是這個,否則報錯

然后配置文件:

?然后在前臺測試:

結果展示:

?3.5.過濾通知

????????過濾通知就是那個適配器,它不需要再建一個類,直接再配置文件里面配置就可以了,需要正則判斷,這里舉例過濾的是后置通知

?結果展示:

??今天小編的分享就結束吶,生活總是需要不斷去學習新的知識,多想想然后再去實操,持之以恒,經驗和思維都會發生轉變,我們要保持謙虛學習和自信的態度,各位加油!

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

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

相關文章

第十四屆中國大學生服務外包大賽細品,上百支隊伍與合合信息用AI共克“記賬”難題

前言 熟悉我的小伙伴應該知道我在大學時期參與了很多競賽&#xff0c;我向來對比賽是比較熱枕的&#xff0c;以我個人觀點&#xff0c;我認為可以通過競賽激發學習激情和檢驗自己的技能水平掌握情況&#xff0c;大學生很少有機會能夠了解到課堂之外市場的需求&#xff0c;外包…

P1123 取數游戲

取數游戲 題目描述 一個 N M N\times M NM 的由非負整數構成的數字矩陣&#xff0c;你需要在其中取出若干個數字&#xff0c;使得取出的任意兩個數字不相鄰&#xff08;若一個數字在另外一個數字相鄰 8 8 8 個格子中的一個即認為這兩個數字相鄰&#xff09;&#xff0c;求…

JWT(JSON Web Token )令牌

1、介紹 jwt就是將原始的json數據格式進行了安全的封裝&#xff0c;這樣就可以直接基于jwt在通信雙方安全的進行信息傳輸了。 2、jwt組成 第一部分&#xff1a;Header(頭&#xff09;&#xff0c; 記錄令牌類型、簽名算法等。 例如&#xff1a;{"alg":"HS256…

EXCEL按列查找,最終返回該列所需查詢序列所對應的值,VLOOKUP函數

EXCEL按列查找&#xff0c;最終返回該列所需查詢序列所對應的值 示例&#xff1a;國標行業分類漢字&#xff0c;匹配id 使用VLOOKUP函數 第一參數&#xff1a;拿去查詢的值。 第二參數&#xff1a;匹配的數據。 Ps&#xff1a;Sheet1!$C 21 : 21: 21:E 117 &#xff0c;需要…

Redis系列(三):深入解讀Redis主從同步機制

首發博客地址 https://blog.zysicyj.top/ Redis高可靠靠什么保證&#xff1f; 為什么要提這個呢&#xff0c;因為Redis主從庫目的呢其實就是為了實現高可靠。上篇文章中我們說過Redis的AOF、RDB日志其實就是為了減少數據丟失&#xff0c;這是高可靠的一部分。 這篇文章呢&#…

Lua 位和字節

一、位運算 從 Lua 5.3 版本開始&#xff0c;提供了針對數值類型的一組標準位運算符&#xff0c;與算數運算符不同的是&#xff0c;運算符只能用于整型數。 運算符描述&按位與|按位或&#xff5e;按位異或>>邏輯右移<<邏輯左移&#xff5e;&#xff08;一元運…

Git 如何使用TortoiseGit 操作本地倉庫

初始化倉庫 方法一: 新建一個文件夾,進入文件夾內部操作 1、右鍵--> 在這里創建Git 版本庫 注意: 不要直接在桌面上操作,否則桌面就是一個倉庫 方法二: 1、右鍵-->Git GUI here 方法三: 命令行模式 1、 git init 創建完畢倉庫,我們發現,此時我們創建的文件夾下…

leetcode做題筆記83刪除排序鏈表中的重復元素

給定一個已排序的鏈表的頭 head &#xff0c; 刪除所有重復的元素&#xff0c;使每個元素只出現一次 。返回 已排序的鏈表 。 輸入&#xff1a;head [1,1,2] 輸出&#xff1a;[1,2] 思路一&#xff1a;模擬題意 struct ListNode* deleteDuplicates(struct ListNode* head){i…

FreeRTOS qemu mps2-an385 bsp 移植制作 :系統運行篇

相關文章 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;環境搭建篇 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;系統啟動篇 開發環境 Win10 64位 VS Code&#xff0c;ssh 遠程連接 ubuntu VMware Workstation Pro 16 Ubuntu 20.04 FreeRTOSv202212.01&a…

React 全棧體系(二)

第二章 React面向組件編程 一、基本理解和使用 1. 使用React開發者工具調試 2. 效果 2.1 函數式組件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>1_函數式組件</title> </head> &l…

計算機競賽 python 爬蟲與協同過濾的新聞推薦系統

1 前言 &#x1f525; 優質競賽項目系列&#xff0c;今天要分享的是 &#x1f6a9; python 爬蟲與協同過濾的新聞推薦系統 &#x1f947;學長這里給一個題目綜合評分(每項滿分5分) 難度系數&#xff1a;3分工作量&#xff1a;3分創新點&#xff1a;4分 該項目較為新穎&…

軟件壓力測試對軟件產品起到什么作用?

一、軟件壓力測試是什么? 軟件壓力測試是一種通過模擬正常使用環境中可能出現的大量用戶和大數據量的情況&#xff0c;來評估軟件系統在壓力下的穩定性和性能表現的測試方法。在軟件開發過程中&#xff0c;經常會遇到一些性能瓶頸和穩定性問題&#xff0c;而軟件壓力測試的作…

react-codemirror2 編輯器需點擊一下或者延時才顯示數據的問題

現象&#xff1a; <Codemirror/>組件的數據已經賦上值的情況下&#xff0c;初始狀態不渲染數據&#xff0c;需要點擊編輯框獲取焦點后才展示&#xff0c;或者延遲了幾秒才顯示出來。 原因&#xff1a; 指定了一些依賴的版本&#xff0c;可能不兼容了一些功能&#xff0c…

C# int ? 關鍵字使用方法

使用C#的時間也不算短。 但是今天看到了一個從來沒有見過的寫法 Int &#xff1f;這是個什么寫法&#xff0c;沒見過啊&#xff0c;百度了查一下&#xff0c;也在這里記錄一下。 1、int? 關鍵字說明 (1)、int? 表示一個int類型,且該int類型可空,如果不加?的話,那么int類…

C語言刷題指南(一)

&#x1f4d9;作者簡介&#xff1a; 清水加冰&#xff0c;目前大二在讀&#xff0c;正在學習C/C、Python、操作系統、數據庫等。 &#x1f4d8;相關專欄&#xff1a;C語言初階、C語言進階、數據結構刷題訓練營、有感興趣的可以看一看。 歡迎點贊 &#x1f44d; 收藏 ?留言 &am…

認識excel篇3之數據的有效性(數據驗證)

數據有效性不僅能夠對單元格的輸入數據進行條件限制&#xff0c;還可以在單元格中創建下拉列表菜單方便用戶選擇輸入。如果沒有做數據驗證&#xff0c;單元格內默認可以輸入任意類型的數據。數據驗證就是限制單元格輸入數據&#xff08;必須輸入符合要求的才能輸入&#xff09;…

VS2022如何查看類成員都在哪里被調用了(VS如何打開Call Hierarchy視圖)

文章目錄 打開Call Hierarchy視圖查看成員的調用 打開Call Hierarchy視圖 單擊菜單欄的“視圖” > “調用層次結構”&#xff0c;即可打卡Call Hierarchy視圖。 查看成員的調用 在代碼編輯窗口&#xff0c;右鍵單擊想要查看的類成員&#xff0c;然后選擇“查看調用層次結…

機器學習算法之-邏輯回歸(2)

為什么需要邏輯回歸 擬合效果太好 特征與標簽之間的線性關系極強的數據&#xff0c;比如金融領域中的 信用卡欺詐&#xff0c;評分卡制作&#xff0c;電商中的營銷預測等等相關的數據&#xff0c;都是邏輯回歸的強項。雖然現在有了梯度提升樹GDBT&#xff0c;比邏輯回歸效果更…

一、數學建模之線性規劃篇

1.定義 2.例題 3.使用軟件及解題 一、定義 1.線性規劃&#xff08;Linear Programming&#xff0c;簡稱LP&#xff09;是一種數學優化技術&#xff0c;線性規劃作為運籌學的一個重要分支&#xff0c;專門研究在給定一組線性約束條件下&#xff0c;如何找到一個最優的決策&…

JavaScript請求數據的4種方法總結(Ajax、fetch、jQuery、axios)

JavaScript請求數據有4種主流方式&#xff0c;分別是Ajax、fetch、jQuery和axios。 一、Ajax、fetch、jQuery和axios的詳細解釋&#xff1a; 1、 Ajax Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一種使用JavaScript在用戶的瀏覽器上發送請求的技術&…