Spring AOP詳解面向切面編程思想
1. 什么是 Spring AOP
AOP (Aspect Oriented Programming): 面向切面編程, 它是一種思想, 它是對(duì)某一類(lèi)事情的集中處理.
例如, 在沒(méi)有學(xué)習(xí)AOP之前, 之前的判斷當(dāng)前登錄狀態(tài), 就需要在每一個(gè)頁(yè)面都實(shí)現(xiàn)登錄校驗(yàn), 在有了AOP之后, 外面只需在某一處配置以下, 所有的頁(yè)面就都可以實(shí)現(xiàn)登錄驗(yàn)證了, 就不需要寫(xiě)太多重復(fù)的代碼,
Spring AOP, 是一個(gè)框架, 提高了一種對(duì) AOP 思想的實(shí)現(xiàn).
2. AOP 的組成

2.1 切面 (Aspect)
切面由切點(diǎn)和通知組成, 它既包含了橫切邏輯的定義, 也包括了連接點(diǎn)的定義.
切面是包含了: 通知, 切點(diǎn)和切面的類(lèi), 相當(dāng)于 AOP 實(shí)現(xiàn)的某個(gè)功能的集合
2.2 切點(diǎn) (Pointcur)
切點(diǎn)的作用就是提供一組規(guī)則 (使用 AspectJ pointcut expression language 來(lái)描述) 來(lái)匹配 連接點(diǎn), 給滿足規(guī)則的 連接點(diǎn)添加 Advice
切點(diǎn)相當(dāng)于保存了眾多連接點(diǎn)的一個(gè)集合
2.3 連接點(diǎn) (Join Point)
應(yīng)用執(zhí)行過(guò)程中能夠插入切面的一個(gè)點(diǎn), 這個(gè)點(diǎn)可以是方法的調(diào)用時(shí), 拋出異常時(shí), 甚至修改字段時(shí). 切面代碼可以利用這些點(diǎn)插入到應(yīng)用的正常流程之中, 并添加新的行為.
連接點(diǎn)相當(dāng)于需要被增強(qiáng)的某個(gè) AOP 功能的所有方法.
2.4 通知 (Advice)
定義了切面是什么, 何時(shí)使用, 其描述切面要完成的工作, 還解決何時(shí)執(zhí)行這個(gè)工作的問(wèn)題,
Spring切面類(lèi)中, 可以在方法上使用以下注解, 會(huì)設(shè)置方法為通知方法, 在滿足條件后會(huì)通知本方法進(jìn)行調(diào)用.
?法進(jìn)?調(diào)用:
前置通知使用 @Before:通知方法會(huì)在目標(biāo)方法調(diào)用之前執(zhí)行.
后置通知使用 @After:通知方法會(huì)在目標(biāo)方法返回或者拋出異常后調(diào)用.
返回之后通知使用 @AfterReturning:通知方法會(huì)在目標(biāo)方法返回后調(diào)用.
拋異常后通知使用 @AfterThrowing:通知方法會(huì)在目標(biāo)方法拋出異常后調(diào)用.
環(huán)繞通知使用 @Around:通知包裹了被通知的方法, 在被通知的方法通知之前和調(diào)用之后執(zhí)行自定義的行為.
3. Spring AOP 的使用
3.1 添加 AOP 框架
在 pom.xml 中添加依賴(lài)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/springboot-starter-aop --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
3.2 定義切面和切點(diǎn)
@Aspect // 定義切面
@Component
public class UserAspect {
// 切點(diǎn) (配置攔截規(guī)則)
@Pointcut("execution(* com.example.demo.controller.UserController.*)")
public void pointcut() {
// 這是一個(gè)空方法, 不需要有具體的實(shí)現(xiàn)
}
}
切點(diǎn)表達(dá)式注意事項(xiàng)
AspectJ 支持三種通配符
*: 匹配任意字符, 只匹配一個(gè)元素 (包, 類(lèi), 方法, 方法參數(shù))..: 匹配任意字符,可以匹配多個(gè)元素, 在標(biāo)識(shí)類(lèi)時(shí), 必須聯(lián)合*使用+: 表示按類(lèi)型匹配指定類(lèi)和所有類(lèi), 必須跟在類(lèi)名后面, 如com.cad.Car+, 表示繼承該類(lèi)的所有子類(lèi)包括本身
execution() 是最常用的切點(diǎn)函數(shù)
語(yǔ)法為: execution(<修飾符> <返回類(lèi)型> <包.類(lèi).方法(參數(shù))> <異常>) (注意: 修飾符和異??梢允÷?
示例:
execution(* com.cad.demo.User.*(..)):匹配 User 類(lèi)?的所有?法。execution(* com.cad.demo.User+.*(..)):匹配該類(lèi)的?類(lèi)包括該類(lèi)的所有?法。execution(* com.cad.*.*(..)):匹配 com.cad 包下的所有類(lèi)的所有?法。execution(* com.cad..*.*(..)):匹配 com.cad 包下、?孫包下所有類(lèi)的所有?法。execution(* addUser(String, int)):匹配 addUser ?法,且第?個(gè)參數(shù)類(lèi)型是 String,第?個(gè)參數(shù)類(lèi)型是 int。
3.3 定義通知 (五種)
@Aspect // 定義切面
@Component
public class UserAspect {
// 切點(diǎn) (配置攔截規(guī)則)
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut() {
// 這是一個(gè)空方法, 不需要有具體的實(shí)現(xiàn)
}
@Before("pointcut()")
public void doBefore(){
System.out.println("執(zhí)行 Before 方法");
}
@After("pointcut()")
public void doAfter(){
System.out.println("執(zhí)行 After 方法");
}
@AfterReturning("pointcut()")
public void doAfterReturning() {
System.out.println("執(zhí)行 AfterReturning 方法");
}
@AfterThrowing("pointcut()")
public void doAfterThrowing() {
System.out.println("執(zhí)行 AfterThrowing 方法");
}
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) {
Object object = null;
System.out.println("Around 方法開(kāi)始執(zhí)行");
try {
// 執(zhí)行攔截方法
object = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("Around 方法結(jié)束執(zhí)行");
return object;
}
}正常時(shí)

拋出異常時(shí)

4. Spring AOP 實(shí)現(xiàn)原理
Spring AOP 是構(gòu)建在動(dòng)態(tài)代理基礎(chǔ)上, 因此 Spring 對(duì) AOP 的支持局限于方法級(jí)別的攔截.
Spring AOP 是基于動(dòng)態(tài)代理實(shí)現(xiàn)的.
動(dòng)態(tài)代理分為兩類(lèi):
- JDK Proxy(JDK 動(dòng)態(tài)代理機(jī)制)
- CGLIB 動(dòng)態(tài)代理
默認(rèn)情況下, 實(shí)現(xiàn)了接口的類(lèi), 使用 AOP 會(huì)基于 JDK 生成代理類(lèi), 沒(méi)有實(shí)現(xiàn)接口的類(lèi), 會(huì)基于 CGLIB 生成代理類(lèi)
4.1 織入 (Weaving)
代理的生成時(shí)機(jī)
織?是把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過(guò)程,切面在指定的連接點(diǎn)被織?到目標(biāo)對(duì)象中。
在目標(biāo)對(duì)象的?命周期里有多個(gè)點(diǎn)可以進(jìn)?織入:
- 編譯期:切面在目標(biāo)類(lèi)編譯時(shí)被織?。這種?式需要特殊的編譯器。AspectJ的織?編譯器就是以這種方式織入切?的。
- 類(lèi)加載器:切?在目標(biāo)類(lèi)加載到JVM時(shí)被織入。這種方式需要特殊的類(lèi)加載器(ClassLoader),它可以在目標(biāo)類(lèi)被引入應(yīng)用之前增強(qiáng)該目標(biāo)類(lèi)的字節(jié)碼。AspectJ5的加載時(shí)織入(load-time weaving. LTW)就支持以這種方式織入切面。
- 運(yùn)行期:切面在應(yīng)用運(yùn)行的某?時(shí)刻被織入。?般情況下,在織入切面時(shí),AOP容器會(huì)為目標(biāo)對(duì)象動(dòng)態(tài)創(chuàng)建一個(gè)代理對(duì)象. Spring AOP 就是以這種方式織入切面的
4.2 JDK 和 CGLIB 實(shí)現(xiàn)的區(qū)別
- JDK 實(shí)現(xiàn)要求被代理類(lèi)必須實(shí)現(xiàn)接口, 之后是通過(guò)
InvocationHandler及Proxy, 在運(yùn)行時(shí)動(dòng)態(tài)的在內(nèi)存中生成了代理類(lèi)對(duì)象, 該代理對(duì)象是通過(guò)實(shí)現(xiàn)同樣的接口實(shí)現(xiàn) (類(lèi)似靜態(tài)代理接口實(shí)現(xiàn)的方式), 只是該代理類(lèi)是在運(yùn)行期時(shí),動(dòng)態(tài)的織入統(tǒng)一的業(yè)務(wù)邏輯字節(jié)碼來(lái)完成. - CGLIB 實(shí)現(xiàn), 被代理類(lèi)可以不實(shí)現(xiàn)接口, 是通過(guò)繼承被代理類(lèi), 在運(yùn)行時(shí)動(dòng)態(tài)的生成代理類(lèi)對(duì)象.
到此這篇關(guān)于Spring AOP詳解面向切面編程思想的文章就介紹到這了,更多相關(guān)Spring AOP切面編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java網(wǎng)上圖書(shū)商城(4)購(gòu)物車(chē)模塊1
這篇文章主要為大家詳細(xì)介紹了java網(wǎng)上圖書(shū)商城,購(gòu)物車(chē)模塊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)源碼解析
這篇文章主要為大家介紹了Spring?Data?Redis切換底層Jedis和Lettuce實(shí)現(xiàn)方法源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
java中阻塞隊(duì)列和非阻塞隊(duì)列的實(shí)現(xiàn)
在Java并發(fā)編程中,阻塞隊(duì)列和非阻塞隊(duì)列是兩種主要的隊(duì)列類(lèi)型,分別適用于不同的場(chǎng)景,了解這兩種隊(duì)列的特點(diǎn)和工作機(jī)制,可以幫助開(kāi)發(fā)者更好地選擇合適的數(shù)據(jù)結(jié)構(gòu)解決并發(fā)問(wèn)題2024-10-10
Java 實(shí)戰(zhàn)項(xiàng)目錘煉之嘟嘟健身房管理系統(tǒng)的實(shí)現(xiàn)流程
讀萬(wàn)卷書(shū)不如行萬(wàn)里路,只學(xué)書(shū)上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)一個(gè)健身房管理系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2021-11-11
SpringBoot整合RabbitMQ及生產(chǎn)全場(chǎng)景高級(jí)特性實(shí)戰(zhàn)
本文主要介紹了SpringBoot整合RabbitMQ及生產(chǎn)全場(chǎng)景高級(jí)特性實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10

