Spring AOP 与事务

Java / Spring / AOP2026.09.147 分钟阅读

Spring 代理、自调用与声明式事务的生效范围。

代理怎样拦截调用

Spring Framework 6.2 的 Spring AOP 在调用方和目标对象之间放置代理。调用进入代理后,匹配的拦截器在目标方法前后执行逻辑。方法注解由这些基础设施读取,调用经过代理才会触发相应增强。

JDK 动态代理基于接口,类代理通过子类实现增强。类代理无法覆盖 final 方法和 private 方法,能否拦截还取决于方法可见性与切点。AspectJ 使用编织机制,没有相同的代理入口限制。

声明式事务通过事务拦截器,根据方法的事务属性和当前事务状态,开启、加入或挂起事务。使用时要让容器管理对象,并配置好事务基础设施及对应资源。

外部调用与自调用路径

外部通过注入的 Bean 引用调用方法,通常会进入代理。目标方法内部的 this 指向目标对象,其对另一个方法的调用属于普通对象内部调用,不会重新进入代理。省略 this 与显式书写 this.method() 在这一点上没有差异。

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {
    public void place() {
        save(); // 当前对象内部调用
    }

    @Transactional
    public void save() {
        // 示例:通过已配置的数据访问组件写入一条订单
        throw new IllegalStateException("simulate failure");
    }
}

配置好事务管理器、数据源并启用声明式事务后,通过容器注入的 OrderService 调用 save,会进入事务拦截器;调用 place 后再由内部执行 save,则会绕过这个入口。

两种调用路径:外部调用 save 时,调用方经过 Spring 代理和事务拦截器进入目标对象的 save;调用 place 后在目标对象内部调用 this.save,不会重新经过代理和 save 对应的事务拦截器。
图 1 外部调用与目标对象内部调用。自调用不会触发新的代理拦截,但仍可能参与已有的外层事务。

若不存在外层事务,自调用 save 不会因其注解而自动建立事务;若 place 已在外层事务中运行,内部数据操作仍可能参与已有事务。自调用绕过的是该方法上的代理拦截,并不取消线程中已经存在的事务状态。

自调用也会绕过传播属性。例如内部方法配置了新事务,但调用未经过代理,就不会按该配置挂起外层事务。

检查事务是否生效

在 save 入口加入下面的代码,可以观察当前线程是否有活动事务:

// 在示例 save() 开头临时观察;需要 Spring 事务依赖
boolean active = org.springframework.transaction.support
    .TransactionSynchronizationManager.isActualTransactionActive();
System.out.println("transaction active = " + active);

让测试方法不开事务,分别调用 place 和 save,比较输出。再接入记录写入,在方法末尾抛出运行时异常,调用结束后用独立查询检查记录是否回滚。

测试框架创建的外层事务会掩盖自调用的影响。IllegalStateException 属于默认会触发回滚的运行时异常;受检异常需要配置 rollbackFor 等规则。方法内部吞掉异常时,拦截器也可能看不到失败。

经代理调用 save 仍未正确回滚时,检查事务管理器是否对应写入的数据源,以及写入是否使用了异步线程或非受管连接。测试传播属性时,分别检查内层失败、外层失败和正常提交的结果。

把事务放在哪里

如果 place 的所有数据库操作都要共同提交或回滚,就在外部入口 place 上声明事务。尽量减少事务内的远程等待,缩短资源占用时间。

如果 save 是独立业务能力,可以放入另一个受管 Bean,通过注入引用调用,让调用经过代理。只需控制方法中一段操作时,可以用 TransactionTemplate 显式划定事务范围。

暴露当前代理再调用自身,会让业务代码依赖 AOP 运行环境,独立测试也更麻烦。

计时、审计等跨方法的统一规则适合放在 AOP 中。订单状态迁移和库存决策放在明确的业务方法里,调用者更容易看清操作及其事务范围。

— 本页完 —
← 返回文章列表

搜索内容

输入关键词搜索文章、笔记与随笔。