Spring的AOP执行顺序

文章目录

  • 前言
  • 一、问题的提出
  • 二、思考的逻辑
    • 1. advisor运行的顺序
    • 2. advisor添加的顺序
    • 3. 合适的advisor添加
    • 4. 排序逻辑
      • 4.1 Aspect内部方法advisor排序
      • 4.2 不同的Aspect之间的排序
        • 4.2.1 实现Ordered接口
        • 4.2.2 使用Order注解
    • 5.default order
    • 5. 默认情况下的执行逻辑
  • 总结


前言

当一个方法上面上面加了多个AOP注解的时候,运行顺序是如何的呢?


一、问题的提出

我们想对某个加了@Transactional注解的方法再添加一个自定义注解,来进行日志的打印。此时一个问题就出现在脑海里了:到底是先运行@Transactional注解的逻辑还是先运行自定义注解的逻辑呢?自定义注解实现的逻辑会在事务里么?也就是如果抛出异常会使得事务回滚么?

二、思考的逻辑

1. advisor运行的顺序

基于我们以前的了解,最后bean会被封装成一个proxy,proxy里的target才是raw bean。在method进行invoke的时候,需要遍历proxy里的advisors。
此处我们以CglibAopProxy为例,JdkDynamicAopProxy逻辑类似。

class CglibAopProxy implements AopProxy, Serializable {
// 其他属性本文不会涉及,暂时忽略
/** The configuration used to configure this proxy. */
	protected final AdvisedSupport advised;
}

可以看到CglibAopProxy里有个advised属性。

public class AdvisedSupport extends ProxyConfig implements Advised{
	// 其余属性忽略
	/**
	 * Canonical TargetSource when there's no target, and behavior is
	 * supplied by the advisors.
	 */
	public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;

	/** Package-protected to allow direct access for efficiency. */
	TargetSource targetSource = EMPTY_TARGET_SOURCE;
	/**
	 * List of Advisors. If an Advice is added, it will be wrapped
	 * in an Advisor before being added to this List.
	 */
	private List<Advisor> advisors = new ArrayList<>();
}

可以看到advised属性里的targetSource和advisors,分别代表目标方法和相应的advisor。
执行的时候是遍历advisors,把每个advisor里的advice拿出来,然后进行链式调用,具体使用方式类似filter。
那么advisors里的advisor顺序就变得尤为重要。
那么此处我们反推,在生成CglibAopProxy的时候,放入进去的advisors顺序是如何的?咱们去往回找代码。

2. advisor添加的顺序

相信大家看过我之前的博客,应该知道给raw bean变成aop proxy是在AbstractAutoProxyCreator里的wrapIfNecessary
在wrapIfNecessary中调用了createProxy方法

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		// 创建一个ProxyFactory,并把当前对象的某些属性拷贝填充到该proxyFactory对象上
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// 通过proxyFactory创建代理
		return proxyFactory.getProxy(getProxyClassLoader());
	}

注意此处的这个ProxyFactory类
Spring的AOP执行顺序_第1张图片
我们可以发现此处的ProxyFactory其实是AdvisedSupport的子类,所以其实这个proxyFactory也就是咱们最后CglibAopProxy类里的advised属性
那么咱们就需要重点关注proxyFactory.addAdvisors(advisors);
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);这个方法的具体逻辑就是遍历了下specificInterceptors,然后封装成了advisor,所以advisors的顺序取决于传进来的specificInterceptors的顺序
那么答案又要到我们的WrapIfNecessary方法里面找。
方法体有一行

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

3. 合适的advisor添加

确认getAdvicesAndAdvisorsForBean,可以发现调用了findEligibleAdvisors方法

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 返回所有的advisor,此处会把因为@EnableTransManagement注解添加进来的@Transactional注解
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		// 查找适合当前beanClass的advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		// 如果eligibleAdvisors不为空,给eligibleAdvisors加上一个默认的advisor: ExposeInvocationInterceptor.ADVISOR
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

可以看到最后有个sortAdvisors,可以看看里面的逻辑
最终会调用PartialOrder的sort方法

1. 将待排序的对象之间的大小关系保存好,放入到一个sortList中
2. 遍历sortList,从sortList中找出第一个最小的对象o
3. 从sortList里面删除掉对象o,放入一个新的list
4. 从第2步开始重复

最终得到的就是排好序的advisors,那么怎么判断两个advisor谁排在前面呢?根据getOrder返回值,自定义的Aspect,调用BeanFactoryAspectInstanceFactory的getOrder,默认是Ordered.LOWEST_PRECEDENCE,也就是Integer.MAX_VALUE,可以通过实现Ordered接口来指定。
而咱们的@Transactional注解使用的BeanFactoryTransactionAttributeSourceAdvisor是通过BeanFactoryTransactionAttributeSourceAdvisor的getOrder返回默认值,也是Ordered.LOWEST_PRECEDENCE
可以发现默认情况下,咱们自定义的注解的advisor和@Transactional注解的advisor值是一样大的,那么这种情况,按照PartialOrder.sort方法逻辑,就是保持他们加入到sortList的顺序。

4. 排序逻辑

4.1 Aspect内部方法advisor排序

每个加了@Aspect的bean和advisor的对应关系是一对多,那么同一个bean里的多个aop方法执行顺序是什么样的呢?

1. BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors ->
2. ReflectiveAspectJAdvisorFactory.getAdvisors ->
3. ReflectiveAspectJAdvisorFactory.getAdvisorMethods ->
4. ReflectiveAspectJAdvisorFactory.METHOD_COMPARATOR

看一下METHOD_COMPARATOR的逻辑:

Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
				new InstanceComparator<>(
				// advisor执行优先级
						Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
				(Converter<Method, Annotation>) method -> {
					AspectJAnnotation<?> annotation =
						AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
					return (annotation != null ? annotation.getAnnotation() : null);
				});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
// 当添加了相同注解的时候,按照方法名来决定优先级
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);

可以看到执行优先级是按照注解来排序的,当注解相同时,通过方法名排序

4.2 不同的Aspect之间的排序

4.2.1 实现Ordered接口

如上面所说,默认所有的aspect优先级相同,所以按照扫描顺序添加到bean的advisors里面,Aspect可以通过实现Ordered接口,来提高优先级,形如以下

@Aspect
@Component
@Slf4j
public class MyAspect implements Ordered {

    @Override
    public int getOrder() {
    // 此处只要比Integer.MAX_VALUE小就行
        return 123;
    }
}
4.2.2 使用Order注解

代码如下

@Aspect
@Component
@Slf4j
@Order(0)
public class MyAspect {
}

需要注意,如果既实现了Ordered接口又加了Order注解,以Ordered接口生效。原因参见
BeanFactoryAspectInstanceFactory.getOrder

@Override
	public int getOrder() {
		Class<?> type = this.beanFactory.getType(this.name);
		if (type != null) {
		// 如果有Ordered接口
			if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
				return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
			}
			// 查看Order注解
			return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
		}
		return Ordered.LOWEST_PRECEDENCE;
	}

5.default order

所以最终我们需要查看下

List<Advisor> candidateAdvisors = findCandidateAdvisors();

下面来看一下具体的逻辑:
AnnotationAwareAspectJAutoProxyCreator-具体实现类

@Override
protected List<Advisor> findCandidateAdvisors() {
	// Add all the Spring advisors found according to superclass rules.
	// 先调用父类的方法,父类会去查找容器中所有属于Advisor类型的Bean
	List<Advisor> advisors = super.findCandidateAdvisors();
	// Build Advisors for all AspectJ aspects in the bean factory.
	// 这个类本身会通过一个aspectJAdvisorsBuilder来构建通知
	// 构建的逻辑就是解析@Aspect注解所标注的类中的方法
	if (this.aspectJAdvisorsBuilder != null) {
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
	}
	return advisors;
}

具体的逻辑解释一下,就不详写了。super.findCandidateAdvisors();这一句会把容器中所有的Advisor子类实例全都加进来,BeanFactoryTransactionAttributeSourceAdvisor就是Advisor的子类;而this.aspectJAdvisorsBuilder.buildAspectJAdvisors()的功能是查找所有加了@Aspect注解的类实例,加入到advisors里,而因为advisors是List类型的,是有序的。所以默认情况下BeanFactoryTransactionAttributeSourceAdvisor在基于Aspect生成的Advisor之前。

5. 默认情况下的执行逻辑

Spring的AOP执行顺序_第2张图片

上图是proxy在进行method的invoke时的Advisor执行示意图。图中的ExposeInvocationInterceptor因为跟本文主题关系不密切,顾没有解释。

总结

工作中需要多思考,思考就会有结论。而且可以发现spring的扩展点特别多。
默认情况下,自定义注解写的Aspect是被包在@Transactional的事务里的,所以如果自定义的Aspect如果运行报错,可能会导致事务回滚。
advisor的顺序分为两个维度:

  1. 同一个Aspect类里,按照 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 的顺序作为优先级,同一个注解的话,按照方法名字母序
  2. 不同的Aspect,由于默认情况下,优先级一样,会按照spring扫描顺序来,可以通过实现Ordered接口或者添加Order注解来使得某个Aspect顺序优先级提高

你可能感兴趣的:(源码分析,spring,AOP,spring,aop,advisor)