From 08f7076f6e6863516d956ce27c3f582f788d0330 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 16 Mar 2016 17:01:45 -0600 Subject: [PATCH] Mark @FeignClient beans as primary. When fallback beans are created, there was no longer a unique bean of the feign interface which caused autowire problems. fixes gh-899 --- .../main/asciidoc/spring-cloud-netflix.adoc | 2 +- .../netflix/feign/FeignClientsRegistrar.java | 10 ++++++--- .../netflix/feign/valid/FeignClientTests.java | 21 ++++++++++++++----- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index ed75b158..6e3ae0f0 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -789,7 +789,7 @@ In the `@FeignClient` annotation the String value ("stores" above) is an arbitrary client name, which is used to create a Ribbon load balancer (see <>). You can also specify a URL using the `url` attribute -(absolute value or just a hostname). +(absolute value or just a hostname). The name of the bean in the application context is the fully qualified name of the interface. An alias is also created which is the 'name' attribute plus 'FeignClient'. For the example above, `@Qualifier("storesFeignClient")` could be used to reference the bean. The Ribbon client above will want to discover the physical addresses for the "stores" service. If your application is a Eureka client then diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java index 79c7f1fb..d100810e 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java @@ -171,14 +171,18 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); definition.addPropertyValue("url", getUrl(attributes)); - definition.addPropertyValue("name", getServiceId(attributes)); + String name = getName(attributes); + definition.addPropertyValue("name", name); definition.addPropertyValue("type", className); definition.addPropertyValue("decode404", attributes.get("decode404")); definition.addPropertyValue("fallback", attributes.get("fallback")); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + String alias = name + "FeignClient"; + AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); + beanDefinition.setPrimary(true); BeanDefinitionHolder holder = new BeanDefinitionHolder( - definition.getBeanDefinition(), className); + beanDefinition, className, new String[]{alias}); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); } @@ -189,7 +193,7 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, } } - private String getServiceId(Map attributes) { + private String getName(Map attributes) { String name = (String) attributes.get("serviceId"); if (!StringUtils.hasText(name)) { name = (String) attributes.get("name"); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java index 5d464563..a7b3c280 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java @@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -115,6 +116,10 @@ public class FeignClientTests { @Autowired HystrixClient hystrixClient; + @Autowired + @Qualifier("localapp3FeignClient") + HystrixClient namedHystrixClient; + protected enum Arg { A, B; @@ -270,6 +275,12 @@ public class FeignClientTests { }) protected static class Application { + // needs to be in parent context to test multiple HystrixClient beans + @Bean + public HystrixClientFallback hystrixClientFallback() { + return new HystrixClientFallback(); + } + @Bean FeignFormatterRegistrar feignFormatterRegistrar() { return new FeignFormatterRegistrar() { @@ -543,6 +554,11 @@ public class FeignClientTests { assertEquals("message was wrong", "fallbackfuture", hello.getMessage()); } + @Test + public void namedFeignClientWorks() { + assertNotNull("namedHystrixClient was null", this.namedHystrixClient); + } + @Data @AllArgsConstructor @NoArgsConstructor @@ -556,11 +572,6 @@ public class FeignClientTests { Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } - - @Bean - public HystrixClientFallback hystrixClientFallback() { - return new HystrixClientFallback(); - } } // Load balancer with fixed server list for "local" pointing to localhost