private void closeAsync(CompletableFuture<?> future) {
        if (leakTracker != null) {
            leakTracker.close(this);
        }

        final CompletableFuture<?>[] delegateCloseFutures =
                clientFactoriesToClose.stream()
                                      .map(ClientFactory::closeAsync)
                                      .toArray(CompletableFuture[]::new);

        CompletableFuture.allOf(delegateCloseFutures).handle((unused, cause) -> {
            if (cause != null) {
                future.completeExceptionally(cause);
            } else {
                future.complete(null);
            }
            return null;
        });
    }
A {@link ClientFactory} which combines all discovered {@link ClientFactory} implementations.

<h2>How are the {@link ClientFactory}s discovered?</h2>

<p>{@link DefaultClientFactory} looks up the {@link ClientFactoryProvider}s available in the current JVM
using Java SPI (Service Provider Interface). The {@link ClientFactoryProvider} implementations will create
the {@link ClientFactory} implementations.
core/src/main/java/com/linecorp/armeria/client/DefaultClientFactory.java