I have the following configuration class:

@Configuration
class MyFactory(
  @Qualifier("depA1") private val depA: DepA,
) {

  @Bean
  @Scope(BeanDefinition.SCOPE_PROTOTYPE)
  fun myBean(
    depB: DepB,
    depC: DepC,
  ) = MyBean(depA, depB, depC)
}

when running in JVM, the Spring Boot App load up fine, but when compiled as native image, it reported

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'xxxXxxx': Unsatisfied dependency expressed through constructor parameter 3: Error creating bean with name 'myBean': Requested bean is currently in creation: Is there an unresolvable circular reference?

Detail Stacktrace
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'xxxXxxx': Unsatisfied dependency expressed through constructor parameter 3: Error creating bean with name 'myBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:351) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:271) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[app.exe:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[app.exe:6.0.2]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[app.exe:6.0.2]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[app.exe:3.0.0]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[app.exe:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[app.exe:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[app.exe:3.0.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[app.exe:3.0.0]
        at scs.csi5137b.project.MainKt.main(Main.kt:66) ~[app.exe:na]
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'myBean': Requested bean is currently in creation: Is there an unresolvable circular reference?
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:266) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:210) ~[app.exe:6.0.2]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.resolveBeanReference(ConfigurationClassEnhancer.java:361) ~[na:na]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:334) ~[na:na]
        at scs.csi5137b.project.component.observer.CliObserverFactory$$SpringCGLIB$$0.dockerStatsObserver(<generated>) ~[app.exe:na]
        at scs.csi5137b.project.component.observer.CliObserverFactory__BeanDefinitions.lambda$getDockerStatsObserverInstanceSupplier$1(CliObserverFactory__BeanDefinitions.java:41) ~[na:na]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[app.exe:6.0.2]
        at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:208) ~[na:na]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) ~[app.exe:6.0.2]
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:220) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:208) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:344) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[app.exe:6.0.2]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334) ~[na:na]
        ... 20 common frames omitted

However, if I modify my @Configuration class as following:

@Configuration
class MyFactory {

  @Bean
  @Scope(BeanDefinition.SCOPE_PROTOTYPE)
  fun myBean(
    depB: DepB,
    depC: DepC,
  @Qualifier("depA1") depA: DepA,
  ) = MyBean(depA, depB, depC)
}

Then both JVM and the native image run fine.

All tests are running on Spring Boot 3 with GraalVM 22.3 CE (Java 17) on Windows 10

Let me know if you need more information

Comment From: scottfrederick

@CXwudi We'll need more information on exactly what you're trying to do.

For example, code like this does create a cycle, as it is trying to injectMyFactory with a bean that MyFactory is creating:

@Configuration
class MyFactory(@Qualifier("depA1") private val depA: DepA) {

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    fun myBean(depB: DepB, depC: DepC) = MyBean(depA, depB, depC)

    @Bean
    @Qualifier("depA1")
    fun depA() = DepA()

    @Bean
    fun depB() = DepB()

    @Bean
    fun depC() = DepC()
}

class MyBean(depA: DepA, depB: DepB, depC: DepC) {
}

class DepC {
}

class DepB {
}

class DepA {
}

While this code, and your second example, eliminates the cycle:

@Configuration
class MyFactory(@Qualifier("depA1") private val depA: DepA) {

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    fun myBean(depB: DepB, depC: DepC) = MyBean(depA, depB, depC)

    @Configuration
    class OtherFactory {

        @Bean
        @Qualifier("depA1")
        fun depA() = DepA()

        @Bean
        fun depB() = DepB()

        @Bean
        fun depC() = DepC()
    }
}

class MyBean(depA: DepA, depB: DepB, depC: DepC) {
}

class DepC {
}

class DepB {
}

class DepA {
}

Please share a complete app that we can run ourselves to reproduce the problem, with all of the beans (DepA, DepB, DepC, MyBean) declared and configured. You can share it with us by pushing it to a separate repository on GitHub or by zipping it and attaching it to this issue.

Comment From: CXwudi

I am pretty sure I won't make this easy mistake. Also, like I said this issue only exists on AOT app but not normal JVM app, so I am pretty sure something is wrong in the native compilation (but not sure if the issue comes from Spring Boot or GraalVM).

Anyway, let's take this project as a reproducible sample csi5137b-project.zip

This is a Spring Boot 3 project with Gradle 7.6, using GraalVM CE 22.3 Java 17.

Simply run ./gradlew :app:nativeCompile to get the native executable binary at app\build\native\nativeCompile\app.exe, then run that app.exe to see the UnsatisfiedDependencyException

Now, if we run ./gradlew :app:run, you won't see UnsatisfiedDependencyException

In this project, the myBean is dockerStatsObserver declared in scs.csi5137b.project.component.observer.CliObserverFactory (which is the MyFactory)

Comment From: scottfrederick

@CXwudi I wasn't implying that you would make such an easy mistake. My examples were intended to show that simple variations to configuration can behave very differently, so a sample of exactly what you are doing was necessary for us to help you.

I've simplified the provided sample, reducing it down to the minimal number of classes to reproduce the problem. The simplified sample is here: gh-33539-sample.zip

Comment From: CXwudi

Thanks for reducing the sample down and reporting it to the internal issue tracker. I am looking forward to the investigation result and the future release of Spring Boot 🙂

Comment From: snicoll

I am trying to run the sample but the build is failing for me with

> Could not resolve all task dependencies for configuration ':app:runtimeClasspath'.
   > Could not resolve com.github.CXwudi.jMetal:jmetal-algorithm:7525b46405.
     Required by:
         project :app
      > Could not resolve com.github.CXwudi.jMetal:jmetal-algorithm:7525b46405.
         > Could not get resource 'https://jitpack.io/com/github/CXwudi/jMetal/jmetal-algorithm/7525b46405/jmetal-algorithm-7525b46405.pom'.

Then fixing that there's a bunch of error for test in Kotlin. It would be nice if the sample wasn't involving all those parts. @CXwudi can you please look at it and clean it up?

Comment From: CXwudi

Hi @snicoll, thanks for replying me. I agree that the sample was too complicated (which involved a snapshot version of a dependency that no longer exists). I will try to reproduce the issue with minimal dependencies involved. However, the issue was created 10 months ago, so not sure if this issue still there.

I will let u know shortly

Comment From: CXwudi

Looks like this issue is no longer existing in Spring Boot 3.1.5. I can't reproduce this issue in Spring Boot 3.1.5, neither Windows or Linux, and neither Java nor Kotlin. The sample I used are: issue29709.zip issue29709 - Kotlin.zip

So I am closing this issue for now. If I found a similar issue I will create a new issue and link to this one

Comment From: snicoll

Thanks for the follow-up @CXwudi!

Comment From: tb8367085

spring boot 3.2.2 Does it not support aot?

2024-02-29 22:01:28.393 | WARN 16004 | main w.s.c.ServletWebServerApplicationContext | Exception encountered during context initialization - cancelling refresh attempt: org.springfra mework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dictDataServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference? 2024-02-29 22:01:28.393 | INFO 16004 | main c.b.d.d.DynamicRoutingDataSource | dynamic-datasource start closing .... 2024-02-29 22:01:28.393 | INFO 16004 | main c.b.d.d.DynamicRoutingDataSource | dynamic-datasource all closed success,bye 2024-02-29 22:01:28.393 | INFO 16004 | main o.apache.catalina.core.StandardService | Stopping service [Tomcat] 2024-02-29 22:01:28.394 | ERROR 16004 | main o.s.boot.SpringApplication | Application run failed

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dictDataServiceImpl': Requested bean is currently in creation: Is there an unresolvable circular reference? at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:355) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:227) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)

application.yaml: spring.main.allow-circular-references: true

Comment From: snicoll

@tb8367085 asking a question with minimal information like this is not actionable. If you think you've found an issue, please take the time to prepare a small sample that we can run ourselves (as you can see in the history of this very issue).