Spring的AOP执行顺序


前言

当一个方法上面上面加了多个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类
ProxyFactory的类继承示意图
我们可以发现此处的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.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. 默认情况下的执行逻辑

代理类的方法运行流程示意图【proxy.proceed()】

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

总结

工作中需要多思考,思考就会有结论。
而且可以发现spring的扩展点特别多。
默认情况下,自定义注解写的Aspect是被包在@Transactional的事务里的,但是可以通过实现Ordered接口来修改执行顺序,使得事务被包在我们定义的Aspect执行逻辑里面,使得执行异常不会影响事务。


版权声明:本文为liangsheng_g原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。