在使用Spring AOP時,有時會有在同一切入點存在多個Advice的狀況出現,這裏的多個Advice多是不一樣的Advice,好比後置加強和環繞加強,也多是多個相同的Advice,好比多個後置加強,甚至是更復雜的狀況。於是就存在一個需求:不一樣Advice的執行順序是怎樣的,一樣類型的Advice如何排序,一步一步來看。java
對於不一樣類型的Advice執行順序,你們都比較熟悉,可是爲了比較更復雜的狀況,仍是先簡單介紹下。ide
Spring AOP中定義的基本加強有五種,分別是前置加強(BeforeAdvice),後置加強(AfterReturningAdvice),後置finally加強(AfterAdvice),拋出加強(AfterThrowingAdvice)和環繞加強(AroundAdvice)。測試
因爲環繞加強能夠經過ProceedingJoinPoint調用proceed方法執行原始方法,所以環繞加強能夠分爲環繞加強前(around before)和環繞加強後(around after),對應proceed方法的先後。this
後置加強爲return操做後操做,拋出加強爲異常拋出時操做,故這二者是互斥的。後置finally加強,是finally類型的操做,於是不論方法是否有異常,都會執行,且在後置加強和拋出加強前執行。編碼
用代碼定義下以上Advicelua
// 環繞加強 @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("around before"); Object retVal = pjp.proceed(); System.out.println("around after"); return retVal; } // 前置加強 @Before("pointcut()") public void before(){ System.out.println("before"); } // 後置finally加強 @After("pointcut()") public void after(){ System.out.println("after"); } // 後置return加強 @AfterReturning("pointcut()") public void afterReturning(){ System.out.println("after returning"); } // 拋出加強 @AfterThrowing(value="pointcut()",throwing="ex") public void afterThrowing(Exception ex){ System.out.println("afterThrowing"); }
經過測試執行的結果爲代理
around before before //method execute around after after after returning
若是方法拋出異常,結果爲code
around before before //method execute after afterThrowing
於是對於五種加強類型的執行順序以下對象
若是存在兩個相同類型的Advice,如何進行排序?答案Spring AOP不支持Advice層級的排序,只支持Aspect層級的排序。不一樣的Aspect經過實現Ordered接口,或使用@Order註解設置優先級。對於getOrder返回的值或@Order中設置的值,值越小優先級越高。排序
@Aspect public class AspectJAspect implements Ordered{ @Override public int getOrder() { return 1; } }
或者
@Aspect @Order(1) public class AspectJAspect{ }
而多個Aspect中的相同類型Advice執行順序,也分爲兩種狀況:
且對於多個不一樣排序的Aspect中的多個Advice,一個Aspect執行完纔到下一個Aspect,一樣也是以原始方法的執行爲界。
還以上面的多個Advice代碼爲例,若是存在兩個Aspect,分別標註@Order(1)和@Order(2),@Order(1)對應的Advice打印內容後加1,@Order(2)對應的加2。之前置加強舉例:
@Aspect @Order(1) public class AspectJAspect1{ @Before("pointcut()") public void before(){ System.out.println("before 1"); } } @Aspect @Order(2) public class AspectJAspect2{ @Before("pointcut()") public void before(){ System.out.println("before 2"); } }
通過測試,打印結果以下:
around before 1 before 1 around before 2 before 2 // method execute around after 2 after 2 after returning 2 around after 1 after 1 after returning 1
對於這個測試結果,之後有相似的實現時仍是要多注意的。至於原理,一是建立代理時造成的攔截器的鏈式調用,可見ReflectiveMethodInvocation的proceed方法,二是建立同一Aspect內的Advice有一個默認的排序方式,見ReflectiveAspectJAdvisorFactory中static代碼庫的METHOD_COMPARATOR建立。
Aspect類的排序,經過Ordered接口或@Order註解來實現。而註解狀況下,獲取徹底部的Advice並封裝成Advisor後,使用模板方法sortAdvisors完成了排序。
AbstractAdvisorAutoProxyCreator中的默認實現以下
protected List<Advisor> sortAdvisors(List<Advisor> advisors) { OrderComparator.sort(advisors); return advisors; }
OrderComparator是Comparator的子類,經過compare方法比較兩個對象
public int compare(Object o1, Object o2) { return doCompare(o1, o2, null); } private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) { boolean p1 = (o1 instanceof PriorityOrdered); boolean p2 = (o2 instanceof PriorityOrdered); if (p1 && !p2) { return -1; } else if (p2 && !p1) { return 1; } // Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation. int i1 = getOrder(o1, sourceProvider); int i2 = getOrder(o2, sourceProvider); return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0; }
若是有Advisor實現了PriorityOrdered,而另外一個沒有實現,則實現PriorityOrdered的優先級更高。若是兩個都沒有實現PriorityOrdered,則繼續比較getOrder方法返回的值。
private int getOrder(Object obj, OrderSourceProvider sourceProvider) { Integer order = null; if (sourceProvider != null) { order = findOrder(sourceProvider.getOrderSource(obj)); } return (order != null ? order : getOrder(obj)); } protected int getOrder(Object obj) { Integer order = findOrder(obj); return (order != null ? order : Ordered.LOWEST_PRECEDENCE); } protected Integer findOrder(Object obj) { return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null); }
若是Advisor實現了Ordered接口,則調用getOrder()方法,若是沒實現,返回Ordered.LOWEST_PRECEDENCE,即Integer.MAX_VALUE。
到此排序的思路基本清晰了,可是忽然發現一個問題,使用@Order的Aspect並無實現Ordered接口啊,這裏不是掛了嗎?
這時回頭看下sortAdvisors方法,進行排序的都是Advisor,並非Aspect。而AspectJ方式的AOP,都是經過硬編碼的方式指定了實際的Advisor類。XML方式的是AspectJPointcutAdvisor,註解方式的是InstantiationModelAwarePointcutAdvisorImpl,而這兩個類都實現了Ordered接口。
註解方式的InstantiationModelAwarePointcutAdvisorImpl,其getOrder方法以下
public int getOrder() { return this.aspectInstanceFactory.getOrder(); }
這裏的aspectInstanceFactory的類型爲MetadataAwareAspectInstanceFactory,其實際的實現類爲BeanFactoryAspectInstanceFactory,其爲Aspect實例的工廠類
public int getOrder() { Class<?> type = this.beanFactory.getType(this.name); if (type != null) { if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) { return ((Ordered) this.beanFactory.getBean(this.name)).getOrder(); } // Aspect非Ordered實現時處理 return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE); } return Ordered.LOWEST_PRECEDENCE; }
這裏對Aspect類未實現Ordered接口進行了處理,查詢Aspect是否有@Order註解,若是存在則返回其value值。另外若是不存在@Order,再去查詢是否有javax.annotation.Priority註解,這是java通用註解包裏支持優先級的註解。
public static Integer getOrder(Class<?> type, Integer defaultOrder) { Order order = AnnotationUtils.findAnnotation(type, Order.class); if (order != null) { return order.value(); } Integer priorityOrder = getPriority(type); if (priorityOrder != null) { return priorityOrder; } return defaultOrder; }
在AOP AspectJ方式的驅動類AspectJAwareAdvisorAutoProxyCreator中,重寫了sortAdvisors方法,使用AspectJPrecedenceComparator比較器代替以前的OrderComparator,但其內部實現仍是使用OrderComparator,只是在優先級同樣且是同一個Aspect時,對Advice的declarationOrder進行排序。declarationOrder目前並不能進行配置,而只是經過ReflectiveAspectJAdvisorFactory中的METHOD_COMPARATOR按規則對Advice賦值。