前言
当探讨 Spring 框架的事务管理机制时,我们需要深入了解其背后的工作原理。本文将从事务的注解以及动态代{过}{滤}理机制对 Spring 事务进行深入解析。
spring版本: 5.0.2
掘金原文
一、@EnableTransactionManagement注解分析
通常情况下,我们在 Spring Boot 项目的启动类上添加 @EnableTransactionManagement
注解来开启事务管理:
@SpringBootApplication
@EnableTransactionManagement
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
进入@EnableTransactionManagement
看看都做了些什么?
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
//是否使用cglib代{过}{滤}理,默认JDK代{过}{滤}理
boolean proxyTargetClass() default false;
//代{过}{滤}理模式
//1. PROXY :Spring AOP
//2. ASPECTJ:AspectJ
AdviceMode mode() default AdviceMode.PROXY;
//通知执行优先级,默认最低优先级
int order() default Integer.MAX_VALUE;
}
上述的注解细节中,我们需要重点关注 @Import
扩展点。这个扩展点用于导入了 TransactionManagementConfigurationSelector
类。而值得注意的是,TransactionManagementConfigurationSelector
实现了 ImportSelector
接口。如果你之前看过上一篇 《深入剖析Spring Boot 源码系列 - 自动装配原理》 ,那么你可能对 @Import
的概念已经有所了解,因此在这里不再详述。
接下来看看TransactionManagementConfigurationSelector
做了什么?
TransactionManagementConfigurationSelector分析
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//默认 PROXY
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
通过以上代码,我们可以看出TransactionManagementConfigurationSelector
根据事务管理的代{过}{滤}理模式(PROXY或ASPECTJ)导入了不同的类。
- 在 PROXY 模式下,它导入了
AutoProxyRegistrar
和 ProxyTransactionManagementConfiguration
这两个关键类。
- 在 ASPECTJ 模式下,它导入了Aspectj特定的类。
这些导入的类在事务管理中起着重要的作用。例如,AutoProxyRegistrar
注册了基于 Bean 的 AOP 代{过}{滤}理后置处理器,而 ProxyTransactionManagementConfiguration
则用于注册 Spring 事务的切面。
通过这种方式,TransactionManagementConfigurationSelector
在配置过程中灵活地选择了不同代{过}{滤}理模式来进行spring事务管理。这里先不考虑 ASPECTJ 模式,因为我们一般都是PROXY代{过}{滤}理模式使用Spring AOP进行动态代{过}{滤}理
ProxyTransactionManagementConfiguration分析
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
// 【重点】注册事务通知器
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
// BeanDefinition的角色是一个基础设施类
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
//事务通知器
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//@Transacational解析器为切点
advisor.setTransactionAttributeSource(transactionAttributeSource());
//事务拦截器
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
// @Transactional 注解 解析器
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
// 事务拦截器,将事务属性应用于目标方法。
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
ProxyTransactionManagementConfiguration
是被 @Configuration
标注的配置类,它创建了事务通知器、事务注解解析器以及事务拦截器。当进行AOP代{过}{滤}理时,通过IOC容器获取BeanFactoryTransactionAttributeSourceAdvisor
对目标bean做切点匹配,切点会通过TransactionAttributeSource
去解析@Transacational
注解,只有在方法/类上添加@Transacational
注解才会进行AOP代{过}{滤}理走TransactionInterceptor
事务拦截器。
AutoProxyRegistrar分析
//org.springframework.context.annotation.AutoProxyRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 获取@EnableTransactionManagement所在配置类上的注解元信息
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
// 可以理解为将注解中的属性转换成一个map
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
// 直接从map中获取对应的属性,默认代{过}{滤}理模式:PROXY
Object mode = candidate.get("mode");
// proxyTargetClass,是否使用cglib代{过}{滤}理。 默认false ,使用JDK代{过}{滤}理
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 【重点】注册一个bean后置处理器 InfrastructureAdvisorAutoProxyCreator 的 beanDefinition
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
//如果为ture,使用CGlib代{过}{滤}理
//设置 InfrastructureAdvisorAutoProxyCreator 的 beanDefinition属性proxyTargetClass为true
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
...省略日志
}
AutoProxyRegistrar
实现了 ImportBeanDefinitionRegistrar
接口,该接口常用于一些中间件/组件与spring整合时,注册整合的bean后置处理器做扩展点,以便在bean生命周期中进行扩展操作。
当定位解析 BeanDefinition时,就会触发 AutoProxyRegistrar#registerBeanDefinitions
方法。我们重点关注 AopConfigUtils#registerAutoProxyCreatorIfNecessary(registry)
注册AOP代{过}{滤}理后置处理器
AopConfigUtils分析
public abstract class AopConfigUtils {
//AOP代{过}{滤}理后置处理器的唯一BeanName
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
//...省略
//【重点】AOP代{过}{滤}理相关的bean后置处理器优先级
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
...省略
//基于Bean的AOP代{过}{滤}理后置处理器
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
//基于XML配置的AOP代{过}{滤}理后置处理器
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
//基于注解的AOP代{过}{滤}理后置处理器
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
...省略
//注册AOP代{过}{滤}理后置处理器到BeanDefinition容器
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
@Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//【重点】只能存在一个AOP代{过}{滤}理相关的Bean后置处理器
//如果已经注册到BeanDefinition容器,那么进行优先级覆盖
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
/**
* 开启AOP代{过}{滤}理 @EnableAspectJAutoProxy -> AnnotationAwareAspectJAutoProxyCreator 优先级最高
* 开启事务管理 @EnableTransactionManagement -> InfrastructureAdvisorAutoProxyCreator 优先级最低
*
*/
// 获取注册到容器中的AOP代{过}{滤}理Bean后置处理器的优先级(List中的索引下标)
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
// 获取当前AOP代{过}{滤}理Bean后置处理器的优先级(List中的索引下标) 。例如 InfrastructureAdvisorAutoProxyCreator的优先级
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
// 谁的优先级大就注册谁
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//【重点】注册bean后置处理器beanDefinetion
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
}
通过registerOrEscalateApcAsRequired
方法,我们发现只能注册一个AOP代{过}{滤}理的Bean后置处理器,如果已注册AOP代{过}{滤}理的Bean后置处理器优先级低,那么会被优先级高的覆盖。根据AopConfigUtils
静态代码顺序添加AOP代{过}{滤}理后置处理器到List中(List下标越大的优先级越高),可以看到InfrastructureAdvisorAutoProxyCreator
优先级最低,AnnotationAwareAspectJAutoProxyCreator
优先级最高,也就是说InfrastructureAdvisorAutoProxyCreator
是有可能会被覆盖或者无法注册的,那么同时开启AOP代{过}{滤}理(@EnableAspectJAutoProxy
) 和 事务管理(@EnableTransactionManagement
)会不会存在问题呢? 答案是不会。因为 AnnotationAwareAspectJAutoProxyCreator
的作用范围更广泛,它包含了 InfrastructureAdvisorAutoProxyCreator
的功能。
AOP代{过}{滤}理后置处理器类型:
-
InfrastructureAdvisorAutoProxyCreator
:基于Bean的AOP代{过}{滤}理。例如 实现Advice
,Advisor
、Pointcut
、AopInfrastructureBean
接口的bean跳过动态代{过}{滤}理
-
AspectJAwareAdvisorAutoProxyCreator
:基于xml配置的AOP代{过}{滤}理
-
AnnotationAwareAspectJAutoProxyCreator
:在InfrastructureAdvisorAutoProxyCreator
、AspectJAwareAdvisorAutoProxyCreator
基础上,增加了对使用 @Aspect
注解声明的切面的 AOP 代{过}{滤}理支持。
二、Spring事务动态代{过}{滤}理分析
通过上图,发现InfrastructureAdvisorAutoProxyCreator
实现了InstantiationAwareBeanPostProcessor
、SmartInstantiationAwareBeanPostProcessor
接口,这两接口是做什么的呢?这里触及到bean注册IOC容器相关内容,有机会再写一篇这块源码分析内容,这里就简单概括一下它们的职责吧。
InstantiationAwareBeanPostProcessor
提供postProcessBeforeInstantiation
方法,在bean生命周期-实例化阶段进行一些前置处理。
SmartInstantiationAwareBeanPostProcessor
提供了determineCandidateConstructors
方法,用于推断出所有符合要求的构造函数,在bean生命周期-实例化阶段 需要明确到底使用哪个构造函数。此外 getEarlyBeanReference
方法在这个接口中也定义,它用于bean生命周期-属性填充阶段 处理循环依赖时,对目标bean进行提前暴露对象做AOP代{过}{滤}理( @Asyn
不支持循环依赖也在这)
这里我们重点关注bean后置处理器-实例化前置处理方法postProcessBeforeInstantiation
,看看InfrastructureAdvisorAutoProxyCreator
在bean生命周期-实例化阶段做了什么前置处理
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
// 在不考虑通知的情况下,确认哪些Bean不需要被代{过}{滤}理
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//如果为FactoryBean,则在beanName添加&前缀
Object cacheKey = getCacheKey(beanClass, beanName);
// 如果beanName为空或者不在targetSourcedBeans集合中,表示不是从目标源获取的Bean
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// advisedBeans是一个map,其中key是BeanName,value代表了这个Bean是否需要被代{过}{滤}理
// 如果在advisedBeans中已经包含了该Bean,说明在bean实例化前已经标识过是否需要代{过}{滤}理
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 说明还没有对这个Bean进行处理
// 在这里会对SpringAOP中的基础设施bean,例如实现Advice,Pointcut,Advisor接口的bean标记它们不需要被代{过}{滤}理
// 其次,如果这个Bean不是最原始的Bean,那么也不进行代{过}{滤}理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
//标记该Bean不需要代{过}{滤}理,将其放入advisedBeans,值设为false
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
// 如果提供了定制的TargetSource(通常不提供)
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
//获取能够匹配当前bena的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
//根据通知为当前bean生成代{过}{滤}理对象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
上述代码作用就是在bean生命周期-实例化阶段对目标bean进行实例化前置处理,判断bean是否需要进行AOP代{过}{滤}理
- 类型为
Advice
、Advisor
、Pointcut
、AopInfrastructureBean
的 bean 不需要被代{过}{滤}理。
- 不是原始bean而是被包装过的bean也不需要被代{过}{滤}理,例如
ScopedProxyFactoryBean
。
接下来,我们继续跟踪在 bean生命周期-初始化阶段 进行事务动态代{过}{滤}理核心流程
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//发生循环依赖的话,会提前暴露进行动态代{过}{滤}理,所以这个判断不会成立
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 需要代{过}{滤}理的话,在这里完成的代{过}{滤}理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 在postProcessBeforeInstantiation方法中可能已经完成过代{过}{滤}理了
// 如果已经完成代{过}{滤}理了,那么直接返回这个代{过}{滤}理的对象
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 在postProcessBeforeInstantiation方法中可能已经将其标记为不需要代{过}{滤}理了
// 这种情况下,也直接返回这个Bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 跟在postProcessBeforeInstantiation方法中的逻辑一样
// 如果不需要代{过}{滤}理,直接返回,同时在advisedBeans中标记成false
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
/**
* 上述流程已在bean实例化阶段的前置方法处理过
*/
// 【重点】获取适用于该Bean的通知
// 说白了bean是否满足切点条件,不满足则不进行代{过}{滤}理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果存在通知的话,说明需要被代{过}{滤}理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 【重点】到这里创建代{过}{滤}理,实际上底层就是new一个ProxyFactory来创建JDK/CGLiB代{过}{滤}理工厂
// spring事务使用的jdk代{过}{滤}理工厂
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 如果没有通知的话,也将这个Bean标记为不需要代{过}{滤}理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
可以看到在bean生命周期-初始化阶段,由AOP后置处理器对目标bean进行初始化后置处理。这里我们重点两个核心步骤:getAdvicesAndAdvisorsForBean
和 createProxy
,它们涉及到了事务通知器的匹配筛选以及AOP代{过}{滤}理过程。
-
getAdvicesAndAdvisorsForBean
根据文章前面分析,我们知道事务通知器(BeanFactoryTransactionAttributeSourceAdvisor
)是在配置类(ProxyTransactionManagementConfiguration
)中创建并注入到了 IOC 容器中,所以通过IOC容器中可以拿到我们事务通知器(BeanFactoryTransactionAttributeSourceAdvisor
),然后使用事务通知器中的切点在目标bean初始化阶段匹配方法/类上是否有@Transacational
,如果匹配就返回事务通知器(BeanFactoryTransactionAttributeSourceAdvisor
)
-
createProxy
首先在new
一个 ProxyFactory
时,使用策略设计模式选择(JDK代{过}{滤}理或 CGLIB代{过}{滤}理)创建相应的代{过}{滤}理工厂对象( ProxyFactory
)进行事务的AOP代{过}{滤}理。这些 ProxyFactory
都继承了AdvisedSupport
,而AdvisedSupport
主要用于缓存前面getAdvicesAndAdvisorsForBean
匹配筛选出来的通知器。当事务代{过}{滤}理对象执行时,就可以通过AdvisedSupport
缓存中获取事务通知器添加到List集合中,使用集合索引下标+模板方法形成责任链去执行事务拦截器
这里就简单概括一下它们都做了些什么事,关于这块AOP代{过}{滤}理核心逻辑,后续写Spring AOP源码分析时,再展开唠唠。
三、小结
通过对 Spring 事务原理的AOP 代{过}{滤}理机制深入分析,我们了解到事务的 AOP 代{过}{滤}理机制是 Spring 中非常重要的一环。通过bean后置处理器在 bean 的实例化阶段前置处理和初始化阶段后置进行一些扩展操作,从而实现了事务的切面逻辑。关于Spring事务拦截器内容,下一篇《深入剖析Spring源码系列-Spring事务原理(下)》展开分析。