Describe the bug
According to the documentation, in Feign 4.x, the attribute resolution mode was introduced. By default, when this mode is set to false, it can cause issues with other configuration files that use @ConditionalOnMissingBean and fail to correctly detect the already registered Feign beans.
This issue can be resolved by adjusting the attribute resolution mode or downgrade to Feign 3.x.
Sample
Here's a example:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@Import(EnableFeignConfig.class)
class MyAutoConfig {
@Bean("my-api")
@ConditionalOnMissingBean(MyApi.class)
MyApi noOp() {
return () -> {};
}
}
@ConditionalOnProperty(value = "enable.my.feign.client", matchIfMissing = true)
@ConditionalOnMissingBean(MyApi.class)
@EnableFeignClients(clients = MyFeignClient.class)
class EnableFeignConfig {
}
interface MyApi {
@GetMapping
void hello();
}
@FeignClient(value = "my-client",
url = "http://yet.another.app",
qualifiers = "my-api")
interface MyFeignClient extends MyApi {
}
In org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.example.demo.MyAutoConfig
During startup, the following error occurs:
Description:
The bean 'my-api', defined in class path resource [com/example/demo/MyAutoConfig.class], could not be registered. A bean with that name has already been defined and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
This scenario works fine with spring.cloud.openfeign.lazy-attributes-resolution=true. (works fine with spring-cloud-starter-openfeign 3.1.7 too)
After further digging into the source code, the issue might be related to the following section:
In the eagerlyRegisterFeignClientBeanDefinition(...) method (lazy-attributes-resolution=false), FeignClientFactoryBean.class is currently used as the beanClass.
However, in the lazilyRegisterFeignClientBeanDefinition(...) method (lazy-attributes-resolution=true), the registered class is used instead.
In the OnBeanCondition class, it seems that the allowEagerInit flag is consistently set to false when searching for already registered beans.
It is likely that this is the cause of the issue. during the application's startup phase, the Feign client bean is actually registered. However, when reaching the code that uses the @ConditionalOnMissingBean annotation, the bean cannot be found, resulting in a duplicate registration exception.
Comment From: OlgaMaciaszek
Thanks @shihyuho. Will need to take a look at. Have some other issues queued, so probably later in July.
Comment From: MelleD
Hey i also have an issue with the new feign creation in spring boot test. I would like to create the feign client after the webserver is started to use the random port (this worked in spring boot 2.7.x)
For spring boot 3 I tried to set spring.cloud.openfeign.lazy-attributes-resolution.
spring.cloud.openfeign.lazy-attributes-resolution=true
client.server=http://localhost:${local.server.port}
If I set a breakpoint into FeignClientFactoryBean#setUrl. After change the property from false to true the url looks correct and right. With 'false' the port is always 0.
So far so good I set the new property to true, BUT now I cannot create the feign clients:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'my.FeignApiClient': Unexpected exception during bean creation
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:533)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:711)
... 76 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.openfeign.FeignClientFactory' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:341)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:431)
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:421)
at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$lazilyRegisterFeignClientBeanDefinition$0(FeignClientsRegistrar.java:288)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1254)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1158)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
... 84 more
Is there maybe a workaround for the missing bean?
Comment From: OlgaMaciaszek
I will look at it in July.
Comment From: MelleD
I will look at it in July.
Then I'll hear you on Monday after a relaxing weekend :P
EDIT: Was there actually a release note or a reference to the new property in a migration guide?
Comment From: shihyuho
Hi @OlgaMaciaszek, Any updates so far?
Comment From: MelleD
Hey @OlgaMaciaszek,
do you have any updates for us?
Comment From: OlgaMaciaszek
Hi @shihyuho @MelleD, I'm sorry for the delay on this. I have it in my queue, but we needed to prioritise some tasks pertaining to the upcoming GA. I will look at it as soon as I'm done with those.
Comment From: MelleD
@OlgaMaciaszek thanks for the quick update
Comment From: MelleD
@OlgaMaciaszek any updates here :)?
Comment From: OlgaMaciaszek
@MelleD sorry for delays on this. We're planning for a GA release this week, so that's the current priority. I hope to be able to circle back to a lot of Spring Cloud OpenFeign issues in January and February of next year.
Comment From: shihyuho
@OlgaMaciaszek
update:
When I first reported this issue, I was using Spring Boot 3.1.2 and Spring Cloud 2022.0.3. Now, with the latest release of the Spring Boot 3.1.x (Spring Boot 3.1.7 and Spring Cloud 2022.0.4), the problem still exists. However, after updating to Spring Boot 3.2.x (Spring Boot 3.2.1 and Spring Cloud 2023.0.0), the issue has been resolved.
Comment From: OlgaMaciaszek
Thanks for the information @shihyuho. Since at this point only 4.1.x or higher versions will be in OSS support (https://spring.io/projects/spring-cloud-openfeign/#support), and the problem is not present on that version, I'm going to close this issue.