Spring源碼-AOP(九)-Advice排序

在使用Spring AOP時,有時會有在同一切入點存在多個Advice的狀況出現,這裏的多個Advice多是不一樣的Advice,好比後置加強和環繞加強,也多是多個相同的Advice,好比多個後置加強,甚至是更復雜的狀況。於是就存在一個需求:不一樣Advice的執行順序是怎樣的,一樣類型的Advice如何排序,一步一步來看。java

1.Advice的執行順序

對於不一樣類型的Advice執行順序,你們都比較熟悉,可是爲了比較更復雜的狀況,仍是先簡單介紹下。ide

不一樣類型的Advice

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

於是對於五種加強類型的執行順序以下對象

  1. 環繞加強前(around advice before)
  2. 前置加強(before advice)
  3. -- 方法執行
  4. 環繞加強後(around advice after)
  5. 後置finally加強(after advice)
  6. 後置加強/拋出加強

相同類型Advice的排序

若是存在兩個相同類型的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執行順序,也分爲兩種狀況:

  1. 方法執行以前的加強Advice,優先級高的先執行,如前置加強
  2. 方法執行以後的加強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建立。

2.@Order原理解析

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;
}

3.AspectJ方式的Advisor排序

在AOP AspectJ方式的驅動類AspectJAwareAdvisorAutoProxyCreator中,重寫了sortAdvisors方法,使用AspectJPrecedenceComparator比較器代替以前的OrderComparator,但其內部實現仍是使用OrderComparator,只是在優先級同樣且是同一個Aspect時,對Advice的declarationOrder進行排序。declarationOrder目前並不能進行配置,而只是經過ReflectiveAspectJAdvisorFactory中的METHOD_COMPARATOR按規則對Advice賦值。

相關文章
相關標籤/搜索