面试知识库

Spring IoC → AOP → 事务 → 循环依赖 追问链#

追问路径#

涉及知识点#

核心串联逻辑#

  1. IoC容器:BeanFactory负责Bean创建与管理,ApplicationContext扩展了事件、国际化等能力
  2. Bean生命周期:核心是BeanPostProcessor机制,AOP代理就是通过BPP在初始化后创建的
  3. 三级缓存:一级存成品Bean,二级存半成品(已实例化未填充属性),三级存ObjectFactory——只有涉及AOP时第三级才有意义,它允许在循环依赖时提前生成代理
  4. AOP与事务:@Transactional通过TransactionInterceptor(AOP代理)实现,自调用绕过了代理所以事务失效
  5. 代码示例
    // 三级缓存核心逻辑 (AbstractAutowireCapableBeanFactory)
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    // getEarlyBeanReference 会检查是否需要AOP代理,需要则提前创建
    java

面试回答串联#

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方法。构造器注入无法解决循环依赖,因为实例化阶段就需要完整的依赖对象。“

相关追问链#