当探讨 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:
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
通过以上代码,我们可以看出根据事务管理的代理模式(PROXY 或 ASPECTJ),TransactionManagementConfigurationSelector
导入了不同的类。
- 在 PROXY 模式下,它导入了
AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
这两个关键类。 - 在 ASPECTJ 模式下,它导入了Aspectj特定的类。
这些导入的类在事务管理中起着重要的作用。例如,AutoProxyRegistrar
注册了基于 Bean 的 AOP 代理处理器,而 ProxyTransactionManagementConfiguration
则用于注册 Spring 事务的切面。
通过这种方式,TransactionManagementConfigurationSelector
在配置过程中灵活地选择了不同的类来适应不同的事务管理模式。这里先不考虑 ASPECTJ 模式,我们一般都是使用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.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
注解才会使用进行TransactionInterceptor
进行AOP代理。
AutoProxyRegistrar分析
//org.springframework.context.annotation.AutoProxyRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 获取@EnableTransactionManagement所在配置类上的注解元信息
Set annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
// 可以理解为将注解中的属性转换成一个map
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
// 直接从map中获取对应的属性,默认代理模式:PROXY:SpringAOP
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
接口,该接口通常用于在各种扩展中间件/组件中注册 bean 后置处理器,以便在 bean 的生命周期中进行扩展操作。当进行 BeanDefinition 的定位和解析时,会触发 AutoProxyRegistrar
的 registerBeanDefinitions
方法。在这一过程中,我们应该关注 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
的调用。
AopConfigUtils分析
public abstract class AopConfigUtils {
//AOP bean后置处理器的唯一BeanName
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
...省略
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
...省略
//基于Bean的AOP代理Bean后置处理器
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
//基于XML配置的AOP代理Bean后置处理器
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
//基于注解的AOP代理Bean后置处理器
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
...省略
//注册AOP代理Bean后置处理器到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 优先级最低
*
*/
// 获取注册到BeanDefinition容器中的AOP代理Bean后置处理器的优先级(List中的索引下标)
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
// 获取当前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
静态代码按照顺序添加到List中,下标越大优先级越高。可以看到InfrastructureAdvisorAutoProxyCreator
优先级最低,AnnotationAwareAspectJAutoProxyCreator
优先级最高,也就是说InfrastructureAdvisorAutoProxyCreator
是有可能会被覆盖或者无法注册的,那么 有的小伙伴可能会问,如果同时开启AOP代理(@EnableAspectJAutoProxy
) 和 事务管理(@EnableTransactionManagement
)会不会存在问题呢? 答案是不会。因为 AnnotationAwareAspectJAutoProxyCreator
的作用范围更广泛,它包含了 InfrastructureAdvisorAutoProxyCreator
的功能。
下面是不同类型的 AOP 代理bean后置处理器:
-
InfrastructureAdvisorAutoProxyCreator
:基于bean的AOP代理,例如 bean实现Advice
,Advisor
、Pointcut
、AopInfrastructureBean
接口 -
AspectJAwareAdvisorAutoProxyCreator
:基于xml配置的AOP代理 -
AnnotationAwareAspectJAutoProxyCreator
:在InfrastructureAdvisorAutoProxyCreator
、AspectJAwareAdvisorAutoProxyCreator
基础上,增加了对使用@Aspect
注解声明的切面的 AOP 代理支持。
二、Spring事务动态代理分析
通过上图,发现InfrastructureAdvisorAutoProxyCreator
实现了InstantiationAwareBeanPostProcessor
、SmartInstantiationAwareBeanPostProcessor
接口,这两接口是做什么的呢?这里触及到bean注册IOC容器相关内容,有机会再写一篇这块内容,这里就简单概括一下它们的职责吧。
InstantiationAwareBeanPostProcessor
提供postProcessBeforeInstantiation
方法,在bean生命周期的实例化阶段进行一些前置处理。SmartInstantiationAwareBeanPostProcessor
则提供了determineCandidateConstructors
方法,用于推断出所有符合要求的构造函数,在实例化对象的时候我们就需要明确到底使用哪个构造函数。此外 getEarlyBeanReference
方法也在这个接口中定义,它用于在循环依赖时,提前暴露对象进行AOP代理( @Aysn
不支持循环依赖也在这)
这里我们重点关注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是否需要进行AOP代理
1. 类型为 `Advice`、`Advisor`、`Pointcut`、`AopInfrastructureBean` 的 bean 不需要被代理。
2. 不是原始 bean 而是被包装过的 bean 也不需要被代理,例如 `ScopedProxyFactoryBean`。
接下来,我们将关注 bean 生命周期初始化阶段的事务 AOP 代理核心流程
//org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
//AOP
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来创建代理的
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初始化阶段进行bean后置处理器的初始化后置处理时,我们重点两个核心步骤:getAdvicesAndAdvisorsForBean
和 createProxy
,它们涉及到了事务通知器的匹配筛选以及代理的创建过程。
-
getAdvicesAndAdvisorsForBean
根据文章前面分析,我们知道事务通知器(
BeanFactoryTransactionAttributeSourceAdvisor
)是在配置类(ProxyTransactionManagementConfiguration
)创建并注入到了 IOC 容器中,所以通过IOC容器中拿到我们事务通知器(BeanFactoryTransactionAttributeSourceAdvisor
),然后依赖事务通知器中的切点匹配bena方法上是否有@Transacational
,如果匹配就返回事务通知器(BeanFactoryTransactionAttributeSourceAdvisor
) -
createProxy
首先在
new
一个ProxyFactory
时,使用策略设计模式选择(JDK 动态代理或 CGLIB 代理)创建相应的代理工厂对象。这些ProxyFactory
都继承了AdvisedSupport
,根据getAdvicesAndAdvisorsForBean
匹配筛选出来的通知器会缓存到AdvisedSupport
,然后进行动态代理。在后续事务代理对象执行时,就可以通过AdvisedSupport
获取事务通知器,最后使用责任链+模板方法方式执行事务拦截器逻辑。
这里就简单概括一下它们都做了些什么事,关于这块AOP代理核心逻辑,后续写Spring AOP源码分析时,再展开唠唠。
三、小结
通过对 Spring 事务原理的AOP 代理机制深入分析,我们了解到事务的 AOP 代理机制是 Spring 中非常重要的一环。通过bean后置处理器在 bean 的实例化阶段前置处理和初始化阶段后置进行一些扩展操作,从而实现了事务的切面逻辑。关于Spring事务拦截器内容,下一章展开分析。
觉得有收获的小伙伴,欢迎一键三连,感谢~