Feign client with custom Configuration (custom RequestInterceptor) picking up another client Configuration (RequestInterceptor)
See original GitHub issueHi,
This seems to be a bug, given that this is suppose to be supported as of #288.
I am currently using Spring Boot 2.0.0.RC2 with Spring Cloud Finchley.M7.
I have two Feign clients, each with a custom Feign Configuration class adding a custom RequestInterceptor. One RequestInterceptor adds a header for auth and another is an expensive one because it does all the OAuth2 Authorization Code flow.
@FeignClient(name = "gAuthifyApiClient", url = "{gAuthifyUrl}", configuration = GAuthifyApiClient.FeignClientConfiguration.class, decode404 = true)
public interface GAuthifyApiClient {
...
@Configuration("gAuthifyFeignClientConfiguration")
class FeignClientConfiguration {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor(@Value("${gauthify.api.key}") String apiKey) {
return new BasicAuthRequestInterceptor("", apiKey);
}
}
...
}
@FeignClient(name = "profileIdApiClient", url = "{profileIdUrl}", configuration = ProfileIdApiClient.FeignClientConfiguration.class, decode404 = true)
public interface ProfileIdApiClient {
...
@Configuration("profileIdFeignClientConfiguration")
class FeignClientConfiguration {
@Bean
public BearerHeaderAuthRequestInterceptor bearerHeaderAuthRequestInterceptor() {
return new BearerHeaderAuthRequestInterceptor();
}
}
...
class BearerHeaderAuthRequestInterceptor implements RequestInterceptor {
//Expensive OAuth2 flow logic
}
...
}
The problem is that the client that uses the former (header auth) is picking up both interceptors. Hence, when using the first client, both interceptors are triggered.
I did some debugging and it seems it has to do with the hierarchical nature of the FactoryBean used to search for RequestInterceptors for the named factory bean.
More specifically…
FeignClientFactoryBean.configureUsingConfiguration(...) {
...
Map<String, RequestInterceptor> requestInterceptors = **context.getInstances**(this.name, RequestInterceptor.class);
...
}
NamedContextFactory.**getInstances**(String name, Class<T> type) {
AnnotationConfigApplicationContext context = getContext(name);
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) {
return **BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);**
}
return null;
}
**BeanFactoryUtils.beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<T> type)**
throws BeansException {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
Map<String, T> result = new LinkedHashMap<>(4);
result.putAll(lbf.getBeansOfType(type));
**if (lbf instanceof HierarchicalBeanFactory)** {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
Map<String, T> parentResult = beansOfTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type);
parentResult.forEach((beanName, beanType) -> {
if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {
result.put(beanName, beanType);
}
});
}
}
return result;
}
Any ideas? Is this already supported in the specified version?
Thanks in advance!
Issue Analytics
- State:
- Created 6 years ago
- Comments:7 (1 by maintainers)
Can you try removing the
@Configuration
annotations? They are not necessary. http://cloud.spring.io/spring-cloud-static/Edgware.SR2/single/spring-cloud.html#spring-cloud-feign-overriding-defaultsAlso as an FYI the Feign code has been moved to its own top level project, so future Feign specific issues should be opened in https://github.com/spring-cloud/spring-cloud-openfeign
Hi.
I can tell you what it worked for me…
My Application
Notice that
SpringBootApplication
contains aComponentScan.excludeFilters
.Feign client
I would try removing the
@ComponentScan.excludeFilters
and adding both annotations,@SpringBootApplication
and@EnableFeignClients
.As a side note, I would suggest renaming
ReportExportInterceptor
toConfiguration
, as it is a configuration class that configures anRequestInterceptor
.Hope it helps. Please let me know how it went.
Bests