Spring中getBean()是否共享Bean实例?循环依赖代码疑问
关于Spring Setter注入解决循环依赖的实例复用疑问
我编写了一个使用setter-based dependency injection解决循环依赖的程序,但输出结果有些令人困惑。
代码
package com.spring.core.di; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Configuration @ComponentScan("com.spring.core.di") class CoolAppConfig { } @Component class DependencyA { DependencyB dependencyB; public DependencyA() { System.out.println("I am constructor of Dependency A"); } @Autowired public void setDependencyB(@Qualifier("dependencyB") DependencyB dependencyB) { System.out.println("I am setDependencyB !"); this.dependencyB = dependencyB; } public void say() { this.dependencyB.who(); } public void who() { System.out.println("I am Dependency A"); } } @Component class DependencyB { DependencyA dependencyA; public DependencyB() { System.out.println("I am constructor of Dependency B"); } @Autowired public void setDependencyA(@Qualifier("dependencyA") DependencyA dependencyA) { System.out.println("I am setDependencyA !"); this.dependencyA = dependencyA; } public void say() { this.dependencyA.who(); } public void who() { System.out.println("I am dependency B"); } } public class CircularDependencyIssue { public static void main(String[] args) { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CoolAppConfig.class); DependencyA dependencyA = applicationContext.getBean(DependencyA.class); DependencyB dependencyB = applicationContext.getBean(DependencyB.class); dependencyA.say(); dependencyB.say(); } }
输出
I am constructor of Dependency A I am constructor of Dependency B I am setDependencyA ! I am setDependencyB ! I am dependency B I am Dependency A
我的疑问是:在main方法中获取DependencyB的Bean时,为何DependencyB的构造器没有被再次调用?输出中“I am constructor of Dependency B”仅出现一次,但按预期应打印两次。这是否意味着解决DependencyA依赖时创建的DependencyB实例与后续获取的DependencyB Bean是同一个?同时想确认getBean()方法是否会为不同的Bean请求共享实例,以及整个流程的运作原理。
解答
核心原因:Spring默认Bean作用域是单例(Singleton)
Spring容器中,默认所有用@Component(或同类注解)标记的Bean都是单例作用域,容器只会为每个Bean创建一个实例,并将这个实例缓存起来,后续所有getBean()请求都会直接返回缓存中的对象,不会重新调用构造器创建新实例。这就是你看到构造器只执行一次的根本原因。
循环依赖的完整解决流程
- 容器启动后,扫描到
DependencyA和DependencyB,开始初始化Bean:- 先创建
DependencyA的未完全初始化实例(仅调用构造器),并将这个实例放入Spring的「早期单例缓存」中。 - 接着处理
DependencyA的setter注入,发现需要DependencyB,于是转向创建DependencyB。
- 先创建
- 创建
DependencyB的实例(调用构造器),放入缓存,接着处理它的setter注入,发现需要DependencyA:- 此时直接从「早期单例缓存」中取出那个未完全初始化的
DependencyA实例,注入给DependencyB,DependencyB完成初始化。
- 此时直接从「早期单例缓存」中取出那个未完全初始化的
- 回到
DependencyA的setter注入,将已经完全初始化的DependencyB实例注入,DependencyA也完成初始化。 - 最终两个Bean都被存入Spring的单例缓存池,后续任何
getBean()请求都直接取缓存里的实例。
getBean()的行为规则
- 单例作用域(默认):每次调用
getBean()都会返回同一个缓存中的实例,构造器仅在Bean第一次初始化时执行一次。 - 原型作用域(
@Scope("prototype")):每次调用getBean()都会创建新的实例,构造器会重复执行,但注意:原型作用域下Spring无法自动解决循环依赖,会抛出异常,这也是Spring只在单例作用域下支持循环依赖解决的原因之一。
内容的提问来源于stack exchange,提问作者Neeraj-Kumar-Coder
相关产品推荐
相关产品推荐

