Skip to content

Commit f52a724

Browse files
authored
Use different WebClient.Builder instances per Retrofit context support non-loadbalancer. (#43)
1 parent d73bbb7 commit f52a724

File tree

3 files changed

+74
-16
lines changed

3 files changed

+74
-16
lines changed

docs/src/main/asciidoc/spring-cloud-square.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public WebClient.Builder webClientBuilder() {
159159

160160
They are used under the hood to run load-balanced HTTP requests.
161161

162-
NOTE: You can create various instances of `WebClient.Builder` with different setup. If a `@LoadBalanced WebClient.Builder` bean is found with name matching the pattern `[retrofit-context-name]WebClientBuilder`, it will be picked for the Retrofit context in question, otherwise the first found `@LoadBalaced WebClient.Builder` bean will be picked.
162+
NOTE: You can create various instances of `WebClient.Builder` with different setup. If a `WebClient.Builder` bean is found with name matching the pattern `[retrofit-context-name]WebClientBuilder`, it will be picked for the Retrofit context in question, otherwise the first found `WebClient.Builder` bean will be picked.
163163

164164

165165
=== Retrofit Reactor support

spring-cloud-square-retrofit-webclient/src/main/java/org/springframework/cloud/square/retrofit/webclient/WebClientRetrofitClientFactoryBean.java

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
*
3333
* @author Spencer Gibb
3434
* @author Olga Maciaszek-Sharma
35+
* @author HouYe Hua
3536
*/
3637
public class WebClientRetrofitClientFactoryBean extends AbstractRetrofitClientFactoryBean {
3738

@@ -48,22 +49,18 @@ protected Retrofit.Builder retrofit(RetrofitContext context, boolean hasUrl) {
4849

4950
if (hasUrl) {
5051
// this is not load balanced and needs a WebClient
51-
WebClient.Builder nonLoadBalancedBuilder = null;
5252
Map<String, WebClient.Builder> instances = context.getInstances(this.name, WebClient.Builder.class);
53-
for (Map.Entry<String, WebClient.Builder> entry : instances.entrySet()) {
54-
String beanName = entry.getKey();
55-
WebClient.Builder clientBuilder = entry.getValue();
56-
57-
if (applicationContext.findAnnotationOnBean(beanName, LoadBalanced.class) == null) {
58-
nonLoadBalancedBuilder = clientBuilder;
59-
break;
60-
}
61-
}
62-
63-
if (nonLoadBalancedBuilder == null) {
53+
List<Map.Entry<String, WebClient.Builder>> webClientBuilders = instances.entrySet().stream().filter(
54+
entry -> applicationContext.findAnnotationOnBean(entry.getKey(), LoadBalanced.class) == null)
55+
.collect(Collectors.toList());
56+
if (webClientBuilders.isEmpty()) {
6457
throw new IllegalStateException("No WebClient.Builder bean defined.");
6558
}
66-
builder.callFactory(new WebClientCallFactory(nonLoadBalancedBuilder.build()));
59+
WebClient.Builder selectedWebClientBuilder = webClientBuilders.stream()
60+
.filter(entry -> entry.getKey().equals(name + WEB_CLIENT_BUILDER_SUFFIX)).findAny()
61+
.orElse(webClientBuilders.stream().findAny().get()).getValue();
62+
63+
builder.callFactory(new WebClientCallFactory(selectedWebClientBuilder.build()));
6764
}
6865

6966
return builder;

spring-cloud-square-retrofit-webclient/src/test/java/org/springframework/cloud/square/retrofit/webclient/WebClientRetrofitLoadBalancerTests.java

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.Objects;
2020

21+
import org.junit.jupiter.api.AfterAll;
22+
import org.junit.jupiter.api.BeforeAll;
2123
import org.junit.jupiter.api.Test;
2224
import reactor.core.publisher.Mono;
2325
import retrofit2.Retrofit;
@@ -39,6 +41,7 @@
3941
import org.springframework.context.annotation.Bean;
4042
import org.springframework.core.style.ToStringCreator;
4143
import org.springframework.test.annotation.DirtiesContext;
44+
import org.springframework.util.SocketUtils;
4245
import org.springframework.web.bind.annotation.GetMapping;
4346
import org.springframework.web.bind.annotation.RestController;
4447
import org.springframework.web.reactive.function.client.WebClient;
@@ -50,6 +53,7 @@
5053
/**
5154
* @author Spencer Gibb
5255
* @author Olga Maciaszek-Sharma
56+
* @author HouYe Hua
5357
*/
5458
@SpringBootTest(properties = { "spring.application.name=retrofitclientloadbalancertest",
5559
"logging.level.org.springframework.cloud.square.retrofit=DEBUG",
@@ -65,9 +69,28 @@ class WebClientRetrofitLoadBalancerTests {
6569
@Autowired
6670
TestClientWithCustomWebClientBuilder testClientWithCustomWebClientBuilder;
6771

72+
@Autowired
73+
TestClientWithoutLoadBalancedWebClientBuilder testClientWithoutLoadBalancedWebClientBuilder;
74+
6875
@Autowired
6976
private RetrofitContext retrofitContext;
7077

78+
@LocalServerPort
79+
private int port;
80+
81+
@BeforeAll
82+
static void init() {
83+
int port = SocketUtils.findAvailableTcpPort();
84+
System.setProperty("server.port", String.valueOf(port));
85+
System.setProperty("retrofit.client.url.tests.url", "http://localhost:" + port);
86+
}
87+
88+
@AfterAll
89+
static void destroy() {
90+
System.clearProperty("server.port");
91+
System.clearProperty("retrofit.client.url.tests.url");
92+
}
93+
7194
@Test
7295
void testRetrofitConfiguration() {
7396
Retrofit retrofit = retrofitContext.getInstance("localapp", Retrofit.class);
@@ -84,11 +107,17 @@ void testSimpleType() {
84107
}
85108

86109
@Test
87-
void testCustomWebClientBuilderPickeByRetrofitName() {
110+
void testCustomWebClientBuilderPickedByRetrofitName() {
88111
assertThatExceptionOfType(UnsupportedOperationException.class)
89112
.isThrownBy(() -> testClientWithCustomWebClientBuilder.getHello().block());
90113
}
91114

115+
@Test
116+
void testCustomWebClientBuilderPickedByRetrofitNameWithoutLoadBalanced() {
117+
assertThatExceptionOfType(ExceptionForTest.class)
118+
.isThrownBy(() -> testClientWithoutLoadBalancedWebClientBuilder.getHello().block());
119+
}
120+
92121
@RetrofitClient("localapp")
93122
protected interface TestClient {
94123

@@ -105,9 +134,18 @@ protected interface TestClientWithCustomWebClientBuilder {
105134

106135
}
107136

137+
@RetrofitClient(name = "withoutLoadBalanced", url = "${retrofit.client.url.tests.url}")
138+
protected interface TestClientWithoutLoadBalancedWebClientBuilder {
139+
140+
@GET("/hello")
141+
Mono<Hello> getHello();
142+
143+
}
144+
108145
@SpringBootConfiguration
109146
@EnableAutoConfiguration
110-
@EnableRetrofitClients(clients = { TestClient.class, TestClientWithCustomWebClientBuilder.class })
147+
@EnableRetrofitClients(clients = { TestClient.class, TestClientWithCustomWebClientBuilder.class,
148+
TestClientWithoutLoadBalancedWebClientBuilder.class })
111149
@LoadBalancerClients({ @LoadBalancerClient(name = "localapp", configuration = TestAppConfig.class),
112150
@LoadBalancerClient(name = "localapp2", configuration = TestAppConfig.class) })
113151
@SuppressWarnings("unused")
@@ -133,6 +171,29 @@ public WebClient.Builder localapp2WebClientBuilder() {
133171
});
134172
}
135173

174+
@Bean
175+
public WebClient.Builder withoutLoadBalancedDefaultWebClientBuilder() {
176+
return WebClient.builder();
177+
}
178+
179+
@Bean
180+
public WebClient.Builder withoutLoadBalancedWebClientBuilder() {
181+
return WebClient.builder().filter((request, next) -> {
182+
throw new ExceptionForTest("Failing WebClient Instance From withoutLoadBalancedWebClientBuilder");
183+
});
184+
}
185+
186+
}
187+
188+
protected static class ExceptionForTest extends RuntimeException {
189+
190+
public ExceptionForTest() {
191+
}
192+
193+
public ExceptionForTest(String message) {
194+
super(message);
195+
}
196+
136197
}
137198

138199
protected static class TestAppConfig {

0 commit comments

Comments
 (0)