深入刨析Spring源码系列-Spring事务原理(上)
当探讨 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;
}
接下来看看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源码分析时,再展开唠唠。
三、小结
觉得有收获的小伙伴,欢迎点个赞,感谢~
转载自:https://juejin.cn/post/7269744082649726987