Spring中的AOP(六)——定義切入點和切入點指示符

定義切入點java

    在前文(點擊查看)中使用到的AdviceTest類中同一個切點(即* com.abc.service.*.advice*(..)匹配的鏈接點)卻重複定義了屢次,這顯然不符合軟件設計的原則,爲了解決這個問題,AspectJ和Spring都提供了切入點的定義。所謂定義切入點,其實質就是爲一個切入點表達式起一個名稱,從而容許在多個加強處理中重用該名稱。
編程

    Spring AOP只支持以Spring Bean的方法執行組做爲鏈接點,因此能夠把切入點看做全部能和切入表達式匹配的Bean方法。切入點定義包含兩個部分:
框架

  • 一個切入點表達式:用於指定切入點和哪些方法進行匹配this

  • 一個包含名字和任意參數的方法簽名:將做爲切入點的名稱spa

    在@AspectJ風格的AOP中,切入點簽名採用一個普通的方法定義(方法體一般爲空)來提供(方法名即爲切點名),且該方法的返回值必須爲void,切入點表達式需使用@Pointcut註解來標註。下面的代碼片斷定義了一個切入點,這個切入點將匹配任何名爲transfer的方法的執行:.net

//使用@Pointcut註解時指定切入點表達式
@Pointcut("execution(* transfer(..))")
//使用一個返回值爲void,方法體爲空的方法來命名切入點,方法名即爲切點名
private void myPointcut(){}

    切入點表達式,也就是組成@Pointcut註解的值,是規範的AspectJ 5切入點表達式。若是想要了解更多的關於AspectJ切入點語言,請參見AspectJ編程指南。
設計

    一旦採用上面的代碼片斷定義了名爲myPointcut的切入點以後,程序就能夠屢次重複使用該切點了,甚至能夠在其餘切面類、其餘包的切面類裏使用該切點,至因而否能夠在其餘切面類、其餘包下使用這個切點,那就要看該方法前的訪問控制修飾符了——本例中myPointcut使用private修飾,則意味着僅能在當前切面類中使用這個切點。
代理

    若是須要使用本切面類中的切點,則可在使用@Pointcut註解時,指定value屬性值爲已有的切入點,以下:
code

@AfterReturning(pointcut="myPointcut()", returning="returnValue")
public void log(String message, Object returnValue) {
    //do something...
}

    從指定pointcut來看,其語法很是相似於Java中調用方法——只是該方法表明一個切點,其實質是爲該加強處理方法定義一個切入點表達式。若是須要使用其餘類中定義的切點,則定義這些切點的方法的修飾符不能爲private。如今假設在另外一個類PointcutDefinition中定義了一個名爲myPointcutTest的切點:對象

public class PointcutDefinition {
    @Pointcut("execution(* something(..))")
    //訪問控制符爲public,這個切點能夠在其餘任何地方引用
    public void myPointcutTest(){}
}

    則在引用的時候須要帶上類名,例如:

@AfterReturning(
    pointcut="PointcutDefinition.myPointcutTest() && args(message)", 
    returning="returnValue")
public void log(String message, Object returnValue) {
    //do something...
}


切入點指示符

    前面定義切點表達式時使用了大量的execution表達式,其中execution就是一個切入點指示符。Spring AOP僅支持部分AspectJ的切入點指示符,但Spring AOP還額外支持一個bean切入點指示符。不只如此,由於Spring AOP只支持使用方法調用做爲鏈接點,因此Spring AOP的切入點指示符僅匹配方法執行的鏈接點。

    完整的AspectJ切入點語言支持大量切入點指示符,可是Spring並不支持它們。它們是:call,get,preinitialization,staticinitialization,initialization,handler,adviceexecution,withincode,cflow,cflowbelow,if,@this和@withincode。一旦在Spring AOP中使用這些切點指示符,就會拋出IllegalArgumentException。

    Spring AOP支持的切入點指示符有以下幾個:

  • execution:用於匹配執行方法的鏈接點,這是Spring AOP中國最主要的切入點指示符。該切入點的用法也相對複雜,execution表達式的格式以下:

    execution(modifier-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

    上面的格式中,execution是不變的,用於做爲execution表達式的開頭,整個表達式中幾個參數的詳細解釋以下:

    • modifier-pattern:指定方法的修飾符,支持通配符,該部分能夠省略

    • ret-type-pattern:指定返回值類型,支持通配符,可使用「*」來通配全部的返回值類型

    • declaring-type-pattern:指定方法所屬的類,支持通配符,該部分能夠省略

    • name-pattern:指定匹配的方法名,支持通配符,可使用「*」來通配全部的方法名

    • param-pattern:指定方法的形參列表,支持兩個通配符,「*」和「..」,其中「*」表明一個任意類型的參數,而「..」表明0個或多個任意類型的參數。

    • throw-pattern:指定方法聲明拋出的異常,支持通配符,該部分能夠省略

    以下是幾個execution表達式:

    execution(public * * (..))//匹配全部public方法

    execution(* set*(..))//匹配以set開始的方法

    execution(* com.abc.service.AdviceManager.* (..))//匹配AdviceManager中任意方法

    execution(* com.abc.service.*.* (..))//匹配com.abc.servcie包中任意類的任意方法

  • within:限定匹配特定類型的鏈接點,當使用Spring AOP的時候,只能匹配方法執行的鏈接點。下面是幾個例子:

  • within(com.abc.service.*)//匹配com.abc.service包中的任意鏈接點

    within(com.abc.service..*)//匹配com.abc.service包或子包中任意的鏈接點

  • this:用於指定AOP代理必須是指定類型的實例,用於匹配該對象的全部鏈接點。當使用Spring AOP的時候,只能匹配方法執行的鏈接點。下面是個例子:

        this(com.abc.service.AdviceManager)//匹配實現了AdviceManager接口的代理對象的全部鏈接點,在Spring中只是方法執行的鏈接點

  • target:用於限定目標對象必須是指定類型的實例,用於匹配該對象的全部鏈接點。當使用Spring AOP的時候,只能匹配方法執行的鏈接點。下面是個例子:

        target(com.abc.servcie.AdviceManager)//匹配實現了AdviceManager接口的目標對象的全部鏈接點,在Spring中只是方法執行的鏈接點

  • args:用於對鏈接點的參數類型進行限制,要求參數的類型時指定類型的實例。一樣,當使用Spring AOP的時候,只能匹配方法執行的鏈接點。下面是個例子:

  • args(java.io.Serializable)//匹配只接受一個參數,且參數類型是Serializable的全部鏈接點,在Spring中只是方法執行的鏈接點

    注意,這個例子與使用execution(* *(java.io.Serializable))定義的切點不一樣,args版本只匹配運行時動態傳入參數值是Serializable類型的情形,而execution版本則匹配方法簽名只包含一個Serializable類型的形參的方法。


    另外,Spring AOP還提供了一個名爲bean的切入點提示符,它是Spring AOP額外支持的,並非AspectJ所支持的切入點指示符。這個指示符對Spring框架來講很是有用:它將指定爲Spring中的哪一個Bean織入加強處理。固然,Spring AOP中只能使用方法執行做爲鏈接點。

  • bean:用於指定只匹配該Bean實例內的鏈接點,實際上只能使用方法執行做爲鏈接點。定義bean表達式時須要傳入Bean的id或name,支持使用"*"通配符。下面是幾個例子:

        bean(adviceManager)//匹配adviceManager實例內方法執行的鏈接點

        bean(*Manager)//匹配以Manager結尾的實例內方法執行的鏈接點


使用組合切點表達式

    Spring支持使用以下三個邏輯運算符來組合切入點表達式:

  • &&:要求鏈接點同時匹配兩個切點表達式

  • ||:要求鏈接點匹配至少一個切入點表達式

  • !:要求鏈接點不匹配指定的切入點表達式

    其實在以前介紹args的時候,已經用到了「&&」運算符:

pointcut("execution(* com.abc.service.*.*(..) && args(name))")

    上面的pointcut由兩個表達式組成,並且使用&&來組合這兩個表達式,所以鏈接點須要同時知足這兩個表達式才能被織入加強處理。

相關文章
相關標籤/搜索