Describe the bug
I have an application where a bean that implements ApplicationListener<ApplicationContextEvent> depends on a feign client. The application fails to start because Spring thinks there is a dependency cycle. Debugging shows that this is due to AbstractApplicationContext.refresh() being called during creation of the feign client bean.
spring-cloud version is Hoxton.SR1, spring-boot version is 2.2.4.RELEASE.
Sample Here's a simple application that shows the problem. I created a Kotlin app using Spring Initalizr with only OpenFeign selected as a dependency, then changed the DemoApplication.kt as follows:
package com.example.demo
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cloud.openfeign.EnableFeignClients
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.context.ApplicationListener
import org.springframework.context.annotation.Configuration
import org.springframework.context.event.ApplicationContextEvent
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
@SpringBootApplication
@EnableFeignClients
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
@FeignClient(name = "myFeignClient")
interface MyFeignClient {
@RequestMapping(method = [RequestMethod.POST])
fun hello(): String
}
@Configuration
class MyApplicationListener(private val myFeignClient: MyFeignClient) : ApplicationListener<ApplicationContextEvent> {
override fun onApplicationEvent(event: ApplicationContextEvent) {
println("ApplicationEvent: $event")
}
}
The application fails to start, saying:
2020-02-03 15:21:38.365 WARN 81421 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'myApplicationListener': Requested bean is currently in creation: Is there an unresolvable circular reference?
2020-02-03 15:22:02.452 WARN 81421 --- [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myApplicationListener' defined in file [.../target/classes/com/example/demo/MyApplicationListener.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.demo.MyFeignClient': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'myApplicationListener': Requested bean is currently in creation: Is there an unresolvable circular reference?
2020-02-03 15:22:02.464 INFO 81421 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-02-03 15:22:02.480 ERROR 81421 --- [ 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:
┌─────┐
| myApplicationListener defined in file [.../target/classes/com/example/demo/MyApplicationListener.class]
↑ ↓
| com.example.demo.MyFeignClient
└─────┘
Comment From: spencergibb
Inject an ObjectProvider<MyFeignClient>
Comment From: lbilger
Ah, I see this is in the docs of the latest Snapshot but not yet in the GA docs. Thanks!
I had tried adding the @Lazy annotation to the client, but that didn't work. Now I see that adding @Lazy to the injection point works as well - i guess it does more or less the same as using an ObjectProvider but hides it behind a proxy.
Comment From: wylswz
Why does ObjectProvider resolve this issue?
Comment From: lbilger
It breaks up the dependency cycle, you could say. Using ObjectProvider or the Lazy annotation will give Spring a chance to initialize the object only when it‘s used, not when it’s injected.
Comment From: wylswz
it looks like feign client depends on ApplicationListerners, but I cannot find that declaration