diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java index 0854132ec..a143eb2d2 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientFactory.java @@ -44,21 +44,21 @@ public FeignClientFactory() { } public FeignClientFactory( - Map> applicationContextInitializers) { + Map> applicationContextInitializers) { super(FeignClientsConfiguration.class, "spring.cloud.openfeign", "spring.cloud.openfeign.client.name", - applicationContextInitializers); + applicationContextInitializers); } public @Nullable T getInstanceWithoutAncestors(String name, Class type) { try { return BeanFactoryUtils.beanOfType(getContext(name), type); - } - catch (BeansException ex) { + } catch (BeansException ex) { return null; } } - @Nullable public Map getInstancesWithoutAncestors(String name, Class type) { + @Nullable + public Map getInstancesWithoutAncestors(String name, Class type) { return getContext(name).getBeansOfType(type); } @@ -71,8 +71,8 @@ public FeignClientFactory withApplicationContextInitializers(Map Map> convertedInitializers = new HashMap<>(); applicationContextInitializers.keySet() .forEach(contextId -> convertedInitializers.put(contextId, - (ApplicationContextInitializer) applicationContextInitializers - .get(contextId))); + (ApplicationContextInitializer) applicationContextInitializers + .get(contextId))); return new FeignClientFactory(convertedInitializers); } 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 2e2183c53..17ae406d2 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 @@ -59,6 +59,39 @@ import org.springframework.util.StringUtils; /** + * A {@link FactoryBean} responsible for creating Feign client proxies. + * + *

Note: Custom {@link Client} beans provided in a Feign client + * context should be singleton-scoped. Defining a prototype-scoped {@code Client} + * may lead to multiple underlying HTTP connection pools being created, which + * can result in resource exhaustion. + * + * @author Spencer Gibb + * @author Venil Noronha + * @author Eko Kurniawan Khannedy + * @author Gregor Zurowski + * @author Matt King + * @author Olga Maciaszek-Sharma + * @author Ilia Ilinykh + * @author Marcin Grzejszczak + * @author Jonatan Ivanov + * @author Sam Kruglov + * @author Jasbir Singh + * @author Hyeonmin Park + * @author Felix Dittrich + * @author Dominique Villard + * @author Can Bezmen + */ + +/** + * A {@link FactoryBean} responsible for creating Feign client proxies. + * + *

+ * Note: Custom {@link Client} beans provided in a Feign client context + * should be singleton-scoped. Defining a prototype-scoped {@code Client} may lead to + * multiple underlying HTTP connection pools being created, which can result in resource + * exhaustion. + * * @author Spencer Gibb * @author Venil Noronha * @author Eko Kurniawan Khannedy @@ -76,7 +109,7 @@ * @author Can Bezmen */ public class FeignClientFactoryBean - implements FactoryBean, InitializingBean, ApplicationContextAware, BeanFactoryAware { + implements FactoryBean, InitializingBean, ApplicationContextAware, BeanFactoryAware { /*********************************** * WARNING! Nothing in this class should be @Autowired. It causes NPEs because of some @@ -117,7 +150,7 @@ public class FeignClientFactoryBean private final List additionalCustomizers = new ArrayList<>(); - private String[] qualifiers = new String[] {}; + private String[] qualifiers = new String[]{}; // For AOT testing public FeignClientFactoryBean() { @@ -152,7 +185,7 @@ protected Feign.Builder feign(FeignClientFactory context) { private void applyBuildCustomizers(FeignClientFactory context, Feign.Builder builder) { Map customizerMap = context.getInstances(contextId, - FeignBuilderCustomizer.class); + FeignBuilderCustomizer.class); if (customizerMap != null) { customizerMap.values() @@ -165,7 +198,7 @@ private void applyBuildCustomizers(FeignClientFactory context, Feign.Builder bui protected void configureFeign(FeignClientFactory context, Feign.Builder builder) { FeignClientProperties properties = beanFactory != null ? beanFactory.getBean(FeignClientProperties.class) - : applicationContext.getBean(FeignClientProperties.class); + : applicationContext.getBean(FeignClientProperties.class); FeignClientConfigurer feignClientConfigurer = getOptional(context, FeignClientConfigurer.class); setInheritParentContext(feignClientConfigurer.inheritParentConfiguration()); @@ -174,17 +207,15 @@ protected void configureFeign(FeignClientFactory context, Feign.Builder builder) if (properties.isDefaultToProperties()) { configureUsingConfiguration(context, builder); configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), - properties.getConfig().get(contextId), builder); - } - else { + properties.getConfig().get(contextId), builder); + } else { configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()), - properties.getConfig().get(contextId), builder); + properties.getConfig().get(contextId), builder); configureUsingConfiguration(context, builder); } configureDefaultRequestElements(properties.getConfig().get(properties.getDefaultConfig()), - properties.getConfig().get(contextId), builder); - } - else { + properties.getConfig().get(contextId), builder); + } else { configureUsingConfiguration(context, builder); } } @@ -201,8 +232,7 @@ protected void configureUsingConfiguration(FeignClientFactory context, Feign.Bui ErrorDecoder errorDecoder = getInheritedAwareOptional(context, ErrorDecoder.class); if (errorDecoder != null) { builder.errorDecoder(errorDecoder); - } - else { + } else { FeignErrorDecoderFactory errorDecoderFactory = getOptional(context, FeignErrorDecoderFactory.class); if (errorDecoderFactory != null) { ErrorDecoder factoryErrorDecoder = errorDecoderFactory.create(type); @@ -221,7 +251,7 @@ protected void configureUsingConfiguration(FeignClientFactory context, Feign.Bui followRedirects = options.isFollowRedirects(); } Map requestInterceptors = getInheritedAwareInstances(context, - RequestInterceptor.class); + RequestInterceptor.class); if (requestInterceptors != null) { List interceptors = new ArrayList<>(requestInterceptors.values()); AnnotationAwareOrderComparator.sort(interceptors); @@ -239,7 +269,7 @@ protected void configureUsingConfiguration(FeignClientFactory context, Feign.Bui builder.dismiss404(); } ExceptionPropagationPolicy exceptionPropagationPolicy = getInheritedAwareOptional(context, - ExceptionPropagationPolicy.class); + ExceptionPropagationPolicy.class); if (exceptionPropagationPolicy != null) { builder.exceptionPropagationPolicy(exceptionPropagationPolicy); } @@ -254,11 +284,11 @@ protected void configureUsingConfiguration(FeignClientFactory context, Feign.Bui } protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration baseConfig, - FeignClientProperties.FeignClientConfiguration finalConfig, Feign.Builder builder) { + FeignClientProperties.FeignClientConfiguration finalConfig, Feign.Builder builder) { configureUsingProperties(baseConfig, builder); configureUsingProperties(finalConfig, builder); Boolean dismiss404 = finalConfig != null && finalConfig.getDismiss404() != null ? finalConfig.getDismiss404() - : (baseConfig != null && baseConfig.getDismiss404() != null ? baseConfig.getDismiss404() : null); + : (baseConfig != null && baseConfig.getDismiss404() != null ? baseConfig.getDismiss404() : null); if (dismiss404 != null) { if (dismiss404) { builder.dismiss404(); @@ -267,7 +297,7 @@ protected void configureUsingProperties(FeignClientProperties.FeignClientConfigu } protected void configureUsingProperties(FeignClientProperties.FeignClientConfiguration config, - Feign.Builder builder) { + Feign.Builder builder) { if (config == null) { return; } @@ -278,12 +308,12 @@ protected void configureUsingProperties(FeignClientProperties.FeignClientConfigu if (!refreshableClient) { connectTimeoutMillis = config.getConnectTimeout() != null ? config.getConnectTimeout() - : connectTimeoutMillis; + : connectTimeoutMillis; readTimeoutMillis = config.getReadTimeout() != null ? config.getReadTimeout() : readTimeoutMillis; followRedirects = config.isFollowRedirects() != null ? config.isFollowRedirects() : followRedirects; builder.options(new Request.Options(connectTimeoutMillis, TimeUnit.MILLISECONDS, readTimeoutMillis, - TimeUnit.MILLISECONDS, followRedirects)); + TimeUnit.MILLISECONDS, followRedirects)); } if (config.getRetryer() != null) { @@ -334,7 +364,7 @@ protected void configureUsingProperties(FeignClientProperties.FeignClientConfigu } protected void configureDefaultRequestElements(FeignClientProperties.FeignClientConfiguration defaultConfig, - FeignClientProperties.FeignClientConfiguration clientConfig, Feign.Builder builder) { + FeignClientProperties.FeignClientConfiguration clientConfig, Feign.Builder builder) { Map> defaultRequestHeaders = new HashMap<>(); if (defaultConfig != null) { defaultConfig.getDefaultRequestHeaders() @@ -374,7 +404,7 @@ private void addDefaultQueryParams(Map> defaultQueryP } private void addDefaultRequestHeaders(Map> defaultRequestHeaders, - Feign.Builder builder) { + Feign.Builder builder) { builder.requestInterceptor(requestTemplate -> { Map> headers = requestTemplate.headers(); defaultRequestHeaders.keySet().forEach(key -> { @@ -388,8 +418,7 @@ private void addDefaultRequestHeaders(Map> defaultReq private T getOrInstantiate(Class tClass) { try { return beanFactory != null ? beanFactory.getBean(tClass) : applicationContext.getBean(tClass); - } - catch (NoSuchBeanDefinitionException e) { + } catch (NoSuchBeanDefinitionException e) { return BeanUtils.instantiateClass(tClass); } } @@ -409,8 +438,7 @@ protected T getOptional(FeignClientFactory context, Class type) { protected T getInheritedAwareOptional(FeignClientFactory context, Class type) { if (inheritParentContext) { return getOptional(context, type); - } - else { + } else { return context.getInstanceWithoutAncestors(contextId, type); } } @@ -418,8 +446,7 @@ protected T getInheritedAwareOptional(FeignClientFactory context, Class t protected Map getInheritedAwareInstances(FeignClientFactory context, Class type) { if (inheritParentContext) { return context.getInstances(contextId, type); - } - else { + } else { return context.getInstancesWithoutAncestors(contextId, type); } } @@ -434,19 +461,20 @@ protected T loadBalance(Feign.Builder builder, FeignClientFactory context, H } throw new IllegalStateException( - "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?"); + "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?"); } /** * Meant to get Options bean from context with bean name. - * @param context context of Feign client + * + * @param context context of Feign client * @param contextId name of feign client * @return returns Options found in context */ protected Request.Options getOptionsByName(FeignClientFactory context, String contextId) { if (refreshableClient) { return context.getInstance(contextId, Request.Options.class.getCanonicalName() + "-" + contextId, - Request.Options.class); + Request.Options.class); } return null; } @@ -464,43 +492,63 @@ public Object getObject() { @SuppressWarnings("unchecked") T getTarget() { FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class) - : applicationContext.getBean(FeignClientFactory.class); + : applicationContext.getBean(FeignClientFactory.class); + Feign.Builder builder = feign(feignClientFactory); + if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) { if (LOG.isInfoEnabled()) { LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing."); } + if (!name.startsWith("http://") && !name.startsWith("https://")) { url = "http://" + name; - } - else { + } else { url = name; } + url += cleanPath(); return (T) loadBalance(builder, feignClientFactory, new HardCodedTarget<>(type, name, url)); } + if (StringUtils.hasText(url) && !url.startsWith("http://") && !url.startsWith("https://")) { url = "http://" + url; } + Client client = getOptional(feignClientFactory, Client.class); + if (client != null) { + + try { + Map clients = feignClientFactory.getInstances(contextId, Client.class); + + if (clients != null && clients.size() > 1) { + LOG.warn("Multiple Feign Client beans detected for contextId '" + contextId + + "'. Custom Client beans should typically be singleton-scoped " + + "to avoid multiple underlying connection pools."); + } + } catch (Exception ex) { + if (LOG.isDebugEnabled()) { + LOG.debug("Unable to inspect Feign Client beans for contextId '" + contextId + "'", ex); + } + } + if (client instanceof FeignBlockingLoadBalancerClient) { - // not load balancing because we have a url, - // but Spring Cloud LoadBalancer is on the classpath, so unwrap client = ((FeignBlockingLoadBalancerClient) client).getDelegate(); } + if (client instanceof RetryableFeignBlockingLoadBalancerClient) { - // not load balancing because we have a url, - // but Spring Cloud LoadBalancer is on the classpath, so unwrap client = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate(); } + builder.client(client); } applyBuildCustomizers(feignClientFactory, builder); Targeter targeter = get(feignClientFactory, Targeter.class); + return targeter.target(this, builder, feignClientFactory, resolveTarget(feignClientFactory, contextId, url)); } @@ -520,7 +568,7 @@ private String cleanPath() { return path; } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) private HardCodedTarget resolveTarget(FeignClientFactory context, String contextId, String url) { if (StringUtils.hasText(url)) { return new HardCodedTarget(type, name, url + cleanPath()); @@ -528,7 +576,7 @@ private HardCodedTarget resolveTarget(FeignClientFactory context, String if (refreshableClient) { RefreshableUrl refreshableUrl = context.getInstance(contextId, - RefreshableUrl.class.getCanonicalName() + "-" + contextId, RefreshableUrl.class); + RefreshableUrl.class.getCanonicalName() + "-" + contextId, RefreshableUrl.class); if (Objects.nonNull(refreshableUrl) && StringUtils.hasText(refreshableUrl.getUrl())) { return new RefreshableHardCodedTarget<>(type, name, refreshableUrl, cleanPath()); } @@ -536,7 +584,7 @@ private HardCodedTarget resolveTarget(FeignClientFactory context, String FeignClientProperties.FeignClientConfiguration config = findConfigByKey(contextId); if (Objects.isNull(config) || !StringUtils.hasText(config.getUrl())) { throw new IllegalStateException( - "Provide Feign client URL either in @FeignClient() or in config properties."); + "Provide Feign client URL either in @FeignClient() or in config properties."); } return new PropertyBasedTarget(type, name, config, cleanPath()); @@ -549,7 +597,7 @@ private boolean isUrlAvailableInConfig(String contextId) { private FeignClientProperties.FeignClientConfiguration findConfigByKey(String configKey) { FeignClientProperties properties = beanFactory != null ? beanFactory.getBean(FeignClientProperties.class) - : applicationContext.getBean(FeignClientProperties.class); + : applicationContext.getBean(FeignClientProperties.class); return properties.getConfig().get(configKey); } @@ -671,21 +719,21 @@ public boolean equals(Object o) { } FeignClientFactoryBean that = (FeignClientFactoryBean) o; return Objects.equals(applicationContext, that.applicationContext) - && Objects.equals(beanFactory, that.beanFactory) && dismiss404 == that.dismiss404 - && inheritParentContext == that.inheritParentContext && Objects.equals(fallback, that.fallback) - && Objects.equals(fallbackFactory, that.fallbackFactory) && Objects.equals(name, that.name) - && Objects.equals(path, that.path) && Objects.equals(type, that.type) && Objects.equals(url, that.url) - && Objects.equals(connectTimeoutMillis, that.connectTimeoutMillis) - && Objects.equals(readTimeoutMillis, that.readTimeoutMillis) - && Objects.equals(followRedirects, that.followRedirects) - && Objects.equals(refreshableClient, that.refreshableClient); + && Objects.equals(beanFactory, that.beanFactory) && dismiss404 == that.dismiss404 + && inheritParentContext == that.inheritParentContext && Objects.equals(fallback, that.fallback) + && Objects.equals(fallbackFactory, that.fallbackFactory) && Objects.equals(name, that.name) + && Objects.equals(path, that.path) && Objects.equals(type, that.type) && Objects.equals(url, that.url) + && Objects.equals(connectTimeoutMillis, that.connectTimeoutMillis) + && Objects.equals(readTimeoutMillis, that.readTimeoutMillis) + && Objects.equals(followRedirects, that.followRedirects) + && Objects.equals(refreshableClient, that.refreshableClient); } @Override public int hashCode() { return Objects.hash(applicationContext, beanFactory, dismiss404, inheritParentContext, fallback, - fallbackFactory, name, path, type, url, readTimeoutMillis, connectTimeoutMillis, followRedirects, - refreshableClient); + fallbackFactory, name, path, type, url, readTimeoutMillis, connectTimeoutMillis, followRedirects, + refreshableClient); } @Override diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java index 5a31b1c18..c54672579 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignClientsRegistrar.java @@ -86,7 +86,7 @@ static void validateFallback(final Class clazz) { static void validateFallbackFactory(final Class clazz) { Assert.isTrue(!clazz.isInterface(), "Fallback factory must produce instances " - + "of fallback classes that implement the interface annotated by @FeignClient"); + + "of fallback classes that implement the interface annotated by @FeignClient"); } static String getName(String name) { @@ -99,14 +99,12 @@ static String getName(String name) { String url; if (!name.startsWith("http://") && !name.startsWith("https://")) { url = "http://" + name; - } - else { + } else { url = name; } host = new URI(url).getHost(); - } - catch (URISyntaxException ignored) { + } catch (URISyntaxException ignored) { } Assert.state(host != null, "Service id not legal hostname (" + name + ")"); return name; @@ -122,8 +120,7 @@ static String getUrl(String url) { } try { new URI(url); - } - catch (URISyntaxException e) { + } catch (URISyntaxException e) { throw new IllegalArgumentException(url + " is malformed", e); } } @@ -161,8 +158,7 @@ private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefin String name; if (metadata.hasEnclosingClass()) { name = "default." + metadata.getEnclosingClassName(); - } - else { + } else { name = "default." + metadata.getClassName(); } registerClientConfiguration(registry, name, "default", defaultAttrs.get("defaultConfiguration")); @@ -181,8 +177,7 @@ public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegi for (String basePackage : basePackages) { candidateComponents.addAll(scanner.findCandidateComponents(basePackage)); } - } - else { + } else { for (Class clazz : clients) { candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz)); } @@ -207,20 +202,19 @@ public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegi } private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, - Map attributes) { + Map attributes) { String className = annotationMetadata.getClassName(); if (String.valueOf(false) .equals(environment.getProperty("spring.cloud.openfeign.lazy-attributes-resolution", - String.valueOf(false)))) { + String.valueOf(false)))) { eagerlyRegisterFeignClientBeanDefinition(className, attributes, registry); - } - else { + } else { lazilyRegisterFeignClientBeanDefinition(className, attributes, registry); } } private void eagerlyRegisterFeignClientBeanDefinition(String className, Map attributes, - BeanDefinitionRegistry registry) { + BeanDefinitionRegistry registry) { validate(attributes); BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class); definition.addPropertyValue("url", getUrl(null, attributes)); @@ -234,19 +228,19 @@ private void eagerlyRegisterFeignClientBeanDefinition(String className, Map attributes, - BeanDefinitionRegistry registry) { + BeanDefinitionRegistry registry) { ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory - ? (ConfigurableBeanFactory) registry : null; + ? (ConfigurableBeanFactory) registry : null; Class clazz = ClassUtils.resolveClassName(className, null); String contextId = getContextId(beanFactory, attributes); String name = getName(attributes); @@ -283,12 +277,12 @@ private void lazilyRegisterFeignClientBeanDefinition(String className, Map) fallback - : ClassUtils.resolveClassName(fallback.toString(), null)); + : ClassUtils.resolveClassName(fallback.toString(), null)); } Object fallbackFactory = attributes.get("fallbackFactory"); if (fallbackFactory != null) { factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class) fallbackFactory - : ClassUtils.resolveClassName(fallbackFactory.toString(), null)); + : ClassUtils.resolveClassName(fallbackFactory.toString(), null)); } return factoryBean.getObject(); }); @@ -306,7 +300,7 @@ private void lazilyRegisterFeignClientBeanDefinition(String className, Map client) { } throw new IllegalStateException( - "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName()); + "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName()); } private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className, - Object configuration) { + Object configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(className); builder.addConstructorArgValue(configuration); registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), - builder.getBeanDefinition()); + builder.getBeanDefinition()); } @Override @@ -477,20 +471,21 @@ public void setEnvironment(Environment environment) { /** * This method registers beans definition with refreshScope. - * @param registry spring bean definition registry - * @param contextId name of feign client - * @param beanType type of bean + * + * @param registry spring bean definition registry + * @param contextId name of feign client + * @param beanType type of bean * @param factoryBeanType points to a relevant bean factory */ private void registerRefreshableBeanDefinition(BeanDefinitionRegistry registry, String contextId, Class beanType, - Class factoryBeanType) { + Class factoryBeanType) { if (isClientRefreshEnabled()) { String beanName = beanType.getCanonicalName() + "-" + contextId; BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(factoryBeanType); definitionBuilder.setScope("refresh"); definitionBuilder.addPropertyValue("contextId", contextId); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(definitionBuilder.getBeanDefinition(), - beanName); + beanName); definitionHolder = ScopedProxyUtils.createScopedProxy(definitionHolder, registry, true); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry); } diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientWithRefreshableOptionsTest.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientWithRefreshableOptionsTest.java index cb35386a2..65f048797 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientWithRefreshableOptionsTest.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignClientWithRefreshableOptionsTest.java @@ -121,7 +121,7 @@ public void connectTimeoutShouldChangeAfterContextRefresh() { } private void assertConnectionAndReadTimeout(OptionsTestClient.OptionsResponseForTests options, - int expectedConnectTimeoutInMillis, int expectedReadTimeoutInMillis) { + int expectedConnectTimeoutInMillis, int expectedReadTimeoutInMillis) { assertThat(options.connectTimeout()).isEqualTo(expectedConnectTimeoutInMillis); assertThat(options.readTimeout()).isEqualTo(expectedReadTimeoutInMillis); } @@ -129,8 +129,8 @@ private void assertConnectionAndReadTimeout(OptionsTestClient.OptionsResponseFor @Configuration @EnableAutoConfiguration @EnableConfigurationProperties(FeignClientProperties.class) - @EnableFeignClients(clients = { Application.OverrideOptionsClient.class, Application.RefreshableClient.class, - Application.ReadTimeoutClient.class, Application.ConnectTimeoutClient.class }) + @EnableFeignClients(clients = {Application.OverrideOptionsClient.class, Application.RefreshableClient.class, + Application.ReadTimeoutClient.class, Application.ConnectTimeoutClient.class}) protected static class Application { @Bean