Закрыть Java HTTP-клиент - PullRequest
0 голосов
/ 25 декабря 2018

Есть ли способ закрыть java.net.http.HttpClient, чтобы мгновенно высвободить имеющиеся у него ресурсы?

Внутренне он содержит селектор, пул соединений и Executor (при использовании по умолчанию).Однако он не реализует Closeable / AutoCloseable.

Ответы [ 3 ]

0 голосов
/ 12 августа 2019

В Java 11 каждый HttpClient порождает поток демона с именем selmgr, который должен обрабатывать запросы fly.Этот поток будет закрыт, если в коде нет ссылки на HttpClient.Однако, по моему опыту, это не надежно.Особенно, когда вы используете асинхронные методы с будущими таймаутами.

Вот фрагмент кода, который я написал, используя отражение, чтобы надежно закрыть HttpClient

static void shutDownHttpClient(HttpClient httpClient)
{
    ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) httpClient.executor().get();
    threadPoolExecutor.shutdown();
    try {
        Field implField = httpClient.getClass().getDeclaredField("impl");
        implField.setAccessible(true);
        Object implObj = implField.get(httpClient);
        Field selmgrField = implObj.getClass().getDeclaredField("selmgr");
        selmgrField.setAccessible(true);
        Object selmgrObj = selmgrField.get(implObj);
        Method shutDownMethod = selmgrObj.getClass().getDeclaredMethod("shutdown");
        shutDownMethod.setAccessible(true);
        shutDownMethod.invoke(selmgrObj);
    }
    catch (Exception e) {
        System.out.println("exception " + e.getMessage());
        e.printStackTrace();
    }

}

Как видите, этозависит от реализации и может не работать с будущими версиями Java.Он протестирован с Java 11 и Java 12.

Кроме того, вам нужно добавить --add-opens java.net.http/jdk.internal.net.http=ALL-UNNAMED к вашей команде java.

0 голосов
/ 12 августа 2019

Очевидно, HttpClient предназначен для самостоятельного управления.Поэтому он отвечает за поддержание пула соединений, кеширует ttl сам по себе.

В HttpClientCode Мы могли бы найти следующий код:

if (!owner.isReferenced()) {
                                Log.logTrace("{0}: {1}",
                                        getName(),
                                        "HttpClient no longer referenced. Exiting...");
                                return;
                            }

это изящный способ выхода из SelectorManagerЗацикливание и очистка всех ресурсов.

 @Override
 public void run() {
            ...

            try {

                while (!Thread.currentThread().isInterrupted()) {

                    ...

                    if (!owner.isReferenced()) {
                        Log.logTrace("{0}: {1}",
                                getName(),
                                "HttpClient no longer referenced. Exiting...");
                        return;
                    }

                    ...
                }
            } catch (Throwable e) {
                ...
            } finally {
                ...
                shutdown();
            }
        }




    final boolean isReferenced() {
            HttpClient facade = facade();
            return facade != null || referenceCount() > 0;
        }

Таким образом, когда на ваш объект HttpClient не будут ссылаться, он будет очищать все ресурсы.

UPD: также вы должны настроить свои запросы, передавтаймауты

0 голосов
/ 25 декабря 2018

Как вы заметили, java.net.http.HttpClient не реализует Closeable или AutoCloseable.Таким образом, я могу думать только о двух вариантах, но ни один из них не является действительно пуленепробиваемым или даже хорошим:

Вы можете исключить каждую сильную ссылку на HttpClient, которую держит ваша программа и запросить сборку мусора .Однако существует реальный риск того, что что-то, находящееся за пределами вашего прямого контроля, удерживает его или один из его компонентов.Любые оставшиеся строгие ссылки будут препятствовать сборке мусора на объект, на который он ссылается, и любые объекты, на которые он содержит строгую ссылку.Тем не менее, это, возможно, более идиоматический вариант, чем альтернативный.

Я также нашел другой вариант .

final class HttpClientImpl extends HttpClient implements Trackable {
    ...
    // Called from the SelectorManager thread, just before exiting.
    // Clears the HTTP/1.1 and HTTP/2 cache, ensuring that the connections
    // that may be still lingering there are properly closed (and their
    // possibly still opened SocketChannel released).
    private void stop() {
        // Clears HTTP/1.1 cache and close its connections
        connections.stop();
        // Clears HTTP/2 cache and close its connections.
        client2.stop();
    }
    ...
}

Я бы не чувствовал себя комфортно, если бы ядругого выбора не было.Ваша ссылка, вероятно, имеет тип HttpClient, поэтому вам нужно привести ее к HttpClientImpl.Плохо полагаться на конкретную реализацию, которая может измениться в будущих выпусках, а не на интерфейс HttpClient.Метод также является частным.Есть способы обойти это , но это грязно.

...