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赋值。

相关文章
相关标签/搜索