Spring 事务全链路解析(二):深入探索 Spring 事务代理机制
约 6001 字大约 20 分钟
2026-05-24
你有没有遇到过这种情况:在方法上明明加了 @Transactional 注解,结果事务就是不生效?或者,你有没有想过,为什么 @Transactional 放在 private 方法上不生效?今天,我们就来揭开 AOP 代理的神秘面纱,看看它到底是怎么"偷偷"帮我们管理事务的。
为什么 @Transactional 放在 private 方法上不生效?
先来看一个经典的"坑":
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 调用同一个类的 public 带有 @Transactional 注解的方法
public void handle(User user) {
// 事务不生效
createUser(user);
}
// 公共方法,事务生效
@Transactional
public void createUser(User user) {
userMapper.insert(user);
// 调用同一个类的 private 方法
updateUserStatus(user.getId());
}
// private 方法,@Transactional 不生效!
@Transactional
private void updateUserStatus(Long userId) {
// 这里的操作不会在事务中执行!
userMapper.updateStatus(userId, "active");
}
}你有没有产生过疑问,为什么都加了 @Transactional 注解了,事务怎么还不生效呢?
实际上这就是 AOP 代理的局限性 & Spring 事务属性源的显式检查 问题。
Spring 事务属性源的显式检查
很多人以为 @Transactional 不生效只是因为"AOP 代理无法拦截 private 方法"。但真相是:Spring 在读取事务注解时,就显式地把非 public 方法过滤掉了!
AbstractFallbackTransactionAttributeSource:事务属性读取的基类
这个类是 Spring 读取事务注解的基类。它的 computeTransactionAttribute() 方法中,显式地检查了方法的修饰符:
// 类路径:org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
public abstract class AbstractFallbackTransactionAttributeSource
implements TransactionAttributeSource, EmbeddedValueResolverAware {
/**
* 【核心方法】:计算事务属性。
*
* 这个方法会:
* 1. 检查方法是否为 non-public(如果配置为只允许 public 方法)
* 2. 如果是 non-public,直接返回 null(不识别事务注解)
* 3. 如果是 public,才去查找 @Transactional 注解
*/
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// :不允许 non-public 方法,根据配置。
// 如果 allowPublicMethodsOnly() 返回 true,并且方法不是 public 的,
// 直接返回 null!也就是说,@Transactional 注解不会被识别!
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null; // :non-public 方法,直接返回 null!
}
// 如果是 public 方法,才继续查找事务注解
// ... 省略后续代码 ...
}
/**
* 是否只允许 public 方法具有事务语义?
*
* 默认实现返回 false(允许 non-public 方法)。
* 但 AnnotationTransactionAttributeSource 重写了这个方法,返回 true!
*/
protected boolean allowPublicMethodsOnly() {
return false; // 默认:允许 non-public 方法
}
}AnnotationTransactionAttributeSource:注解事务属性源
这个类是 Spring 读取 @Transactional 注解的实现类。它**重写了 allowPublicMethodsOnly() 方法,返回 true!
// 类路径:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
private final boolean publicMethodsOnly;
/**
* 默认构造函数。
*
* :publicMethodsOnly 默认为 true!
* 也就是说,默认情况下,@Transactional 注解只能放在 public 方法上才生效!
*/
public AnnotationTransactionAttributeSource() {
this(true); // :publicMethodsOnly = true!
}
/**
* 自定义构造函数。
*
* @param publicMethodsOnly 是否只允许 public 方法(通常用于基于代理的 AOP),
* protected/private 方法也允许(通常用于 AspectJ 类织入)
*/
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
// ... 省略后续代码 ...
}
/**
* 【核心方法】:是否只允许 public 方法?
*
* 重写父类的方法,返回 this.publicMethodsOnly。
* 默认情况下,这个值是 true!
*/
@Override
protected boolean allowPublicMethodsOnly() {
// 默认:true(只允许 public 方法)
return this.publicMethodsOnly;
}
}默认情况下,AnnotationTransactionAttributeSource.allowPublicMethodsOnly() 返回 true!也就是说,@Transactional 注解只能放在 public 方法上才生效,如果放在 protected、package-private、private 方法上,Spring 在读取注解时就会直接忽略!
这是一个显式的检查,不是 AOP 代理的锅!即使你用 AspectJ 织入(可以拦截 private 方法),如果 publicMethodsOnly = true,事务也不会生效!当然,AspectJ 织入时,可以传入 publicMethodsOnly = false,这样 private 方法上的 @Transactional 也能生效。
::: tip如何解决显式检查问题呢? 如果你真的想让 non-public 方法上的 @Transactional 生效(比如用 AspectJ 织入),可以:
@Configuration
public class AppConfig {
@Bean
public TransactionAttributeSource transactionAttributeSource() {
// :传入 false,允许 non-public 方法
return new AnnotationTransactionAttributeSource(false);
}
}但是 Spring 并不推荐这样做,至于是为啥呢?除了 private 方法通常是内部实现,不应该有事务边界之外,另一个就是 AOP 代理的局限性! :::
AOP 代理的局限性
好了,现在我们知道:即使没有 AOP 代理的问题,Spring 默认也会忽略 non-public 方法上的 @Transactional 注解。
但是,如果你把 publicMethodsOnly 设为 false,AOP 代理的局限性就会显现出来了:
JDK 动态代理的局限性
JDK 动态代理只能代理接口方法。也就是说:
接口(public 方法) → 可以代理
类(public/protected/package-private/private 方法) → 不能代理所以,如果你用 JDK 动态代理,即使把 publicMethodsOnly 设为 false,类上的 non-public 方法(即使有 @Transactional 注解)也不会被拦截!
因为 JDK 动态代理生成的代理类,只实现了接口方法,没有实现类方法。
CGLIB 代理的局限性
CGLIB 代理是通过继承来实现的。也就是说,它只能重写非 final 的非 private 方法。
public 方法 → 可以重写(可以代理)
protected 方法 → 可以重写(可以代理)
package-private 方法 → 可以重写(可以代理,但要求代理类和目标类在同一个包)
private 方法 → 不能重写(不能代理)!
final 方法 → 不能重写(不能代理)!所以,即使把 publicMethodsOnly 设为 false,private 方法和 final 方法上的 @Transactional 也不会生效!
因为 CGLIB 生成的子类,无法重写 private 方法和 final 方法。
AOP 代理的基本原理
要理解为什么 @Transactional 放在 private 方法上不生效,我们得先搞清楚:Spring 的 AOP 代理是怎么工作的?
代理模式的本质
代理模式,说白了就是:你以为你在调用目标对象的方法,其实你是在调用代理对象的方法。
你 ——> 代理对象 ——> 目标对象代理对象会在调用目标对象的方法之前和之后,做一些"额外"的事情(比如开启事务、提交事务)。
Spring 的两种代理方式
Spring AOP 支持两种代理方式:
| 代理方式 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| JDK 动态代理 | 基于接口,运行时生成接口的实现类 | 无需额外依赖,JDK 自带 | 只能代理接口,不能代理类 |
| CGLIB 代理 | 基于继承,运行时生成目标类的子类 | 可以代理类(不需要接口) | 需要引入 CGLIB 依赖(Spring 已内置) |
那么问题来了:Spring Boot 默认使用哪种代理方式?
答案是:CGLIB 代理。
为什么?因为 Spring Boot 的 TransactionAutoConfiguration 中,CglibAutoProxyConfiguration 的 matchIfMissing = true
// 类路径:org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
@Configuration(proxyBeanMethods = false)
// 强制使用 CGLIB 代理
@EnableTransactionManagement(proxyTargetClass = true)
// 默认匹配
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class",
havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}JDK 动态代理
JDK 动态代理的核心是 java.lang.reflect.Proxy 类。
原理:运行时生成一个实现了指定接口的代理类,所有方法调用都会转发到 InvocationHandler.invoke() 方法。
// 类路径:java.lang.reflect.Proxy
public class Proxy implements java.io.Serializable {
/**
* 创建一个动态代理对象。
*
* @param loader 类加载器
* @param interfaces 要实现的接口列表
* @param h 调用处理器(所有方法调用都会转发到这里)
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
// ... 省略实现 ...
}
}Spring 对 JDK 动态代理的封装是 JdkDynamicAopProxy:
// 类路径:org.springframework.aop.framework.JdkDynamicAopProxy
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
private final AdvisedSupport advised;
/**
* 【核心方法】:拦截所有方法调用。
*
* 当调用代理对象的任何方法时,都会先走到这个方法!
*
* @param proxy 代理对象本身
* @param method 被调用的方法
* @param args 方法参数
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.getTargetSource();
Object target = null;
try {
// 1. 处理 equals() 和 hashCode() 方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
// 2. 获取目标对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 3. :获取拦截器链
// 这个方法会返回:所有适用于当前方法的 Advice(包括 TransactionInterceptor)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 4. 如果拦截器链为空,直接调用目标方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// 5. 如果拦截器链不为空,创建 MethodInvocation,并执行拦截器链
else {
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// :执行拦截器链
retVal = invocation.proceed();
}
return retVal;
}
finally {
// 6. 释放目标对象
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
}JDK 动态代理只能代理接口:
- 因为
Proxy.newProxyInstance()要求你传入接口列表 - 如果你的 Service 没有实现接口,JDK 动态代理就用不了
所有方法调用都会先走到 invoke() 方法:
- 包括
toString()、equals()、hashCode()等 - 所以,
@Transactional放在接口方法上才生效,放在类方法上不生效(如果只用 JDK 动态代理的话)
CGLIB 代理
CGLIB 代理的核心是 et.sf.cglib.proxy.Enhancer` 类。
原理:运行时生成一个继承了目标类的子类,重写所有非 final 的方法,在子类中"插入"拦截逻辑。
// 类路径:org.springframework.cglib.proxy.Enhancer
public class Enhancer extends AbstractClassGenerator {
/**
* 创建一个 CGLIB 代理对象。
*
* @param superclass 要继承的父类
* @param callbacks 回调数组(每个方法对应一个回调)
*/
public Object create() {
// ... 省略实现 ...
}
}Spring 对 CGLIB 代理的封装是 CglibAopProxy:
// 类路径:org.springframework.aop.framework.CglibAopProxy
class CglibAopProxy implements AopProxy, Serializable {
private final AdvisedSupport advised;
/**
* 【核心方法】:获取 CGLIB 回调数组。
*
* CGLIB 代理的核心就是:为每个方法分配一个回调(Callback)。
* 当调用方法时,会执行对应的回调。
*/
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 1. 创建事务拦截器回调(AOP 回调)
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised.getInterceptorsAndDynamicInterceptionAdvice(),
this.advised);
// 2. 创建目标对象调用回调(直接调用目标方法,不经过拦截器链)
Callback targetInterceptor = new StaticUnadvisedExposedInterceptor(
this.advised.getTargetSource(), this.advised.getTargetClass());
// 3. 创建回调数组
Callback[] callbacks = new Callback[] {
aopInterceptor, // 0: AOP 拦截器回调(处理事务等)
targetInterceptor, // 1: 目标对象调用回调
NoOp.INSTANCE, // 2: 不重写(直接调用父类方法)
// ... 省略其他回调 ...
};
return callbacks;
}
/**
* CGLIB 拦截器(核心内部类)。
*
* 当调用代理对象的方法时,会执行这个拦截器的 intercept() 方法。
*/
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
/**
* 【核心方法】:拦截所有方法调用。
*
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法参数
* @param methodProxy 方法代理(用于调用父类方法)
*/
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.getTargetSource();
Object target = null;
try {
// 1. 获取目标对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 2. :获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 3. 如果拦截器链为空,直接调用目标方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
// 4. 如果拦截器链不为空,创建 MethodInvocation,并执行拦截器链
else {
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
return retVal;
}
finally {
// 5. 释放目标对象
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
}CGLIB 可以代理类,主要是因为 CGLIB 生成的是目标类的子类,所以即使你的 Service 没有实现接口,事务也能生效
CGLIB 代理不能代理 final 类或 final 方法,也是因为 CGLIB 是通过继承来实现代理的。如果类是 final 的,就不能被继承;如果方法是 final 的,就不能被重写。所以,@Transactional 放在 final 方法上也不生效!
所有方法调用都会先走到 intercept() 方法,包括 public 方法、protected 方法,但是,private 方法不会被拦截!因为 CGLIB 是通过重写方法来实现代理的,而 private 方法不能被重写!
为什么 @Transactional 放在 private 方法上不生效?
现在,我们可以回答这个问题了:
如果你用的是 JDK 动态代理
JDK 动态代理只能代理接口方法。如果你的 Service 没有实现接口,JDK 动态代理就用不了。
如果你的 Service 实现了接口,那么 @Transactional 必须放在接口方法上,才能生效。
为什么? 因为 JDK 动态代理生成的代理类,只实现了接口方法,没有实现类方法。所以,即使你在类方法上加了 @Transactional,代理类也"看不见"这个注解。
而且,即使你把 publicMethodsOnly 设为 false,JDK 动态代理也代理不了类方法!
如果你用的是 CGLIB 代理(Spring Boot 默认)
CGLIB 代理是通过重写方法来实现代理的。但是,private 方法不能被重写!
所以,当你调用一个 private 方法时,CGLIB 代理的 intercept() 方法根本不会被调用,事务就不会生效。
而且,即使你把 publicMethodsOnly 设为 false,CGLIB 也拦截不了 private 方法!
因为 Java 语言规范规定:private 方法不能被子类重写。CGLIB 生成的子类,无法重写 private 方法。
总结:@Transactional 不生效的情况
同理,以下情况事务也不会生效:
@Transactional放在 private 方法上(Java 规定 private 方法不能被重写)@Transactional放在 final 方法上(Java 规定 final 方法不能被重写)@Transactional放在 static 方法上(static 方法属于类,不属于实例,不能被重写)- 同一个类中,方法 A 调用方法 B(方法 B 上有
@Transactional)- 因为 this 调用不会经过代理对象!
- 解决方法:用
AopContext.currentProxy()获取代理对象,然后通过代理对象调用方法 B
TransactionInterceptor 是如何被"织入"到代理对象中的?
现在,我们来看看:Spring 是如何把 TransactionInterceptor 织入到代理对象中的?
精细化流程:从 BeanPostProcessor 到代理对象
在讲解具体实现之前,让我们先梳理一下完整的代理创建流程。这个流程涉及多个核心类的协作:
Spring 容器启动
↓
@EnableTransactionManagement 导入 AutoProxyRegistrar
↓
AutoProxyRegistrar 注册 InfrastructureAdvisorAutoProxyCreator(BeanPostProcessor)
↓
InfrastructureAdvisorAutoProxyCreator 注册 TransactionInterceptor + TransactionAttributeSourceAdvisor
↓
容器创建普通 Bean(比如 UserService)
↓
BeanPostProcessor.postProcessAfterInitialization() 被调用
↓
AbstractAutoProxyCreator.wrapIfNecessary() 判断是否需要代理
↓
AbstractAdvisorAutoProxyCreator.findEligibleAdvisors() 查找符合条件的 Advisor
↓
├→ TransactionAttributeSourcePointcut.matches() 检查类和方法
│ ↓
│ ├→ ClassFilter 检查类是否匹配
│ └→ MethodMatcher 检查方法是否有 @Transactional
│
└→ SpringTransactionAnnotationParser 解析 @Transactional 注解
↓
AbstractAutoProxyCreator.createProxy() 创建代理对象
↓
返回代理对象,替换原始 BeanBeanFactoryTransactionAttributeSourceAdvisor 的组合关系
自动配置信息
/**
* 创建事务 Advisor(通知器)。
*
* Advisor = Pointcut(切点) + Advice(通知)
*
* 这个 Advisor 的 Pointcut 是:"所有带有 @Transactional 注解的方法"
* 这个 Advisor 的 Advice 是:TransactionInterceptor(事务拦截器)
*/
@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;
}在 Spring 事务体系中,BeanFactoryTransactionAttributeSourceAdvisor 是一个核心的 Advisor,它组合了切点和通知,其中切点由注入 AnnotationTransactionAttributeSource 进行构建:
- 切点:
TransactionAttributeSourcePointcut- 决定哪些类/方法需要被拦截 - 通知:
TransactionInterceptor- 决定拦截后做什么(开启事务、提交、回滚)
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
// @Transactional 切点
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
/**
* Set the transaction attribute source which is used to find transaction
* attributes. This should usually be identical to the source reference
* set on the transaction interceptor itself.
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}TransactionAttributeSourcePointcut:切点匹配
TransactionAttributeSourcePointcut 是事务代理的切点实现。它决定了哪些类和方法需要被代理:
// 类路径:org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut
implements Serializable {
protected TransactionAttributeSourcePointcut() {
// 设置类过滤器
setClassFilter(new TransactionAttributeSourceClassFilter());
}
// 方法匹配:检查方法是否有事务属性
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
// 如果能获取到事务属性,说明这个方法需要事务
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
// 类过滤器:过滤不需要检查的类
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
// 排除事务相关的类
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
TransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
// 调用 TransactionAttributeSource 判断是否需要检查
return (tas == null || tas.isCandidateClass(clazz));
}
}
}切点匹配分两步:
- 第一步:类过滤(ClassFilter)- 快速排除明显不需要代理的类
- 第二步:方法匹配(MethodMatcher)- 精确检查方法是否有
@Transactional
类过滤器的优化:
- 排除
TransactionManager相关类(避免自我代理) - 排除
PersistenceExceptionTranslator相关类 - 调用
TransactionAttributeSource.isCandidateClass()做进一步过滤
方法匹配的核心:
- 调用
TransactionAttributeSource.getTransactionAttribute() - 如果返回非 null,说明方法上有
@Transactional注解
AbstractFallbackTransactionAttributeSource:事务属性解析
AbstractFallbackTransactionAttributeSource 是事务属性解析的核心基类。它实现了多级回退查找机制:
// 类路径:org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource
public abstract class AbstractFallbackTransactionAttributeSource
implements TransactionAttributeSource, EmbeddedValueResolverAware {
// 事务属性缓存(key = method + targetClass)
private final Map<Object, TransactionAttribute> attributeCache =
new ConcurrentHashMap<>(1024);
// 获取事务属性(带缓存)
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 1. 忽略 Object 类的方法
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 2. 先从缓存中获取
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// 缓存命中,直接返回
return (cached == NULL_TRANSACTION_ATTRIBUTE ? null : cached);
}
// 3. 计算事务属性
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// 4. 存入缓存
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
} else {
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
// 计算事务属性(四级回退查找)
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 1. 检查方法修饰符(非 public 方法直接返回 null)
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null; // private/protected 方法直接返回 null
}
// 2. 获取最具体的方法(处理继承情况)
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// 3. 第一级查找:方法上的注解
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 4. 第二级查找:类上的注解
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 5. 第三级查找:接口方法上的注解(针对代理)
if (specificMethod != method) {
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 6. 第四级查找:接口类上的注解
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null; // 找不到,返回 null
}
// 是否只允许 public 方法
protected boolean allowPublicMethodsOnly() {
return false; // 默认:允许所有方法
}
}使用 ConcurrentHashMap 存储事务属性作为缓存机制,避免了重复计算,提高性能,同时采用了四级回退查找机制:
- 第一级:具体方法上的
@Transactional注解 - 第二级:类上的
@Transactional注解 - 第三级:接口方法上的
@Transactional注解 - 第四级:接口类上的
@Transactional注解
AnnotationTransactionAttributeSource:注解解析
AnnotationTransactionAttributeSource 是 AbstractFallbackTransactionAttributeSource 的实现类,负责解析 @Transactional 注解:
// 类路径:org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
private final boolean publicMethodsOnly;
private final Set<TransactionAnnotationParser> annotationParsers;
public AnnotationTransactionAttributeSource() {
this(true); // 默认:publicMethodsOnly = true
}
// 重写:返回 true(只允许 public 方法)
@Override
protected boolean allowPublicMethodsOnly() {
return this.publicMethodsOnly; // 默认:true
}
// 查找方法上的事务属性
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
// 查找类上的事务属性
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
// 解析注解
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr; // 找到注解,返回事务属性
}
}
return null; // 没找到注解,返回 null
}
}SpringTransactionAnnotationParser:注解解析器
SpringTransactionAnnotationParser 是真正解析 @Transactional 注解的类:
// 类路径:org.springframework.transaction.annotation.SpringTransactionAnnotationParser
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
// 解析 @Transactional 注解
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 使用 Spring 的注解工具解析注解
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
return null;
}
// 将注解属性转换为事务属性对象
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 解析传播行为
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
// 解析隔离级别
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
// 解析超时
rbta.setTimeout(attributes.getNumber("timeout").intValue());
// 解析只读标记
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 解析回滚规则
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
}AbstractAdvisorAutoProxyCreator:拦截器链的组装
AbstractAdvisorAutoProxyCreator 是自动代理创建器的核心实现。它负责查找符合条件的 Advisor:
// 类路径:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
// 获取适用于 Bean 的 Advisor 列表
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 查找符合条件的 Advisor
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY; // 没有 Advisor,不需要代理
}
return advisors.toArray();
}
// 查找符合条件的 Advisor
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 1. 获取所有候选 Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2. 过滤出适用于当前 Bean 的 Advisor
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(
candidateAdvisors, beanClass, beanName);
// 3. 扩展 Advisor 列表
extendAdvisors(eligibleAdvisors);
// 4. 排序
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// 过滤 Advisor(使用 AopUtils)
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
// 使用 AopUtils 过滤 Advisor
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
}Advisor 匹配:AopUtils.findAdvisorsThatCanApply
AopUtils.findAdvisorsThatCanApply() 是匹配 Advisor 和 Bean 的核心方法:
// 类路径:org.springframework.aop.support.AopUtils
public static List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<>();
// 1. 先处理引介通知(IntroductionAdvisor)
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
if (canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
}
// 2. 处理普通通知(包括 TransactionAttributeSourceAdvisor)
List<Advisor> eligibleAdvisors1 = new LinkedList<>();
for (Advisor candidate : candidateAdvisors) {
if (!(candidate instanceof IntroductionAdvisor)) {
// 调用 canApply() 进行匹配
if (canApply(candidate, clazz)) {
eligibleAdvisors1.add(candidate);
}
}
}
eligibleAdvisors.addAll(eligibleAdvisors1);
return eligibleAdvisors;
}
// 检查 Advisor 是否适用于类
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
if (advisor instanceof IntroductionAdvisor) {
// 引介通知的处理
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
// 普通通知的处理
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass);
}
else {
// 没有切点的通知,适用于所有类
return true;
}
}
// 检查切点是否适用于类
public static boolean canApply(Pointcut pointcut, Class<?> targetClass) {
// 1. 类过滤
if (!pointcut.getClassFilter().matches(targetClass)) {
return false; // 类不匹配,直接返回 false
}
// 2. 如果是 IntroductionAwarePointcutAdvisor,还需要检查方法
if (pointcut instanceof IntroductionAwarePointcutAdvisor) {
return ((IntroductionAwarePointcutAdvisor) pointcut)
.getPointcut().getMethodMatcher()
.matches(new TargetClassMethod(targetClass)) != MethodMatcher.TRUE;
}
return true; // 类匹配,返回 true
}7.9 整体协作流程图
现在,让我们用一张图来总结整个代理创建过程:
┌─────────────────────────────────────────────────────────────────┐
│ Spring 容器启动 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ @EnableTransactionManagement → AutoProxyRegistrar │
│ → 注册 InfrastructureAdvisorAutoProxyCreator │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ TransactionAutoConfiguration │
│ → 注册 TransactionInterceptor │
│ → 注册 TransactionAttributeSource │
│ → 注册 TransactionAttributeSourceAdvisor │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 创建普通 Bean(比如 UserService) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ BeanPostProcessor.postProcessAfterInitialization() │
│ → AbstractAutoProxyCreator.postProcessAfterInitialization() │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ wrapIfNecessary() │
│ → isInfrastructureClass() 排除基础设施类 │
│ → getAdvicesAndAdvisorsForBean() 获取 Advisor │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AbstractAdvisorAutoProxyCreator.findEligibleAdvisors() │
│ → findCandidateAdvisors() 获取所有候选 Advisor │
│ → findAdvisorsThatCanApply() 过滤 Advisor │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ AopUtils.findAdvisorsThatCanApply() │
│ → 对每个 Advisor 调用 canApply() │
│ → TransactionAttributeSourceAdvisor.canApply() │
│ → TransactionAttributeSourcePointcut.getClassFilter() │
│ → TransactionAttributeSourcePointcut.matches() │
│ → TransactionAttributeSource.getTransactionAttribute() │
│ → AbstractFallbackTransactionAttributeSource │
│ → SpringTransactionAnnotationParser │
│ → parseTransactionAnnotation() │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ createProxy() │
│ → ProxyFactory.addAdvisors() 添加 Advisor │
│ → ProxyFactory.getProxy() 创建代理对象 │
│ → JdkDynamicAopProxy 或 CglibAopProxy │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 返回代理对象,替换原始 Bean │
└─────────────────────────────────────────────────────────────────┘7.10 调用时的拦截流程
当调用代理对象的方法时,会触发以下流程:
调用 userService.createUser()
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ JdkDynamicAopProxy.invoke() 或 CglibAopProxy.intercept() │
│ → 获取拦截器链 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ReflectiveMethodInvocation.proceed() │
│ → 依次执行拦截器链中的拦截器 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ TransactionInterceptor.invoke() │
│ → invokeWithinTransaction() │
│ → 获取事务属性 │
│ → 获取事务管理器 │
│ → 创建事务 │
│ → 执行目标方法 │
│ → 提交/回滚 │
└─────────────────────────────────────────────────────────────────┘八、InfrastructureAdvisorAutoProxyCreator 的作用
InfrastructureAdvisorAutoProxyCreator 是 AbstractAdvisorAutoProxyCreator 的子类。
它的特殊之处在于:它只代理"基础设施 Bean"(role = ROLE_INFRASTRUCTURE)。
// 类路径:org.springframework.aop.framework.autoproxy.InfrastructureAdvisorAutoProxyCreator
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
/**
* 【核心方法】:判断一个 Advisor Bean 是否合格。
*
* 这个方法会:
* 1. 判断这个 Advisor Bean 的 role 是否为 ROLE_INFRASTRUCTURE
* 2. 如果是,才认为是合格的 Advisor
*
* 【意义】:这样,就只会代理那些"基础设施 Bean"(比如事务 Advisor),
* 而不会代理用户自定义的 Advisor。
*/
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}关键发现:
InfrastructureAdvisorAutoProxyCreator只会代理"基础设施 Bean":- 什么是"基础设施 Bean"?就是那些 role =
ROLE_INFRASTRUCTURE的 Bean - 比如:
TransactionInterceptor、BeanFactoryTransactionAttributeSourceAdvisor等 - 这些 Bean 都是 Spring 事务基础设施的一部分
- 什么是"基础设施 Bean"?就是那些 role =
这样做的好处是什么?
- 避免代理用户自定义的 Advisor
- 提高性能(不需要检查所有的 Advisor)
Spring Boot 如何自定义代理?
Spring Boot 默认使用 CGLIB 代理。
# application.yml
spring:
aop:
proxy-target-class: true # 默认值就是 true,可以省略如果你想用 JDK 动态代理,可以这样配置:
# application.yml
spring:
aop:
proxy-target-class: false # 使用 JDK 动态代理总结
到这里,我们已经把 AOP 代理的"神秘面纱"揭开了。
让我们来回顾一下整个流程:
- Spring 容器启动时,
AutoProxyRegistrar会注册InfrastructureAdvisorAutoProxyCreator InfrastructureAdvisorAutoProxyCreator会在每个 Bean 初始化后,判断这个 Bean 是否需要被代理- 如果需要代理,创建代理对象(JDK 动态代理或 CGLIB 代理)
- 把
TransactionInterceptor添加到代理对象的拦截器链中 - 当调用代理对象的方法时,
TransactionInterceptor.invoke()会被执行 invoke()方法调用了父类TransactionAspectSupport.invokeWithinTransaction()方法- 这个方法才是事务管理的真正核心!