深入理解spring的AOP機制原理
前言
在軟件開發(fā)中,散布于應(yīng)用中多處的功能被稱為橫切關(guān)注點,通常來講,這些橫切關(guān)注點從概念上是與應(yīng)用的業(yè)務(wù)邏輯相分離的。把這些橫切關(guān)注點和業(yè)務(wù)邏輯分離出來正是AOP要解決的問題。AOP能夠幫我們模塊化橫切關(guān)注點,換言之,橫切關(guān)注點可以被描述為影響應(yīng)用多出的功能。這些橫切點被模塊化特殊的類,這些類被稱為切面。
術(shù)語定義
通知:切面有必須要完成的工作,在AOP中,切面的工作被稱為通知。通知定義了切面是什么以及何時使用,除了描述切面要完成的工作,通知還解決了何時執(zhí)行這個工作的問題,它應(yīng)該在某個方法之前?之后?之前和之后都調(diào)用?還是只在方法拋出異常時調(diào)用?
連接點:連接點是應(yīng)用程序執(zhí)行過程中,能夠插入切面的一個點。
切點:是在連接點的基礎(chǔ)上定義切點,比方說一個類由十幾個方法,每個方法的調(diào)用前和調(diào)用后都可以插入通知,但是你只想選擇幾個方法插入通知,因此你定義一個切點來選擇你想插入的通知的方法。
切面:切面就是通知和切點的結(jié)合。
織入:織入是把切面應(yīng)用到目標(biāo)對象并創(chuàng)建新的代理對象的過程,切面在指定的連接點被織入到目標(biāo)對象中。在目標(biāo)對象的生命周期里有多個點可以進行織入:編譯期、類加載期、運行期。其中編譯器織入需要特殊的編譯器,類加載器織入需要特殊的類加載器,spring的AOP 是在運行期織入通知的。
Spring的AOP支持
spring提供了AOP的四種支持,分別是:基于代理的經(jīng)典Spring AOP模式;純POJO切面;@AspectJ注解驅(qū)動的切面;@注入式AspectJ切面。spring所創(chuàng)建的通知都是用標(biāo)準(zhǔn)的Java類編寫的,而且定義通知所應(yīng)用的切點通常會使用注解或在Spring配置文件里采用XML來編寫。
spring只支持方法級別的連接點。
在spring AOP中,要使用AspectJ的切點表達式語言來定義切點,關(guān)于Spring AOP的AspectJ切點,最重要的一點就是Spring僅支持AspectJ切點指示器的一個子集:
1.arg() 限制連接點匹配參數(shù)為指定類型的執(zhí)行方法;
2.@args() 限制連接點匹配參數(shù)由指定注解標(biāo)注的執(zhí)行方法;
3.execution() 用于匹配是連接點的執(zhí)行方法;
4.this() 限制連接點匹配AOP代理的bean引用為指定類型的類
5.target 限制連接點匹配目標(biāo)對象為指定類型的類
6.@target() 限制連接點匹配特定的執(zhí)行對象,這些對象對應(yīng)的類要具有指定類型的注解
7.within() 限制連接點匹配指定的類型
8.@within() 限制連接點匹配特定注解所標(biāo)注的類型
9.@annotation 限定匹配帶有指定注解的連接點
spring 注解創(chuàng)建切面
目標(biāo)對象:
package concert;
public interface Performance{
public void perform();
}
切面對象:
package concert;
@Aspect//表示Audience的實例是一個切面
public class Audience{
@Before("execution(**concert.Performance.perform(..))")
public void silenceCellPhones(){
//在perfrom方法執(zhí)行之前
}
@Before("execution(**concert.Performance.perform(..))")
public void takeSeats(){
//在perfrom方法執(zhí)行之前
}
@AfterReturning("execution(**concert.Performance.perform(..))")
public void silenceCellPhones(){
//在perfrom方法執(zhí)行之后
}
@AfterThrowing("execution(**concert.Performance.perform(..))")
public void silenceCellPhones(){
//在perfrom方法拋出異常之后
}
}
上面的類中切點表達式execution(**concert.Performance.perform(..))多次出現(xiàn),我們也可以通過@Pointcut注解避免每次都寫很長的切點表但是如下所示:
@Aspect//表示Audience的實例是一個切面
public class Audience{
@Pointcut("execution(**concert.Performance.perform(..))")
public void performance(){}
@Before("performance()")
public void silenceCellPhones(){
//在perfrom方法執(zhí)行之前
}
@Before("performance()")
public void takeSeats(){
//在perfrom方法執(zhí)行之前
}
@AfterReturning("performance()")
public void silenceCellPhones(){
//在perfrom方法執(zhí)行之后
}
@AfterThrowing("performance()")
public void silenceCellPhones(){
//在perfrom方法拋出異常之后
}
}
接下來需要在配置文件中配置切面如下所示:
@Configuration
@EnableAspectJAutoProxy//啟動AspectJ自動代理
@ComponentScan
public class ConcertConfig{
}
//或者在配置文件中配置中添加
<aop:aspectj-autoproxy />
表示啟動切面代理
環(huán)繞通知:
@Aspect//表示Audience的實例是一個切面
public class Audience{
@Pointcut("execution(**concert.Performance.perform(..))")
public void performance(){}
@Before("performance()")
public void watchPerformance(ProceedingJoinPoint jp){
//在方法之前執(zhí)行
System.out.println(" beform the method is invoked");
jp.proceed()//控制權(quán)交給目標(biāo)方法
//在方法之后執(zhí)行
System.out.println(" after the method is invoked");
}
}
處理通知中的參數(shù)
public class Audience{
@Pointcut("execution(**concert.Performance.perform(int))&&args(trackNumber)")
public void performance(){}
@Before("performance(trackNumber)")
public void watchPerformance(int trackNumber){
//截獲傳遞給目標(biāo)方法的參數(shù)并傳遞給切面中處理方法
System.out.println(trackNumber);
}
}
xml中聲明切面
spring AOP提供的xml配置元素:
1.<aop:advisor> 定義AOP通知;
2.<aop:after> 后置通知;
3.<aop:after-returning> 返回通知
4.<aop:around> 環(huán)繞通知
5.<aop:aspect> 定義一個切面
6.<aop:aspectj-autoproxy> 啟用切面注解驅(qū)動
7.<aop:before> 前置通知
8.<aop:config> 頂層的AOP配置元素;
9.<aop:pointcut>:定義個切點
<aop:config>
<aop:aspect ref="audience">
<aop:before
pointcut="execution(**concert.Performance.perform())" method="silenceCellPhones"/>
<aop:before
pointcut="execution(**concert.Performance.perform())" method="takeSeats"/>
<aop:after-returning
pointcut="execution(**concert.Performance.perform())" method="applause"/>
<aop:after-throwing
pointcut="execution(**concert.Performance.perform())" method="demandRefund"/>
</aop:aspect>
</aop config>
定義切點:
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="performance" expression="execution(**concert.Performance.perform())">
<aop:before
pointcut-ref="performance" method="silenceCellPhones"/>
<aop:before
pointcut="performance" method="takeSeats"/>
<aop:after-returning
pointcut="performance" method="applause"/>
<aop:after-throwing
pointcut="performance" method="demandRefund"/>
</aop:aspect>
</aop config>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
MybatisPlus使用idworker解決雪花算法重復(fù)
本文主要介紹了MybatisPlus使用idworker解決雪花算法重復(fù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
Java多線程CountDownLatch的實現(xiàn)
本文主要介紹了Java多線程CountDownLatch的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
Java調(diào)用計算機攝像頭拍照實現(xiàn)過程解析
這篇文章主要介紹了Java調(diào)用計算機攝像頭拍照實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-05-05
java線程之用Thread類創(chuàng)建線程的方法
本篇文章介紹了,Thread類創(chuàng)建線程的方法。需要的朋友參考下2013-05-05
如何在Mac上安裝并配置JDK環(huán)境變量詳細(xì)步驟
這篇文章主要介紹了如何在Mac上安裝并配置JDK環(huán)境變量詳細(xì)步驟,包括下載JDK、安裝JDK、配置環(huán)境變量、驗證JDK配置以及可選地設(shè)置PowerShell為默認(rèn)終端,需要的朋友可以參考下2025-04-04
使用IDEA直接連接MySQL數(shù)據(jù)庫的方法
這篇文章主要介紹了如何使用IDEA直接連接MySQL數(shù)據(jù)庫,首先需要新建一個空項目,第一次連接 需要先下載驅(qū)動,文中給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-04-04
SpringBoot配置返回數(shù)據(jù)不存在null的問題小結(jié)
文章介紹了在Spring Boot項目中使用Jackson序列化器處理JSON數(shù)據(jù)時遇到的問題,特別是如何配置Jackson以返回不包含null值的JSON響應(yīng),并探討了Jackson的三種主要JSON處理方法,感興趣的朋友一起看看吧2025-02-02

