Spring Aop基於註解的實現

不懶人發表於2020-07-04

一.AspectOriented Programing,面向切面程式設計。

  AOP主要用於日誌記錄,效能統計,安全控制(許可權控制),事務處理,異常處理等。將日誌記錄,效能統計,安全控制,事務處理,異常處理等程式碼從業務邏輯程式碼中劃分出來,透過對這些行為的分離,我們希望可以將它們獨立到非指導業務邏輯的方法中,進而改變這些行為的時候不影響業務邏輯的程式碼。
  Spring AOP織入增強(Advice)的方式有兩種 如果連線點實現了介面採用jdk自帶的動態代理的形式實現織入,如果連線點沒有實現介面則採用動態位元組碼生成技術(CGLIB)實現織入。

二.AOP常用術語:

連線點(Joinpoint)

  增強程式執行的某個特定位置(要在哪個地方做增強操作)。Spring僅支援方法的連線點,既僅能在方法呼叫前,方法呼叫後,方法丟擲異常時等這些程式執行點進行織入增強。

切點(Pointcut)

  切點是一組連線點的集合。AOP透過“切點”定位特定的連線點。透過資料庫查詢的概念來理解切點和連線點的關係再適合不過了:連線點相當於資料庫中的記錄,而切點相當於查詢條件。

增強(Advice)

  增強是織入到目標類連線點上的一段程式程式碼。表示要在連線點上做的操作。

切面(Aspect)

  切面由切點和增強(引介)組成(可以包含多個切點和多個增強),它既包括了橫切邏輯的定義,也包括了連線點的定義,SpringAOP就是負責實施切面的框架,它將切面所定義的橫切邏輯織入到切面所指定的連結點中。

註解切面類例子:

@Aspect
public class LogAspect {
    @Pointcut("execution(* com.ctj.service.*.*(..))")
    public void pointcutName(){}

    @Before("pointcutName()")
    public void performance(){
        System.out.println("Spring AOP");
    }
}

 

三.常用註解:

  • @aspect 定義切面
  • @pointcut 定義切點
  • @before 標註Before Advice定義所在的方法
  • @afterreturning 標註After Returning Advice定義所在的方法
  • @afterthrowing 標註After Throwing Advice定義所在的方法
  • @after 標註 After(Finally) Advice定義所在的方法
  • @around 標註Around Advice定義所在的方法

我們如何在定義切點(Pointcut)的時候指定一類Joinpoint呢?有兩種方式 簡單的方法名指定以及正規表示式兩種方式。

四.常用的@AspectJ形式Pointcut表示式的標誌符:

execution:

  Spring AOP僅支援方法執行型別的Joinpoint 所以execution將會是我們用的最多的標誌符,用它來幫我們匹配擁有指定方法前面的Joinpoint。匹配規則如下:
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern)

  • modifiers-pattern 修飾符 比如public private這種(可以指定可以不指定)
  • return-type-pattern 返回值型別(必須指定)
  • declaring-type-pattern 型別(可以是含包名的全路徑型別 可以指定可以不指定)
  • name-pattern 方法名(必須指定)
  • param-pattern 引數型別(必須指定)

方法的返回型別 方法名及引數部分的匹配模式是必須指定的 其他部分可以省略。
我們還可以在表示式中使用兩種萬用字元:*和..
  第一:*可以用於任何部分的匹配模式中,匹配相鄰的多個字元,即一個Work 。如果放在了方法引數的位置標示引數是任何型別的。
例如:execution(* *(String))
  第二:..萬用字元可以在兩個位置使用 一個是declaring-type-pattern的位置,一個是在方法引數匹配模式的位置。
如果是放在了方法型別的位置,可以指定多個層次的型別宣告。例如:
execution(void cn.spring.*.doSomething(*)) 指定到cn.spring下的所有型別。
如果是放在了方法引數的匹配位置,則表示該方法可以有0到多個引數。例如:
execution(void *.doSomething(..))

within:

  within標誌符只接受型別宣告,它將匹配指定型別下所有的Joinpoint。
例如:within(cn.spring.aop.target.*) 將會匹配 cn.spring.aop.target包下所有型別的方法級別的Joinpoint。

@annotation

  使用@annotation標誌符會檢查系統中所有物件的所有方法級別Joinpoint,如果被檢測的方法標註有@annotation標誌符所指定的註解型別,那麼當前方法所在的Joinpoint將被Pointcut表示式匹配。例如:@pointcut("@annotation(com.test.aop.log.ALog)") 匹配所有使用了ALog註解的方法。

匹配表示式的維度有很多 上面只是一小部分常用的,並且這些維度是可以組合的 使用||或者$$等等
例如:@around("within(com.test.finance..*) && @annotation(com.test.finance.platform.intf.base.db.ReadOnly)")

在定義Advice的時候 我們匹配的維度可以直接寫定義有@pointcut的方法名稱 也可以直接使用定義@joinpoint的那一套東西來直接定義要在哪些地方織入(可以直接在Advice上指定匹配哪些方法)

定義完切面之後我們要在spring中註冊這個切面類,為了讓spring能自動幫我們實現織入 我們還需要開啟自動注入 在spring配置檔案中:<aop:aspectj-autoproxy proxy-target-class="true"/> 這樣spring就能在IOC容器找到所有要織入的方法 動態幫我們織入。

五.一個完整的Spring AOP的小例子:

業務類程式碼:

package com.ctj.service;
import org.springframework.stereotype.Service;

@Service
public class BusinessService {

    public void say(){
        System.out.println("Business Code");
    }
}

 

切面類定義:

package com.ctj.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LogAspect {
    @Pointcut("execution(* com.ctj.service.*.*(..))")
    public void pointcutName(){}
    @Before("pointcutName()")
    public void performance(){
        System.out.println("Spring AOP");
    }
}

 

spring-aop.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean id="logAspect" class="com.ctj.aspect.LogAspect">
    </bean>
</beans>

 

基於註解的Spring AOP需要JDK1.5版本以後才能使用,之前的版本需要使用基於Schema也就是配置檔案的形式來實現,如果jdk版本高的話 建議還是使用註解的形式。

相關文章