【JavaEE】 AOP(1)
【JavaEE】AOP(1)
1. Spring AOP 是什么
1.1 AOP 與 Spring AOP
AOP ( A spect O riented Programming),是一種思想,即面向切面編程
Spring AOP 則是一個(gè)框架,Spring項(xiàng)目中需要引入依賴(lài)而使用
- AOP和Spring AOP的關(guān)系就相當(dāng)于IoC和DI
- Spring AOP讓開(kāi)發(fā)者能夠半自動(dòng)的開(kāi)發(fā)AOP思想下實(shí)現(xiàn)的功能
1.2 沒(méi)有AOP的世界是怎樣的
我們要實(shí)現(xiàn)用戶(hù)登錄校驗(yàn)的功能,沒(méi)有實(shí)現(xiàn)AOP之前,我們只能這樣做:
博客系統(tǒng)登錄功能實(shí)現(xiàn),博客傳送門(mén):【JavaEE】前后端綜合項(xiàng)目-博客系統(tǒng)(下)_s:103的博客-CSDN博客
- 前端進(jìn)入每一個(gè)頁(yè)面的時(shí)候,專(zhuān)門(mén)發(fā)送“登錄校驗(yàn)”的請(qǐng)求給后端進(jìn)行登錄校驗(yàn)
- 前端發(fā)送每一個(gè)請(qǐng)求的時(shí)候,后端都會(huì)自動(dòng)進(jìn)行登錄校驗(yàn)
無(wú)論是哪種,都有這樣的特性,就是代碼耦合度高,網(wǎng)頁(yè)的每個(gè)功能都要各自實(shí)現(xiàn)“登錄校驗(yàn)”的代碼,這樣的壞處是:
- 不符合專(zhuān)一設(shè)計(jì)原則,開(kāi)發(fā)者開(kāi)發(fā)一個(gè)功能就應(yīng)該全心全意,有針對(duì)性,這樣開(kāi)發(fā)效率也會(huì)高點(diǎn)兒~
- 耦合度很高,一改則需萬(wàn)改
圖示:
1.3 AOP是什么
剛才說(shuō)了,AOP是面向切面編程,這是英語(yǔ)直譯的結(jié)果,不用太多理會(huì)~
- 可以理解為,它是 對(duì)某一類(lèi)事情的集中處理
有了AOP后,我們只需要在代碼的某一處配置一下,所有的功能就能實(shí)現(xiàn)用戶(hù)登錄校驗(yàn)了,不再需要重復(fù)寫(xiě)那些代碼了~
- 也對(duì)“登錄校驗(yàn)”這個(gè)步驟,集中處理了,這個(gè)代碼開(kāi)發(fā)過(guò)程就是面向切面編程
切面可以理解為,切下來(lái)的一個(gè)方面,一個(gè)步驟
切下來(lái)后有種藕斷絲連的感覺(jué):
例如這個(gè)圖,再等一下講解AOP的組成之后,回頭看可能會(huì)有更好的理解~
- AOP后,功能表現(xiàn)還是左上,但是代碼長(zhǎng)成右下
- “登錄校驗(yàn)”被切了下來(lái)一樣
如果把切面看成動(dòng)作執(zhí)行者,?
- 我們可以將切面形象地比喻為一把剪刀。
- 剪刀可以在不改變?cè)疾牧系那闆r下,將其切割成不同的形狀
- 同樣,切面在編程中也可以在不修改原始代碼的情況下,將橫切關(guān)注點(diǎn)應(yīng)用到不同的對(duì)象或方法上
- 在代碼實(shí)現(xiàn)的時(shí)候,將需要的統(tǒng)一處理的功能,“剪”下來(lái)進(jìn)行統(tǒng)一處理
- 就像剪刀可以將材料切割成不同的形狀一樣,切面可以將橫切關(guān)注點(diǎn)切割并應(yīng)用到代碼的不同部分,從而實(shí)現(xiàn)代碼的模塊化和重用
例如,調(diào)用功能1的時(shí)候,會(huì)通過(guò)切下來(lái)的“面”的匹配對(duì)應(yīng)的“塊”,之后進(jìn)行“組裝”~
- 這樣就在調(diào)用功能1之前進(jìn)行了登錄校驗(yàn)
好處:
- 滿(mǎn)足單一設(shè)計(jì)原則,登錄校驗(yàn)的存在,不會(huì)改變各個(gè)功能的原代碼
- 耦合度低,改一處等于改一萬(wàn)處
AOP就很適合解決這種功能統(tǒng)一,且是使用的地方較多的功能了
- AOP的統(tǒng)一處理!
除了登錄校驗(yàn)外,還可以實(shí)現(xiàn):
-
統(tǒng)一
- 日志記錄
- 方法執(zhí)行時(shí)間統(tǒng)計(jì)
- 返回格式設(shè)置
- 異常處理
- 事務(wù)開(kāi)啟與提交
- 等等…
也可以說(shuō),AOP面向了多個(gè)對(duì)象
也就是說(shuō),AOP是OOP(Object Oriented Programming,面向?qū)ο缶幊蹋┑囊粋€(gè)補(bǔ)充和完善
2. Spring AOP 框架的學(xué)習(xí)
Spring AOP框架內(nèi)部實(shí)現(xiàn)了AOP,開(kāi)發(fā)者按照規(guī)則寫(xiě)下的代碼,就對(duì)應(yīng)著AOP邏輯
Spring AOP的學(xué)習(xí)分為以下三步:
- AOP的組成
- Spring AOP的基本使用
- Spring AOP的實(shí)現(xiàn)原理
2.1 AOP的組成
2.1.1 Aspect 切面
一個(gè)Aspect代表一個(gè)“統(tǒng)一處理”,因?yàn)榻y(tǒng)一設(shè)計(jì)原則,一個(gè)切面就是一個(gè)功能,例如“登錄校驗(yàn)”
- 包含切點(diǎn)、通知,即有橫切邏輯的定義,也有連接點(diǎn)的定義
如果把這些定義,看成“切面”的獨(dú)一無(wú)二的橫切面,看成標(biāo)識(shí),切面就對(duì)應(yīng)那個(gè)“塊”,也就是功能,所以切面就看成一個(gè)功能~
即,AOP是干啥的
2.1.2 Pointcut 切點(diǎn)
規(guī)定 這個(gè)切面是從哪些,前后端交互接口,“剪”下來(lái)的
- 例如:定義用戶(hù)登錄攔截規(guī)則,哪些接口才需要判斷用戶(hù)登錄權(quán)限
2.1.3 Advice 通知
AOP執(zhí)行的具體方法
- 例如:獲取用戶(hù)信息,如果后端有記錄對(duì)應(yīng)的登錄信息,就說(shuō)明已經(jīng)登錄,否則沒(méi)有登錄
2.1.4 Join Point 連接點(diǎn)
有可能觸發(fā)切點(diǎn)的所有點(diǎn)
- 滿(mǎn)足切點(diǎn)規(guī)則的所有前后端交互接口
2.2 Spring AOP的基本使用
通過(guò)代碼實(shí)現(xiàn),你可能會(huì)有更切合的體驗(yàn)!
- 我只講一種方式,其他感興趣的可以去學(xué),有需要的去學(xué)
2.2.1 引入依賴(lài)
你會(huì)發(fā)現(xiàn),在IDEA的勾選選入依賴(lài)?yán)?,沒(méi)有AOP這個(gè)選項(xiàng),這也很正常,因?yàn)椴⒉皇撬幸蕾?lài)都包含在其中!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 第一次加載會(huì)有點(diǎn)慢,注意網(wǎng)絡(luò)通暢~
2.2.2 定義一個(gè)Aspect
一個(gè)切面其實(shí)就是一個(gè)類(lèi),加上@Aspect注解,這個(gè)類(lèi)就是為了實(shí)現(xiàn)某個(gè)“統(tǒng)一處理”的
- 需要加五大類(lèi)注解,這個(gè)算是個(gè)組鍵吧,所以用@Component
2.2.3 定義一個(gè)Pointcut
一個(gè)方法加上注解@Pointcut,在括號(hào)內(nèi)寫(xiě)一些語(yǔ)句,就定義了一個(gè)切點(diǎn)
- 這個(gè)方法可以不返回一切,方法名自定義,沒(méi)有參數(shù)列表,沒(méi)有代碼體…,如果加了會(huì)怎么樣感興趣可以去了解,但是暫時(shí)用不到~
- 括號(hào)內(nèi)部的語(yǔ)句是有對(duì)應(yīng)的語(yǔ)法的,這里了解這句話(huà)的含義,舉一反三就好,語(yǔ)法是啥感興趣可以去了解
execution(* com.example.demo.controller.TestController.*(..))
,解析:
execution()
,執(zhí)行括號(hào)中提及的方法,就觸發(fā)切點(diǎn)*
,不限制方法權(quán)限(public、private…),全部方法com.example.demo.controller.TestController.
,針對(duì)的類(lèi)的位置*(..)
,代表類(lèi)中的所有方法
*
,所有的方法名(..)
,任意的參數(shù)列表
2.2.4 Join Point
對(duì)于連接點(diǎn),則是剛才切點(diǎn)對(duì)應(yīng)的前后端交互接口:
- /test/say_hi
- /test/say_hello
我們?cè)谶@里不需要在意其他業(yè)務(wù),只需要專(zhuān)注開(kāi)發(fā),而Aspect的代碼開(kāi)發(fā)里則面向了這幾個(gè)連接點(diǎn)!
為了與通知的方法區(qū)分,我在控制臺(tái)打印信息:
2.2.5 定義Advice
通知就是訪(fǎng)問(wèn)對(duì)應(yīng)接口的時(shí)候,要執(zhí)行的業(yè)務(wù),分為五種通知:
- 前置通知
- 后置通知
- 環(huán)繞通知
- 返回通知
- 異常通知
顧名思義,區(qū)分就是,通知執(zhí)行的時(shí)機(jī)~
對(duì)應(yīng)五種注解(加在一個(gè)方法的上面,此方法被稱(chēng)為通知方法):
- @Before,通知方法在目標(biāo)方法執(zhí)行之前執(zhí)行
- @After,通知方法在目標(biāo)方法執(zhí)行之后執(zhí)行
- @Around,通知包裹了目標(biāo)方法,自定義行為
- @AfterReturning,通知方法在目標(biāo)方法返回后調(diào)用
- @AfterThrowing,通知方法在目標(biāo)拋出異常后調(diào)用
2.2.5.1 前置通知,后置通知與返回通知
// 前置通知
@Before("pointcut()")
public void doBefore(){
System.out.println("執(zhí)? Before ?法");
}
// 后置通知
@After("pointcut()")
public void doAfter(){
System.out.println("執(zhí)? After ?法");
}
// return 之前通知
@AfterReturning("pointcut()")
public void doAfterReturning(){
System.out.println("執(zhí)? AfterReturning ?法");
}
注解括號(hào)內(nèi)代表,對(duì)應(yīng)的切點(diǎn)方法
效果:
按多次:
2.2.5.2 異常通知
// 拋出異常之前通知
@AfterThrowing("pointcut()")
public void doAfterThrowing(){
System.out.println("執(zhí)? doAfterThrowing ?法");
}
對(duì)于異常通知的觸發(fā)案例,暫時(shí)不介紹
2.2.5.3 環(huán)繞通知
自定義行為的通知,可以模擬其他通知~
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object object = null;
System.out.println("Around方法開(kāi)始執(zhí)行");
object = joinPoint.proceed();
System.out.println("Around方法結(jié)束執(zhí)行");
return object;
}
ProceedingJoinPoint這個(gè)類(lèi)的對(duì)象joinPoint,代表著連接點(diǎn)對(duì)象
- 調(diào)用proceed()方法代表進(jìn)行這個(gè)連接點(diǎn)對(duì)于的方法
- try catch后能模擬異常通知
記得返回這個(gè)object,不然框架處理不了返回值作為響應(yīng)!
- 默認(rèn)執(zhí)行后的返回值是交給框架的,而這里是交給object~
效果:
這樣也看出了優(yōu)先級(jí)~
環(huán)繞通知,更靈活
-
更好的實(shí)現(xiàn)“原子性”,通過(guò)加鎖就行,如執(zhí)行時(shí)間統(tǒng)計(jì)…
-
如后置通知方法需要跟前置通知方法有“數(shù)據(jù)交互”
2.3 Spring AOP的實(shí)現(xiàn)原理
Spring AOP 是構(gòu)建在**動(dòng)態(tài)代理的基礎(chǔ)上,因此Spring 對(duì) AOP的支持局限于方法級(jí)的攔截**
2.3.1 動(dòng)態(tài)代理
原本訪(fǎng)問(wèn)目標(biāo)對(duì)象:
AOP之后:
就像fiddler一樣,代理了請(qǐng)求,期間保留了其信息…
通過(guò)代理類(lèi),目標(biāo)對(duì)象Join Point何時(shí)執(zhí)行目標(biāo)方法,代理說(shuō)了算
- 在環(huán)繞通知的時(shí)候體現(xiàn)尤為顯著
- 代理類(lèi) 根據(jù) Aspect 進(jìn)行對(duì)應(yīng)的行為
我們不通過(guò)Spring AOP框架,我們只能自己實(shí)現(xiàn)AOP才能實(shí)現(xiàn)在目標(biāo)方法調(diào)用之前和調(diào)用之后…時(shí)機(jī)進(jìn)行一些業(yè)務(wù)!
2.3.2 Spring AOP動(dòng)態(tài)代理組成
-
JDK Proxy
- 代理類(lèi)必須實(shí)現(xiàn)某個(gè)接口,才能使用JDK Proxy
- 底層有用到反射…
-
CGLIB
- 通過(guò)實(shí)現(xiàn)代理類(lèi)的子類(lèi)來(lái)實(shí)現(xiàn)動(dòng)態(tài)代理,只能代理能被繼承的類(lèi)
通過(guò)這兩種動(dòng)態(tài)代理的實(shí)現(xiàn)~
- 單獨(dú)一種有局限性
2.3.3 JDK Proxy 與 CGLIB的區(qū)別
-
出身不同
- JDK Proxy 來(lái)自java
- CGLIB 來(lái)自第三方
-
實(shí)現(xiàn)不同
- JDK Proxy,通過(guò)代理類(lèi)必須實(shí)現(xiàn)某個(gè)接口
- CGLIB,通過(guò)實(shí)現(xiàn)代理類(lèi)的子類(lèi)
-
性能不同
- jdk 7/7+,JDK Proxy性能略高于CBLIB
- jdk7-,CBLIB性能遠(yuǎn)高于JDK Proxy
文章到此結(jié)束!謝謝觀看
可以叫我 小馬,我可能寫(xiě)的不好或者有錯(cuò)誤,但是一起加油鴨??!不得不提的是,切面、切點(diǎn)、連接點(diǎn)、通知,這些名詞,不要糾結(jié)他們?yōu)樯哆@么叫,咱們知道他們的含義,知道Spring AOP怎么開(kāi)發(fā)就行了~文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-669279.html
代碼:spring_aop-demo · 游離態(tài)/馬拉圈2023年8月 - 碼云 - 開(kāi)源中國(guó) (gitee.com)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-669279.html
到了這里,關(guān)于【JavaEE】面向切面編程AOP是什么-Spring AOP框架的基本使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!