Spring之AOP

Aop爲什麼會出現呢?本質上來說,是爲了實現單一職責原則的思想,我們在做一個save操作的時候,往往需要先開啓事務,如果成功提交事務,失敗了回滾事務,最後還得關閉事務。最後說的這些事情其實在所有的業務邏輯中都是需要的,所以說都是些重複的操作,顯然這樣很不"程序猿"。於是爲了對業務進行增強,加入一些必要的附屬操作,AOP就這麼誕生出來了

其實有可能你會發現,AOP好像和代理模式非常的相似,沒錯,AOP就是用代理模式進行實現的。

代理模式可以分爲兩種

  1. 靜態代理

    在編譯期間就已經存在一個代理類

  2. 動態代理

    不存在代理類的字節碼文件,是通過反射動態生成的,是在運行期間,才確定關係的。

    1.Java動態代理(真實對象必須存在接口)

    • 原理:動態代理其實本質上也是靜態代理的實現方法,只不過代理類不是由我們提供的,而是通過程序生成一個字節碼文件,然後加載進虛擬機中。是通過實現接口的方式
    • 使用的是reflect包下的Proxy和InvocationHandler 接口進行代理的
    • 動態代理的最小單位是類,也就是說會爲該類的所有public方法進行增強。(但是可以通過判斷方法的一些特性,決定是否放行)

    2.CGlib動態代理

    • 原理: 通過繼承了實現類的方式,對方法進行增強
    • 被代理的類必須得是非final的

    性能方面: Javassit > CGlib > JDK

Tips: AOP 使用了一種攔截器(Interceptor)的思想,相對於Filter只能應用於web領域,interceptor可以應用於各個領域,應用範圍更過

AOP之關鍵字

  1. JoinPoint 連接點,連接的是需要被增強的方法,強調的是去哪裏做增強
  2. PointCut 切入點, 是JoinPoint的一個集合,強調的是取哪些地方做增強。
  3. Advice 增強,在方法執行的某一個時機,應該如何做增強。增強的類型共分爲5種:
    1. 前置增強
    2. 後置增強
    3. 異常增強
    4. 最終增強
    5. 環繞增強
  4. Target 目標對象
  5. Aspect 切面 = JoinPoint + Advice
  6. weaving 植入,把advise加到target上,然後創建代理過程的對象

PointCut語法

參考spring官網

AspectJ與動態代理

他倆最大的差別就在於動態代理是在運行的時候生成相應的class文件,而AspectJ則不是,它是通過編譯成字節碼文件的時候就被織入了字節碼文件中,所以AspectJ也可以切私有方法,而動態代理卻做不到。

AOP的配置使用

xml方式

在xml文件中加入了aop的命名空間後,寫入以下代碼:

<aop:config>
    <aop:aspect ref="使用哪個類做增強">
    <aop:pointcut id="pointcutA" expression="pointcut的execution表達式"/> <!--對哪些方法做增強-->
    <aop:before method="aop:aspect標籤中ref屬性的某個方法" pointcut-ref="pointcutA"/><!--調用前增強-->
    <aop:after-returning  method="aop:aspect標籤中ref屬性的某個方法" pointcut-ref="pointcutA" /><!--對返回後增強-->
    <aop:after-throwing method="aop:aspect標籤中ref屬性的某個方法" pointcut-ref="pointcutA" throwing =""/> <!--出現異常後增強-->
    <aop:after-throwing method="aop:aspect標籤中ref屬性的某個方法" pointcut-ref="pointcutA" /> <!--最終增強,無論有沒有異常,適用於釋放資源-->
    <aop:around />
  </aop:aspect>  
</aop:config>
註解方式

與上面的xml方式,十分類似也可以一一對應上。

  • 首先需要在切面類上面使用@aspect
  • 如果是前置的增強使用@Before
  • 如果是返回後置的使用@AfterReturning
  • 如果是異常後置的使用@AfterThrowing
  • 如果是最後的返回,使用@After
  • 如果是全方位的進行定製化,使用@Around

對應的這些註解擁有的屬性,也是和xml中擁有的屬性幾乎相同。

Tips:經過我的實驗證明@After會在@AfterReturning 和@AfterThrowing之前執行的

那麼問題來了,我們現在想要獲取被切的對象的相關信息應該如何做呢?

1.如果是異常增強:我們可以通過配置配置throwing參數,拿到被拋出的異常的對象。

2.除了異常增強和環繞增強之外,可以通過JoinPoint作爲第一個參數獲取到相關的信息,包括被切的對象,方法參數等等

3.如果是應用於環繞增強那麼,使用ProcessingJoinPoint,它其實是JoinPoint的一個子類,不僅可以獲取相關的信息,還可以調用真實被環繞的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章