BAEL-5720 Java HttpClient Connection Management (#13452)

* BAEL-5642 Using @NotNull as a method parameter

* BAEL-5642 Add Spring Boot and bump spring and hibernate-validator versions

* BAEL-5720 Java HttpClient Connection Management

* BAEL-5720 Java HttpClient Connection Management

* BAEL-5720 move JavaHttpClient test to core-java-httpclient module

* BAEL-5720 move jetty-logging-properties to core-java-httpclient module

* BAEL-5720 add wiremock to pom

* Update pom.xml

* Delete jetty-logging.properties

---------

Co-authored-by: Loredana Crusoveanu <lore.crusoveanu@gmail.com>
This commit is contained in:
Roger 2023-02-11 02:19:24 +10:00 committed by GitHub
parent 5c9dcf7733
commit 5fb9fe4642
5 changed files with 159 additions and 2 deletions

View File

@ -32,6 +32,12 @@
<version>${assertj.version}</version> <version>${assertj.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>${wiremock.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -53,6 +59,7 @@
<maven.compiler.target.version>11</maven.compiler.target.version> <maven.compiler.target.version>11</maven.compiler.target.version>
<assertj.version>3.22.0</assertj.version> <assertj.version>3.22.0</assertj.version>
<mockserver.version>5.11.2</mockserver.version> <mockserver.version>5.11.2</mockserver.version>
<wiremock.version>2.27.2</wiremock.version>
</properties> </properties>
</project> </project>

View File

@ -0,0 +1,147 @@
package com.baeldung.httpclient.conn;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import static java.net.URI.create;
public class HttpClientConnectionManagementUnitTest {
WireMockConfiguration firstConfiguration = WireMockConfiguration
.options()
.dynamicPort();
WireMockConfiguration secondConfiguration = WireMockConfiguration
.options()
.dynamicPort();
WireMockServer firstServer = new WireMockServer(firstConfiguration);
WireMockServer secondServer = new WireMockServer(secondConfiguration);
private String firstUrl;
private String secondUrl;
private HttpClient client = HttpClient.newHttpClient();
private HttpClient secondClient = HttpClient.newHttpClient();
private HttpRequest getRequest;
private HttpRequest secondGet;
@Before
public void setup() {
firstServer.start();
secondServer.start();
// add some request matchers
firstServer.stubFor(WireMock
.get(WireMock.anyUrl())
.willReturn(WireMock
.aResponse()
.withStatus(200)));
secondServer.stubFor(WireMock
.get(WireMock.anyUrl())
.willReturn(WireMock
.aResponse()
.withStatus(200)));
firstUrl = "http://localhost:" + firstServer.port() + "/first";
secondUrl = "http://localhost:" + secondServer.port() + "/second";
getRequest = HttpRequest
.newBuilder()
.uri(create(firstUrl))
.version(HttpClient.Version.HTTP_1_1)
.build();
secondGet = HttpRequest
.newBuilder()
.uri(create(secondUrl))
.version(HttpClient.Version.HTTP_1_1)
.build();
}
@After
public void tearDown() {
// display all the requests that the WireMock servers handled
List<ServeEvent> firstWiremockAllServeEvents = firstServer.getAllServeEvents();
List<ServeEvent> secondWiremockAllServeEvents = secondServer.getAllServeEvents();
firstWiremockAllServeEvents
.stream()
.map(event -> event
.getRequest()
.getAbsoluteUrl())
.forEach(System.out::println);
secondWiremockAllServeEvents
.stream()
.map(event -> event
.getRequest()
.getAbsoluteUrl())
.forEach(System.out::println);
// stop the WireMock servers
firstServer.stop();
secondServer.stop();
}
// Example 1. Use an HttpClient to connect to the same endpoint - reuses a connection from the internal pool
@Test
public final void givenAnHttpClient_whenTwoConnectionsToSameEndpointMadeSequentially_thenConnectionReused() throws InterruptedException, IOException {
// given two requests to the same destination
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
final HttpResponse<String> secondResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
assert (firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200);
}
// Example 2. Use separate HttpClients to connect to the same endpoint - creates a connection per client
@Test
public final void givenTwoHttpClients_whenEachClientMakesConnectionSequentially_thenConnectionCreatedForEach() throws InterruptedException, IOException {
// given requests from two different client to same destination
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
final HttpResponse<String> secondResponse = secondClient.send(getRequest, HttpResponse.BodyHandlers.ofString());
assert (firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200);
}
// Example 3. Use an HttpClient to Connect to first, second, then first endpoint again.
// New connections made each time when pool size is 1, or re-used when not restricted.
// Make sure to set the JVM arg when running the test:
// -Djdk.httpclient.connectionPoolSize=1
@Test
public final void givenAnHttpClientAndAPoolSizeOfOne_whenTwoConnectionsMadeBackToOriginal_thenFirstConnectionPurged() throws InterruptedException, IOException {
// given 3 requests, two to the first server and one to the second server
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
final HttpResponse<String> secondResponse = client.send(secondGet, HttpResponse.BodyHandlers.ofString());
final HttpResponse<String> thirdResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
assert ((firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200) && (thirdResponse.statusCode() == 200));
}
// Example 4. Use an HttpClient to connect, wait for connection keepalive to pass, then connect again. New connection made for both calls.
// Make sure to set the JVM arg when running the test:
// -Djdk.httpclient.keepalive.timeout=2
@Test
public final void givenAnHttpClientAndConnectionKeepAliveOfTwoSeconds_whenCallMadeAfterKeepaliveExpires_thenNewConnection() throws InterruptedException, IOException {
// given 2 requests to the same destination with the second call made after the keepalive timeout has passed
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
Thread.sleep(3000); // exceeds 2 seconds configured by JVM arg
final HttpResponse<String> secondResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
assert ((firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200));
}
}

View File

@ -0,0 +1,3 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog
org.eclipse.jetty.LEVEL=DEBUG
jetty.logs=logs