AOP(Aspect Oriented Programming)就是面向切面程式設計,也是一種程式設計思想,接觸了JAVA是Spring架構後我才了解AOP,在我的工作中會經常用到,舉個存儲分層的例子,就像硬碟、記憶體和CPU中的寄存器,對應的高性能應用系統會有普通資料庫、Redis和本地記憶體:

那麼這裡的緩存操作我們可以抽出來統一做,這裡我們就用到了AOP,切點就是對資料的存取方法,還有就是調用外部系統的接口擷取資料時,我們也可以用AOP來實作統一的緩存操作,我們通常用的AOP的架構是aspectj,實作的原理是動态代理,動态代理的方案有JDK Proxy、cglib等,cglib是代碼的動态生成技術,用asm提供的動态生成JAVA位元組碼的技術,而JDK的動态代理是一種設計模式,依懶接口的實作。寫一個AOP簡單如下
我們還在spring的XML配置檔案中加上
表示使用cglib動态代理技術織入增強,利用cglib的好處是提高了系統的性能,利用注解讓spring幫我們完成了自動代碼織入,注解@Around中的參數就是織入的切點,around表示包圍了整個方法,被切的代碼的執行可以通過joinPoint(連接配接點)來調用,當然除了around的還有其他的織入方式,例如before和after,表示在被切方法前執行和被切方法後執行。
我們可以在around、before或after的方法裡進行統一的緩存處理,而在需要進行此類操作的地方隻需要加個被設定為切點的注解即可,如果還需要傳方法參數以外的資料,可以對自定義的注解進行優化,例如我自定義的的作為切點的注解:
擷取注解中的參數方法如下:
對于@around、@before和@after中value的值有個專業的名詞:pointcut expression(切點表達式)
Aspectj的源碼中是這樣說明的:
pointcut expression的作用就是為了說明切點是什麼,在哪,比如是某個注解、是某個方法或某個類中的所有方法等等。
接下來說明AOP是如何實作代碼織入的,織入是在類加載前的環節,當某個類被加載時,如果發現有切面,這時會生成一個新的類,這個新的類會被動态位址增加一些JAVA的指令操作,然後加載這個新的類。這個織入的操作其實就像人為的修改class檔案一樣,如果對java虛拟機的彙編指令熟悉,完全可以手動修改,然而現在隻是有專門的程式幫我們完成的這個操作而矣,這個專門的程式熟悉JAVA的指令集,它就是asm,而具體的要把代碼加在什麼位置,怎麼加,則是由具體的上層代碼指定,像@around、@before和@after。
ASM中有一個ClassReader和一個ClassWriter,見名就知其義了,前者是用來解析class檔案的,而後者是用來寫入class檔案的,ASM主要的設計思想是Visitor通路者模式,與疊代器模式不同的是通路者模式的通路邏輯是由實作類來決定的,ASM的上層是ClassVisitor,而ClassWriter就是其的一個實作,還有其它的一些實作:
下面是我用ASM寫的簡單的代碼動态生成的例子:
測試類,隻有一個名為out的方法
動态生成代碼,先輸出原位元組碼,分隔符下是新生成的代碼
測試的結果如下:
如果想要了解ASM的,可以要多看看JVM和其指令集了,也就是JAVA的彙編。
最後總結一下,其實AOP重要的是思想,至于如何實作AOP,可以有很多種方式,隻是在衆多方式中,利用ASM的JAVA位元組碼動态自動生成的方式可能性能是最好的。