Spring AOP高級應(yīng)用與源碼剖析
Spring AOP 高級應(yīng)用
AOP的本質(zhì):在不改變原有業(yè)務(wù)邏輯的情況下增強橫切邏輯,橫切邏輯代碼往往是權(quán)限校驗代碼,日志代碼,事務(wù)控制代碼,性能監(jiān)測代碼。
AOP相關(guān)術(shù)語
名詞 | 解釋 |
JoinPoint(連接點) | 可以用于把增強代碼加入到業(yè)務(wù)主線中的點 |
Pointcut(切入點) | 已經(jīng)把增強代碼加入到業(yè)務(wù)主線進來之后的連接點 |
Adice(通知/增強) | 切面類中用于提供增強功能的方法 |
Target(目標(biāo)對象) | 代理的目標(biāo)對象。即被代理對象 |
Proxy(代理) | 一個類被AOP植入增強后,產(chǎn)生的代理類 |
Weaving(織入) | 把增強應(yīng)用到目標(biāo)對象來創(chuàng)建新的代理對象的過程 |
Aspect(切面) | 指定增強的代碼所關(guān)注的方面,把這些相關(guān)的增強代碼定義到一個類中,這個類就是切面類。 |
Spring中AOP的代理選擇
AOP思想使用的是動態(tài)代理。默認情況下Spring會根據(jù)代理對象是否實現(xiàn)接口來選擇使用JDK還是CGLIB。當(dāng)代理對象沒有實現(xiàn)任何接口時,Spring會選擇CGLIB。
Spring中AOP實現(xiàn)XML形式
maven坐標(biāo)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>Aop核心配置
<!-- Spring基于XML的AOP配置前期準(zhǔn)備: 在spring的配置?件中加?aop的約束 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd Spring基于XML的AOP配置步驟、 第?步:把通知Bean交給Spring管理 第?步:使?aop:config開始aop的配置 第三步:使?aop:aspect配置切? 第四步:使?對應(yīng)的標(biāo)簽配置通知的類型 ??案例采?前置通知,標(biāo)簽為aop:before --> <!--把通知bean交給spring來管理--> <bean id="logUtil" class="com.lagou.utils.LogUtil"></bean> <!--開始aop的配置--> <aop:config> <!--配置切?--> <aop:aspect id="logAdvice" ref="logUtil"> <!--配置前置通知--> <aop:before method="printLog" pointcut="execution(public * com.lagou.service.impl.TransferServiceImpl.updateAccountByCardNo(com.lagou .pojo.Account))"></aop:before> </aop:aspect> </aop:config>
切入表達式,也稱之為Aspectj切入點表達式,指的是遵循特定語法結(jié)構(gòu)的字符串,其作用是用于對符合語法格式的連接點進行增強。
改變代理方式的配置:
我們知道只要不是final修飾的類都可以是cglib提供的方式來創(chuàng)建代理對象,spring提供了兩種配置方式:
- 使用aop:config標(biāo)簽配置
<aop:config proxy-target-class="true">
- 使用aop:aspectj-autoproxy標(biāo)簽配置
<!--此標(biāo)簽是基于XML和注解組合配置AOP時的必備標(biāo)簽,表示Spring開啟注解配置AOP的?持--> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectjautoproxy>
5中AOP通知類型:
1. 前置通知
- 配置方式:
<aop:before method="方法名" pointcut-ref="切入點引用"/> - 出現(xiàn)位置:僅在
<aop:aspect>標(biāo)簽內(nèi) - 執(zhí)行時機:切入方法(業(yè)務(wù)核心方法)執(zhí)行之前(必定執(zhí)行)
- 細節(jié):可獲取切入方法的參數(shù)并增強
2. 正常執(zhí)行時通知(后置返回通知)
- 配置方式:
<aop:after-returning method="方法名" pointcut-ref="切入點引用"/> - 出現(xiàn)位置:僅在
<aop:aspect>標(biāo)簽內(nèi) - 執(zhí)行時機:切入方法正常執(zhí)行完成后(若方法拋異常則不執(zhí)行)
3. 異常通知
- 配置方式:
<aop:after-throwing method="方法名" pointcut-ref="切入點引用"/> - 出現(xiàn)位置:僅在
<aop:aspect>標(biāo)簽內(nèi) - 執(zhí)行時機:切入方法產(chǎn)生異常之后(無異常則不執(zhí)行)
- 細節(jié):可獲取切入方法的參數(shù) + 異常信息
4. 最終通知
- 配置方式:
<aop:after method="方法名" pointcut-ref="切入點引用"/> - 出現(xiàn)位置:僅在
<aop:aspect>標(biāo)簽內(nèi) - 執(zhí)行時機:切入方法執(zhí)行完成后、返回之前(無論是否拋異常,必定執(zhí)行)
- 細節(jié):可獲取參數(shù),常用于清理操作
5. 環(huán)繞通知
- 配置方式:
<aop:around method="方法名" pointcut-ref="切入點引用"/> - 出現(xiàn)位置:僅在
<aop:aspect>標(biāo)簽內(nèi) - 特殊說明:是 Spring 的 “特殊通知”,可通過編程控制通知執(zhí)行時機(區(qū)別于前四種 “指定時機” 的通知);依賴
ProceedingJoinPoint接口,實現(xiàn)手動觸發(fā)切入方法的調(diào)用
Spring中AOP實現(xiàn)XML+注解形式
XML配置 | 注解配置 |
<aop:before method="方法名" pointcut-ref="切入點引用"/> | @Before |
<aop:after-returning method="方法名" pointcut-ref="切入點引用"/> | @AfterReturning |
<aop:after-throwing method="方法名" pointcut-ref="切入點引用"/> | @AfterThrowing |
<aop:after method="方法名" pointcut-ref="切入點引用"/> | @After |
<aop:around method="方法名" pointcut-ref="切入點引用"/> | @Around |
Spring中AOP實現(xiàn)注解形式
在我們使用注解開發(fā)時候要用注解替換掉配置文件
<!--開啟spring對注解aop的?持--> <aop:aspectj-autoproxy/>
需要在啟動類上面添加
@EnableAspectJAutoProxy //開啟spring對注解AOP的?持
Spring聲明式事務(wù)的支持
編程式事務(wù):在業(yè)務(wù)代碼中添加事務(wù)控制代碼,這樣的事務(wù)控制機制叫做編程式事務(wù)。
聲明式事務(wù):通過xml或者注解配置的方式達到事務(wù)控制的目的,叫做聲明式事務(wù)。
事務(wù)的四大特性:
- 原子性:原子性式指事務(wù)是一個不可分割的工作單位,事務(wù)中的操作要么全部發(fā)生,要么全部不發(fā)生。
- 一致性:事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換成另一個一致性狀態(tài)。
- 隔離性:事務(wù)的隔離性式多個用戶并發(fā)訪問數(shù)據(jù)庫時,數(shù)據(jù)庫未每一個用戶開啟的事務(wù),每個事務(wù)不能被其他事務(wù)的操作數(shù)據(jù)所干擾,多個并發(fā)事務(wù)之間要相互隔離。
- 持久性:持久性時指一個事務(wù)一旦被提交,它對數(shù)據(jù)中數(shù)據(jù)的改變就是永久性的,接下來即使數(shù)據(jù)庫發(fā)送故障也不應(yīng)該對其有任何影響。
不考慮事務(wù)隔離級別會出現(xiàn)的問題:
- 臟讀:一個線程中的事務(wù)讀到另一個線程中未提交的數(shù)據(jù)。
- 不可重復(fù)讀:一個線程的事務(wù)讀到另一個線程中已經(jīng)提交的update的數(shù)據(jù)(前后內(nèi)容不一樣)。
- 幻讀:一個線程中的事務(wù)讀取到了另一個線程中已經(jīng)提交的insert或者delete的數(shù)據(jù)(前后條數(shù)不一樣)。
數(shù)據(jù)庫中定義的四種隔離級別(從高到低):
- Serializable(串行化):避免臟讀,不可重復(fù)讀,虛讀情況的發(fā)生。
- Repeatable read(可重復(fù)讀):可避免臟讀,不可重復(fù)讀情況發(fā)生。
- Read committed(讀已提交):可避免臟讀情況發(fā)生。
- Read uncommitted(讀未提交):以上情況都沒有保證。
Mysql默認的事務(wù)隔離級別是:讀已提交。
查詢當(dāng)前使用的隔離級別:SELECT @@session.transaction_isolation;
設(shè)置Mysql事務(wù)的隔離級別:(僅僅是當(dāng)前會話的隔離級別)SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
傳播行為常量 | 中文名稱 | 核心規(guī)則 | 適用場景 |
(默認) | 必需的 | 如果當(dāng)前有事務(wù),加入該事務(wù);如果無事務(wù),新建事務(wù)。 | 絕大多數(shù)業(yè)務(wù)(如訂單 + 庫存) |
| 支持的 | 如果當(dāng)前有事務(wù),加入;無事務(wù),則以非事務(wù)方式執(zhí)行。 | 查詢類方法(可選事務(wù)) |
| 強制的 | 必須在已有事務(wù)中執(zhí)行;無事務(wù)則拋異常( | 核心子操作(必須依賴外層事務(wù)) |
| 新建的 | 無論當(dāng)前是否有事務(wù),都新建獨立事務(wù);原有事務(wù)暫停,新事務(wù)執(zhí)行完后恢復(fù)。 | 日志記錄、消息發(fā)送(獨立事務(wù)) |
| 不支持的 | 以非事務(wù)方式執(zhí)行;若當(dāng)前有事務(wù),暫停原有事務(wù)。 | 純查詢(無需事務(wù),提升性能) |
| 從不 | 必須以非事務(wù)方式執(zhí)行;若當(dāng)前有事務(wù),拋異常。 | 絕對禁止事務(wù)的操作 |
| 嵌套的 | 基于當(dāng)前事務(wù)創(chuàng)建嵌套子事務(wù)(Savepoint 實現(xiàn));子事務(wù)回滾不影響外層,外層回滾則全滾。 | 批量操作(部分失敗可回滾) |
純xml方式
<!-- 配置事務(wù)管理器(基于JDBC數(shù)據(jù)源) -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/> <!-- 引用已配置的數(shù)據(jù)源 -->
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 全局默認配置:所有方法默認非只讀,傳播行為REQUIRED -->
<tx:method name="*" read-only="false"
propagation="REQUIRED" isolation="DEFAULT" timeout="-1"/>
<!-- 針對查詢方法的單獨配置:只讀,傳播行為SUPPORTS -->
<tx:method name="query*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切入點:匹配TransferServiceImpl類的所有方法 -->
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))"/>
</aop:config>xml+注解方式
<!-- 開啟Spring注解事務(wù)的支持 --> <tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
純注解方式
需要在啟動類上加入@EnableTransactionManagement
到此這篇關(guān)于Spring AOP高級應(yīng)用與源碼剖析的文章就介紹到這了,更多相關(guān)Spring AOP源碼分析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在IDEA中搭建最小可用SpringMVC項目(純Java配置)
這篇文章主要介紹了在IDEA中搭建最小可用SpringMVC項目(純Java配置),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
IDEA運行導(dǎo)入的javaweb項目tomcat正常,但是運行失敗404問題
這篇文章主要介紹了IDEA運行導(dǎo)入的javaweb項目tomcat正常但是運行失敗404問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07
xxl-job在 Spring Boot 項目中的完整配置指南(最新整理)
本文詳細介紹了Spring Boot任務(wù)調(diào)度配置,包括依賴配置、多環(huán)境支持、任務(wù)處理器、高級配置、常見問題及解決方法,以及項目結(jié)構(gòu)和注意事項,感興趣的朋友跟隨小編一起看看吧2025-12-12
基于springboot服務(wù)間Feign調(diào)用超時的解決方案
這篇文章主要介紹了基于springboot服務(wù)間Feign調(diào)用超時的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

