前言
语句描述不是专业,比如统一用【切面】代指各个aop处理的代码,大家意会即可
问题引入
你是否有注意过各个注解下切面的执行顺序,假如有有以下代码
@Async(xxxx)
@Cacheable(xxxx)
@Transactional(xxxx)
@CustomBizLog(xxx)
@RedisLock(xxx)
public Future<Data> queryData(@Valid Query query) {
// xxxxxxxxxx
}
从代码中至少可以看出,包含了 异步、缓存、事务、参数校验、两个自定义注解(业务日志、redis分布式锁)等至少6个切面,此时将不得不考虑它们的执行顺序
如何查看执行顺序
org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
在这个方法中定位到这一行
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
断点打下面即可看到 chain 里面的执行顺序
假设我的自定义切面 @CustomBizLog 配置了 order=10, @RedisLock 的 order=0,那大概率顺序是这样:
AnnotationAsyncExecutionInterceptorExposeInvocationInterceptoeAspectJAroundAdvice(aspectName=redisLockAspect)AspectJAroundAdvice(aspectName=customBizLogAspect)CacheInterceptorTransactionInterceptorMethodValidationInterceptor
调整顺序
业务上的查询,实际还需要再多张表中记录和变更一些数据的,所以需要用事务控制
整体顺序需要是:
- 尝试从缓存获取,获取到则返回
- 缓存没有,需要先加锁,然后进入事务管理,进入日志记录切面,在进入业务代码
于是在调整事务和缓存注解上调整顺序
@EnableTransactionManagement(order = 1)
@EnableCaching(order = -1)
然后发现需要将参数校验也提前到缓存切面之前,但蒙蔽了,没有找到可配置的方式
先说结论,处理方法1
把 bean 代理成执行 MethodValidationInterceptor 和 AnnotationAsyncExecutionInterceptor 的 PostProcessor 不是 AnnotationAwareAspectJAutoProxyCreator,即便各种方式给 advisor 设置了排序,最后也无法同其它的几个切面排序。个人简单看了下源码,常规方法只能给加到几个切面的前后,大佬有办法望告知
可以在 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 中断点,或者跟随注解或auto configuration类查找,定位到它们分别由
MethodValidationPostProcessor、AsyncAnnotationBeanPostProcessor 来包装代理
最后执行到 AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization 进行代理,可以发现 advisor(即 pointcut + advice(MethodValidationInterceptor)) 只能加到最前或最后
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
所以最后配置代码为(不同spring版本自行参考 ValidationAutoConfiguration 中的写法)
@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
ObjectProvider<Validator> validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
FilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(
excludeFilters.orderedStream());
boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
processor.setProxyTargetClass(proxyTargetClass);
processor.setValidatorProvider(validator);
// 加上以下2段代码
processor.setBeforeExistingAdvisors(true);
processor.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
return processor;
}
继续分析
我试过把上述 processor 的 order 设置到 HIGHEST_PRECEDENCE,结果 chain 没有 MethodValidationInterceptor 了,怎么回事?只能看 AnnotationAwareAspectJAutoProxyCreator 如何 proxy bean 的。
定位到对应 AbstractAutoProxyCreator#postProcessAfterInitialization,发现调用 wrapIfNecessary,里面有段关键代码
// 获取当前bean适用的advisor,内部排序
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 关键,这里根据 bean 的 class 重新创建生成了个 bean,原本代理 bean 里的 advisor 丢失了
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
处理方法2
笔者能力有限,只做得到其中一种解决方案,就是继承 MethodValidationPostProcessor, 重写 postProcessAfterInitialization 方法,对 advisor 进行排序
public class MyMethodValidationPostProcessor extends FilteredMethodValidationPostProcessor {
private int advisorOrder = 0;
public MyMethodValidationPostProcessor(Stream<? extends MethodValidationExcludeFilter> excludeFilters) {
super(excludeFilters);
}
public MyMethodValidationPostProcessor(Collection<? extends MethodValidationExcludeFilter> excludeFilters) {
super(excludeFilters);
}
public void setAdvisorOrder(int advisorOrder) {
this.advisorOrder = advisorOrder;
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
DefaultPointcutAdvisor advisor = (DefaultPointcutAdvisor) this.advisor;
advisor.setOrder(this.advisorOrder);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
return bean;
}
if (bean instanceof Advised advised) {
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
if (advised.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE &&
advised.getAdvisorCount() > 0) {
advised.addAdvisor(advised.getAdvisorCount() - 1, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
// 这里进行排序
Advisor[] advisors = advised.getAdvisors();
AnnotationAwareOrderComparator.sort(advisors);
for (Advisor value : advisors) {
advised.removeAdvisor(value);
}
for (Advisor value : advisors) {
advised.addAdvisor(value);
}
return bean;
}
}
// ........
}
}
@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
ObjectProvider<Validator> validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {
MyMethodValidationPostProcessor processor = new MyMethodValidationPostProcessor(
excludeFilters.orderedStream());
// 设置排序
processor.setAdvisorOrder(-2);
boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
processor.setProxyTargetClass(proxyTargetClass);
processor.setValidatorProvider(validator);
return processor;
}