出发点

闲来无事回顾几个项目中的一些内容,把一些重复代码用AOP重新处理了一下,定义切入点时采用了自定义注解的形式,原因是这样最精准、最容易控制,当然缺点是需要手动把注解加到各个方法上去。项目里还有用到声明式事务(@Transactional)和声明式缓存(@Cacheable),所以有的方法就会存在3个以上的切面相关注解,注解一多就发现对它们的执行顺序机理的理解有些模糊,遂打算重新理一遍Spring AOP的内容,回顾一把这个经典到不能再经典的工具。为了方便,底子还是用的SpringBoot,顺便也回顾下SpringBoot中事务、AOP等自动配置的相关内容,分析分析源码。本文默认您已经有对Spring AOP与声明式事务管理的基本认知,采用的版本信息:SpringBoot 2.3.3.RELEASE(Spring 5.2.8.RELEASE)

声明式事务原理

首先整理下声明式事务,在SpringBoot环境下不需要单独引入事务相关的依赖或者单独添加启用事务的注解,通常引入相关的持久层依赖就可以直接使用@Transactional这个注解,而如果要使用Spring AOP您需要显式引入依赖项spring-boot-starter-aop。声明式事务本质上也是AOP思想的产物,那么为什么没有诸如spring-boot-starter-transaction,为什么使用声明式事务不需要引入spring-aop是个值得思考的问题。

对于普通Spring项目来说,使用声明式事务需要显式进行指定。xml配置中需要添加标签<tx:annotation-driven>(使@Transactional生效)或者使用标签<tx:advice>来声明事务切入;使用Java config形式则需要在配置类上添加注解@EnableTransactionManage。而SpringBoot可以不准确的描述为更高级的Java config,我们知道SpringBoot自带的自动配置类都在spring-boot-autoconfigure包下,很容易找到事务相关的自动配置类org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
@Configuration(proxyBeanMethods = false)
// 依赖PlatformTransactionManager, 该类位于spring-tx包下
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
// 引入事务属性配置
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {

// 事务管理器自定义收集器
@Bean
@ConditionalOnMissingBean
public TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
}

// reactive相关,可以暂不考虑
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(ReactiveTransactionManager.class)
public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) {
return TransactionalOperator.create(transactionManager);
}

// 配置TransactionTemplate
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {

@Bean
@ConditionalOnMissingBean(TransactionOperations.class)
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}

}

// 事务的主要配置内容,根据使用的代理方式分成两种:jdk proxy和cglib proxy
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TransactionManager.class)
// 这个contion意味着你可以主动使用@EnableTransactional,不采用如下的默认配置
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {

@Configuration(proxyBeanMethods = false)
// 使用与普通java config相同的注解
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {

}

@Configuration(proxyBeanMethods = false)
// 同上, 只是注解的参数不同
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {

}

}

}

因此还是回到了@EnableTransactionManagement这注解上,值得额外注意的一点是当前版本SpringBoot环境下该注解的proxyTargetClass属性默认设置为true(matchIfMissing的作用),这与注解属性本身的默认值(false)不同,也就是说SpringBoot默认采用CGLIB作为动态代理解决方案,有关于这一点的具体可以参考这个issue的讨论。接下来继续深入该注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

boolean proxyTargetClass() default false;

AdviceMode mode() default AdviceMode.PROXY;

int order() default Ordered.LOWEST_PRECEDENCE;

}

该注解主要的功能就是引入TransactionManagementConfigurationSelector,其作为接口ImportSelector的实现类目的是引入一些Configuration配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

// 根据@EnableTransactionManagement注解的mode属性来确定引入的配置类
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// 默认使用PROXY,引入了两个类
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}

private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}

}

以默认的PROXY模式为例(ASPECTJ需要额外引入spring-aspects依赖并执行其他操作),可以看到引入了两个配置类:AutoProxyRegistrarProxyTransactionManagementConfiguration,这两个类自身代码量都不多,逐个查看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

private final Log logger = LogFactory.getLog(getClass());

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 重点在于如下几句代码,尝试注册AutoProxyCreator
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}

}

// ===========================================================

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

// 事务Advisor实现类,引用了后面两个Bean
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}

// 事务属性解析器,使用的是AnnotaionTransactionAtributeSource,用于解析@Transactional注解的属性
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}

// 事务拦截器,事务处理的真正逻辑就在这个类中,如果想探究事务是如何执行的可以深入查看这个类的源码
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}

}

ProxyTransactionManagementConfiguration引入了事务处理的解析、处理和整体描述相关的Bean,那么如何让这些Bean发挥作用,真正应用到方法中就应该是AutoProxyRegistrar所引入的Bean(严格来说是Bean Definition)要做的事情。沿着关键代码AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)的调用链一直到最后,可以看到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// from org.springframework.aop.config.AopConfigUtils

// 入参 cls 的类对象为InfrastructureAdvisorAutoProxyCreator
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

// 查看是否存在固定名称的BeanDefinition
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 如果这个名称的Bean的对象类型与入参不同,则根据优先级来判断是否替换对象类型
// 查看findPriorityForClass方法,可以看到返回的是一个List的下标,这个list的
// 内容是静态写死的,包含了三种类型(见下方代码)。所以可以理解为这是一个逐步升级
// 的逻辑,后面将进一步分析这三个类型
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}

// 不存在则创建BD并注册到BeanFactory
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
// 注意这个Bean的优先级被设为最高
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

/**
* Stores the auto proxy creator classes in escalation order.
*/
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

在没有其他配置的情况下InfrastructureAdvisorAutoProxyCreator将作为AutoProxyRegistrar引入的Bean的具体类型,查看它的类图如下:

实现的核心接口为SmartInstaniationAwareBeanPostProcessor,它的继承结构说明了它是一个修改Bean的钩子,核心的处理逻辑方法是postProcessAfterInitialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// from org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator

/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 判断是否需要使用代理来包装
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 这一步将从获取BeanFactory中获取匹配的Advisor,包括上述的事务Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

看到这里基本上就能够明白注解配置的声明式事务是如何生效的了,以PROXY模式为例,总结如下:

  1. 使用注解@EnableTransactionManagement,该注解根据配置的mode属性引入了AutoProxyRegistrarProxyTransactionManagementConfiguration两个组件。
  2. AutoProxyRegistrar尝试向容器中添加自动代理生成器(Auto Proxy Creator)的BeanDefinition,采用的实现类为InfrastructureAdvisorAutoProxyCreator。APC实现了BeanPostProcessor接口,将在Bean实例化后执行代理的生成操作,PC会尝试从BeanFactory中获取实现了Advisor接口的Bean来作为代理生成的依据。
  3. ProxyTransactionManagementConfiguration是一个配置类,它注册了BeanFactoryTransactionAttributeSourceAdvisor(事务增强Advisor)、TransactionAttributeSource(事务注解属性解析器)、TransactionInterceptor(事务执行拦截器)三个组件。
  4. TransactionAttributeSource的职能是解析@Transactional注解中的属性值并包装为事务相关属性,TransactionInterceptor包含了事务的具体执行逻辑。这两个Bean作为BeanFactoryTransactionAttributeSourceAdvisor的组件由它进行方法调用。
  5. APC将在Bean实例化时根据获取到的事务Advisor判断是否需要生成增强代理,如果Bean的类或方法上包含了@Transactional注解,那么将生成包含事务拦截器的代理类,完成事务增强。

Spring AOP原理

其实我们都知道声明式事务是AOP的子集,是它的应用之一,但是我们使用AOP需要引入spring-boot-starter-aop,而不引入并不影响我们使用声明式事务。接下来一探究竟Spring AOP是如何生效的。

找到AOP的自动配置类org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Configuration(proxyBeanMethods = false)
// 引入依赖后自动生效,可以通过配置spring.aop.auto=false来关闭
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

// 依赖类org.aspectj.weaver.Advice,该类属于包org.aspectj.weaver,并且
// spring-aop依赖该包,因此通常这个配置会生效
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {

@Configuration(proxyBeanMethods = false)
// 使用与普通java config相同的注解
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {

}

@Configuration(proxyBeanMethods = false)
// 同上, 只是注解的参数不同
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {

}

}

// 当org.aspectj.weaver.Advice不存在,即缺少依赖时作为候补配置项
// 通常不会进入这个配置块
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {

ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}

}

}

可以看到配置内容和声明式事务非常相似,同样还是以Java Config注解@EnableAspectJAutoProxy作为入口,也是将注解的proxy-target-class暴露到配置文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

// 是否采用CGLIB作为代理实现
boolean proxyTargetClass() default false;

// 是否将代理自身暴露到ThreadLocal环境以便在拦截器中能够获取到代理本身
boolean exposeProxy() default false;

}

还是同样的配方,使用了@Import注解引入组件,但是数量略有减少,只有一个名为AspectJAutoProxyRegistrar的工具类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

// 注册Bean Definition
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

// 注册AutoProxyCreator,这里使用实现类是AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

// 根据注解@EnableAspectJAutoProxy上的参数修改BD
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}

}

很明显起作用的还是添加Aspect Proxy Creator相关的Bean Definition,根据上述的优先级AnnotationAwareAspectJAutoProxyCreator将会覆盖InfrastructureAdvisorAutoProxyCreator。这几个候选APC的继承关系如下图所示:

对比一下InfrastructureAdvisorAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator这两个同级的类分别覆盖了哪些方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

@Nullable
private ConfigurableListableBeanFactory beanFactory;

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}

// 这个方法最终被org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
// 所使用,即限制只有框架本身的Advisor能够生效
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}

}

// ===========================================================

public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();

// 覆盖了Advisor排序方法,本质原因是需要对源自统一个Aspect的Advisor进行进一步排序
// 这排序还挺复杂的,应用了偏序排序,具体规则请查看该方法的javadoc
@Override
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
for (Advisor advisor : advisors) {
partiallyComparableAdvisors.add(
new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
}
List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
if (sorted != null) {
List<Advisor> result = new ArrayList<>(advisors.size());
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
result.add(pcAdvisor.getAdvisor());
}
return result;
}
else {
return super.sortAdvisors(advisors);
}
}

// 添加一个暴露AspectJ调用(MethodInvocation)的前置Advisor,也是利用ThreadLocal
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}

// 作为Aspect本身的Bean不能被代理
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}

// 用于排序的辅助类
private static class PartiallyComparableAdvisorHolder implements PartialComparable {
// ...
}

}

可以看到两者并没有进行核心内容上的更改,都是针对各自应用场景的修补,InfrastructureAdvisorAutoProxyCreator只为框架本身的工具服务,而AspectJAwareAdvisorAutoProxyCreator添加了一些针对AspectJ声明切面的处理逻辑,所以本质上两者还是保持一致的。AspectJAwareAdvisorAutoProxyCreator并没有创建Advisor的相关逻辑,而EnableAspectJAutoProxy只引入这一个工具,可以猜想到根据注解解析Advisor的内容包含在它的子类AnnotationAwareAspectJAutoProxyCreator中,忽略一些非主要代码展示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {

@Nullable
private List<Pattern> includePatterns;

@Nullable
private AspectJAdvisorFactory aspectJAdvisorFactory;

@Nullable
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;

// 忽略一些非主要代码 ...

@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
// 创建advisor factory
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
// 创建advisor builder
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

@Override
protected List<Advisor> findCandidateAdvisors() {
// 父类逻辑调用
List<Advisor> advisors = super.findCandidateAdvisors();
// 这里将根据aspectj注解解析生成额外的advisor
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}

// 忽略一些非主要代码 ...

}

正如这个类的名称AnnotationAwareAspectJAutoProxyCreator,它添加了对aspectj注解(@Aspect@PointCut@Before 等等)的支持。Spring AOP生效逻辑总结如下:

  1. 使用注解@EnableAspectJAutoProxy,由它引入AspectJAutoProxyRegistrar,开启对Java注解声明式AOP的支持
  2. AspectJAutoProxyRegistrar向容器中添加AnnotationAwareAspectJAutoProxyCreator作为APC的实现类,它将覆盖其他APC(如果存在)
  3. AnnotationAwareAspectJAutoProxyCreator除了对实现了Advisor接口的Bean的处理之外,同时会判断Bean是否包含了aspectj相关的注解,并根据这些注解生成对应的Advisor
  4. APC将在Bean实例化时根据获取到的Advisor判断是否需要生成增强代理
  5. 三种候选APC优先级依次提高,分别对应不同的场景:
    1. InfrastructureAdvisorAutoProxyCreator:对应一些内部框架功能实现的支持,例如声明式事务、声明式缓存等
    2. AspectJAwareAdvisorAutoProxyCreator:对应XML配置场景下的AOP声明支持(所以它不直接包含对于切面定义的处理)
    3. AnnotationAwareAspectJAutoProxyCreator:对应Java Config配置场景下注解式AOP声明的支持

切入顺序解析

当业务功能逐步增加,可能会加入各种各样的切面逻辑,这种情况下就需要额外关注切入的顺序,顺序不对可能会造成严重的问题。接下来顺着代码看看Spring AOP对于切面顺序是如何处理的。

经过上面的分析,我们可以从AbstractAutoProxyCreator的postProcessAfterInitialization方法进入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// ========= AbstractAutoProxyCreator =========
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 进入这个方法内部
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 很明显这一步在获取切面,返回的数组中内容的顺序即代表了切面的顺序
// 这个方法在该类中为抽象方法,由子类覆盖实现。由此处继续往下走
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// ========= AbstractAdvisorAutoProxyCreator =========

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 继续往下走
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
// 这里对返回值做了一些处理
if (advisors.isEmpty()) {
return DO_NOT_PROXY; // 如果没有,返回null
}
return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 这一步将获取所有候选的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 遍历候选的Advisor筛选出其中与Bean相匹配的
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 本类中为空方法,AspectJAwareAdvisorAutoProxyCreator对其进行了覆盖
// 添加了一个暴露AOP调用的advisor,这个advisor的order值为PriorityOrdered.HIGHEST_PRECEDENCE + 1
extendAdvisors(eligibleAdvisors);
// 对advisor进行排序,进入下面的方法,查看是如何排序的
// 这一步不同的APC会有不同的实现,但是也是属于扩展的关系
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

// AbstractAdvisorAutoProxyCreator的默认实现
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
// 内部调用的是List.sort(AnnotationAwareOrderComparator.INSTANCE)
AnnotationAwareOrderComparator.sort(advisors);
return advisors;
}

// AspectJAwareAdvisorAutoProxyCreator的覆盖实现
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
// 这里把所有的advisor都包装成为PartiallyComparableAdvisorHolder
// DEFAULT_PRECEDENCE_COMPARATOR 的类型为AspectJPrecedenceComparator
// 而这个类型内部同样包含了一个AnnotationAwareOrderComparator
for (Advisor advisor : advisors) {
partiallyComparableAdvisors.add(
new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
}
// 使用偏序排序,偏序排序属于离散数学范畴,本人也不是特别清楚
// 使用这种排序主要是为了处理同一个切面中声明的advice
List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
if (sorted != null) {
List<Advisor> result = new ArrayList<>(advisors.size());
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
result.add(pcAdvisor.getAdvisor());
}
return result;
}
else {
return super.sortAdvisors(advisors);
}
}

所以不同的切面之间都是使用AnnotationAwareOrderComparator来确定顺序,该类继承自OrderComparator,增加了对Spring注解@Order和J2EE注解@Priority的支持。它的比较的逻辑可以总结如下:

  1. 如果实现了Ordered接口则使用Ordered.getOrder()方法获取排序值
  2. 如果没有实现Ordered接口,查找类对象是否有添加两种支持的注解(包括继承关系),如果找到注解则使用注解的属性值作为排序值
  3. 如果都没有,排序值取Ordered.LOWEST_PRECEDENCE(2147483647)
  4. 如果两者只有一方实现了PriorityOrdered接口,那么实现方优先级更高,否则根据排序值比较
  5. 排序值越大,优先级越低

而对于同一个切面中的advice来说,就需要使用额外的判断,这部分说实话不是特别明白,有兴趣可以深入一下源码,这里就翻译一下AspectJAwareAdvisorAutoProxyCreator#sortAdvisors方法的javadoc吧:

根据aspectj优先级对提供的advisor实例进行排序。如果两个advice来自同一个advisor,那么它们的顺序是一样的。同一个advisor的advice将使用如下规则进一步排序:如果任意一方是’After’类型的advice,那么后声明的优先级最高(即最后运行),否则先声明的优先级最高(即最先运行)。

这其实也是符合常识逻辑的排序,即先声明的先执行,但是由于切面的结构,在出方向上优先级最高的最后执行,所以最后声明的’After’类型的advice因为优先级最高最后执行。

原始顺序

那么在排序值相同的情况下,不同advice的同类型的advice如何确定顺序呢?我们可以看到执行advice之间排序的AbstractAdvisorAutoProxyCreator.sortAdvisors这个方法最终会使用List.sort(Comparator)来执行排序,查看该方法的javadoc可以得知使用的排序实现是从MergeSort优化而来的TimSort,它是一种稳定排序算法,因此可以推断出如果排序值相同,那么顺序就取决于他们之间原来的顺序。重新追溯回到原始顺序的源头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// ========= AbstractAdvisorAutoProxyCreator =========
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 这一步获取原始Advisor列表,往里面走
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

// 该方法被子类AnnotationAwareAspectJAutoProxyCreator重写
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// 使用工具类来获取,继续往里走
return this.advisorRetrievalHelper.findAdvisorBeans();
}

// AnnotationAwareAspectJAutoProxyCreator重写的findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// 调用父类方法
List<Advisor> advisors = super.findCandidateAdvisors();
// 构造根据注解声明的对应的advisor
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}

// ========= AbstractAdvisorAutoProxyCreator =========

public List<Advisor> findAdvisorBeans() {
// 获取所有实现了Advisor接口的Bean名称,同时做了缓存处理
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 获取相关的Bean名称,进入此方法继续走
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}

List<Advisor> advisors = new ArrayList<>();
// 按照获取到的Bean名称逐个添加到List中
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
// 一些初始化相关的代码 ...
}
}
}
}
return advisors;
}

由上面的代码可知,Advisor的原始顺序取决于BeanFactory取出相关Bean名称的顺序,同时由注解描述构建出的Advisor全部排在原生Advisor实现类的后面。具体到SpringBoot的应用场景下,最后执行的内容为DefaultListableBeanFactory下的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<>();

// 根据beanDefinitionNames这个list成员进行遍历
for (String beanName : this.beanDefinitionNames) {
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
(mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// 省略匹配逻辑校验代码 ...
if (matchFound) {
result.add(beanName);
}
}
}
// 省略异常处理代码 ...
}
}

// 根据manualSingletonNames这个list成员遍历
// 这里主要包含一些手动控制、无需处理Bean生命周期的单例,比如SpringBootBanner
// 通常Advisor实现类不会出现在这里
for (String beanName : this.manualSingletonNames) {
try {
// 省略代码...

if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
logger.trace(LogMessage.format(
"Failed to check manually registered singleton with name '%s'", beanName), ex);
}
}

return StringUtils.toStringArray(result);
}

最终我们可以看到原始数据的顺序来源于BeanFactory的beanDefinitionNames这个List<String>类型的成员,这个集合包含了所有注册的Bean名称,并且维持了Bean注册的顺序,Bean注册的细节此处就不展开了,我们可以直接在上述方法打断点调试,根据SpringBoot运行调试结果可以看出如下几点规则:

  1. 6个内置的Bean和SpringBoot启动类最先注册,内置Bean包括internalConfigurationAnnotationProcessorinternalAutowiredAnnotationProcessorinternalCommonAnnotationProcessorinternalEventListenerProcessorinternalEventListenerFactoryinternalCachingMetadataReaderFactory
  2. 接下来根据扫包获取应用代码中声明的Bean,扫包顺序通常是按照全类名的字母序(包括@Configuration修饰的配置类,但不包括其中定义的Bean)
  3. 然后是应用代码中引入的Bean,包括配置类下声明的Bean以及Import引入的Bean
  4. 最后是SpringBoot自动配置类相关的内容

总结

Spring AOP的核心类是AutoProxyCreator,它作为钩子工具在Bean实例化时执行了代理创建操作,这也再一次表明Spring AOP在默认的proxy模式下使用的是动态代理,Spring只是借用了AspectJ的一些切面描述的注解,并没有使用依赖特殊编译器的静态织入。

切面的顺序是一个必须考虑的问题,Spring主要通过org.springframework.core.Ordered接口以及org.springframework.core.annotation.Order注解(还包括j2ee的Priority注解)来声明排序值以控制顺序。在SpringBoot应用环境下,您需要额外注意几点:

  1. 开启声明式事务的注解@EnableTransactionManagement包含在自动配置类中,并没有将order属性直接暴露到配置文件中,其默认的顺序值为Ordered.LOWEST_PRECEDENCE即最低顺序。如果必须要配置,可以手动在应用配置类上主动使用@EnableTransactionManagement并修改order属性值,但是这会让配置文件中的一些相关配置失效。
  2. 同时使用声明式事务和声明式缓存并且不修改order值,由于声明式缓存需要手动添加@EnableCaching,这使得默认情况下缓存Advisor的原始顺序高于事务Advisor,因此先切面的入口处先执行缓存逻辑再执行事务逻辑,这恰好满足一般的使用常理。
  3. 在开启Spring AOP使用aspectj注解声明切面时,如果不指定Order顺序值,那么默认顺序值为最低顺序,根据原始顺序的逻辑,构建出来的切面全部位于原生切面的后面,也就是排在事务等框架提供的逻辑之后,您需要确保这是没问题的,否则请显式指定顺序值。
  4. 不同的切面推荐放在不同的类中并指定顺序值,防止意想不到的结果发生。
Spring-Data MongoDB小试牛刀
再谈转行