Spring AOP AspectJ 切面表示式高階用法

zollty發表於2020-12-21

 

一、Spring AOP 配置

 

首先,明白一點,Spring的AOP代理,分為JDK動態代理和Cglib動態代理,這兩種代理的實現方式不一樣,他們針對同一Aspect的配置效果也可能不一樣。

  1. JDK的動態代理,只能代理介面,無法代理非介面的方法。

  2. Cglib動態代理,採用的是繼承代理物件的方法,所以可以代理非private的所有方法。

 

Spring和AspectJ的關係:

  1. AspectJ是Eclipse基金會的一個動態代理框架(官方網站為:http://www.eclipse.org/aspectj/),它發明了一種表示式,按照這種表示式可以很方便的配置AOP的切入點。

  2. Spring選擇模仿和遵循AspectJ定義的表示式規範,並實現了對Aspect表示式的解析,但是它只實現了AspectJ官方表示式的一部分功能,同時又擴充套件了一些Spring特有的功能。

  3. Spring引用了AspectJ的核心包: aspectjweaver,其關鍵的底層功能應該都是呼叫的AspectJ的函式。

 

SpringMVC要開啟AOP,需要配置一個標籤:

<aop:aspectj-autoproxy proxy-target-class="true" />

其中proxy-target-class=true表示可以啟用Cglib代理(至於什麼時候使用,由Spring自己決定:判斷是否基於介面代理,如果是就採用JDK動態代理,否則採用Cglib代理),如果配置proxy-target-class=false就意味著禁用Cglib代理,如果Spring發現無法代理時,就會報錯。因為Cglib動態代理的效率比JDK動態代理的效率要低很多,所以如果你只代理介面,你可以設定proxy-target-class=false。

public AopProxy createAopProxy(AdvisedSupport config) {

   if (config.isOptimize() || config.isProxyTargetClass()) {

      Class<?> targetClass = config.getTargetClass();

      if (targetClass == null) {

         throw new AopConfigException("TargetSource cannot determine target class: " +

               "Either an interface or a target is required for proxy creation.");

      }

      if (targetClass.isInterface()) { // 基於介面

         return new JdkDynamicAopProxy(config);

      }

      return new ObjenesisCglibAopProxy(config);

   }

   else // 如果配置proxy-target-class=false,直接JDK

      return new JdkDynamicAopProxy(config);

   }

}

 

SpringBoot,預設會識別工程中是否有AOP配置,如果有,則自動啟用aop,無需配置,但是預設配置是基於JDK的,如果需要用到Cglib,則如下配置:

@EnableAspectJAutoProxy(proxyTargetClass=true)

 

 

二、個人常用的AspectJ表示式介紹

 

1、execution(* com.zollty.**.dao.*.*(..))

其含義為:所有 com.zollty.**.dao包 下面的類(只包含一級目錄,不包含下面的子目錄),匹配這些類的所有 非private的方法。

這個表示式簡單,但是效率低。官方不建議這麼做,後面會講,官方的建議做法。

 

2、within(com.zollty.**.dao.*) && execution(public * *(..))

加上了within篩選,效率要高一些。效果同(1)一樣,只是後面加上了&&條件限制,只匹配public的方法。

 

3、within(com.zollty..BaseService+) && @annotation(anno)

基於 包路徑 和 BaseService基類的匹配,並且 帶有 anno 註解,anno註解在@Pointcut的方法引數裡面指定,例如:

@Pointcut(@annotation(anno))

public void test(SelectDB anno) {

}

 

4、within(com.zollty..BaseMapper+)  && !execution(* toString())  && !execution(* hashCode()) && !execution(* getClass())

和(3)類似,同時排除掉 toString等方法。

 

3、官方建議的切面表示式效能優化方法

However, AspectJ can only work with what it is told, and for optimal performance of matching the user should think about what they are trying to achieve and narrow the search space for matches as much as they can in the definition. Basically there are three kinds of pointcut designator: kinded, scoping and context:

  1. Kinded designators are those which select a particular kind of join point. For example: execution, get, set, call, handler

  2. Scoping designators are those which select a group of join points of interest (of probably many kinds). For example: within, withincode

  3. Contextual designators are those that match (and optionally bind) based on context. For example: this, target, @annotation

A well written pointcut should try and include at least the first two types (kinded and scoping), whilst the contextual designators may be included if wishing to match based on join point context, or bind that context for use in the advice. Supplying either just a kinded designator or just a contextual designator will work but could affect weaving performance (time and memory used) due to all the extra processing and analysis. Scoping designators are very fast to match, they can very quickly dismiss groups of join points that should not be further processed - that is why a good pointcut should always include one if possible.

翻譯過來,即:至少使用兩者型別的匹配模式,建議使用 within 和execution的組合,或者 within 和 @annotation的組合。

 

四、切面表示式 參考文件:

 

Spring:

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts

 

Aspectj官方:

http://www.eclipse.org/aspectj/doc/released/progguide/quick.html

http://www.eclipse.org/aspectj/doc/released/progguide/language-joinPoints.html

http://www.eclipse.org/aspectj/doc/released/adk15notebook/index.html

 

參考文章:

https://wenku.baidu.com/view/7e91a92d4b73f242336c5ff4.html

http://www.360doc.com/content/13/1212/09/14416931_336521220.shtml

https://blog.csdn.net/qq525099302/article/details/53996344

 

相關文章