Browse Source

Add `HttpClientTransport` factory support

Update `JettyClientHttpRequestFactoryBuilder` and
`JettyClientHttpConnectorBuilder` with support for create the
`HttpClientTransport` from a factory function.

Closes gh-47251
pull/47286/head
Phillip Webb 6 months ago
parent
commit
255ea92a57
  1. 15
      module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JettyClientHttpRequestFactoryBuilder.java
  2. 40
      module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JettyHttpClientBuilder.java
  3. 15
      module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/JettyClientHttpConnectorBuilder.java
  4. 21
      module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/JettyClientHttpRequestFactoryBuilderTests.java
  5. 21
      module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/JettyClientHttpConnectorBuilderTests.java

15
module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JettyClientHttpRequestFactoryBuilder.java

@ -20,6 +20,7 @@ import java.time.Duration; @@ -20,6 +20,7 @@ import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import org.eclipse.jetty.client.HttpClient;
@ -78,6 +79,20 @@ public final class JettyClientHttpRequestFactoryBuilder @@ -78,6 +79,20 @@ public final class JettyClientHttpRequestFactoryBuilder
this.httpClientBuilder.withCustomizer(httpClientCustomizer));
}
/**
* Return a new {@link JettyClientHttpRequestFactoryBuilder} that uses the given
* factory to create the {@link HttpClientTransport}.
* @param httpClientTransportFactory the {@link HttpClientTransport} factory to use
* @return a new {@link JettyClientHttpRequestFactoryBuilder} instance
* @since 4.0.0
*/
public JettyClientHttpRequestFactoryBuilder withHttpClientTransportFactory(
Function<ClientConnector, HttpClientTransport> httpClientTransportFactory) {
Assert.notNull(httpClientTransportFactory, "'httpClientTransportFactory' must not be null");
return new JettyClientHttpRequestFactoryBuilder(getCustomizers(),
this.httpClientBuilder.withHttpClientTransportFactory(httpClientTransportFactory));
}
/**
* Return a new {@link JettyClientHttpRequestFactoryBuilder} that applies additional
* customization to the underlying {@link HttpClientTransport}.

40
module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JettyHttpClientBuilder.java

@ -19,6 +19,7 @@ package org.springframework.boot.http.client; @@ -19,6 +19,7 @@ package org.springframework.boot.http.client;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import javax.net.ssl.SSLContext;
@ -48,22 +49,31 @@ public final class JettyHttpClientBuilder { @@ -48,22 +49,31 @@ public final class JettyHttpClientBuilder {
private final Consumer<HttpClient> customizer;
private final Function<ClientConnector, HttpClientTransport> httpClientTransportFactory;
private final Consumer<HttpClientTransport> httpClientTransportCustomizer;
private final Consumer<ClientConnector> clientConnectorCustomizerCustomizer;
public JettyHttpClientBuilder() {
this(Empty.consumer(), Empty.consumer(), Empty.consumer());
this(Empty.consumer(), JettyHttpClientBuilder::createHttpClientTransport, Empty.consumer(), Empty.consumer());
}
private JettyHttpClientBuilder(Consumer<HttpClient> customizer,
Function<ClientConnector, HttpClientTransport> httpClientTransportFactory,
Consumer<HttpClientTransport> httpClientTransportCustomizer,
Consumer<ClientConnector> clientConnectorCustomizerCustomizer) {
this.customizer = customizer;
this.httpClientTransportFactory = httpClientTransportFactory;
this.httpClientTransportCustomizer = httpClientTransportCustomizer;
this.clientConnectorCustomizerCustomizer = clientConnectorCustomizerCustomizer;
}
private static HttpClientTransport createHttpClientTransport(ClientConnector connector) {
return (connector.getSslContextFactory() != null) ? new HttpClientTransportDynamic(connector)
: new HttpClientTransportOverHTTP(connector);
}
/**
* Return a new {@link JettyClientHttpRequestFactoryBuilder} that applies additional
* customization to the underlying {@link HttpClient}.
@ -72,8 +82,22 @@ public final class JettyHttpClientBuilder { @@ -72,8 +82,22 @@ public final class JettyHttpClientBuilder {
*/
public JettyHttpClientBuilder withCustomizer(Consumer<HttpClient> customizer) {
Assert.notNull(customizer, "'customizer' must not be null");
return new JettyHttpClientBuilder(this.customizer.andThen(customizer), this.httpClientTransportCustomizer,
this.clientConnectorCustomizerCustomizer);
return new JettyHttpClientBuilder(this.customizer.andThen(customizer), this.httpClientTransportFactory,
this.httpClientTransportCustomizer, this.clientConnectorCustomizerCustomizer);
}
/**
* Return a new {@link JettyClientHttpRequestFactoryBuilder} that uses the given
* factory to create the {@link HttpClientTransport}.
* @param httpClientTransportFactory the {@link HttpClientTransport} factory to use
* @return a new {@link JettyClientHttpRequestFactoryBuilder} instance
* @since 4.0.0
*/
public JettyHttpClientBuilder withHttpClientTransportFactory(
Function<ClientConnector, HttpClientTransport> httpClientTransportFactory) {
Assert.notNull(httpClientTransportFactory, "'httpClientTransportFactory' must not be null");
return new JettyHttpClientBuilder(this.customizer, httpClientTransportFactory,
this.httpClientTransportCustomizer, this.clientConnectorCustomizerCustomizer);
}
/**
@ -85,7 +109,7 @@ public final class JettyHttpClientBuilder { @@ -85,7 +109,7 @@ public final class JettyHttpClientBuilder {
public JettyHttpClientBuilder withHttpClientTransportCustomizer(
Consumer<HttpClientTransport> httpClientTransportCustomizer) {
Assert.notNull(httpClientTransportCustomizer, "'httpClientTransportCustomizer' must not be null");
return new JettyHttpClientBuilder(this.customizer,
return new JettyHttpClientBuilder(this.customizer, this.httpClientTransportFactory,
this.httpClientTransportCustomizer.andThen(httpClientTransportCustomizer),
this.clientConnectorCustomizerCustomizer);
}
@ -99,7 +123,8 @@ public final class JettyHttpClientBuilder { @@ -99,7 +123,8 @@ public final class JettyHttpClientBuilder {
public JettyHttpClientBuilder withClientConnectorCustomizerCustomizer(
Consumer<ClientConnector> clientConnectorCustomizerCustomizer) {
Assert.notNull(clientConnectorCustomizerCustomizer, "'clientConnectorCustomizerCustomizer' must not be null");
return new JettyHttpClientBuilder(this.customizer, this.httpClientTransportCustomizer,
return new JettyHttpClientBuilder(this.customizer, this.httpClientTransportFactory,
this.httpClientTransportCustomizer,
this.clientConnectorCustomizerCustomizer.andThen(clientConnectorCustomizerCustomizer));
}
@ -127,8 +152,9 @@ public final class JettyHttpClientBuilder { @@ -127,8 +152,9 @@ public final class JettyHttpClientBuilder {
private HttpClientTransport createTransport(HttpClientSettings settings) {
ClientConnector connector = createClientConnector(settings.sslBundle());
return (connector.getSslContextFactory() != null) ? new HttpClientTransportDynamic(connector)
: new HttpClientTransportOverHTTP(connector);
HttpClientTransport clientTransport = this.httpClientTransportFactory.apply(connector);
Assert.state(clientTransport != null, "'httpClientTransportFactory' did not return a client transport");
return clientTransport;
}
private ClientConnector createClientConnector(@Nullable SslBundle sslBundle) {

15
module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/JettyClientHttpConnectorBuilder.java

@ -19,6 +19,7 @@ package org.springframework.boot.http.client.reactive; @@ -19,6 +19,7 @@ package org.springframework.boot.http.client.reactive;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import org.eclipse.jetty.client.HttpClient;
@ -62,6 +63,20 @@ public final class JettyClientHttpConnectorBuilder @@ -62,6 +63,20 @@ public final class JettyClientHttpConnectorBuilder
return new JettyClientHttpConnectorBuilder(mergedCustomizers(customizers), this.httpClientBuilder);
}
/**
* Return a new {@link JettyClientHttpConnectorBuilder} that uses the given factory to
* create the {@link HttpClientTransport}.
* @param httpClientTransportFactory the {@link HttpClientTransport} factory to use
* @return a new {@link JettyClientHttpConnectorBuilder} instance
* @since 4.0.0
*/
public JettyClientHttpConnectorBuilder withHttpClientTransportFactory(
Function<ClientConnector, HttpClientTransport> httpClientTransportFactory) {
Assert.notNull(httpClientTransportFactory, "'httpClientTransportFactory' must not be null");
return new JettyClientHttpConnectorBuilder(getCustomizers(),
this.httpClientBuilder.withHttpClientTransportFactory(httpClientTransportFactory));
}
/**
* Return a new {@link JettyClientHttpConnectorBuilder} that applies additional
* customization to the underlying {@link HttpClient}.

21
module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/JettyClientHttpRequestFactoryBuilderTests.java

@ -18,12 +18,15 @@ package org.springframework.boot.http.client; @@ -18,12 +18,15 @@ package org.springframework.boot.http.client;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.io.ClientConnector;
import org.junit.jupiter.api.Test;
import org.springframework.http.client.JettyClientHttpRequestFactory;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JettyClientHttpRequestFactoryBuilder} and
* {@link JettyHttpClientBuilder}.
@ -62,6 +65,16 @@ class JettyClientHttpRequestFactoryBuilderTests @@ -62,6 +65,16 @@ class JettyClientHttpRequestFactoryBuilderTests
customizer.assertCalled();
}
@Test
void withHttpClientTransportFactory() {
JettyClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jetty()
.withHttpClientTransportFactory(TestHttpClientTransport::new)
.build();
assertThat(factory).extracting("httpClient")
.extracting("transport")
.isInstanceOf(TestHttpClientTransport.class);
}
@Override
protected long connectTimeout(JettyClientHttpRequestFactory requestFactory) {
return ((HttpClient) ReflectionTestUtils.getField(requestFactory, "httpClient")).getConnectTimeout();
@ -72,4 +85,12 @@ class JettyClientHttpRequestFactoryBuilderTests @@ -72,4 +85,12 @@ class JettyClientHttpRequestFactoryBuilderTests
return (long) ReflectionTestUtils.getField(requestFactory, "readTimeout");
}
static class TestHttpClientTransport extends HttpClientTransportOverHTTP {
TestHttpClientTransport(ClientConnector connector) {
super(connector);
}
}
}

21
module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/JettyClientHttpConnectorBuilderTests.java

@ -20,6 +20,7 @@ import java.time.Duration; @@ -20,6 +20,7 @@ import java.time.Duration;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.io.ClientConnector;
import org.junit.jupiter.api.Test;
@ -27,6 +28,8 @@ import org.springframework.boot.http.client.JettyHttpClientBuilder; @@ -27,6 +28,8 @@ import org.springframework.boot.http.client.JettyHttpClientBuilder;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JettyClientHttpConnectorBuilder} and {@link JettyHttpClientBuilder}.
*
@ -63,6 +66,16 @@ class JettyClientHttpConnectorBuilderTests extends AbstractClientHttpConnectorBu @@ -63,6 +66,16 @@ class JettyClientHttpConnectorBuilderTests extends AbstractClientHttpConnectorBu
customizer.assertCalled();
}
@Test
void withHttpClientTransportFactory() {
JettyClientHttpConnector connector = ClientHttpConnectorBuilder.jetty()
.withHttpClientTransportFactory(TestHttpClientTransport::new)
.build();
assertThat(connector).extracting("httpClient")
.extracting("transport")
.isInstanceOf(TestHttpClientTransport.class);
}
@Override
protected long connectTimeout(JettyClientHttpConnector connector) {
return ((HttpClient) ReflectionTestUtils.getField(connector, "httpClient")).getConnectTimeout();
@ -74,4 +87,12 @@ class JettyClientHttpConnectorBuilderTests extends AbstractClientHttpConnectorBu @@ -74,4 +87,12 @@ class JettyClientHttpConnectorBuilderTests extends AbstractClientHttpConnectorBu
return ((Duration) ReflectionTestUtils.getField(httpClient, "readTimeout")).toMillis();
}
static class TestHttpClientTransport extends HttpClientTransportOverHTTP {
TestHttpClientTransport(ClientConnector connector) {
super(connector);
}
}
}

Loading…
Cancel
Save