diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientBuilder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientBuilder.java index 213083dd..963c1d9f 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientBuilder.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientBuilder.java @@ -16,6 +16,7 @@ package org.springframework.cloud.openfeign; +import feign.Feign; import feign.hystrix.FallbackFactory; import org.springframework.context.ApplicationContext; @@ -28,6 +29,7 @@ import org.springframework.context.ApplicationContext; * * @author Sven Döring * @author Matt King + * @author Sam Kruglov */ public class FeignClientBuilder { @@ -69,6 +71,19 @@ public class FeignClientBuilder { return this; } + /** + * Applies a {@link FeignBuilderCustomizer} to the underlying {@link Feign.Builder}. + * May be called multiple times. + * + * @param customizer applied in the same order as supplied here + * after applying customizers found in the context. + * @return the {@link Builder} with the customizer added + */ + public Builder customize(final FeignBuilderCustomizer customizer) { + this.feignClientFactoryBean.addCustomizer(customizer); + return this; + } + public Builder contextId(final String contextId) { this.feignClientFactoryBean.setContextId(contextId); return this; diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java index 7647868c..620a3bad 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactoryBean.java @@ -17,6 +17,7 @@ package org.springframework.cloud.openfeign; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -64,6 +65,7 @@ import org.springframework.util.StringUtils; * @author Olga Maciaszek-Sharma * @author Ilia Ilinykh * @author Marcin Grzejszczak + * @author Sam Kruglov */ public class FeignClientFactoryBean implements FactoryBean, InitializingBean, ApplicationContextAware, BeanFactoryAware { @@ -103,6 +105,8 @@ public class FeignClientFactoryBean implements FactoryBean, Initializing private boolean followRedirects = new Request.Options().isFollowRedirects(); + private List additionalCustomizers = new ArrayList<>(); + @Override public void afterPropertiesSet() { Assert.hasText(contextId, "Context id must be set"); @@ -138,6 +142,7 @@ public class FeignClientFactoryBean implements FactoryBean, Initializing .forEach(feignBuilderCustomizer -> feignBuilderCustomizer .customize(builder)); } + additionalCustomizers.forEach(customizer -> customizer.customize(builder)); } protected void configureFeign(FeignContext context, Feign.Builder builder) { @@ -494,6 +499,10 @@ public class FeignClientFactoryBean implements FactoryBean, Initializing this.inheritParentContext = inheritParentContext; } + public void addCustomizer(FeignBuilderCustomizer customizer) { + additionalCustomizers.add(customizer); + } + public ApplicationContext getApplicationContext() { return applicationContext; } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignBuilderCustomizerTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignBuilderCustomizerTests.java index d66d3423..f240556b 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignBuilderCustomizerTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignBuilderCustomizerTests.java @@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Matt King + * @author Sam Kruglov */ public class FeignBuilderCustomizerTests { @@ -78,6 +79,24 @@ public class FeignBuilderCustomizerTests { context.close(); } + @Test + public void testBuildCustomizerOrderedWithAdditional() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + FeignBuilderCustomizerTests.SampleConfiguration3.class); + + FeignClientFactoryBean clientFactoryBean = context.getBean(FeignClientFactoryBean.class); + clientFactoryBean.addCustomizer(builder -> builder.logLevel(Logger.Level.BASIC)); + clientFactoryBean.addCustomizer(Feign.Builder::doNotCloseAfterDecode); + FeignContext feignContext = context.getBean(FeignContext.class); + + Feign.Builder builder = clientFactoryBean.feign(feignContext); + assertFeignBuilderField(builder, "logLevel", Logger.Level.BASIC); + assertFeignBuilderField(builder, "decode404", true); + assertFeignBuilderField(builder, "closeAfterDecode", false); + + context.close(); + } + private static FeignClientFactoryBean defaultFeignClientFactoryBean() { FeignClientFactoryBean feignClientFactoryBean = new FeignClientFactoryBean(); feignClientFactoryBean.setContextId("test"); diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientBuilderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientBuilderTests.java index b7ec76e4..ed4c58ba 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientBuilderTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientBuilderTests.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import feign.Feign; import feign.hystrix.FallbackFactory; import org.hamcrest.Matchers; import org.junit.Before; @@ -40,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Sven Döring + * @author Sam Kruglov */ public class FeignClientBuilderTests { @@ -56,10 +58,16 @@ public class FeignClientBuilderTests { return method.getDefaultValue(); } - private static void assertFactoryBeanField(final FeignClientBuilder.Builder builder, - final String fieldName, final Object expectedValue) { - final Field factoryBeanField = ReflectionUtils - .findField(FeignClientBuilder.Builder.class, "feignClientFactoryBean"); + private static void assertFactoryBeanField(final FeignClientBuilder.Builder builder, final String fieldName, + final Object expectedValue) { + final Object value = getFactoryBeanField(builder, fieldName); + assertThat(value).as("Expected value for the field '" + fieldName + "':").isEqualTo(expectedValue); + } + + @SuppressWarnings("unchecked") + private static T getFactoryBeanField(final FeignClientBuilder.Builder builder, final String fieldName) { + final Field factoryBeanField = ReflectionUtils.findField(FeignClientBuilder.Builder.class, + "feignClientFactoryBean"); ReflectionUtils.makeAccessible(factoryBeanField); final FeignClientFactoryBean factoryBean = (FeignClientFactoryBean) ReflectionUtils .getField(factoryBeanField, builder); @@ -67,9 +75,7 @@ public class FeignClientBuilderTests { final Field field = ReflectionUtils.findField(FeignClientFactoryBean.class, fieldName); ReflectionUtils.makeAccessible(field); - final Object value = ReflectionUtils.getField(field, factoryBean); - assertThat(value).as("Expected value for the field '" + fieldName + "':") - .isEqualTo(expectedValue); + return (T) ReflectionUtils.getField(field, factoryBean); } @Before @@ -131,7 +137,8 @@ public class FeignClientBuilderTests { .forType(TestFeignClient.class, "TestClient").inheritParentContext(false) .fallback(TestFeignClientFallback.class) .fallbackFactory(TestFeignClientFallbackFactory.class).decode404(true) - .url("Url/").path("/Path").contextId("TestContext"); + .url("Url/").path("/Path").contextId("TestContext") + .customize(Feign.Builder::doNotCloseAfterDecode);; // then: assertFactoryBeanField(builder, "applicationContext", this.applicationContext); @@ -147,6 +154,8 @@ public class FeignClientBuilderTests { assertFactoryBeanField(builder, "fallback", TestFeignClientFallback.class); assertFactoryBeanField(builder, "fallbackFactory", TestFeignClientFallbackFactory.class); + List additionalCustomizers = getFactoryBeanField(builder, "additionalCustomizers"); + assertThat(additionalCustomizers).hasSize(1); } @Test