Feign client with custom Configuration (custom RequestInterceptor) picking up another client Configuration (RequestInterceptor)

See original GitHub issue

Hi,

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:closed
  • Created 6 years ago
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
ryanjbaxtercommented, Feb 28, 2018

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-defaults

Also 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

1reaction
cebbenscommented, Oct 17, 2018

Hi.

I can tell you what it worked for me…

My Application

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

Notice that SpringBootApplication contains a ComponentScan.excludeFilters.

Feign client

@FeignClient(name = "acmeApiClient", url = "${acme.api.url}", configuration = AcmeApiClient.Configuration.class)
public interface AcmeApiClient {

    @GetMapping("/users")
    ResponseEntity getUsers();

    class Configuration {
        @Bean
        public BasicAuthRequestInterceptor basicAuthRequestInterceptor(@Value("${acme.api.key}") String apiKey) {
            return new BasicAuthRequestInterceptor("", apiKey);
        }
    }

I would try removing the @ComponentScan.excludeFilters and adding both annotations, @SpringBootApplication and @EnableFeignClients.

As a side note, I would suggest renaming ReportExportInterceptor to Configuration, as it is a configuration class that configures an RequestInterceptor.

Hope it helps. Please let me know how it went.

Bests

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to set a custom Feign RequestInterceptor for specific ...
With this assignment, each FeignClient has its own configuration and RequestInterceptor doesn't deal with other clients.
Read more >
Multiple Configurations for Feign Clients - Amir Shokri - Medium
We have two Feign clients for two services, FooClient and BarClient. These Feign clients need to adopt different authentication configuration.
Read more >
Setting Up Multiple Configurations for Feign Clients [A Step-by ...
We have two Feign clients for two services, FooClient and BarClient. These Feign clients need to adopt different authentication configuration.
Read more >
Feign RequestInterceptor in Spring Boot - JavaCodeMonk
All we need to do is to create a Bean of type RequestInterceptor inside a config class and provide that configuration to FeignClient....
Read more >
Configure Feign Client in Spring Boot - Coding N Concepts
Enable Feign Client; Create Feign Client; Feign Client Configuration. From Property file; From Configuration Class file; Request Interceptor ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found