Spring默认采用单例(Singleton)作用域,因此同一类的Bean在整个IoC容器中仅存在一个共享实例;getBean()多次调用返回的是同一个对象引用,而非新实例——这正是循环依赖能被解决且构造器只执行一次的根本原因。
spring默认采用单例(singleton)作用域,因此同一类的bean在整个ioc容器中仅存在一个共享实例;`getbean()`多次调用返回的是同一个对象引用,而非新实例——这正是循环依赖能被解决且构造器只执行一次的根本原因。
在你提供的代码中,DependencyA 和 DependencyB 均未显式声明作用域,因此遵循Spring默认规则:@Scope("singleton")。这意味着:
DependencyA dependencyA = applicationContext.getBean(DependencyA.class); // 返回已创建好的ADependencyB dependencyB = applicationContext.getBean(DependencyB.class); // 返回已创建好的B
——两者均从 singletonObjects 直接获取,不再触发构造函数,故 "I am constructor of Dependency B" 仅输出一次。
若希望每次 getBean() 都新建实例(即构造器重复执行),需显式指定作用域:
@Component@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 或 @Scope("prototype")class DependencyB { // ... 同上}
此时运行将抛出 BeanCurrentlyInCreationException:因为Prototype Bean不参与三级缓存机制,Spring无法提前暴露其引用,循环依赖将直接失败——这也印证了单例+字段/Setter注入是Spring唯一支持循环依赖的组合。
System.out.println(System.identityHashCode(dependencyA)); // 例如:123456789System.out.println(System.identityHashCode(applicationContext.getBean(DependencyA.class))); // 相同值
总结:getBean() 不“创建”Bean,而是“获取”容器中已管理的实例;单例作用域下的循环依赖之所以可行,本质是Spring利用三级缓存实现了对象实例化与初始化的时空解耦——先有“壳”,再填“瓤”,从而在闭环中建立可靠引用链。