Spring IoC → AOP → 事务 → 循环依赖 追问链#
追问路径#
Q: Spring IoC是什么?解决什么问题?
→ 控制反转,将对象创建和依赖管理交给容器,降低耦合
Q: Bean的生命周期有哪些阶段?
→ 实例化 → 属性填充 → Aware回调 → BeanPostProcessor前置 → InitializingBean/init-method → BPP后置 → 使用 → destroy
Q: 循环依赖怎么解决的?
→ 三级缓存:singletonObjects / earlySingletonObjects / singletonFactories
├─ Q: 为什么需要三级缓存而不是两级?
│ → 第三级放ObjectFactory(lambda),支持AOP场景下提前创建代理对象
│ Q: AOP代理是怎么创建的?
│ → AnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor)在初始化后创建代理
│ Q: JDK动态代理和CGLIB怎么选?
│ → 有接口用JDK(Proxy.newProxyInstance),无接口用CGLIB(字节码子类);SpringBoot2默认强制CGLIB
│ Q: @Transactional为什么会失效?
│ → 自调用(绕过代理)/非public方法/异常类型不匹配(默认只回滚RuntimeException)/未被Spring管理
│ Q: 怎么排查事务失效?
│ → 打印bean.getClass()看是否是代理类;debug TransactionInterceptor#invoke;检查propagation配置
└─ Q: 构造器注入能解决循环依赖吗?
→ 不能,实例化阶段就需要依赖对象,无法提前暴露
Q: 那怎么解决构造器循环依赖?
→ @Lazy延迟加载(生成代理占位);重构设计消除循环;用setter注入替代plaintext涉及知识点#
- Spring-IoC原理 — 控制反转与依赖注入
- Bean生命周期 — 从实例化到销毁的完整流程
- 循环依赖与三级缓存 — 三级缓存的设计意图
- Spring-AOP原理 — 切面编程与代理机制
- JDK动态代理与CGLIB — 两种代理的实现差异
- Spring事务传播行为 — REQUIRED/REQUIRES_NEW等7种传播行为
- Spring事务失效场景 — 8大事务失效原因
- Spring-BeanFactory与ApplicationContext — 容器层次
- Spring-Bean作用域 — singleton/prototype等
- 代理模式 — GoF设计模式基础
- Spring设计模式应用 — Spring中的设计模式实践
核心串联逻辑#
- IoC容器:BeanFactory负责Bean创建与管理,ApplicationContext扩展了事件、国际化等能力
- Bean生命周期:核心是BeanPostProcessor机制,AOP代理就是通过BPP在初始化后创建的
- 三级缓存:一级存成品Bean,二级存半成品(已实例化未填充属性),三级存ObjectFactory——只有涉及AOP时第三级才有意义,它允许在循环依赖时提前生成代理
- AOP与事务:@Transactional通过TransactionInterceptor(AOP代理)实现,自调用绕过了代理所以事务失效
- 代码示例:
java// 三级缓存核心逻辑 (AbstractAutowireCapableBeanFactory) addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); // getEarlyBeanReference 会检查是否需要AOP代理,需要则提前创建
面试回答串联#
30秒速答#
“Spring通过IoC容器管理Bean生命周期,用三级缓存解决循环依赖——第三级缓存放ObjectFactory支持AOP代理提前暴露。AOP代理通过BeanPostProcessor创建,@Transactional基于AOP实现,自调用导致事务失效是因为绕过了代理对象。“
2分钟展开答#
“Spring IoC的核心是BeanFactory,Bean生命周期经历实例化、属性填充、Aware回调、BeanPostProcessor、初始化等阶段。循环依赖通过三级缓存解决:一级存成品Bean,二级存半成品,三级存ObjectFactory。为什么不是两级?因为AOP场景下需要在循环引用时提前创建代理对象,ObjectFactory的lambda可以按需调用getEarlyBeanReference判断是否需要代理。AOP代理由AnnotationAwareAspectJAutoProxyCreator这个BPP创建,SpringBoot2默认使用CGLIB而非JDK动态代理。@Transactional就是基于AOP的TransactionInterceptor实现的,所以自调用不走代理会导致事务失效。排查时可以通过打印bean.getClass()确认是否是代理类,或者debug TransactionInterceptor的invoke方法。构造器注入无法解决循环依赖,因为实例化阶段就需要完整的依赖对象。“
相关追问链#
- 线程池-Spring异步-MQ消费追问链 — Spring @Async也依赖AOP代理机制
- HashMap-ConcurrentHashMap-并发集合追问链 — Spring容器内部使用ConcurrentHashMap存储Bean定义