【spring源碼分析】spring探祕之aop的執行順序

注:本系列源碼分析基於spring 5.2.2.RELEASE,本文的分析基於 annotation 註解方式,gitee倉庫鏈接:spring-framework.

spring aop 執行時,順序是怎樣的,如何改變執行的優先級?本文將從源碼上來探究aop執行順序的祕密。

spring aop 之 AnnotationAwareAspectJAutoProxyCreator 分析(上)spring aop 之 AnnotationAwareAspectJAutoProxyCreator 分析(下)中,縱觀 spring aop 創建與執行過程,我們一共遇到兩次關於aop的排序操作:

  • ReflectiveAspectJAdvisorFactory#getAdvisorMethods:對 aspect 中的 @Around/@Before/@After 等方法進行排序;
  • AspectJAwareAdvisorAutoProxyCreator#sortAdvisors:對 advisor 進行排序。

接下來我們重點來分析這兩個方法。

1 ReflectiveAspectJAdvisorFactory#getAdvisorMethods

第一次排序在ReflectiveAspectJAdvisorFactory#getAdvisorMethods,調用結構如下:

|-AbstractAutoProxyCreator#postProcessBeforeInstantiation
  |-AspectJAwareAdvisorAutoProxyCreator#shouldSkip
   |-AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
    |-BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
     |-ReflectiveAspectJAdvisorFactory#getAdvisors
      |-ReflectiveAspectJAdvisorFactory#getAdvisorMethods

代碼如下:

ReflectiveAspectJAdvisorFactory

// 獲取 @Aspect 類中的方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    final List<Method> methods = new ArrayList<>();
    // 省略獲取方法的操作
    ...

    //對得到的所有方法排序,
    methods.sort(METHOD_COMPARATOR);
    return methods;
}

這個方法的操作在spring aop 之 AnnotationAwareAspectJAutoProxyCreator 分析(上) 一文已作了詳細分析,這裏我們僅關注排序規則:

ReflectiveAspectJAdvisorFactory

/**
 * METHOD_COMPARATOR 詳解
 */
private static final Comparator<Method> METHOD_COMPARATOR;
static {
    Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
            // 比較器,按傳入順序進行比較
            new InstanceComparator<>(
                    Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
            // 轉換器,將方法轉化爲 @Around, @Before, @After, @AfterReturning, @AfterThrowing 等註解
            (Converter<Method, Annotation>) method -> {
                AspectJAnnotation<?> annotation =
                    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
                return (annotation != null ? annotation.getAnnotation() : null);
            });
    // 轉換比較器,
    // 1. 轉換:將傳入的方法(Method)轉換爲方法名(String)
    // 2. 比較:按傳入類型進行比較,這裏傳入的的類型爲String,原因是轉換器將傳入的Method轉換成String了
    Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
    /*
     * METHOD_COMPARATOR 比較規則:
     * 1. 如果方法標識了切面註解, 則按 @Around, @Before, @After, @AfterReturning,
     *       @AfterThrowing 順序排序 (`adviceKindComparator`)
     * 2. 如果沒有標識這些註解,則按方法名稱的字符串排序(`methodNameComparator`)
     */
    METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}

這裏對這個方法的排序規則總結如下:

  1. 這個方法排序的對象是同一個@Aspect中的方法;
  2. 對於切面方法,排序如下:@Around, @Before, @After, @AfterReturning, @AfterThrowing
  3. 對於非切面方法,按方法名(String的排序規則)排序。

該方法排序前後的變化如下:

排序前:

排序後:

排序後與我們分析的 @Around, @Before, @After, @AfterReturning,@AfterThrowing的順序一致。

得到List<Method>後,接着會遍歷這些method,將其包裝爲一個個advisor

ReflectiveAspectJAdvisorFactory

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 省略了一些代碼
    ...

    List<Advisor> advisors = new ArrayList<>();
    //獲取這個類所有的增強方法
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 生成增強實例,advisors.size() 依次爲 0,1,2,... 這是
        // declarationOrderInAspect 的值,後面排序會用到
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 
                advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // 省略了一些代碼
    ...
}

包裝成Advisor時,會傳入declarationOrderInAspect值,該值爲advisors.size(),依次爲0,1,2,...,這個值在後面的排序中會用到。

2. advisor的排序:AspectJAwareAdvisorAutoProxyCreator#sortAdvisors

@Aspect類中的切面方法包裝成advisor後,或者獲取完自定義advisor後,接着就進行了第二次排序:AspectJAwareAdvisorAutoProxyCreator#sortAdvisors,方法的調用鏈如下:

|-AbstractAutoProxyCreator#postProcessAfterInitialization
 |-AbstractAutoProxyCreator#wrapIfNecessary
  |-AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
   |-AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
    |-AspectJAwareAdvisorAutoProxyCreator#sortAdvisors

AspectJAwareAdvisorAutoProxyCreator

protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors 
            = new ArrayList<>(advisors.size());
    for (Advisor element : advisors) {
        partiallyComparableAdvisors.add(
            // 比較規則爲 DEFAULT_PRECEDENCE_COMPARATOR,其實是AspectJPrecedenceComparator
            new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    // 具體的比較操作,比較規則由 AspectJPrecedenceComparator 提供
    List<PartiallyComparableAdvisorHolder> sorted 
            = PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {
        List<Advisor> result = new ArrayList<>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
            result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {
        return super.sortAdvisors(advisors);
    }
}

這裏進行了兩個排序,一個是PartialOrder.sort(...),一個是super.sortAdvisors(...),我們先來分析PartialOrder.sort(...)

2.1 PartialOrder.sort(...)的比較器:AspectJPrecedenceComparator

實際上,PartialOrder.sort(...)只要做了一個排序而已,這個方法沒啥分析的,我們真正要分析的應該是傳入的排序規則,也就是DEFAULT_PRECEDENCE_COMPARATOR

private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR 
        = new AspectJPrecedenceComparator();

DEFAULT_PRECEDENCE_COMPARATOR的類型是AspectJPrecedenceComparator,我們直接查看其compare(xxx)方法:

AspectJPrecedenceComparator

@Override
public int compare(Advisor o1, Advisor o2) {
    // 比較規則:AnnotationAwareOrderComparator
    int advisorPrecedence = this.advisorComparator.compare(o1, o2);
    // 順序相同,且來源於同一 aspect,調用 comparePrecedenceWithinAspect 再次比較
    if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
        // 比較聲明順序,如果其中有一個是after通知,則後聲明的優先級高;否則先聲明的優先級高
        advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
    }
    return advisorPrecedence;
}

AspectJPrecedenceComparator#compare 比較簡單,過程如下:

  1. 調用advisorComparator.compare進行比較,這個比較規則我們接下來會分析;
  2. 如果由上述比較規則得到的優先級相同,且兩個advisor是在同一aspect中定義的,則調用comparePrecedenceWithinAspect繼續比較.
this.advisorComparator.compare

我們來看看this.advisorComparator.compare的比較規則:

private final Comparator<? super Advisor> advisorComparator;

public AspectJPrecedenceComparator() {
    this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
}

public int compare(Advisor o1, Advisor o2) {
    // 比較規則:AnnotationAwareOrderComparator
    int advisorPrecedence = this.advisorComparator.compare(o1, o2);
    ...
}

this.advisorComparator.compare的比較規則由AnnotationAwareOrderComparator提供:

public int compare(@Nullable Object o1, @Nullable Object o2) {
    return doCompare(o1, o2, null);
}

/**
 * 具體的比較操作,先比較 PriorityOrdered,再比較 Ordered
 */
private int doCompare(@Nullable Object o1, @Nullable Object o2, 
        @Nullable OrderSourceProvider sourceProvider) {
    // 兩者之一爲 PriorityOrdered,誰是PriorityOrdered,誰的優先級高
    boolean p1 = (o1 instanceof PriorityOrdered);
    boolean p2 = (o2 instanceof PriorityOrdered);
    if (p1 && !p2) {
        return -1;
    }
    else if (p2 && !p1) {
        return 1;
    }
    // 查找order的值,先查找Ordered接口,如果沒找到,再查找 @Order 註解
    int i1 = getOrder(o1, sourceProvider);
    int i2 = getOrder(o2, sourceProvider);
    // 按Integer規則進行比較
    return Integer.compare(i1, i2);
}

從上面的代碼可知,先比較PriorityOrdered,再比較 Ordered,比較規則如下:

  1. PriorityOrdered比較:兩者之中,只有其一實現了 PriorityOrdered接口,那麼類型爲 PriorityOrdered 優先級高, 其他情況則按 Ordered 的規則比較;
  2. Ordered 比較規則:
    1. 如果實現了OrderedPriorityOrdered接口,則根據 getOrder() 返回值進行比較,值越小優先級越高;
    2. 如果標註了@Order/@Priority註解,則根據其value()返回值進行比較,值越小優先級越高;
    3. 如果沒有實現Ordered/PriorityOrdered,也沒有標註@Order/@Priority註解,則爲最低優先級(Integer.MAX_VALUE).
comparePrecedenceWithinAspect

對於 @Aspect標註的類,如果同一aspect裏定義了同樣的 advice,spring aop 也提供了一套比較規則:

/**
 * 針對 @Aspect, 同一aspect裏定義了同樣的 advice,再次比較
 */
private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
    boolean oneOrOtherIsAfterAdvice = (AspectJAopUtils.isAfterAdvice(advisor1) 
            || AspectJAopUtils.isAfterAdvice(advisor2));
    int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) 
            - getAspectDeclarationOrder(advisor2);
    // 其中有一個是after通知,declarationOrderInAspect大的優先級高
    if (oneOrOtherIsAfterAdvice) {
        if (adviceDeclarationOrderDelta < 0) {
            return LOWER_PRECEDENCE;
        }
        else if (adviceDeclarationOrderDelta == 0) {
            return SAME_PRECEDENCE;
        }
        else {
            return HIGHER_PRECEDENCE;
        }
    }
    // 兩者都不是after通知,declarationOrderInAspect小的優先級高
    else {
        if (adviceDeclarationOrderDelta < 0) {
            return HIGHER_PRECEDENCE;
        }
        else if (adviceDeclarationOrderDelta == 0) {
            return SAME_PRECEDENCE;
        }
        else {
            return LOWER_PRECEDENCE;
        }
    }
}

比較規則如下:比較兩者的declarationOrderInAspect值,如果兩者之一爲after通知,declarationOrderInAspect大的優先級高;如果兩者都不是after通知,declarationOrderInAspect小的優先級高。

這裏的declarationOrderInAspect是什麼呢?這是上一小節提到的advisor.size(),代碼如下:

ReflectiveAspectJAdvisorFactory

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 省略了一些代碼
    ...

    List<Advisor> advisors = new ArrayList<>();
    //獲取這個類所有的增強方法
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 生成增強實例,advisors.size() 依次爲 0,1,2,... 這是
        // declarationOrderInAspect 的值,後面排序會用到
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 
                advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // 省略了一些代碼
    ...
}

特別強調的是,這個規則只適用於同一@Aspect類定義的、同樣的通知方法,如:

@Aspect
public class AspectTest {
    @Before
    public void before1() {
        ...
    }

    @Before
    public void before2() {
        ...
    }

}

這裏的before1()before2()對應的advisor適用於comparePrecedenceWithinAspect排序,而以下代碼就不適用了,原因是在不同的@Aspect類中定義的:

@Aspect
public class AspectTest1 {
    @Before
    public void before() {
        ...
    }

}

@Aspect
public class AspectTest2 {
    @Before
    public void before() {
        ...
    }

}

2. super.sortAdvisors

我們再回過頭來看super.sortAdvisors(advisors):

AspectJAwareAdvisorAutoProxyCreator

protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    ...
    else {
        return super.sortAdvisors(advisors);
    }
}

我們跟進去:

AbstractAdvisorAutoProxyCreator

 protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
     AnnotationAwareOrderComparator.sort(advisors);
     return advisors;
 }

發現最後使用的是AnnotationAwareOrderComparator.sort(advisors),實際上,這個就是上面分析的this.advisorComparator.compare的比較規則,這裏就不再分析了。

3. getOrder() 值的由來

BeanFactoryTransactionAttributeSourceAdvisor#getOrder()

BeanFactoryTransactionAttributeSourceAdvisor沒有@Order/@Priority,但它實現了Ordered接口,因此它的執行順序由getOrder()方法的返回值決定,對應的getOrder()方法如下:

    /**
     * 獲取 order,方法如下:
     * 1. 如果已指定了 order,直接返回;
     * 2. 獲取 advisor 的 advice,如果 advice 實現了 Ordered 接口,調用 getOrder();
     * 3. 如果以上都不滿足,則返回 Ordered.LOWEST_PRECEDENCE (最低優先級)。
     * @return
     */
    @Override
    public int getOrder() {
        if (this.order != null) {
            return this.order;
        }
        Advice advice = getAdvice();
        if (advice instanceof Ordered) {
            return ((Ordered) advice).getOrder();
        }
        return Ordered.LOWEST_PRECEDENCE;
    }

Ordered.LOWEST_PRECEDENCEInteger.MAX_VALUE,即2147483647,我們再看看 BeanFactoryTransactionAttributeSourceAdvisorgetOrder() 方法返回的值:

可見,BeanFactoryTransactionAttributeSourceAdvisor 的執行順序是默認的Integer.MAX_VALUE。如果調度的話,發現這個值是在return this.order返回的:

public int getOrder() {
    // 通過調度發現,this.order 並不爲null
    if (this.order != null) {
        return this.order;
    }
    // 省略一些代碼
    ...
}

那麼這值是從哪裏來的呢?經過重重分析,發現是在創建BeanFactoryTransactionAttributeSourceAdvisor對象時,調用BeanFactoryTransactionAttributeSourceAdvisor#setOrder設置的:

ProxyTransactionManagementConfiguration

@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    BeanFactoryTransactionAttributeSourceAdvisor advisor 
            = new BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    advisor.setAdvice(transactionInterceptor());
    if (this.enableTx != null) {
        // 這裏獲取的是 @EnableTransactionManagement 註解的 order() 值
        advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    }
    return advisor;
}

到這裏我們就明白了,事務advisor的執行順序可以在@EnableTransactionManagement中指定:

public @interface EnableTransactionManagement {

    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    /**
     * 這裏指定advisor執行順序,默認是最低優先級
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

}

結論:@EnableTransactionManagement註解的order()方法可以指定advisor的執行順序。

InstantiationModelAwarePointcutAdvisorImpl#getOrder()

從前面的分析可知,@Aspect類中的每一個方法最終都會轉化爲advisor,類型爲InstantiationModelAwarePointcutAdvisorImpl,它也實現了Ordered接口,因此執行順序也是由InstantiationModelAwarePointcutAdvisorImpl#getOrder()方法決定,它的getOrder()方法如下:

InstantiationModelAwarePointcutAdvisorImpl

@Override
public int getOrder() {
    return this.aspectInstanceFactory.getOrder();
}

spring aop 之 AnnotationAwareAspectJAutoProxyCreator 分析(上)我們已經詳細分析了methodadvisor的轉變過程,能從代碼上輕鬆找到aspectInstanceFactory的類型,這裏我們就不再一步步分析源碼了,直接通過調試的方法獲取aspectInstanceFactory的類型:

從調試的結果來看,aspectInstanceFactory 類型爲 LazySingletonAspectInstanceFactoryDecorator,我們跟進其getOrder()方法:

LazySingletonAspectInstanceFactoryDecorator

@Override
public int getOrder() {
    return this.maaif.getOrder();
}

我們依然使用調試的方式獲取maaif的類型:

maaif 類型爲 BeanFactoryAspectInstanceFactory,我們繼續跟進:

BeanFactoryAspectInstanceFactory

public int getOrder() {
    // this.name 指的是標註了 @Aspect 註解的類
    Class<?> type = this.beanFactory.getType(this.name);
    if (type != null) {
        // 如果實現了 Ordered 接口,就調用 getOrder() 方法獲取
        // PriorityOrdered 是 Ordered 的子接口,也有 getOrder() 方法,因此這裏也會獲取到
        if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
            return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
        }
        // 1. 查找類是是否有 @Order 註解,如果有,則返回 @Order 註解指定的值;
        // 2. 否則查詢類是否有 @Priority 註解,如果有,則返回 @Priority 註解指定的值;
        // 3. 如果以上都不滿足,返回 Ordered.LOWEST_PRECEDENCE,值爲 Integer.MAX_VALUE
        return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
    }
    return Ordered.LOWEST_PRECEDENCE;
}

從代碼上來看,getOrder()邏輯如下:

  1. 通過名稱獲取切面類,也就是標註了@Aspect的類;
  2. 如果切面類實現了 Ordered 接口,就調用 getOrder() 方法獲取,返回(值得一提的是,PriorityOrderedOrdered 的子接口,也有 getOrder() 方法,這裏也會獲取到);
  3. 如果上面沒有獲取到,則查找切面類是是否有 @Order 註解,如果有,則返回 @Order 註解指定的值;如果沒有,查找切面類是否有 @Priority註解,如果有,則返回 @Priority 註解指定的值;
  4. 如果以上沒有獲取到值,就返回默認值:Ordered.LOWEST_PRECEDENCE

到這裏就明白了,@Aspect 類可以通過實現 Ordered/PriorityOrdered接口來指定執行優先級,也可以通過@Order/@Priority註解來指定執行優先級。

需要特別指出的是,從getOrder()代碼來看,這部分 代碼只 是把PriorityOrdered/@Priority 當作Order來處理,優先級並不比 Ordered/@Order高。也就是說,如果AspectA 標註了的了@PriorityAspectB 標註了的了@OrderAspectA的優先級並不一定比AspectB高,真正決定優先級的是註解 裏的value()值。

4. 如何自定義優先級

我們在自己寫代碼時,如何指定優先級呢?

  1. 如果是自主實現advisor,可實現Ordered接口,也可以在advisor類上標註@Order註解:

    public class MyAdvisor extends AbstractBeanFactoryPointcutAdvisor implements Ordered {
    
        @Override
        public int getOrder() {
            return xxx;
        }
    
    }
    
    @Order(xxx)
    public class MyAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    
        @Override
        public int getOrder() {
            return xxx;
        }
    
    }
    
  2. 如果是單個切面類(@Aspect標註的類),且無重複的@Around/@Before/@After

    @Aspect
    public class MyAspectj {
    
        @Around("xxx")
        public Object around(ProceedingJoinPoint p){
            ...
        }
    
        @Before("xxx")
        public void before(JoinPoint p) {
            ...
        }
    
        @After("xxx")
        public void after(JoinPoint p) {
            ...
        }
    
        @AfterReturning("xxx")
        public void afterReturning(JoinPoint p) {
            ...
        }
    
        @AfterThrowing("xxx")
        public void afterThrowing(JoinPoint p) {
            ...
        }
    }
    

    對於同一切面的不同通知,spring已經幫我們設置好了執行順序,我們無從更改,執行順序依次爲Around, Before, After, AfterReturning, AfterThrowing.

  3. 單個切面類(@Aspect標註的類)內有重複的@Around/@Before/@After等,情況如下:

    @Aspect
    public class MyAspectj {
    
        @Around("xxx")
        public Object around(ProceedingJoinPoint p){
            ...
        }
    
        @Before("xxx")
        public void before(JoinPoint p) {
            ...
        }
    
        @Around("xxx")
        public Object around(ProceedingJoinPoint p){
            ...
        }
    
        @Before("xxx")
        public void before(JoinPoint p) {
            ...
        }
    
    }
    

    這種情況我們在AspectJPrecedenceComparator#comparePrecedenceWithinAspect方法時有分析過,得到的結論是:比較兩者的declarationOrderInAspect值,如果兩者之一爲after通知,declarationOrderInAspect大的優先級高;如果兩者都不是after通知,declarationOrderInAspect小的優先級高。這個declarationOrderInAspect完全依賴於jdk的反射機制,先獲取到的是哪個方法,哪個方法的declarationOrderInAspect就小,不同jdK版本之間,難以保證獲得的順序一致。

  4. 多個切面類(@Aspect標註的類)的執行順序可以通過@Order註解,或實現Ordered接口來指定:

    @Order(xxx)
    public class MyAspectj1 {
        ...
    }
    
    @Order(xxx)
    public class MyAspectj2 {
        ...
    }
    

另外,getOrder()返回的值或@Order(xxx)指定的值越小,表明優先級越高。


本文原文鏈接:https://my.oschina.net/funcy/blog/4784828 ,限於作者個人水平,文中難免有錯誤之處,歡迎指正!原創不易,商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

本系列的其他文章

【spring源碼分析】spring源碼分析系列文章

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