Improvements to the Jetty documentation.

Clarified that HttpClient cannot be stopped from its own threads.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2021-04-20 17:22:54 +02:00
parent d3a8817c76
commit 9176d83423
4 changed files with 41 additions and 3 deletions

View File

@ -84,6 +84,17 @@ include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPCli
Stopping `HttpClient` makes sure that the memory it holds (for example, authentication credentials, cookies, etc.) is released, and that the thread pool and scheduler are properly stopped allowing all threads used by `HttpClient` to exit.
[NOTE]
====
You cannot call `HttpClient.stop()` from one of its own threads, as it would cause a deadlock.
It is recommended that you stop `HttpClient` from an unrelated thread, or from a newly allocated thread, for example:
[source,java,indent=0]
----
include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=stopFromOtherThread]
----
====
[[pg-client-http-arch]]
==== HttpClient Architecture

View File

@ -66,6 +66,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.HttpCookieStore;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import static java.lang.System.Logger.Level.INFO;
@ -97,6 +98,17 @@ public class HTTPClientDocs
// end::stop[]
}
public void stopFromOtherThread() throws Exception
{
HttpClient httpClient = new HttpClient();
httpClient.start();
// tag::stopFromOtherThread[]
// Stop HttpClient from a new thread.
// Use LifeCycle.stop(...) to rethrow checked exceptions as unchecked.
new Thread(() -> LifeCycle.stop(httpClient)).start();
// end::stopFromOtherThread[]
}
public void tlsExplicit() throws Exception
{
// tag::tlsExplicit[]

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.client;
import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.io.ClientConnector;
@ -30,7 +31,7 @@ public abstract class AbstractConnectorHttpClientTransport extends AbstractHttpC
protected AbstractConnectorHttpClientTransport(ClientConnector connector)
{
this.connector = connector;
this.connector = Objects.requireNonNull(connector);
addBean(connector);
}

View File

@ -19,6 +19,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -86,7 +87,12 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
*/
public HttpClientTransportDynamic()
{
this(new ClientConnector(), HttpClientConnectionFactory.HTTP11);
this(HttpClientConnectionFactory.HTTP11);
}
public HttpClientTransportDynamic(ClientConnectionFactory.Info... factoryInfos)
{
this(findClientConnector(factoryInfos), factoryInfos);
}
/**
@ -98,7 +104,6 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
public HttpClientTransportDynamic(ClientConnector connector, ClientConnectionFactory.Info... factoryInfos)
{
super(connector);
addBean(connector);
if (factoryInfos.length == 0)
factoryInfos = new Info[]{HttpClientConnectionFactory.HTTP11};
this.factoryInfos = Arrays.asList(factoryInfos);
@ -112,6 +117,15 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
new MultiplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, 1));
}
private static ClientConnector findClientConnector(ClientConnectionFactory.Info[] infos)
{
return Arrays.stream(infos)
.map(info -> info.getBean(ClientConnector.class))
.filter(Objects::nonNull)
.findFirst()
.orElse(new ClientConnector());
}
@Override
public Origin newOrigin(HttpRequest request)
{