part1-transactional-proxy-mechanism
约 2431 字大约 8 分钟
2026-05-24
系列文章:《深入Spring事务与数据源:从注解到数据库连接的全链路解析》
第一篇:Spring事务代理机制详解
基于版本:Spring Framework 5.3.x
前言
在日常的Spring开发中,我们只需要在Service方法上添加一个@Transactional注解,就能轻松实现事务管理。但这个简单的注解背后,隐藏着怎样精妙的机制呢?
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 如果此处抛出异常,整个事务将回滚
}
}当我们调用userService.createUser()时,真正执行的并非目标方法本身,而是经过Spring代理增强后的方法。本文将深入源码,揭示@Transactional注解是如何被激活,以及Spring如何为Bean创建事务代理的。
一、@EnableTransactionManagement:事务管理的启动开关
1.1 注解的引入
在Spring Boot项目中,我们通常不需要显式添加@EnableTransactionManagement注解,因为Spring Boot的自动配置会帮我们完成。但在传统的Spring项目中,我们需要在配置类上显式声明:
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public DataSource dataSource() {
// 配置数据源
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}1.2 注解源码解析
让我们先看看@EnableTransactionManagement的定义:
源码位置:spring-tx/src/main/java/org/springframework/transaction/annotation/EnableTransactionManagement.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/**
* 是否使用CGLIB创建子类代理
* false:使用JDK接口代理(默认)
* true:使用CGLIB子类代理
*/
boolean proxyTargetClass() default false;
/**
* 代理模式:
* PROXY(默认):基于代理的AOP
* ASPECTJ:基于AspectJ的织入
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* 事务通知的执行顺序
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}核心要点:
@Import(TransactionManagementConfigurationSelector.class):这是整个事务管理的启动入口- 通过
mode属性可以选择PROXY或ASPECTJ模式,默认使用PROXY模式 proxyTargetClass控制代理的创建方式
二、TransactionManagementConfigurationSelector:配置导入器
2.1 导入机制
@Import注解是Spring提供的一种导入配置类的方式。TransactionManagementConfigurationSelector实现了ImportSelector接口,会根据mode属性返回需要导入的配置类。
源码位置:spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionManagementConfigurationSelector.java
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {
AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()
};
case ASPECTJ:
return new String[] {
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
};
default:
return null;
}
}
}关键发现:
- 当
mode=PROXY(默认)时,会导入两个配置类:AutoProxyRegistrar:注册自动代理创建器ProxyTransactionManagementConfiguration:事务代理的核心配置
三、AutoProxyRegistrar:自动代理创建器的注册
3.1 注册InfrastructureAdvisorAutoProxyCreator
源码位置:spring-tx/src/main/java/org/springframework/transaction/annotation/AutoProxyRegistrar.java
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@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) {
// 注册关键组件:InfrastructureAdvisorAutoProxyCreator
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
}3.2 InfrastructureAdvisorAutoProxyCreator的作用
InfrastructureAdvisorAutoProxyCreator是Spring AOP的核心组件,它实现了BeanPostProcessor接口,会在Bean初始化过程中介入,为符合条件的Bean创建代理对象。
核心职责:
- 扫描所有Bean定义
- 查找适用于该Bean的Advisor(通知器)
- 如果存在匹配的Advisor,则创建代理对象替换原Bean
// BeanPostProcessor的核心方法
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;
}wrapIfNecessary方法会:
- 检查该Bean是否有
@Transactional注解 - 如果有,则创建代理对象
- 将代理对象返回给Spring容器
四、ProxyTransactionManagementConfiguration:事务代理的核心配置
这是整个事务管理的核心配置类,注册了事务拦截所需的所有基础设施组件。
源码位置:spring-tx/src/main/java/org/springframework/transaction/annotation/ProxyTransactionManagementConfiguration.java
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/**
* 注册事务注解解析器
* 负责解析方法上的@Transactional注解
*/
@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;
}
/**
* 注册事务属性源
* 负责从注解中提取事务属性
*/
@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;
}
}4.1 三大核心组件
1. AnnotationTransactionAttributeSource(事务属性源)
职责:解析@Transactional注解,提取事务属性(传播行为、隔离级别、超时时间等)
public class AnnotationTransactionAttributeSource extends AbstractTransactionAttributeSource {
private final TransactionAnnotationParser annotationParser;
public AnnotationTransactionAttributeSource() {
this.annotationParser = new SpringTransactionAnnotationParser();
}
@Override
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
@Override
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// 使用注解解析器提取事务属性
return this.annotationParser.parseTransactionAnnotation(element);
}
}2. TransactionInterceptor(事务拦截器)
职责:拦截带有@Transactional注解的方法,在方法执行前后进行事务管理
这是整个事务管理的核心执行组件,我们将在下一篇文章中深入分析。
public class TransactionInterceptor extends TransactionAspectSupport
implements MethodInterceptor, Serializable {
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取目标类
Class<?> targetClass = (invocation.getThis() != null
? AopUtils.getTargetClass(invocation.getThis()) : null);
// 调用父类的事务处理方法
return invokeWithinTransaction(
invocation.getMethod(),
targetClass,
invocation::proceed
);
}
}关键点:
TransactionInterceptor实现了AOP Alliance的MethodInterceptor接口invoke方法会在目标方法执行前被调用- 核心逻辑委托给父类
TransactionAspectSupport的invokeWithinTransaction方法
3. BeanFactoryTransactionAttributeSourceAdvisor(事务通知器)
职责:将事务属性源和事务拦截器组合在一起,形成一个完整的Advisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut =
new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}工作流程:
pointcut用于判断方法是否有@Transactional注解- 如果匹配,则应用
TransactionInterceptor通知
五、Spring AOP代理的创建过程
5.1 代理创建的时机
当Spring容器创建Bean时,会经过以下生命周期:
1. 实例化Bean (Instantiation)
2. 属性填充 (Populate)
3. 初始化前 (BeanPostProcessor.postProcessBeforeInitialization)
4. 初始化 (InitializingBean.afterPropertiesSet / @PostConstruct)
5. 初始化后 (BeanPostProcessor.postProcessAfterInitialization) ← 代理创建点
6. 注册到容器InfrastructureAdvisorAutoProxyCreator在第5步介入,检查是否需要创建代理。
5.2 代理创建的完整流程
// AbstractAutoProxyCreator.wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 1. 检查是否已经处理过
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 2. 检查是否需要跳过
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 3. 判断是否是基础设施类,或者是需要跳过的类型
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 4. 获取适用于该Bean的所有Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
bean.getClass(), beanName, null);
// 5. 如果存在匹配的Advisor,则创建代理
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;
}5.3 代理对象的执行链
当调用代理对象的方法时,执行链如下:
userService.createUser(user)
↓
[代理对象] JDK Dynamic Proxy / CGLIB Proxy
↓
[拦截器链] TransactionInterceptor.invoke()
↓
[前置处理] 开启事务
↓
[目标方法] userRepository.save(user)
↓
[后置处理] 提交/回滚事务
↓
返回结果六、事务代理的完整执行时序图
┌─────────────┐
│ 客户端代码 │
└──────┬──────┘
│ createUser(user)
↓
┌─────────────────────────────┐
│ InfrastructureAdvisorAuto │
│ ProxyCreator │
│ (BeanPostProcessor) │
│ │
│ 在Bean初始化后创建代理对象 │
└────────┬────────────────────┘
│ 返回代理对象
↓
┌─────────────────────────────┐
│ JDK Dynamic Proxy / CGLIB │
│ (代理对象) │
│ │
│ 拦截所有方法调用 │
└────────┬────────────────────┘
│ 方法调用
↓
┌─────────────────────────────┐
│ BeanFactoryTransaction │
│ AttributeSourceAdvisor │
│ │
│ 判断方法是否有@Transaction │
│ al注解 │
└────────┬────────────────────┘
│ 匹配成功
↓
┌─────────────────────────────┐
│ TransactionInterceptor │
│ .invoke() │
│ │
│ invokeWithinTransaction() │
└────────┬────────────────────┘
│
┌────┴─────┐
│ │
↓ ↓
[开启事务] [执行业务方法]
│ │
│ ↓
│ [目标方法执行]
│ │
↓ ↓
[提交/回滚] [返回结果]七、关键问题解答
Q1:为什么同一个类内部方法调用,事务会失效?
@Service
public class UserService {
@Transactional
public void methodA() {
// 这里调用不会开启新事务!
methodB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 业务逻辑
}
}原因:Spring的事务是基于代理实现的。当你调用userService.methodA()时:
- 实际调用的是代理对象的
methodA() - 代理对象会执行
TransactionInterceptor - 但在
methodA()内部调用methodB()时,使用的是this.methodB() this指向的是目标对象本身,而非代理对象- 因此不会经过代理,事务注解失效
解决方案:
- 注入自身:通过
@Autowired注入自己,使用注入的对象调用 - 使用
AopContext.currentProxy():获取当前代理对象
Q2:JDK代理和CGLIB代理有什么区别?
| 特性 | JDK动态代理 | CGLIB代理 |
|---|---|---|
| 实现方式 | 实现接口 | 继承类 |
| 适用范围 | 只能代理接口 | 可以代理类 |
| 性能 | 调用稍慢 | 调用稍快 |
| 限制 | 必须有接口 | 不能代理final类/final方法 |
Spring的默认行为:
- Spring 5.3之前:默认使用JDK代理
- Spring 5.3之后:默认使用CGLIB代理(通过
proxyTargetClass=true)
Q3:事务拦截器的执行顺序如何控制?
通过@EnableTransactionManagement(order = xxx)设置:
@EnableTransactionManagement(order = Ordered.LOWEST_PRECEDENCE - 1)数值越小,优先级越高。
八、总结与伏笔
通过本文的分析,我们完整梳理了@Transactional注解的激活机制:
- @EnableTransactionManagement通过
@Import导入配置 - TransactionManagementConfigurationSelector根据mode选择配置类
- AutoProxyRegistrar注册自动代理创建器
- ProxyTransactionManagementConfiguration注册三大核心组件:
AnnotationTransactionAttributeSource:解析事务属性TransactionInterceptor:执行事务拦截BeanFactoryTransactionAttributeSourceAdvisor:组合切点和通知
- InfrastructureAdvisorAutoProxyCreator为带有
@Transactional的Bean创建代理 - 当调用代理对象方法时,TransactionInterceptor拦截方法调用
但还有一个关键问题尚未解答:事务拦截器如何与数据源建立联系?
在TransactionInterceptor.invokeWithinTransaction()方法中,我们看到它会调用:
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);这里的ptm(PlatformTransactionManager)是如何获取数据库连接的?createTransactionIfNecessary内部又发生了什么?
下一篇预告:《事务的起点:TransactionInterceptor如何开启一个事务》,我们将深入分析invokeWithinTransaction方法的完整执行流程,揭示事务开启的神秘面纱。
参考资料
- Spring Framework 5.3.x 源码
spring-tx/src/main/java/org/springframework/transaction/annotation/- 《Spring源码深度解析》