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 a2cb39cec..877f674aa 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 @@ * @author Will Tran * @author Gang Li * @author Olga Maciaszek-Sharma + * @author Henning Pöttker */ @AutoConfiguration @Conditional(BlockingRestClassesPresentCondition.class) @@ -86,17 +87,18 @@ static class DeferringLoadBalancerInterceptorConfig { @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 a5c2480f2..653dc8181 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 @@ * @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 Object postProcessBeforeInitialization(Object bean, String beanName) thro 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 000000000..b12ce9771 --- /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 4e419770f..d80dd7ec3 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 @@ void tryResolveDelegate() { if (delegate == null) { delegate = exchangeFilterFunctionProvider.getIfAvailable(); if (delegate == null) { - throw new IllegalStateException("ReactorLoadBalancerExchangeFilterFunction not available."); + throw new IllegalStateException("LoadBalancer ExchangeFilterFunction not available."); } } } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerBeanPostProcessorAutoConfiguration.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerBeanPostProcessorAutoConfiguration.java index 8e61f33c0..f755f95d3 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerBeanPostProcessorAutoConfiguration.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/LoadBalancerBeanPostProcessorAutoConfiguration.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. @@ -39,6 +39,7 @@ * beans. * * @author Olga Maciaszek-Sharma + * @author Henning Pöttker * @since 2.2.0 */ @Configuration(proxyBeanMethods = false) @@ -46,9 +47,11 @@ @Conditional(LoadBalancerBeanPostProcessorAutoConfiguration.OnAnyLoadBalancerImplementationPresentCondition.class) public class LoadBalancerBeanPostProcessorAutoConfiguration { + @SuppressWarnings("rawtypes") @Bean - public LoadBalancerWebClientBuilderBeanPostProcessor loadBalancerWebClientBuilderBeanPostProcessor( - DeferringLoadBalancerExchangeFilterFunction deferringExchangeFilterFunction, ApplicationContext context) { + public static LoadBalancerWebClientBuilderBeanPostProcessor loadBalancerWebClientBuilderBeanPostProcessor( + ObjectProvider deferringExchangeFilterFunction, + ApplicationContext context) { return new LoadBalancerWebClientBuilderBeanPostProcessor(deferringExchangeFilterFunction, context); } @@ -58,7 +61,7 @@ protected static class ReactorDeferringLoadBalancerFilterConfig { @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 bb8db3ff5..e07f9590b 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 @@ * @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 Object postProcessBeforeInitialization(Object bean, String beanName) thro 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; }