diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java index a2cb39ce..877f674a 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java @@ -49,6 +49,7 @@ import org.springframework.web.client.RestTemplate; * @author Will Tran * @author Gang Li * @author Olga Maciaszek-Sharma + * @author Henning Pöttker */ @AutoConfiguration @Conditional(BlockingRestClassesPresentCondition.class) @@ -86,17 +87,18 @@ public class LoadBalancerAutoConfiguration { @Bean @ConditionalOnMissingBean - public DeferringLoadBalancerInterceptor deferringLoadBalancerInterceptor( + public static DeferringLoadBalancerInterceptor deferringLoadBalancerInterceptor( ObjectProvider loadBalancerInterceptorObjectProvider) { return new DeferringLoadBalancerInterceptor(loadBalancerInterceptorObjectProvider); } @Bean @ConditionalOnBean(DeferringLoadBalancerInterceptor.class) - @ConditionalOnMissingBean - LoadBalancerRestClientBuilderBeanPostProcessor lbRestClientPostProcessor( - DeferringLoadBalancerInterceptor loadBalancerInterceptor, ApplicationContext context) { - return new LoadBalancerRestClientBuilderBeanPostProcessor(loadBalancerInterceptor, context); + @ConditionalOnMissingBean(LoadBalancerRestClientBuilderBeanPostProcessor.class) + static LoadBalancerRestClientBuilderBeanPostProcessor lbRestClientPostProcessor( + ObjectProvider loadBalancerInterceptorProvider, + ApplicationContext context) { + return new LoadBalancerRestClientBuilderBeanPostProcessor<>(loadBalancerInterceptorProvider, context); } } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRestClientBuilderBeanPostProcessor.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRestClientBuilderBeanPostProcessor.java index a5c2480f..653dc818 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRestClientBuilderBeanPostProcessor.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRestClientBuilderBeanPostProcessor.java @@ -17,6 +17,7 @@ package org.springframework.cloud.client.loadbalancer; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.http.client.ClientHttpRequestInterceptor; @@ -29,15 +30,21 @@ import org.springframework.web.client.RestClient; * @author Olga Maciaszek-Sharma * @since 4.1.0 */ -public class LoadBalancerRestClientBuilderBeanPostProcessor implements BeanPostProcessor { +public class LoadBalancerRestClientBuilderBeanPostProcessor + implements BeanPostProcessor { - private final ClientHttpRequestInterceptor loadBalancerInterceptor; + private final ObjectProvider loadBalancerInterceptorProvider; private final ApplicationContext context; - public LoadBalancerRestClientBuilderBeanPostProcessor(ClientHttpRequestInterceptor loadBalancerInterceptor, + public LoadBalancerRestClientBuilderBeanPostProcessor(T loadBalancerInterceptor, ApplicationContext context) { + this.loadBalancerInterceptorProvider = new SimpleObjectProvider<>(loadBalancerInterceptor); + this.context = context; + } + + public LoadBalancerRestClientBuilderBeanPostProcessor(ObjectProvider loadBalancerInterceptorProvider, ApplicationContext context) { - this.loadBalancerInterceptor = loadBalancerInterceptor; + this.loadBalancerInterceptorProvider = loadBalancerInterceptorProvider; this.context = context; } @@ -47,7 +54,11 @@ public class LoadBalancerRestClientBuilderBeanPostProcessor implements BeanPostP if (context.findAnnotationOnBean(beanName, LoadBalanced.class) == null) { return bean; } - ((RestClient.Builder) bean).requestInterceptor(loadBalancerInterceptor); + ClientHttpRequestInterceptor interceptor = loadBalancerInterceptorProvider.getIfAvailable(); + if (interceptor == null) { + throw new IllegalStateException(ClientHttpRequestInterceptor.class.getSimpleName() + " not available."); + } + ((RestClient.Builder) bean).requestInterceptor(interceptor); } return bean; } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/SimpleObjectProvider.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/SimpleObjectProvider.java new file mode 100644 index 00000000..b12ce977 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/SimpleObjectProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerWebClientBuilderBeanPostProcessor; + +/** + * Wrapper for {@link ObjectProvider}. Added to use for a workaround in + * {@link LoadBalancerWebClientBuilderBeanPostProcessor}. + * + * @param type of the object to fetch + * @author Spencer Gibb + * @deprecated for removal in 4.0 + */ +@Deprecated(forRemoval = true) +public class SimpleObjectProvider implements ObjectProvider { + + private final T object; + + public SimpleObjectProvider(T object) { + this.object = object; + } + + @Override + public T getObject(Object... args) throws BeansException { + return this.object; + } + + @Override + public T getIfAvailable() throws BeansException { + return this.object; + } + + @Override + public T getIfUnique() throws BeansException { + return this.object; + } + + @Override + public T getObject() throws BeansException { + return this.object; + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DeferringLoadBalancerExchangeFilterFunction.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DeferringLoadBalancerExchangeFilterFunction.java index 4e419770..d80dd7ec 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DeferringLoadBalancerExchangeFilterFunction.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/DeferringLoadBalancerExchangeFilterFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,7 +55,7 @@ public class DeferringLoadBalancerExchangeFilterFunction deferringExchangeFilterFunction, + ApplicationContext context) { return new LoadBalancerWebClientBuilderBeanPostProcessor(deferringExchangeFilterFunction, context); } @@ -58,7 +61,7 @@ public class LoadBalancerBeanPostProcessorAutoConfiguration { @Bean @Primary - DeferringLoadBalancerExchangeFilterFunction reactorDeferringLoadBalancerExchangeFilterFunction( + static DeferringLoadBalancerExchangeFilterFunction reactorDeferringLoadBalancerExchangeFilterFunction( ObjectProvider exchangeFilterFunctionProvider) { return new DeferringLoadBalancerExchangeFilterFunction<>(exchangeFilterFunctionProvider); } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerWebClientBuilderBeanPostProcessor.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerWebClientBuilderBeanPostProcessor.java index bb8db3ff..e07f9590 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerWebClientBuilderBeanPostProcessor.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerWebClientBuilderBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,10 @@ package org.springframework.cloud.client.loadbalancer.reactive; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.client.loadbalancer.SimpleObjectProvider; import org.springframework.context.ApplicationContext; import org.springframework.web.reactive.function.client.WebClient; @@ -30,15 +32,28 @@ import org.springframework.web.reactive.function.client.WebClient; * @author Olga Maciaszek-Sharma * @since 2.2.0 */ +@SuppressWarnings({ "removal", "rawtypes" }) public class LoadBalancerWebClientBuilderBeanPostProcessor implements BeanPostProcessor { - private final DeferringLoadBalancerExchangeFilterFunction exchangeFilterFunction; + private final ObjectProvider exchangeFilterFunctionObjectProvider; private final ApplicationContext context; + /** + * @deprecated in favour of + * {@link LoadBalancerWebClientBuilderBeanPostProcessor#LoadBalancerWebClientBuilderBeanPostProcessor(ObjectProvider, ApplicationContext)} + */ + @Deprecated(forRemoval = true) public LoadBalancerWebClientBuilderBeanPostProcessor( DeferringLoadBalancerExchangeFilterFunction exchangeFilterFunction, ApplicationContext context) { - this.exchangeFilterFunction = exchangeFilterFunction; + this.exchangeFilterFunctionObjectProvider = new SimpleObjectProvider<>(exchangeFilterFunction); + this.context = context; + } + + public LoadBalancerWebClientBuilderBeanPostProcessor( + ObjectProvider exchangeFilterFunction, + ApplicationContext context) { + this.exchangeFilterFunctionObjectProvider = exchangeFilterFunction; this.context = context; } @@ -48,7 +63,12 @@ public class LoadBalancerWebClientBuilderBeanPostProcessor implements BeanPostPr if (context.findAnnotationOnBean(beanName, LoadBalanced.class) == null) { return bean; } - ((WebClient.Builder) bean).filter(exchangeFilterFunction); + DeferringLoadBalancerExchangeFilterFunction exchangeFilterFunction = exchangeFilterFunctionObjectProvider + .getIfAvailable(); + if (exchangeFilterFunction == null) { + throw new IllegalStateException("LoadBalancerExchangeFilterFunction not found"); + } + ((WebClient.Builder) bean).filter(exchangeFilterFunctionObjectProvider.getIfAvailable()); } return bean; }