Customize Spring WebClient with WebClientCustomizer

Last Updated:  August 3, 2021 | Published: March 4, 2020

Spring Once you use the Spring WebClient at multiple places in your application, providing a unified configuration with copy-pasting, e.g., common headers to all places is cumbersome. The Spring WebClient provides a mechanism to customize all instances using the WebClientCustomizer interface globally. This blog post demonstrates how to customize the Spring WebClient at a central place. Due to Spring Boot's autoconfiguration mechanism, there's almost nothing to set up in addition.

Spring WebClient Project Setup

The automatic registration of our WebClient customizations is done by Spring Boot's autoconfiguration. Therefore the demo application uses spring-boot-starter-web and spring-boot-start-webflux.

If your application uses Spring WebFlux without Spring Boot, you can still follow this article. In such cases, make sure to mirror the autoconfiguration of Spring Boot inside your application.

For this example, the WebFlux dependency would be enough. As most projects out there still use the embedded Tomcat and some minor parts from WebFlux, we're using the following project setup:

As part of the Spring Boot dependency, we get the following autoconfiguration class (WebClientAutoConfiguration):

This autoconfiguration exposes a pre-configured instance of WebClient.Builder. Within the constructor of this class, we see the injection of ObjectProvider<WebClientCustomizer>. This ObjectProvider is capable of returning all object instances of the WebClientCustomizer interface to customize the WebClient.Builder.

While exposing this WebClient.Builder instance in this autoconfiguration using @Bean, we might wonder what the @Scope("prototype") annotation is used. This overrides the default singleton scope to use the prototype scope. Spring won't share instances of these beans among the application like for singletons. For each injection point, a new instance is created and returned to the caller.

Defining Customizations with WebClientCustomizer

As we already saw how the autoconfiguration works internally, we now have to implement the WebClientCustomizer.

First, we're creating a global customization to ensure all WebClients include the same User-Agent HTTP header. In a distributed system architecture, this customization can help to understand communication patterns and to identify the origin of an HTTP request:

While implementing the WebClientCustomizer interface, we get access to the WebClient.Builder and can set multiple configurations like headers, cookies, exchange strategies, filters, and much more.

Next, let's provide a logging mechanism for all WebClient instances. Therefore, we can create another customization:

Please note the @Component annotation on top of each of these two classes. This is required for Spring to pick it up while scanning the project for all available beans (aka. component scanning). Without this annotation, the ObjectProvider<WebClientCustomizer> will we empty and won't know about our customization.

Using the Customized Spring WebClient

There are now basically two ways of using this pre-configured WebClient.

First, we can provide a central configuration with all our WebClient instances. For an application that communicates with a stock and random data API, this might look like the following:

Our business logic can then request such an instance by its name, e.g. @Autowired WebClient stockApiClient.

Second, we can also inject the WebClient.Builder into our classes directly and construct a WebClient instance there:

Please note: It's important to always inject and use the autoconfigured WebClient.Builder from Spring Boot. If we manually construct a WebClient using WebClient.builder(), we won't get the customizations out of the box.

Once the WebClient makes the remote call, we'll get the following output and can see all headers, including our custom User-Agent:

The source code for this Spring WebClient customization example is available on GitHub.

For more Spring WebClient related content, consider the following articles:

Have fun customizing your Spring WebClient,

Phil

>