知其然,知其所以然
Spring 全家桶 2026-10-19

CGLIB 代理的限制:final、private 与构造器被调用几次

实测 CGLIB 代理的限制:final 方法不被拦截而且在字段未初始化的代理上执行(读到 null);private 与 static 方法不单独拦截;靠 Objenesis 构造器只调用 1 次(关掉后调用 2 次,只有带参构造器的类会失败);final 类抛 Cannot subclass final class。

Spring AOP CGLIB final Objenesis 真实验证 动画演示
Spring 全家桶 2026-10-19

@Async:线程池、异常去向与上下文传播

实测 @Async:纯 Spring 默认每次调用新建一个线程(100 次调用 100 个线程),Boot 默认 8 个线程的 applicationTaskExecutor;void 方法的异常默认只记 ERROR 日志;返回 String 的 @Async 方法直接抛 IllegalArgumentException;ThreadLocal 不会带到异步线程,TaskDecorator 可以传递;执行器满了默认拒绝 6 个任务、CallerRunsPolicy 让调用者自己跑。

Spring Async 线程池 异常处理 TaskDecorator 真实验证 动画演示
Spring 全家桶 2026-10-19

@Scheduled:默认单线程调度器的串行与阻塞

实测 @Scheduled:默认调度器只有一个线程(纯 Spring 的 pool-1-thread-1、Boot 的 scheduling-1),一个耗时 1000 ms 的慢任务让每 200 ms 的快任务错过 5 次并在结束后 30 ms 内补跑 5 次;线程池设成 3 就不互相挡;fixedRate 与 fixedDelay 在任务比间隔慢时周期约 506 ms 对约 806 ms;任务抛异常不影响后续调度;加 @Async 会重叠执行。

Spring Scheduled 定时任务 fixedRate fixedDelay 真实验证 动画演示
Spring 全家桶 2026-10-19

@Cacheable:Key 生成、同步加载与自调用

实测 Spring 缓存抽象:默认键只由参数决定(不含方法名,同缓存同参数的不同方法会冲突);null 默认也被缓存;8 个线程并发取同一个键,没有 sync 目标方法执行 8 次、sync = true 只执行 1 次;@CacheEvict 在方法抛异常时默认不清缓存;ConcurrentMapCacheManager 缓存的是引用;自调用不走缓存。

Spring Cache Cacheable CacheEvict 缓存 真实验证 动画演示
Spring 全家桶 2026-10-19

@Retryable:Spring Framework 7 内置的重试、退避与异常筛选(以及 @ConcurrencyLimit)

实测 Spring Framework 7 内置的 @Retryable:默认 maxRetries = 3、delay = 1000 ms(执行时刻 5、1014、2019 ms);multiplier = 2、maxDelay = 500 时间隔 100、200、400、500、500;includes / excludes / predicate 筛选异常(嵌套的 cause 也参与匹配);次数用完抛原始异常,timeout 把 maxRetries = 10 截断成 3 次;RetryTemplate 次数用完抛 RetryException;@ConcurrencyLimit(2) 把最大并发限制成 2。

Spring Retryable 重试 退避 ConcurrencyLimit 真实验证 动画演示
Spring 全家桶 2026-10-19

AopContext 与 AopUtils:拿到原始对象

实测怎么从代理拿回原始对象与类:AopUtils.getTargetClass 只脱一层,AopProxyUtils.ultimateTargetClass 一路脱到底,ClassUtils.getUserClass 不处理 JDK 代理;CGLIB 代理类上 getAnnotation 找不到目标类注解(findAnnotation 才行);代理与目标 equals、hashCode 都不相等;两个切面加 @Async 合并成同一个代理的 4 个拦截器。

Spring AOP 代理 AopUtils AopProxyUtils 真实验证 动画演示
Spring 全家桶 2026-10-19

@Transactional 的实现:TransactionInterceptor 到 PlatformTransactionManager

实测 @Transactional 的实现:事务管理器依次 doGetTransaction、doBegin(拿连接、关 autocommit、绑定线程)、doCommit 或 doRollback、doCleanupAfterCompletion;事务里两条 insert 用同一个连接(connection_id 都是 12);MySQL general_log 里一个事务是 SET autocommit=0 … COMMIT … SET autocommit=1 共 7 条,没有 @Transactional 的两条 insert 只有两条语句本身。

Spring 事务 Transactional PlatformTransactionManager MySQL 真实验证 动画演示
Spring 全家桶 2026-10-19

事务传播行为:7 种逐一实测

实测事务传播行为 7 种:外面有事务时 REQUIRED、NESTED、SUPPORTS、MANDATORY 加入同一个连接,REQUIRES_NEW 与 NOT_SUPPORTED 用另一个连接,NEVER 抛异常;外层回滚时 REQUIRES_NEW 与 NOT_SUPPORTED 的行保留;inner 抛异常被外层吞掉时 REQUIRED 在提交时抛 UnexpectedRollbackException,REQUIRES_NEW 与 NESTED 只回滚自己;外面没有事务时 MANDATORY 抛异常。

Spring 事务 传播行为 REQUIRES_NEW NESTED 真实验证 动画演示
Spring 全家桶 2026-10-19

回滚规则:检查异常、RuntimeException 与 rollbackFor

实测事务回滚规则:RuntimeException 与 Error 回滚,受检异常 IOException 默认提交(表里剩 1 行);rollbackFor 才会回滚;方法内部吞掉异常就提交,setRollbackOnly() 可以手动回滚;rollbackFor 与 noRollbackFor 同时匹配时继承层次上更近的一条赢。

Spring 事务 回滚 rollbackFor 受检异常 真实验证 动画演示
Spring 全家桶 2026-10-19

事务失效的场景:自调用、非 public、异常被吞与多线程

实测 @Transactional 不生效的场景:自调用、private、final、吞掉异常、事务里开线程、事务管理器绑错数据库、MyISAM 表、new 出来的对象都不回滚;Spring 7 的 CGLIB 代理下 package-private 与 protected 的方法是生效的;默认 JDK 代理只能按接口取 Bean。

Spring 事务 失效 自调用 真实验证 动画演示
Spring 全家桶 2026-10-19

readOnly 的真实效果:MySQL 与 Hibernate flush 模式

实测 readOnly = true 的效果:JDBC 一侧靠 SET SESSION TRANSACTION READ ONLY 开始、READ WRITE 结束,里面用 JdbcTemplate 写会被驱动在客户端拒绝;Hibernate 一侧实体修改不再刷到数据库(没有 UPDATE,手动 em.flush() 也不报错,修改悄悄丢掉);加入外层读写事务时内层的 readOnly 无效。

Spring 事务 readOnly Hibernate flush 真实验证 动画演示
Spring 全家桶 2026-10-19

TransactionSynchronizationManager:事务资源绑在线程上

实测事务资源绑定在线程上:事务内线程上绑着 HikariDataSource → ConnectionHolder,子线程里事务不活跃、资源 0 个;同步回调提交时依次是 beforeCommit、beforeCompletion、afterCommit、afterCompletion(COMMITTED),回滚时没有 beforeCommit 和 afterCommit;afterCommit 抛异常撤销不了提交;绕过 Spring 直接 ds.getConnection() 拿到另一个连接,写入不会回滚。

Spring 事务 TransactionSynchronizationManager ThreadLocal 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号