什么是AOP
Aspect Oriented Programming:面向切面編程
什么時(shí)候會(huì)出現(xiàn)面向切面編程的需求票灰?
按照軟件重構(gòu)的思想直颅,如果多個(gè)類中出現(xiàn)重復(fù)的代碼吐根,就應(yīng)該考慮定義一個(gè)共同的抽象類迄损,將這些共同的代碼提取到抽象類中,比如Teacher,Student都有username,那么就可以把username及相關(guān)的get轧膘、set方法抽取到SysUser中败富,這種情況,我們稱為縱向抽取拢锹。
但是如果谣妻,我們的情況是以下情況,又該怎么辦卒稳?
給所有的類方法添加性能檢測蹋半,事務(wù)控制,該怎么抽瘸淇印减江?
PerformanceMonitor
TransactionManager
AOP就是希望將這些分散在各個(gè)業(yè)務(wù)邏輯代碼中的相同代碼染突,通過橫向切割的方式抽取到一個(gè)獨(dú)立的模塊中,讓業(yè)務(wù)邏輯類依然保存最初的單純辈灼。
抽取出來簡單份企,難點(diǎn)就是如何將這些獨(dú)立的邏輯融合到業(yè)務(wù)邏輯中,完成跟原來一樣的業(yè)務(wù)邏輯巡莹,這就是AOP解決的主要問題司志。
AOP術(shù)語
l連接點(diǎn)(Joinpoint)
程序執(zhí)行的某個(gè)特定位置,如某個(gè)方法調(diào)用前降宅,調(diào)用后骂远,方法拋出異常后,這些代碼中的特定點(diǎn)稱為連接點(diǎn)腰根。簡單來說激才,就是在哪加入你的邏輯增強(qiáng)
l切點(diǎn)(PointCut)
每個(gè)程序的連接點(diǎn)有多個(gè),如何定位到某個(gè)感興趣的連接點(diǎn)额嘿,就需要通過切點(diǎn)來定位贸营。
比如,連接點(diǎn)--數(shù)據(jù)庫的記錄岩睁,切點(diǎn)--查詢條件
l增強(qiáng)(Advice)
增強(qiáng)是織入到目標(biāo)類連接點(diǎn)上的一段程序代碼钞脂。
在Spring中,像BeforeAdvice等還帶有方位信息
l目標(biāo)對象(Target)
需要被加強(qiáng)的業(yè)務(wù)對象
l織入(Weaving)
織入就是將增強(qiáng)添加到對目標(biāo)類具體連接點(diǎn)上的過程捕儒。
l代理類(Proxy)
一個(gè)類被AOP織入增強(qiáng)后冰啃,就產(chǎn)生了一個(gè)代理類。
l切面(Aspect)
切面由切點(diǎn)和增強(qiáng)組成刘莹,它既包括了橫切邏輯的定義阎毅,也包括了連接點(diǎn)的定義,SpringAOP就是將切面所定義的橫切邏輯織入到切面所制定的連接點(diǎn)中点弯。
userBiz add update del
couseBiz add update del
定義一個(gè)范圍給哪些類的哪些方法
增強(qiáng):加事務(wù)的控制
AOP實(shí)現(xiàn)者
lAspectJ
AspectJ是語言級的AOP實(shí)現(xiàn)扇调,2001發(fā)布,擴(kuò)展了Java語言抢肛,定義了AOP語法狼钮,能夠在編譯期通過提供橫切代碼的織入,所以它有一個(gè)專門的編譯器用來生成遵守Java字節(jié)碼規(guī)范的class文件
lSpringAOP
SpringAOP使用純Java實(shí)現(xiàn)捡絮,在運(yùn)行期通過代理的方式向目標(biāo)類織入增強(qiáng)代碼熬芜。
SpringAOP代理機(jī)制
基于JDK的動(dòng)態(tài)代理,接口
基于CGlib的動(dòng)態(tài)代理福稳,類
問題
現(xiàn)有一個(gè)UserDao的實(shí)現(xiàn)涎拉,想在原有的實(shí)現(xiàn)基礎(chǔ)上添加新的業(yè)務(wù)處理,怎么辦?
假如有多個(gè)實(shí)現(xiàn)
什么是代理模式
我們假設(shè)有一個(gè)UserDao和一個(gè)TransactionManager類
靜態(tài)代理的問題:
1鼓拧,假如還有其他的dao半火,則還需要再創(chuàng)建新的proxy
2,如果目標(biāo)對象的方法發(fā)生改變季俩,比如方法名做了修改慈缔,則代理類也要做修改
基于JDK的動(dòng)態(tài)代理
關(guān)鍵類:
InvocationHandler:其作用就是將橫切邏輯代碼和業(yè)務(wù)邏輯代碼編織到一起的編織器。
Proxy則通過newProxyInstance根據(jù)handler來創(chuàng)建一個(gè)符合第三方接口的代理類
基于接口的模式
基于CGlib的動(dòng)態(tài)代理
CGlib采用非常底層的字節(jié)碼技術(shù)种玛,可以為一個(gè)類創(chuàng)建子類藐鹤,并在子類中采用方法攔截技術(shù)攔截所有父類方法的調(diào)用,并織入橫切邏輯
擴(kuò)展
如果要多層怎么辦赂韵?
AOP小結(jié)
這種實(shí)現(xiàn)方式存在三個(gè)明顯需要改進(jìn)的地方:
1.目標(biāo)類的所有方法都添加了性能監(jiān)視橫切邏輯娱节,而有時(shí),這并不是我們所期望的祭示,我們可能只希望對業(yè)務(wù)類中的某些特定方法添加橫切邏輯肄满;
2.我們通過硬編碼的方式指定了織入橫切邏輯的織入點(diǎn),即在目標(biāo)類業(yè)務(wù)方法的開始和結(jié)束前織入代碼质涛;
3.我們手工編寫代理實(shí)例的創(chuàng)建過程稠歉,為不同類創(chuàng)建代理時(shí),需要分別編寫相應(yīng)的創(chuàng)建代碼汇陆,無法做到通用怒炸。
Spring AOP的主要工作就是圍繞以上三點(diǎn)展開:Spring
AOP通過Pointcut(切點(diǎn))指定在哪些類的哪些方法上織入橫切邏輯,通過Advice(增強(qiáng))描述橫切邏輯和方法的具體織入點(diǎn)(方法前毡代、方法后阅羹、方法的兩端等)。此外教寂,Spring通過Advisor(切面)將Pointcut和Advice兩者組裝起來捏鱼。有了Advisor的信息,Spring就可以利用JDK或CGLib的動(dòng)態(tài)代理技術(shù)采用統(tǒng)一的方式為目標(biāo)Bean創(chuàng)建織入切面的代理對象了酪耕。
創(chuàng)建增強(qiáng)
Spring使用增強(qiáng)類定義橫切邏輯导梆,同時(shí)由于Spring只支持方法連接點(diǎn),增強(qiáng)還包括了在方法的哪一點(diǎn)加入橫切代碼的方位信息迂烁,所以增強(qiáng)既包含橫切邏輯看尼,還包含部分連接點(diǎn)的信息
增強(qiáng)類型
AOP聯(lián)盟為增強(qiáng)定義了org.aopalliance.aop.Advice接口,Spring支持5種類型的增強(qiáng)
前置增強(qiáng):org.springframework.aop.BeforeAdvice代表前置增強(qiáng)婚被,因?yàn)镾pring只支持方法級的增強(qiáng)狡忙,所以MethodBeforeAdvice是目前可用的前置增強(qiáng),表示在目標(biāo)方法執(zhí)行前實(shí)施增強(qiáng)址芯,而BeforeAdvice是為了將來版本擴(kuò)展需要而定
后置增強(qiáng):org.springframework.aop.AfterReturningAdvice代表后增強(qiáng),表示在目標(biāo)方法執(zhí)行后實(shí)施增強(qiáng);
環(huán)繞增強(qiáng):org.aopalliance.intercept.MethodInterceptor代表環(huán)繞增強(qiáng)谷炸,表示在目標(biāo)方法執(zhí)行前后實(shí)施增強(qiáng)北专;
異常拋出增強(qiáng):org.springframework.aop.ThrowsAdvice代表拋出異常增強(qiáng),表示在目標(biāo)方法拋出異常后實(shí)施增強(qiáng)旬陡;
案例:
創(chuàng)建切面
我們可能注意到一個(gè)問題:增強(qiáng)被織入到目標(biāo)類的所有方法中拓颓,假設(shè)我們希望有選擇地織入到目標(biāo)類某些特定的方法中,就需要使用切點(diǎn)進(jìn)行目標(biāo)連接點(diǎn)的定位了描孟。描述連接點(diǎn)是進(jìn)行AOP編程最主要的工作
增強(qiáng)提供了連接點(diǎn)方位信息:如織入到方法前面驶睦、后面等,而切點(diǎn)進(jìn)一步描述織入到哪些類的哪些方法上匿醒。
Spring通過org.springframework.aop.Pointcut接口描述切點(diǎn)场航,Pointcut由ClassFilter和MethodMatcher構(gòu)成,它通過ClassFilter定位到某些特定類上廉羔,通過MethodMatcher定位到某些特定方法上溉痢,這樣Pointcut就擁有了描述某些類的某些特定方法的能力。
Spring使用org.springframework.aop.Advisor接口表示切面的概念憋他,一個(gè)切面同時(shí)包含橫切代碼和連接點(diǎn)信息
從廣義上說孩饼,增強(qiáng)其實(shí)就是一種最簡單的切面,它既包括橫切代碼也包括切點(diǎn)信息竹挡,只不過它的切點(diǎn)只是簡單的方法相對位置的信息镀娶。所以增強(qiáng)一般需要和切點(diǎn)聯(lián)合才可以表示一個(gè)更具實(shí)用性的切面。
AspectJ
Spring AOP揪罕,它包括基于XML配置的AOP和基于@AspcetJ注解的AOP汽畴,這兩種方法雖然在配置切面時(shí)的表現(xiàn)方式不同,但底層都是采用動(dòng)態(tài)代理技術(shù)(JDK代理或CGLib代理)耸序。Spring可以集成AspectJ忍些,但AspectJ本身并不屬于Spring AOP的范疇。
Spring在處理@Aspect注解表達(dá)式時(shí)坎怪,需要將Spring的asm模塊添加到類路徑中罢坝。asm是輕量級的字節(jié)碼處理框架,因?yàn)镴ava的反射機(jī)制無法獲取入?yún)⒚亮琒pring就利用asm處理@AspectJ中所描述的方法入?yún)⒚?/p>
也可以通過配置的方式來生成代理對象
工作原理:
首先嘁酿,在配置文件中引入aop命名空間,然后通過aop命名空間的自動(dòng)為Spring容器中那些匹配@AspectJ切面的Bean創(chuàng)建代理男应,完成切面織入闹司。