spring声明式缓存与事务依赖注解+反射+aop代理机制:@cacheable和@transactional需runtime保留策略,由spring通过动态代理在方法前后织入缓存或事务逻辑,且仅对spring管理的public方法生效。

注解本身不执行任何逻辑,它只是标记;真正实现声明式缓存与事务管理的,是“读取注解 + 动态织入行为”的组合机制。核心链条就三步:定义注解 → 运行时反射读取 → 用AOP代理在方法前后插入缓存或事务逻辑。
注解必须是 RUNTIME 生命周期
只有 @Retention(RetentionPolicy.RUNTIME) 的注解,才能在程序运行时被反射读取到。像 @Cacheable、@Transactional 都属于这一类。如果误设成 CLASS 或 SOURCE,Spring 就完全看不到它,自然不会生效。
- @Cacheable 默认只对 public 方法生效,且要求目标类由 Spring 容器管理(即被 @Component、@Service 等注入)
- @Transactional 同样依赖 Spring 的 AOP 代理,非 Spring 管理的对象(比如 new 出来的实例)加了也无效
- 接口代理和 CGLIB 代理的选择会影响私有方法、final 方法是否能被拦截——默认 JDK 动态代理只支持接口,CGLIB 可代理类,但需开启 proxy-target-class="true"
缓存靠 Spring Cache 抽象 + 缓存管理器驱动
Spring Cache 不绑定具体实现,而是提供统一的注解语义层(@Cacheable、@CacheEvict、@CachePut),底层通过 CacheManager(如 ConcurrentMapCacheManager、RedisCacheManager)完成真实存储操作。
- @Cacheable 标记的方法,首次调用时执行业务逻辑并把结果存入缓存;后续调用先查缓存,命中则直接返回
- 缓存键默认是方法参数,也可用 SpEL 表达式自定义,例如 key="#user.id" 或 unless="#result == null"
- 缓存失效不是自动的,@CacheEvict 可主动清除,@Cacheable 的 unless 或 condition 属性可控制是否缓存
事务靠 AOP 切面 + TransactionInterceptor 拦截
@Transactional 的实际执行者是 TransactionInterceptor,它是一个 Around 类型的增强器,在方法调用前后开启事务、提交或回滚。
- 事务边界由传播行为(propagation)决定:比如 REQUIRED 表示有事务就加入,没有就新建;REQUIRES_NEW 总是挂起当前事务、开新事务
- 默认只对 RuntimeException 及其子类回滚,受检异常(Exception)不会触发回滚,需显式配置 rollbackFor
- 事务隔离级别、超时时间、只读标识等属性,最终都会转化为 TransactionDefinition,交由具体的 TransactionManager(如 DataSourceTransactionManager)执行
本质上,声明式缓存和事务都不是注解“自己干的”,而是框架基于注解元数据,用反射发现它,再用动态代理把横切逻辑织入进去。写对注解只是第一步,理解背后的 AOP 和运行时机制,才能真正用好、调得准、查得清。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











