注:本系列源碼分析基於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);
}
這裏對這個方法的排序規則總結如下:
- 這個方法排序的對象是同一個
@Aspect
中的方法; - 對於切面方法,排序如下:
@Around
,@Before
,@After
,@AfterReturning
,@AfterThrowing
; - 對於非切面方法,按方法名(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
比較簡單,過程如下:
- 調用
advisorComparator.compare
進行比較,這個比較規則我們接下來會分析; - 如果由上述比較規則得到的優先級相同,且兩個
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
,比較規則如下:
PriorityOrdered
比較:兩者之中,只有其一實現了PriorityOrdered
接口,那麼類型爲PriorityOrdered
優先級高, 其他情況則按Ordered
的規則比較;Ordered
比較規則:- 如果實現了
Ordered
或PriorityOrdered
接口,則根據getOrder()
返回值進行比較,值越小優先級越高; - 如果標註了
@Order/@Priority
註解,則根據其value()
返回值進行比較,值越小優先級越高; - 如果沒有實現
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_PRECEDENCE
爲Integer.MAX_VALUE
,即2147483647
,我們再看看 BeanFactoryTransactionAttributeSourceAdvisor
的 getOrder()
方法返回的值:
可見,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 分析(上)我們已經詳細分析了method
到advisor
的轉變過程,能從代碼上輕鬆找到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()
邏輯如下:
- 通過名稱獲取切面類,也就是標註了
@Aspect
的類; - 如果切面類實現了
Ordered
接口,就調用getOrder()
方法獲取,返回(值得一提的是,PriorityOrdered
是Ordered
的子接口,也有getOrder()
方法,這裏也會獲取到); - 如果上面沒有獲取到,則查找切面類是是否有
@Order
註解,如果有,則返回@Order
註解指定的值;如果沒有,查找切面類是否有@Priority
註解,如果有,則返回@Priority
註解指定的值; - 如果以上沒有獲取到值,就返回默認值:
Ordered.LOWEST_PRECEDENCE
。
到這裏就明白了,@Aspect
類可以通過實現 Ordered/PriorityOrdered
接口來指定執行優先級,也可以通過@Order/@Priority
註解來指定執行優先級。
需要特別指出的是,從getOrder()
代碼來看,這部分 代碼只 是把PriorityOrdered/@Priority
當作Order
來處理,優先級並不比 Ordered/@Order
高。也就是說,如果AspectA
標註了的了@Priority
,AspectB
標註了的了@Order
,AspectA
的優先級並不一定比AspectB
高,真正決定優先級的是註解 裏的value()
值。
4. 如何自定義優先級
我們在自己寫代碼時,如何指定優先級呢?
-
如果是自主實現
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; } }
-
如果是單個切面類(
@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
. -
單個切面類(
@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版本之間,難以保證獲得的順序一致。 -
多個切面類(
@Aspect
標註的類)的執行順序可以通過@Order
註解,或實現Ordered
接口來指定:@Order(xxx) public class MyAspectj1 { ... } @Order(xxx) public class MyAspectj2 { ... }
另外,getOrder()
返回的值或@Order(xxx)
指定的值越小,表明優先級越高。
本文原文鏈接:https://my.oschina.net/funcy/blog/4784828 ,限於作者個人水平,文中難免有錯誤之處,歡迎指正!原創不易,商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
本系列的其他文章