Support Jetty RS as HTTP driver for WebClient

This commit adds a new auto-configuration choice for
`ClientHttpConnector`, this time using the Jetty RS HTTP client library
if available.

This is the best choice in case the application runs on a Jetty reactive
server, as both client and server will share resources.

Closes gh-14005
pull/14005/merge
Brian Clozel 6 years ago
parent f74dd7d58c
commit 53f3982748

@ -280,6 +280,11 @@
<artifactId>jetty-webapp</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-reactive-httpclient</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>

@ -39,7 +39,8 @@ import org.springframework.web.reactive.function.client.WebClient;
*/
@Configuration
@ConditionalOnClass(WebClient.class)
@Import({ ClientHttpConnectorConfiguration.ReactorNetty.class })
@Import({ ClientHttpConnectorConfiguration.ReactorNetty.class,
ClientHttpConnectorConfiguration.JettyClient.class })
public class ClientHttpConnectorAutoConfiguration {
@Bean

@ -23,6 +23,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.http.client.reactive.JettyResourceFactory;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
@ -59,4 +61,24 @@ class ClientHttpConnectorConfiguration {
}
@Configuration
@ConditionalOnClass(org.eclipse.jetty.reactive.client.ReactiveRequest.class)
@ConditionalOnMissingBean(ClientHttpConnector.class)
public static class JettyClient {
@Bean
@ConditionalOnMissingBean
public JettyResourceFactory jettyResourceFactory() {
return new JettyResourceFactory();
}
@Bean
public JettyClientHttpConnector jettyClientHttpConnector(
JettyResourceFactory jettyResourceFactory) {
return new JettyClientHttpConnector(jettyResourceFactory, (httpClient) -> {
});
}
}
}

@ -21,6 +21,9 @@ import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.web.reactive.function.client.WebClient;
@ -56,4 +59,49 @@ public class ClientHttpConnectorAutoConfigurationTests {
});
}
@Test
public void shouldNotOverrideCustomClientConnector() {
this.contextRunner.withUserConfiguration(CustomClientHttpConnectorConfig.class)
.run((context) -> {
assertThat(context).hasSingleBean(ClientHttpConnector.class)
.hasBean("customConnector")
.doesNotHaveBean(ReactorResourceFactory.class);
WebClientCustomizer clientCustomizer = context
.getBean(WebClientCustomizer.class);
WebClient.Builder builder = mock(WebClient.Builder.class);
clientCustomizer.customize(builder);
verify(builder, times(1))
.clientConnector(any(ClientHttpConnector.class));
});
}
@Test
public void shouldUseCustomReactorResourceFactory() {
this.contextRunner.withUserConfiguration(CustomReactorResourceConfig.class)
.run((context) -> assertThat(context)
.hasSingleBean(ReactorClientHttpConnector.class)
.hasSingleBean(ReactorResourceFactory.class)
.hasBean("customReactorResourceFactory"));
}
@Configuration
static class CustomClientHttpConnectorConfig {
@Bean
public ClientHttpConnector customConnector() {
return mock(ClientHttpConnector.class);
}
}
@Configuration
static class CustomReactorResourceConfig {
@Bean
public ReactorResourceFactory customReactorResourceFactory() {
return new ReactorResourceFactory();
}
}
}

@ -5822,6 +5822,12 @@ The following code shows a typical example:
Spring Boot will auto-detect which `ClientHttpConnector` to drive `WebClient`, depending
on the libraries available on the application classpath.
The `spring-boot-starter-webflux` depends on `io.projectreactor.netty:reactor-netty` by
default, which brings both server and client implementations. If you choose to use Jetty
as a reactive server instead, you should add a dependency on the Jetty Reactive HTTP
client library, `org.eclipse.jetty:jetty-reactive-httpclient`, because it will
automatically share HTTP resources with the server.
Developers can override this choice by defining their own `ClientHttpConnector` bean;
in this case, and depending on your HTTP client library of choice, you should also
define a resource factory bean that manages the HTTP resources for that client.

Loading…
Cancel
Save