当一个方法上面上面加了多个AOP注解的时候,运行顺序是如何的呢?
我们想对某个加了@Transactional注解的方法再添加一个自定义注解,来进行日志的打印。此时一个问题就出现在脑海里了:到底是先运行@Transactional注解的逻辑还是先运行自定义注解的逻辑呢?自定义注解实现的逻辑会在事务里么?也就是如果抛出异常会使得事务回滚么?
基于我们以前的了解,最后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顺序是如何的?咱们去往回找代码。
相信大家看过我之前的博客,应该知道给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其实是AdvisedSupport的子类,所以其实这个proxyFactory也就是咱们最后CglibAopProxy类里的advised属性
那么咱们就需要重点关注proxyFactory.addAdvisors(advisors);
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);这个方法的具体逻辑就是遍历了下specificInterceptors,然后封装成了advisor,所以advisors的顺序取决于传进来的specificInterceptors的顺序。
那么答案又要到我们的WrapIfNecessary方法里面找。
方法体有一行
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
确认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的顺序。
每个加了@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);
可以看到执行优先级是按照注解来排序的,当注解相同时,通过方法名排序
如上面所说,默认所有的aspect优先级相同,所以按照扫描顺序添加到bean的advisors里面,Aspect可以通过实现Ordered接口,来提高优先级,形如以下
@Aspect
@Component
@Slf4j
public class MyAspect implements Ordered {
@Override
public int getOrder() {
// 此处只要比Integer.MAX_VALUE小就行
return 123;
}
}
代码如下
@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;
}
所以最终我们需要查看下
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之前。
上图是proxy在进行method的invoke时的Advisor执行示意图。图中的ExposeInvocationInterceptor因为跟本文主题关系不密切,顾没有解释。
工作中需要多思考,思考就会有结论。而且可以发现spring的扩展点特别多。
默认情况下,自定义注解写的Aspect是被包在@Transactional的事务里的,所以如果自定义的Aspect如果运行报错,可能会导致事务回滚。
advisor的顺序分为两个维度: