Skip to content

Commit b337f67

Browse files
committed
Add ReactorNettyHttpClientMapper
This new customizer-like interface make it possible to configure the Reactor Netty `HttpClient` that is going to be used by the `WebClient.Builder` provided by Spring Boot. Closes gh-21135
1 parent 8f84147 commit b337f67

File tree

3 files changed

+72
-5
lines changed

3 files changed

+72
-5
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfiguration.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616

1717
package org.springframework.boot.autoconfigure.web.reactive.function.client;
1818

19-
import java.util.function.Function;
20-
2119
import org.eclipse.jetty.client.HttpClient;
2220
import org.eclipse.jetty.util.ssl.SslContextFactory;
2321

22+
import org.springframework.beans.factory.ObjectProvider;
2423
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2524
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2625
import org.springframework.context.annotation.Bean;
@@ -56,8 +55,12 @@ public ReactorResourceFactory reactorClientResourceFactory() {
5655

5756
@Bean
5857
@Lazy
59-
public ReactorClientHttpConnector reactorClientHttpConnector(ReactorResourceFactory reactorResourceFactory) {
60-
return new ReactorClientHttpConnector(reactorResourceFactory, Function.identity());
58+
public ReactorClientHttpConnector reactorClientHttpConnector(ReactorResourceFactory reactorResourceFactory,
59+
ObjectProvider<ReactorNettyHttpClientMapper> mapperProvider) {
60+
ReactorNettyHttpClientMapper mapper = mapperProvider.orderedStream()
61+
.reduce((before, after) -> (client) -> after.configure(before.configure(client)))
62+
.orElse((client) -> client);
63+
return new ReactorClientHttpConnector(reactorResourceFactory, mapper::configure);
6164
}
6265

6366
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2012-2020 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.boot.autoconfigure.web.reactive.function.client;
18+
19+
import reactor.netty.http.client.HttpClient;
20+
21+
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
22+
23+
/**
24+
* Mapper that allows for custom modification of a {@link HttpClient} before it is used as
25+
* the basis for a {@link ReactorClientHttpConnector}.
26+
*
27+
* @author Brian Clozel
28+
* @since 2.3.0
29+
*/
30+
@FunctionalInterface
31+
public interface ReactorNettyHttpClientMapper {
32+
33+
/**
34+
* Configure the given {@link HttpClient} and return the newly created instance.
35+
* @param httpClient the client to configure
36+
* @return the new client instance
37+
*/
38+
HttpClient configure(HttpClient httpClient);
39+
40+
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/function/client/ClientHttpConnectorConfigurationTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,9 @@
2323
import org.eclipse.jetty.util.thread.Scheduler;
2424
import org.junit.jupiter.api.Test;
2525

26+
import org.springframework.boot.autoconfigure.AutoConfigurations;
27+
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
28+
import org.springframework.context.annotation.Bean;
2629
import org.springframework.http.client.reactive.JettyClientHttpConnector;
2730
import org.springframework.http.client.reactive.JettyResourceFactory;
2831
import org.springframework.test.util.ReflectionTestUtils;
@@ -34,6 +37,7 @@
3437
* Tests for {@link ClientHttpConnectorConfiguration}.
3538
*
3639
* @author Phillip Webb
40+
* @author Brian Clozel
3741
*/
3842
class ClientHttpConnectorConfigurationTests {
3943

@@ -68,4 +72,24 @@ private JettyClientHttpConnector getClientHttpConnector(JettyResourceFactory jet
6872
return ReflectionTestUtils.invokeMethod(jettyClient, "jettyClientHttpConnector", jettyResourceFactory);
6973
}
7074

75+
@Test
76+
void shouldApplyHttpClientMapper() {
77+
new ReactiveWebApplicationContextRunner()
78+
.withConfiguration(AutoConfigurations.of(ClientHttpConnectorConfiguration.ReactorNetty.class))
79+
.withUserConfiguration(CustomHttpClientMapper.class)
80+
.run((context) -> assertThat(CustomHttpClientMapper.called).isTrue());
81+
}
82+
83+
static class CustomHttpClientMapper {
84+
85+
static boolean called = false;
86+
87+
@Bean
88+
ReactorNettyHttpClientMapper clientMapper() {
89+
called = true;
90+
return (client) -> client.baseUrl("/test");
91+
}
92+
93+
}
94+
7195
}

0 commit comments

Comments
 (0)