Skip to content

Commit ba93e7b

Browse files
committed
Add @LoadBalanced support for RestTemplateBuilder.
1 parent d0d7e6c commit ba93e7b

File tree

4 files changed

+150
-30
lines changed

4 files changed

+150
-30
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.client.loadbalancer;
18+
19+
import org.springframework.beans.BeansException;
20+
import org.springframework.beans.factory.ObjectProvider;
21+
import org.springframework.beans.factory.config.BeanPostProcessor;
22+
import org.springframework.context.ApplicationContext;
23+
import org.springframework.http.client.ClientHttpRequestInterceptor;
24+
25+
/**
26+
* A {@link BeanPostProcessor} that adds the provided {@link ClientHttpRequestInterceptor}
27+
* to bean instances annotated with {@link LoadBalanced}.
28+
*
29+
* @author Olga Maciaszek-Sharma
30+
* @since 4.2.0
31+
*/
32+
public abstract class AbstractLoadBalancerBlockingBuilderBeanPostProcessor<T extends ClientHttpRequestInterceptor>
33+
implements BeanPostProcessor {
34+
35+
protected final ObjectProvider<T> loadBalancerInterceptorProvider;
36+
37+
protected final ApplicationContext context;
38+
39+
AbstractLoadBalancerBlockingBuilderBeanPostProcessor(ObjectProvider<T> loadBalancerInterceptorProvider,
40+
ApplicationContext context) {
41+
this.loadBalancerInterceptorProvider = loadBalancerInterceptorProvider;
42+
this.context = context;
43+
}
44+
45+
@Override
46+
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
47+
// a separate call to verify supported type before searching for annotation for
48+
// performance reasons
49+
if (isSupported(bean)) {
50+
if (context.findAnnotationOnBean(beanName, LoadBalanced.class) == null) {
51+
return bean;
52+
}
53+
ClientHttpRequestInterceptor interceptor = loadBalancerInterceptorProvider.getIfAvailable();
54+
if (interceptor == null) {
55+
throw new IllegalStateException(ClientHttpRequestInterceptor.class.getSimpleName() + " not available.");
56+
}
57+
bean = apply(bean, interceptor);
58+
}
59+
return bean;
60+
}
61+
62+
protected abstract Object apply(Object bean, ClientHttpRequestInterceptor interceptor);
63+
64+
protected abstract boolean isSupported(Object bean);
65+
66+
}

spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ static LoadBalancerRestClientBuilderBeanPostProcessor<DeferringLoadBalancerInter
101101
return new LoadBalancerRestClientBuilderBeanPostProcessor<>(loadBalancerInterceptorProvider, context);
102102
}
103103

104+
@Bean
105+
@ConditionalOnBean(DeferringLoadBalancerInterceptor.class)
106+
@ConditionalOnMissingBean(LoadBalancerRestTemplateBuilderBeanPostProcessor.class)
107+
static LoadBalancerRestTemplateBuilderBeanPostProcessor<DeferringLoadBalancerInterceptor> lbRestTemplateBuilderPostProcessor(
108+
ObjectProvider<DeferringLoadBalancerInterceptor> loadBalancerInterceptorProvider,
109+
ApplicationContext context) {
110+
return new LoadBalancerRestTemplateBuilderBeanPostProcessor<>(loadBalancerInterceptorProvider, context);
111+
}
112+
104113
}
105114

106115
@AutoConfiguration

spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRestClientBuilderBeanPostProcessor.java

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,63 +16,57 @@
1616

1717
package org.springframework.cloud.client.loadbalancer;
1818

19-
import org.springframework.beans.BeansException;
2019
import org.springframework.beans.factory.ObjectProvider;
21-
import org.springframework.beans.factory.config.BeanPostProcessor;
2220
import org.springframework.context.ApplicationContext;
2321
import org.springframework.http.client.ClientHttpRequestInterceptor;
2422
import org.springframework.web.client.RestClient;
2523

2624
/**
27-
* A {@link BeanPostProcessor} that adds the provided {@link ClientHttpRequestInterceptor}
28-
* to all {@link RestClient.Builder} instances annotated with {@link LoadBalanced}.
25+
* {@link RestClient.Builder}-specific
26+
* {@link AbstractLoadBalancerBlockingBuilderBeanPostProcessor} implementation. Adds the
27+
* provided {@link ClientHttpRequestInterceptor} to all {@link RestClient.Builder}
28+
* instances annotated with {@link LoadBalanced}.
2929
*
3030
* @author Olga Maciaszek-Sharma
3131
* @since 4.1.0
3232
*/
3333
public class LoadBalancerRestClientBuilderBeanPostProcessor<T extends ClientHttpRequestInterceptor>
34-
implements BeanPostProcessor {
35-
36-
private final ObjectProvider<T> loadBalancerInterceptorProvider;
37-
38-
private final ApplicationContext context;
34+
extends AbstractLoadBalancerBlockingBuilderBeanPostProcessor<T> {
3935

4036
/**
41-
* Creates a {@link LoadBalancerRestClientBuilderBeanPostProcessor} instance using a provided {@link ClientHttpRequestInterceptor} and application context.
42-
* @param loadBalancerInterceptor a {@link ClientHttpRequestInterceptor} used for load-balancing
37+
* Creates a {@link LoadBalancerRestClientBuilderBeanPostProcessor} instance using a
38+
* provided {@link ClientHttpRequestInterceptor} and application context.
39+
* @param loadBalancerInterceptor a {@link ClientHttpRequestInterceptor} used for
40+
* load-balancing
4341
* @param context {@link ApplicationContext}
44-
* @deprecated in favour of {@link LoadBalancerRestClientBuilderBeanPostProcessor#LoadBalancerRestClientBuilderBeanPostProcessor(ObjectProvider, ApplicationContext)}
42+
* @deprecated in favour of
43+
* {@link LoadBalancerRestClientBuilderBeanPostProcessor#LoadBalancerRestClientBuilderBeanPostProcessor(ObjectProvider, ApplicationContext)}
4544
*/
4645
@Deprecated(forRemoval = true)
4746
public LoadBalancerRestClientBuilderBeanPostProcessor(T loadBalancerInterceptor, ApplicationContext context) {
48-
this.loadBalancerInterceptorProvider = new SimpleObjectProvider<>(loadBalancerInterceptor);
49-
this.context = context;
47+
this(new SimpleObjectProvider<>(loadBalancerInterceptor), context);
5048
}
5149

5250
/**
53-
* Creates a {@link LoadBalancerRestClientBuilderBeanPostProcessor} instance using interceptor {@link ObjectProvider} and application context.
54-
* @param loadBalancerInterceptorProvider an {@link ObjectProvider} for {@link ClientHttpRequestInterceptor} used for load-balancing
51+
* Creates a {@link LoadBalancerRestClientBuilderBeanPostProcessor} instance using
52+
* interceptor {@link ObjectProvider} and application context.
53+
* @param loadBalancerInterceptorProvider an {@link ObjectProvider} for
54+
* {@link ClientHttpRequestInterceptor} used for load-balancing
5555
* @param context {@link ApplicationContext}
5656
*/
5757
public LoadBalancerRestClientBuilderBeanPostProcessor(ObjectProvider<T> loadBalancerInterceptorProvider,
5858
ApplicationContext context) {
59-
this.loadBalancerInterceptorProvider = loadBalancerInterceptorProvider;
60-
this.context = context;
59+
super(loadBalancerInterceptorProvider, context);
60+
}
61+
62+
@Override
63+
protected Object apply(Object bean, ClientHttpRequestInterceptor interceptor) {
64+
return ((RestClient.Builder) bean).requestInterceptor(interceptor);
6165
}
6266

6367
@Override
64-
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
65-
if (bean instanceof RestClient.Builder) {
66-
if (context.findAnnotationOnBean(beanName, LoadBalanced.class) == null) {
67-
return bean;
68-
}
69-
ClientHttpRequestInterceptor interceptor = loadBalancerInterceptorProvider.getIfAvailable();
70-
if (interceptor == null) {
71-
throw new IllegalStateException(ClientHttpRequestInterceptor.class.getSimpleName() + " not available.");
72-
}
73-
((RestClient.Builder) bean).requestInterceptor(interceptor);
74-
}
75-
return bean;
68+
protected boolean isSupported(Object bean) {
69+
return bean instanceof RestClient.Builder;
7670
}
7771

7872
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.client.loadbalancer;
18+
19+
import org.springframework.beans.factory.ObjectProvider;
20+
import org.springframework.boot.web.client.RestTemplateBuilder;
21+
import org.springframework.context.ApplicationContext;
22+
import org.springframework.http.client.ClientHttpRequestInterceptor;
23+
24+
/**
25+
* {@link RestTemplateBuilder}-specific
26+
* {@link AbstractLoadBalancerBlockingBuilderBeanPostProcessor} implementation. Adds the
27+
* provided {@link ClientHttpRequestInterceptor} to all {@link RestTemplateBuilder}
28+
* instances annotated with {@link LoadBalanced}.
29+
*
30+
* @author Olga Maciaszek-Sharma
31+
* @since 4.2.0
32+
*/
33+
public class LoadBalancerRestTemplateBuilderBeanPostProcessor<T extends ClientHttpRequestInterceptor>
34+
extends AbstractLoadBalancerBlockingBuilderBeanPostProcessor<T> {
35+
36+
public LoadBalancerRestTemplateBuilderBeanPostProcessor(ObjectProvider<T> loadBalancerInterceptorProvider,
37+
ApplicationContext context) {
38+
super(loadBalancerInterceptorProvider, context);
39+
}
40+
41+
@Override
42+
protected boolean isSupported(Object bean) {
43+
return bean instanceof RestTemplateBuilder;
44+
}
45+
46+
@Override
47+
protected Object apply(Object bean, ClientHttpRequestInterceptor interceptor) {
48+
return ((RestTemplateBuilder) bean).interceptors(interceptor);
49+
}
50+
51+
}

0 commit comments

Comments
 (0)