AOP 官方定義
AOP 譯為(面向切面編程)
在軟件業(yè),AOP為Aspect Oriented Programming的縮寫(xiě),意為:面向切面編程; 通過(guò)預(yù)編譯方式和運(yùn)行期間動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù);AOP是OOP的延續(xù),是軟件開(kāi)發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型
利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率
AOP 術(shù)語(yǔ)
橫切關(guān)注點(diǎn)
對(duì)哪些方法進(jìn)行攔截,攔截后怎么處理,這些關(guān)注點(diǎn)稱之為橫切關(guān)注點(diǎn)
切面(aspect)
類是對(duì)物體特征的抽象,切面就是對(duì)橫切關(guān)注點(diǎn)的抽象
連接點(diǎn)(joinpoint)
被攔截到的點(diǎn),因?yàn)閟pring只支持方法類型的連接點(diǎn),所以在Spring中連接點(diǎn)指的就是被攔截到的方法,實(shí)際上連接點(diǎn)還可以是字段或者構(gòu)造器
切入點(diǎn)(pointcut)
對(duì)連接點(diǎn)進(jìn)行攔截的定義
通知(advice)
所謂通知指的就是指攔截到連接點(diǎn)之后要執(zhí)行的代碼,通知分為前置、后置、異常、最終、環(huán)繞通知五類
目標(biāo)對(duì)象
代理的目標(biāo)對(duì)象
織入(weave)
將切面應(yīng)用到目標(biāo)對(duì)象并導(dǎo)致代理對(duì)象創(chuàng)建的過(guò)程
引入(introduction)
在不修改代碼的前提下,引入可以在運(yùn)行期為類動(dòng)態(tài)地添加一些方法或字段
AOP 實(shí)現(xiàn)機(jī)制
橫向抽取機(jī)制,那么什么是橫向抽取機(jī)制呢?
所謂的橫向抽取機(jī)制就是使用動(dòng)態(tài)的代理的方式(cglib代理和jdk代理)來(lái)實(shí)現(xiàn)對(duì)象的代理,實(shí)際上我們操作的是假對(duì)象
既然有橫向抽取機(jī)制,那么有沒(méi)有縱向代理模式呢 ?那么什么是縱向抽取呢?
答案是有的,縱向抽取就是把公共的方法寫(xiě)在父類里,所有的類都繼承父類,這樣就是能調(diào)用父類的方法
例如:你購(gòu)物付款是一個(gè)子類的功能,你可能還會(huì)取款,這也是一個(gè)功能,而在他們結(jié)束之后,銀行都會(huì)發(fā)送一個(gè)信息給你,這又是一個(gè)功能,這個(gè)銀行給你發(fā)送信息是個(gè)公共的方法,所以這個(gè)發(fā)信息的功能就是屬于父類的。子類繼承父類并調(diào)用父類的方法就是縱向抽取
AOP 應(yīng)用場(chǎng)景
在通常的應(yīng)用場(chǎng)景中,都會(huì)進(jìn)行事務(wù)處理、日志記錄等操作,比如:
class User{
public void addUser(){
...... //添加用戶
....... //記錄一條日志:xxx時(shí)間添加xxx用戶,操作者:xxx,操作結(jié)果:xxx
}
public void alterUser(){
....... //修改用戶
........//記錄一條日志:xxx時(shí)間修改xxx用戶,操作者:xxx,操作結(jié)果:xxx
}
public void deleteUser(){
.......//刪除用戶
.......//記錄一條日志:xxx時(shí)間刪除xxx用戶,操作者:xxx,操作結(jié)果:xxx
}
這是一個(gè)操作用戶的類,是對(duì)用戶的抽象,日志操作和用戶操作其實(shí)沒(méi)有半毛錢(qián)關(guān)系,上面的抽象并不好,把用戶操作和日志操作雜糅在一起,應(yīng)該把日志操作分離出去,這樣才符合OOP的編程思想
而且后期不好維護(hù)、升級(jí),比如后面要修改日志操作,你找到User類,在addUser()中一部分是用戶操作,一部分是日志操作,你要先找到哪些是日志操作,然后改。后面的方法也是如此,很繁瑣
AOP解決了此問(wèn)題,AOP是一種新的編程思想,是OOP的一種補(bǔ)充; OOP專心負(fù)責(zé)核心業(yè)務(wù),AOP負(fù)責(zé)其它雜七雜八的業(yè)務(wù)
OOP好比是經(jīng)理,AOP好比是助理。原先所有事兒,什么批文件、見(jiàn)客戶、通知下級(jí)來(lái)開(kāi)會(huì)、向下級(jí)傳達(dá)指示,所有事兒都是自己做,很繁瑣,搞得精疲力竭,還容易出問(wèn)題
現(xiàn)在招了助理AOP,總經(jīng)理OOP可以專心處理核心的業(yè)務(wù),批示下文件、見(jiàn)見(jiàn)客戶就行了;傳遞指示、通知下級(jí)開(kāi)會(huì),這些事兒助理AOP來(lái)做;分工明確,效率高很多
這些操作可以被多個(gè)類使用,叫做切面(Aspect)
實(shí)現(xiàn)AOP的方式
靜態(tài)AOP
在編譯期,切面直接以字節(jié) 碼的形式編譯到目標(biāo)字節(jié)碼文件中
AspectJ屬于靜態(tài)AOP,是在編譯時(shí)進(jìn)行增強(qiáng),會(huì)在編譯的時(shí)候?qū)OP邏輯織入到代碼中,需要專有的編譯器和織入器
● 優(yōu)點(diǎn):被織入的類性能不受影響
● 缺點(diǎn):不夠靈活
動(dòng)態(tài)AOP(JDK動(dòng)態(tài)代理)
在運(yùn)行期,目標(biāo)類加載后,為接口動(dòng)態(tài)生成代理類,將切面植入到代理類中
JAVA從1.3引入動(dòng)態(tài)代理。實(shí)現(xiàn)原理是為被代理的業(yè)務(wù)接口生成代理類,將AOP邏輯寫(xiě)入到代理類中,在運(yùn)行時(shí)動(dòng)態(tài)織入AOP,使用反射執(zhí)行織入的邏輯
主要實(shí)現(xiàn)方式依賴java.lang.reflect包下的InvocationHandler和Proxy類
● 優(yōu)點(diǎn):Java標(biāo)準(zhǔn)庫(kù)原生支持,使用簡(jiǎn)單,無(wú)需引用額外的包。相對(duì)于靜態(tài)AOP更靈活
● 缺點(diǎn):帶代理的類必須是接口,靈活性受到一些限制;使用反射會(huì)影響一些性能
動(dòng)態(tài)代碼字節(jié)生成
在運(yùn)行期,目標(biāo)類加載后,動(dòng)態(tài)構(gòu)建字節(jié)碼文件生成目標(biāo)類的子類,將切面邏輯加入到子類中
CGLib是動(dòng)態(tài)代碼字節(jié)生成的實(shí)現(xiàn),它封裝字節(jié)碼生成工具Asm,原理是在運(yùn)行期間目標(biāo)字節(jié)碼加載后,生成目標(biāo)類的子類,將切面邏輯加入到子類中,所以使用Cglib實(shí)現(xiàn)AOP不需要基于接口
● 優(yōu)點(diǎn):沒(méi)有接口也可以織入,靈活性高
● 缺點(diǎn):擴(kuò)展類的實(shí)例方法為final時(shí),則無(wú)法進(jìn)行織入
自定義類加載器
在運(yùn)行前,目標(biāo)加載前,將切面邏輯加到目標(biāo)字節(jié)碼中
可以考慮javassist來(lái)實(shí)現(xiàn)。Javassist 是一個(gè)編輯字節(jié)碼的框架,可以讓你很簡(jiǎn)單地操作字節(jié)碼;它可以在運(yùn)行期定義或修改Class,使用Javassist實(shí)現(xiàn)AOP的原理是在字節(jié)碼加載前直接修改需要切入的方法
● 優(yōu)點(diǎn):可以對(duì)絕大部分類織入
● 缺點(diǎn):如果用到了其他類加載器,則這些類將不被織入
知識(shí)剖析
為什么要使用 Aop?
● 為了方便,用了aop能讓你少寫(xiě)很多代碼
● 為了更清晰的邏輯,可以讓你的業(yè)務(wù)邏輯去關(guān)注自己本身的業(yè)務(wù),而不去想一些其他的事情,這些其他的事情包括:安全,事物,日志等
● 為了降低之前傳統(tǒng)面向?qū)ο笾胁捎每v向繼承體系增強(qiáng)方法導(dǎo)致的耦合度過(guò)高的問(wèn)題
● 提高了代碼的復(fù)用性
AOP的思想
● AOP的核心思想是幫助我們?cè)跀U(kuò)展功能(方法)時(shí)可以不依靠修改源代碼來(lái)實(shí)現(xiàn)
● 其采取橫向抽取機(jī)制,規(guī)避了傳統(tǒng)面向?qū)ο笾锌v向繼承體系的重復(fù)性高耦合代碼
淺析AOP思想的發(fā)展及原理
發(fā)展:修改源代碼————采用OOP縱向繼承體系————采用AOP橫向織入
實(shí)現(xiàn)原理:通過(guò)動(dòng)態(tài)代理創(chuàng)建代理對(duì)象來(lái)實(shí)現(xiàn),默認(rèn)使用Java動(dòng)態(tài)代理來(lái)創(chuàng)建AOP代理,當(dāng)需要代理的類不是代理接口的時(shí)候,Spring會(huì)切換為使用CGLIB代理
Aop 可以說(shuō)是spring的一大特色,主要應(yīng)用場(chǎng)景有事物管理、權(quán)限、日志這幾塊用的比較多
結(jié)語(yǔ)
技術(shù)是無(wú)止境的,你需要對(duì)自己提交的每一行代碼、使用的每一個(gè)工具負(fù)責(zé),不斷挖掘其底層原理,才能使自己的技術(shù)升華到更高的層面
Android 架構(gòu)師之路還很漫長(zhǎng),與君共勉
PS:有問(wèn)題歡迎指正,可以在評(píng)論區(qū)留下你的建議和感受;
歡迎大家點(diǎn)贊評(píng)論,覺(jué)得內(nèi)容可以的話,可以轉(zhuǎn)發(fā)分享一下






