spring-aop常用切點表達式

AOP是spring的最重要模塊之一,關於AOP的原理,主要就是基於動態代理,可以查看官網Understanding AOP Proxies,本節內容不去深究AOP原理,僅僅列出在spring框架中編寫AOP代碼時,常用的切點表達式寫法,官網上關於AOP這一節的說明,也可以看下,一定會有收穫Aspect Oriented Programming with Spring本文也是基於官方文檔形成的。

需要說明的是在spring框架中共用了AspectJ的一些註解,且目前僅支持方法級別的增強,AspectJ支持更多的切點表達式,在本文例子中也不去詳述,想要了解的可以去看The AspectJTM Programming Guide

由於本文的重點在於切點表達式的例子,所以本文所採用的增強方式一般以環繞增強爲主。

1. spring-aop支持的切點表達式關鍵字

官網很明確的說明了spring支持哪些切點表達式關鍵字,如下:

Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions:

  • execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.
  • within: Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).
  • this: Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.
  • target: Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.
  • args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
  • @target: Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.
  • @args: Limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given types.
  • @within: Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).
  • @annotation: Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.

至於官方暫時不支持的切點表達式關鍵字,也列舉出來了,還表示將來的版本可能會支持更多的關鍵字:

Other pointcut types

The full AspectJ pointcut language supports additional pointcut designators that are not supported in Spring: call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this, and @withincode. Use of these pointcut designators in pointcut expressions interpreted by Spring AOP results in an IllegalArgumentException being thrown.

The set of pointcut designators supported by Spring AOP may be extended in future releases to support more of the AspectJ pointcut designators.

切點表達式之間支持&&, || ! 連接,連接時候可以採用具體的表達式,也可以採用pointcut註解對應的方法簽名:比如在spring中自定義註解中用到的myAnnoCut()&&myPointCut()

2. 常用切點表達式

採用execution關鍵字定義的切點表達式格式如下:

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

表達式中除了返回值類型匹配規則ret-type-pattern (通常是 *來匹配所有返回值類型)之外的其他類型匹配規則都是可選的

name-pattern方法名,可以是具體的方法名,也可以用*圈定所有方法

param-pattern方法入參:()匹配無參方法,(..)匹配多參數方法,(*)匹配單參數任意入參類型的方法,(*,String)匹配有兩個入參的方法,第一個可以是任意類型,第二個必須是字符串類型。

以下是官方文檔中提到的一些表達式:

execution(public * *(..)) //匹配所有public方法
execution(* set*(..))//匹配所有方法名開頭爲set的方法
execution(* com.xyz.service.AccountService.*(..))//匹配AccountService下的所有方法
execution(* com.xyz.service.*.*(..))//匹配service包下的所有方法
execution(* com.xyz.service..*.*(..))//匹配service包或其子包下的所有方法
within(com.xyz.service.*)//匹配service包下的所有方法
within(com.xyz.service..*)//匹配service包或其子包下的所有方法
this(com.xyz.service.AccountService)//匹配所有實現了AccountService接口的類的代理類的方法(注意是代理類)
target(com.xyz.service.AccountService)//匹配所有實現了AccountService接口的類的方法(注意是本類)
args(java.io.Serializable)//匹配只有一個入參,且入參實現了Serializable接口的方法
@target(org.springframework.transaction.annotation.Transactional)//匹配類上標註了@Transactional註解的類中方法
@within(org.springframework.transaction.annotation.Transactional)//匹配運行時子類上標註了@Transactional註解的類中方法
@annotation(org.springframework.transaction.annotation.Transactional)//匹配所有打了@Transactional註解的方法
@args(com.xyz.security.Classified)//匹配只有一個入參,且運行時入參有@Classified註解的方法
bean(tradeService)//匹配命名爲tradeService的類的方法
bean(*Service)//匹配命名後綴爲Service的類的方法

‘this’ is more commonly used in a binding form. See the section on Declaring Advice for how to make the proxy object available in the advice body.

關於上面@target和@within區別請看博客

3. 運算符組合切點表達式

這一部分直接列舉幾個,基礎表達式會寫之後,組合按照自己想圈定的範圍進行組合運算匹配即可:

//或(||)運算符
@Pointcut("execution(* com.xxx.yyy.service.*.*.*(..))||" +
        "execution(* com.xxx.yyy.api.*.*.*(..))")
public void myElseCut(){};
//與(&&)運算符
@Pointcut("execution(* com.xxx.yyy.controller..*.*(..))"
        + "&& @within(org.springframework.web.bind.annotation.RestController)")
public void myAndCut(){};
//非(!)運算符
@Pointcut("@within(org.springframework.validation.annotation.Validated)"
            + "&& !@within(org.springframework.web.bind.annotation.RestController)"
            + "&& !@within(org.springframework.stereotype.Controller)")
public void myNotCut(){};

組合切點表達式均可以拆分成兩個切點聲明,然後再使用運算符連接,這樣可讀性好些,例如:

@Aspect
@Component
public class MyselfAnnotionAspect {
    //通過切點表達式定義切點
    /**@Pointcut("execution(* com.enjoyican.demo.selfannotion.service.impl..*(..))")
    public void myPointCut(){};
    @Pointcut("@annotation(MyselfAnnotion)")
    public void myAnnoCut(){};
    @Pointcut("within(com.enjoyican.demo.selfannotion.service..*)")
    public void myWithinCut(){};
    @Pointcut("target(com.enjoyican.demo.selfannotion.service.MyAnnotionTestService)")
    public void myTargetCut(){};*/
    @Pointcut("@target(MyselfAnnotion)")
    public void myAtTargetCut(){};
    @Pointcut("bean(myAnnotionTestServiceImpl)")
    public void myBeanCut(){};
    //定義方法增強類型(本例子採用環繞增強)
    @Around("myBeanCut()&&myAtTargetCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        System.out.println("AOP切面在執行service方法之前增強");
        point.proceed();
        System.out.println("AOP切面在執行service方法之後增強");
        return null;
    }
}

總結

對於切點表達式的熟悉可以使我們在項目中更好的寫出匹配到更靈活規則的類的表達式,強烈建議看下官網中Aspect Oriented Programming with Spring這一節的內容,很多我們平時用的其實官方文檔上都說明了,而且這裏的英文相對簡單,除了一些專業詞彙外都是很通俗易懂的語句。

如有疑問,可在我的個人博客spring-aop常用切點表達式下留言或者在CSDN留言即可

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