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