From 2acd353c7d2374006b687cecc1e365c7bd9ee898 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Mon, 14 Dec 2015 14:39:35 -0700 Subject: [PATCH] Allow Feign Hystrix support to be disabled. fixes gh-717 --- .../main/asciidoc/spring-cloud-netflix.adoc | 22 ++++++++++++++++++ .../netflix/feign/FeignClientFactoryBean.java | 2 +- .../feign/FeignClientsConfiguration.java | 23 +++++++++++++++++++ .../feign/EnableFeignClientsTests.java | 7 ++++++ .../FeignClientOverrideDefaultsTests.java | 13 +++++++++++ .../feign/valid/FeignHttpClientTests.java | 3 ++- 6 files changed, 68 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 7ea791e9..6ef71485 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -806,6 +806,7 @@ Spring Cloud Netflix provides the following beans by default for feign (`BeanTyp * `Encoder` feignEncoder: `SpringEncoder` * `Logger` feignLogger: `Slf4jLogger` * `Contract` feignContract: `SpringMvcContract` +* `Feign.Builder` feignBuilder: `HystrixFeign.Builder` Spring Cloud Netflix _does not_ provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client: @@ -837,6 +838,27 @@ This replaces the `SpringMvcContract` with `feign.Contract.Default` and adds a ` Default configurations can be specified in the `@EnableFeignClients` attribute `defaultConfiguration` in a similar manner as described above. The difference is that this configuration will apply to _all_ feign clients. +[[spring-cloud-feign-hystrix]] +=== Feign Hystrix Support + +If Hystrix is on the classpath, by default Feign will wrap all methods with a circuit breaker. Returning a `com.netflix.hystrix.HystrixCommand` is also available. This lets you use reactive patterns (with a call to `.toObservable()` or `.observe()` or asynchronous use (with a call to `.queue()`). + +To disable Hystrix support for Feign, set `feign.hystrix.enabled=false`. + +To disable Hystrix support on a per-client basis create a vanilla `Feign.Builder` with the "prototype" scope, e.g.: + +[source,java,indent=0] +---- +@Configuration +public class FooConfiguration { + @Bean + @Scope("prototype") + public Feign.Builder feignBuilder() { + return Feign.builder(); + } +} +---- + [[spring-cloud-feign-inheritance]] === Feign Inheritance Support diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java index 67e651a4..0505bda1 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java @@ -75,7 +75,7 @@ class FeignClientFactoryBean implements FactoryBean, InitializingBean, A } // @formatter:off - Feign.Builder builder = HystrixFeign.builder() + Feign.Builder builder = get(factory, Feign.Builder.class) // required values .logger(logger) .encoder(get(factory, Encoder.class)) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsConfiguration.java index 95346280..87ebb78f 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsConfiguration.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder; import org.springframework.cloud.netflix.feign.support.SpringDecoder; @@ -31,12 +32,17 @@ import org.springframework.cloud.netflix.feign.support.SpringEncoder; import org.springframework.cloud.netflix.feign.support.SpringMvcContract; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import com.netflix.hystrix.HystrixCommand; import feign.Client; import feign.Contract; +import feign.Feign; import feign.codec.Decoder; import feign.codec.Encoder; import feign.httpclient.ApacheHttpClient; +import feign.hystrix.HystrixFeign; /** * @author Dave Syer @@ -68,6 +74,23 @@ public class FeignClientsConfiguration { return new SpringMvcContract(parameterProcessors); } + @Bean + @Scope("prototype") + @ConditionalOnMissingBean + @ConditionalOnClass(HystrixCommand.class) + @ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = true) + public Feign.Builder feignHystrixBuilder() { + return HystrixFeign.builder(); + } + + @Bean + @Scope("prototype") + @ConditionalOnMissingBean + @ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = false, havingValue = "false") + public Feign.Builder feignBuilder() { + return Feign.builder(); + } + @Configuration @ConditionalOnClass(ApacheHttpClient.class) protected static class HttpClientConfiguration { diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/EnableFeignClientsTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/EnableFeignClientsTests.java index ccc7a610..45ab4536 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/EnableFeignClientsTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/EnableFeignClientsTests.java @@ -17,9 +17,11 @@ package org.springframework.cloud.netflix.feign; import feign.Contract; +import feign.Feign; import feign.Logger; import feign.codec.Decoder; import feign.codec.Encoder; +import feign.hystrix.HystrixFeign; import feign.slf4j.Slf4jLogger; import org.junit.Test; import org.junit.runner.RunWith; @@ -70,6 +72,11 @@ public class EnableFeignClientsTests { SpringMvcContract.class.cast(this.factory.getInstance("foo", Contract.class)); } + @Test + public void builderDefaultCorrect() { + HystrixFeign.Builder.class.cast(this.factory.getInstance("foo", Feign.Builder.class)); + } + @Configuration @Import({ PropertyPlaceholderAutoConfiguration.class, ArchaiusAutoConfiguration.class, FeignAutoConfiguration.class }) diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/FeignClientOverrideDefaultsTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/FeignClientOverrideDefaultsTests.java index 10afcec7..64d4d7fa 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/FeignClientOverrideDefaultsTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/FeignClientOverrideDefaultsTests.java @@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.feign; import static org.junit.Assert.*; import feign.Contract; +import feign.Feign; import feign.Logger; import feign.Request; import feign.RequestInterceptor; @@ -27,6 +28,7 @@ import feign.auth.BasicAuthRequestInterceptor; import feign.codec.Decoder; import feign.codec.Encoder; import feign.codec.ErrorDecoder; +import feign.hystrix.HystrixFeign; import feign.slf4j.Slf4jLogger; import org.junit.Test; import org.junit.runner.RunWith; @@ -97,6 +99,12 @@ public class FeignClientOverrideDefaultsTests { ErrorDecoder.Default.class.cast(factory.getInstance("bar", ErrorDecoder.class)); } + @Test + public void overrideBuilder() { + Feign.Builder.class.cast(factory.getInstance("foo", Feign.Builder.class)); + HystrixFeign.Builder.class.cast(factory.getInstance("bar", Feign.Builder.class)); + } + @Test public void overrideRequestOptions() { assertNull(factory.getInstance("foo", Request.Options.class)); @@ -145,6 +153,11 @@ public class FeignClientOverrideDefaultsTests { public Contract feignContract() { return new Contract.Default(); } + + @Bean + public Feign.Builder feignBuilder() { + return Feign.builder(); + } } @FeignClient(value = "bar", configuration = BarConfiguration.class) diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignHttpClientTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignHttpClientTests.java index be5f4b25..0c5e486a 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignHttpClientTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignHttpClientTests.java @@ -62,7 +62,8 @@ import lombok.NoArgsConstructor; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = FeignHttpClientTests.Application.class) @WebAppConfiguration -@IntegrationTest({ "server.port=0", "spring.application.name=feignclienttest" }) +@IntegrationTest({ "server.port=0", "spring.application.name=feignclienttest", + "feign.hystrix.enabled=false" }) @DirtiesContext public class FeignHttpClientTests {