1. 程式人生 > >Spring AOP 註解形式

Spring AOP 註解形式

github 日誌記錄 throw 異常 動態字節碼 span pack 規則 tor

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版本高的話 建議還是使用註解的形式。

Spring AOP 註解形式