Having an issue resolving circular dependency in a Spring Boot Starter project (version 3.1) with Gradle.

Using setter injection with @Autowired annotation.

After building the project, the following output displayed:

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-07-09T16:45:14.463-04:00 ERROR 3398 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  classA
↑     ↓
|  classB
└─────┘


Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

*Note: Project ran successfully with an older Spring Boot version (2.5.15). Also tested it using 2.6.0 - same issue occurred.

Appears to be an issue with versions 2.6 and above.

Application code below:

MainApp.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        SpringApplication.run(MainApp.class);
    }
}

ClassA.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ClassA {
    private ClassB classB;

    @Autowired
    public void setClassB(ClassB classB) {
        this.classB = classB;
    }
}

ClassB.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ClassB {
    private ClassA classA;

    @Autowired
    public void setClassA(ClassA classA) {
        this.classA = classA;
    }
}

Comment From: philwebb

Please see this section of the 2.6 release notes.

Comment From: zpreston123

@philwebb Reviewed the Circular Dependencies section and am aware of the applications.properties file workaround (not recommended).

There should not be a cyclic dependency after using one of the resolution methods.

In this example, setter injection is used.

See code above.

Comment From: snicoll

There should not be a cyclic dependency after using one of the resolution methods.

What resolution method are you talking about? A depends on B and B depends on A so, conceptually, there is clearly a cycle. It looks like you believe that setter injection should fix the cycle. Can you expand on that?

Comment From: zpreston123

@snicoll Setter injection using "@Autowired" annotation.

See https://www.baeldung.com/circular-dependencies-in-spring#3-use-setterfield-injection for more information.

Comment From: bclozel

@zpreston123

  1. The Workarounds

This article lists workarounds to make things work despite the circular dependency, but it doesn't fix the circular dependency itself. @snicoll 's comment still stands and so does the release notes. If you believe this article is misleading, please reach out to the authors.

Comment From: zpreston123

@bclozel This is one of the common methods to resolve the circular dependency issue.

Also mentioned in the Spring documentation (https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html#beans-dependency-resolution).

This method should prevent Spring from injecting the dependencies while the objects are created during context loading.

Any suggestions?

Comment From: wilkinsona

It doesn't resolve a circular dependency issue. It's still very much there, just slightly hidden. You should either refactor your code (recommended) or set spring.main.allow-circular-references=true.

Comment From: zpreston123

@wilkinsona Code provided is a simple example - refactoring is not necessary.

Setting spring.main.allow-circular-references=true is not recommended.

Using setter injection as one of the resolution methods specified in the Spring documentation should not throw an exception.

See exception details below:

2023-07-11T09:43:27.609-04:00  WARN 8992 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'classA': Unsatisfied dependency expressed through method 'setClassB' parameter 0: Error creating bean with name 'classB': Unsatisfied dependency expressed through method 'setClassA' parameter 0: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference?

Comment From: wilkinsona

Setting spring.main.allow-circular-references=true is not recommended.

It isn't recommended as we believe that refactoring your code to remove circular dependencies of any form is a better approach.

Using setter injection as one of the resolution methods specified in the Spring documentation should not throw an exception.

Then please set the property. That's what it's there for.