Skip to content

Commit 7a0c03e

Browse files
committed
Update section in reference on WebClient
Rename "Builder" sub-section to "Configuration" and move it in the beginning before all others since it explains how to create a client in the first place. Update content on Reactor Netty connector based on the API in 0.8 and specifically address Reactor Netty resources and lifecycle. Issue: SPR-16963
1 parent 2f732a8 commit 7a0c03e

File tree

3 files changed

+145
-86
lines changed

3 files changed

+145
-86
lines changed

spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpConnector.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ public class JettyClientHttpConnector implements ClientHttpConnector, SmartLifec
5151

5252

5353
/**
54-
* Create a Jetty {@link ClientHttpConnector} with the default {@link HttpClient}.
54+
* Default constructor that creates a new instance of {@link HttpClient}.
5555
*/
5656
public JettyClientHttpConnector() {
5757
this(new HttpClient());
5858
}
5959

6060
/**
61-
* Create a Jetty {@link ClientHttpConnector} with the given {@link HttpClient}.
61+
* Constructor with an initialized {@link HttpClient}.
6262
*/
6363
public JettyClientHttpConnector(HttpClient httpClient) {
6464
Assert.notNull(httpClient, "HttpClient is required");

src/docs/asciidoc/web/webflux-webclient.adoc

Lines changed: 134 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,142 @@
11
[[webflux-client]]
22
= WebClient
33

4-
The `spring-webflux` module includes a reactive, non-blocking client for HTTP requests
5-
with a functional-style API client and Reactive Streams support. `WebClient` depends on a
6-
lower level HTTP client library to execute requests and that support is pluggable.
4+
Spring WebFlux includes a reactive, non-blocking `WebClient` for performing HTTP requests
5+
using a functional-style API that exposes Reactor `Flux` and `Mono` types, see
6+
<<web-reactive.adoc#webflux-reactive-libraries>>. The client relies on the same
7+
<<web-reactive.adoc#webflux-codecs,codecs>> that WebFlux server applications use to work
8+
with request and response content.
79

8-
`WebClient`
9-
uses the same <<web-reactive.adoc#webflux-codecs,codecs>> as WebFlux server applications do, and
10-
shares a common base package, some common APIs, and infrastructure with the
11-
server <<web-reactive.adoc#webflux-fn,functional web framework>>.
12-
The API exposes Reactor `Flux` and `Mono` types, also see
13-
<<web-reactive.adoc#webflux-reactive-libraries>>. By default it uses
14-
it uses https://github.com/reactor/reactor-netty[Reactor Netty] as the HTTP client
15-
library and
16-
https://github.com/jetty-project/jetty-reactive-httpclient[Jetty ReactiveStreams HttpClient]
17-
is supported as well via `JettyClientHttpConnector`, but others can be plugged in
18-
through a custom `ClientHttpConnector`.
10+
Internally `WebClient` delegates to an HTTP client library. By default it uses
11+
https://github.com/reactor/reactor-netty[Reactor Netty], there is built-in support for
12+
the Jetty https://github.com/jetty-project/jetty-reactive-httpclient[reactive HtpClient],
13+
and others can be plugged in through a `ClientHttpConnector`.
1914

20-
By comparison to the <<integration.adoc#rest-resttemplate,RestTemplate>>, the
21-
`WebClient` is:
2215

23-
* non-blocking, reactive, and supports higher concurrency with less hardware resources.
24-
* provides a functional API that takes advantage of Java 8 lambdas.
25-
* supports both synchronous and asynchronous scenarios.
26-
* supports streaming up or down from a server.
2716

28-
The `RestTemplate` is not a good fit for use in non-blocking applications, and therefore
29-
Spring WebFlux application should always use the `WebClient`. The `WebClient` should also
30-
be preferred in Spring MVC, in most high concurrency scenarios, and for composing a
31-
sequence of remote, inter-dependent calls.
17+
18+
[[webflux-client-builder]]
19+
== Configuration
20+
21+
The simplest way to create a `WebClient` is through one of the static factory methods:
22+
23+
* `WebClient.create()`
24+
* `WebClient.create(String baseUrl)`
25+
26+
The above uses Reactor Netty `HttpClient` from "io.projectreactor.netty:reactor-netty"
27+
with default settings and participates in global resources such for event loop threads and
28+
a connection pool, see <<webflux-client-builder-reactor, Reactor Netty configuration>>.
29+
30+
The `WebClient.Builder` can be used for access to further options:
31+
32+
* `uriBuilderFactory` -- customized `UriBuilderFactory` to use as a base URL.
33+
* `defaultHeader` -- headers for every request.
34+
* `defaultCookie)` -- cookies for every request.
35+
* `defaultRequest` -- `Consumer` to customize every request.
36+
* `filter` -- client filter for every request.
37+
* `exchangeStrategies` -- HTTP message reader/writer customizations.
38+
* `clientConnector` -- HTTP client library settings.
39+
40+
For example, to configure <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
41+
42+
[source,java,intent=0]
43+
[subs="verbatim,quotes"]
44+
----
45+
ExchangeStrategies strategies = ExchangeStrategies.builder()
46+
.codecs(configurer -> {
47+
// ...
48+
})
49+
.build();
50+
51+
WebClient client = WebClient.builder()
52+
.exchangeStrategies(strategies)
53+
.build();
54+
----
55+
56+
Once built a `WebClient` instance is immutable. However, you can clone it, and build a
57+
modified copy without affecting the original instance:
58+
59+
[source,java,intent=0]
60+
[subs="verbatim,quotes"]
61+
----
62+
WebClient client1 = WebClient.builder()
63+
.filter(filterA).filter(filterB).build();
64+
65+
WebClient client2 = client1.mutate()
66+
.filter(filterC).filter(filterD).build();
67+
68+
// client1 has filterA, filterB
69+
70+
// client2 has filterA, filterB, filterC, filterD
71+
----
72+
73+
74+
75+
[[webflux-client-builder-reactor]]
76+
=== Reactor Netty
77+
78+
To customize Reactor Netty settings:
79+
80+
[source,java,intent=0]
81+
[subs="verbatim,quotes"]
82+
----
83+
HttpClient httpClient = HttpClient.create()
84+
httpClient.secure(sslSpec -> ...);
85+
ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
86+
87+
WebClient webClient = WebClient.builder().clientConnector(connector).build();
88+
----
89+
90+
By default `HttpClient` participates in the global Reactor Netty resources held in
91+
`reactor.netty.http.HttpResources`, including event loop threads and a connection pool.
92+
This is the recommended mode since fixed, shared resources are preferred for event loop
93+
concurrency. In this mode global resources remain active until the process exits.
94+
95+
If the server is timed with the process, there is typically no need for an explicit
96+
shutdown. However if the server can start or stop in-process, e.g. Spring MVC
97+
application deployed as a WAR, you can declare a Spring-managed bean of type
98+
`ReactorResourceFactory` with `globaResources=true` (the default) to ensure the Reactor
99+
Netty global resources are shut down when the Spring `ApplicationContext` is closed:
100+
101+
[source,java,intent=0]
102+
[subs="verbatim,quotes"]
103+
----
104+
@Bean
105+
public ReactorResourceFactory reactorResourceFactory() {
106+
return new ReactorResourceFactory();
107+
}
108+
----
109+
110+
You may also choose not to participate in the global Reactor Netty resources. However keep
111+
in mind in this mode the burden is on you to ensure all Reactor Netty client and server
112+
instances use shared resources:
113+
114+
[source,java,intent=0]
115+
[subs="verbatim,quotes"]
116+
----
117+
@Bean
118+
public ReactorResourceFactory resourceFactory() {
119+
ReactorResourceFactory factory = new ReactorResourceFactory();
120+
factory.setGlobalResources(false); // <1>
121+
return factory;
122+
}
123+
124+
@Bean
125+
public WebClient webClient() {
126+
127+
Function<HttpClient, HttpClient> mapper = client -> {
128+
// Further customizations...
129+
};
130+
131+
ClientHttpConnector connector =
132+
new ReactorClientHttpConnector(resourceFactory(), mapper); // <2>
133+
134+
return WebClient.builder().clientConnector(connector).build(); // <3>
135+
}
136+
----
137+
<1> Create resources independent of global ones.
138+
<2> Use `ReactorClientHttpConnector` constructor with resource factory.
139+
<3> Plug the connector into the `WebClient.Builder`.
32140

33141

34142

@@ -268,69 +376,11 @@ inline-style, through the built-in `BodyInserters`. For example:
268376

269377

270378

271-
[[webflux-client-builder]]
272-
== Builder options
273-
274-
A simple way to create `WebClient` is through the static factory methods `create()` and
275-
`create(String)` with a base URL for all requests. You can also use `WebClient.builder()`
276-
for access to more options.
277-
278-
To customize the underlying HTTP client:
279-
280-
[source,java,intent=0]
281-
[subs="verbatim,quotes"]
282-
----
283-
SslContext sslContext = ...
284-
285-
ClientHttpConnector connector = new ReactorClientHttpConnector(
286-
builder -> builder.sslContext(sslContext));
287-
288-
WebClient webClient = WebClient.builder()
289-
.clientConnector(connector)
290-
.build();
291-
----
292-
293-
To customize the <<web-reactive.adoc#webflux-codecs,HTTP codecs>> used for encoding and
294-
decoding HTTP messages:
295-
296-
[source,java,intent=0]
297-
[subs="verbatim,quotes"]
298-
----
299-
ExchangeStrategies strategies = ExchangeStrategies.builder()
300-
.codecs(configurer -> {
301-
// ...
302-
})
303-
.build();
304-
305-
WebClient webClient = WebClient.builder()
306-
.exchangeStrategies(strategies)
307-
.build();
308-
----
309-
310-
The builder can be used to insert <<webflux-client-filter>>.
311-
312-
Explore the `WebClient.Builder` in your IDE for other options related to URI building,
313-
default headers (and cookies), and more.
314-
315-
After the `WebClient` is built, you can always obtain a new builder from it, in order to
316-
build a new `WebClient`, based on, but without affecting the current instance:
317-
318-
[source,java,intent=0]
319-
[subs="verbatim,quotes"]
320-
----
321-
WebClient modifiedClient = client.mutate()
322-
// user builder methods...
323-
.build();
324-
----
325-
326-
327-
328-
329379
[[webflux-client-filter]]
330380
== Client Filters
331381

332-
You can register an `ExchangeFilterFunction` in the `WebClient.Builder` to intercept and
333-
possibly modify requests performed through the client:
382+
You can register a client filter (`ExchangeFilterFunction`) through the `WebClient.Builder`
383+
in order to intercept and/or modify requests:
334384

335385
[source,java,intent=0]
336386
[subs="verbatim,quotes"]

src/docs/asciidoc/web/webmvc-client.adoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,13 @@ See <<integration.adoc#rest-client-access,RestTemplate>> for details.
3333
introduced in 5.0 and offers a modern alternative to the `RestTemplate` with efficient
3434
support for both synchronous and asynchronous, as well as streaming scenarios.
3535

36+
In contrast to the `RestTemplate`, the `WebClient` supports the following:
37+
38+
* Non-blocking I/O.
39+
* Reactive Streams back pressure.
40+
* High concurrency with less hardware resources.
41+
* Functional-style, fluent API taking advantage of Java 8 lambdas.
42+
* Synchronous and asynchronous interactions.
43+
* Streaming up to or streaming down from a server.
44+
3645
See <<web-reactive.adoc#webflux-client,WebClient>> for more details.

0 commit comments

Comments
 (0)