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.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why Spring’s Constructor Injection Fails on Circular Dependencies (and How Setters Help)

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):

Spring bean creation process
Spring bean creation process

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaspringdependency-injectionConstructor InjectionSetter Injectioncircular-dependencyBean Scope
Java Backend Technology
Written by

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!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.