Why Spring’s Constructor Injection Fails on Circular Dependencies (and How Setters Help)
This article explains what circular dependencies are in Spring, shows three ways the framework handles them—constructor injection, singleton setter injection, and prototype setter injection—illustrates each with Java classes and XML configuration, and clarifies why only the singleton setter approach avoids runtime errors.
Circular dependency occurs when a group of classes reference each other in a loop, causing the JVM to repeatedly instantiate objects until a memory overflow occurs.
1. Constructor‑parameter circular dependency
Spring places each bean being created into a "currently created bean pool"; if a bean being instantiated is already in the pool, Spring throws BeanCurrentlyInCreationException. The following three classes form a constructor‑based circular reference:
public class StudentA {
private StudentB studentB;
public void setStudentB(StudentB studentB) { this.studentB = studentB; }
public StudentA() {}
public StudentA(StudentB studentB) { this.studentB = studentB; }
}
public class StudentB {
private StudentC studentC;
public void setStudentC(StudentC studentC) { this.studentC = studentC; }
public StudentB() {}
public StudentB(StudentC studentC) { this.studentC = studentC; }
}
public class StudentC {
private StudentA studentA;
public void setStudentA(StudentA studentA) { this.studentA = studentA; }
public StudentC() {}
public StudentC(StudentA studentA) { this.studentA = studentA; }
}XML configuration using constructor‑arg creates the same circular reference:
<bean id="a" class="com.zfx.student.StudentA">
<constructor-arg index="0" ref="b"/>
</bean>
<bean id="b" class="com.zfx.student.StudentB">
<constructor-arg index="0" ref="c"/>
</bean>
<bean id="c" class="com.zfx.student.StudentC">
<constructor-arg index="0" ref="a"/>
</bean>Running the test class results in:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?2. Setter injection with singleton scope (default)
Spring first instantiates the bean objects, then injects properties. Because the partially created singleton instances are stored in a cache, the setter can retrieve the already‑created bean and resolve the reference without error.
Diagram of Spring bean creation (illustrative image):
XML configuration using property elements (singleton scope):
<bean id="a" class="com.zfx.student.StudentA">
<property name="studentB" ref="b"/>
</bean>
<bean id="b" class="com.zfx.student.StudentB">
<property name="studentC" ref="c"/>
</bean>
<bean id="c" class="com.zfx.student.StudentC">
<property name="studentA" ref="a"/>
</bean>The test class prints a valid bean reference, e.g. com.zfx.student.StudentA@1fbfd6, showing that the circular dependency is resolved.
3. Setter injection with prototype scope
When beans are defined with scope="prototype", Spring does not cache the instance during creation, so it cannot expose an early reference. Consequently, the same circular reference leads to the same BeanCurrentlyInCreationException as in the constructor case.
Prototype XML configuration:
<bean id="a" class="com.zfx.student.StudentA" scope="prototype">
<property name="studentB" ref="b"/>
</bean>
<bean id="b" class="com.zfx.student.StudentB" scope="prototype">
<property name="studentC" ref="c"/>
</bean>
<bean id="c" class="com.zfx.student.StudentC" scope="prototype">
<property name="studentA" ref="a"/>
</bean>Running the same test now produces the same circular‑dependency exception, demonstrating that prototype beans cannot resolve such cycles.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
