Асинхронный HTTP с async-http-клиентом в Java
1. обзор
AsyncHttpClient (AHC) - это библиотека, построенная на основеNetty, с целью простого выполнения HTTP-запросов и асинхронной обработки ответов.
В этой статье мы расскажем, как настроить и использовать HTTP-клиент, как выполнить запрос и обработать ответ с помощью AHC.
2. Настроить
Последнюю версию библиотеки можно найти в папкеMaven repository. Мы должны быть осторожны, чтобы использовать зависимость с идентификатором группыorg.asynchttpclient, а не с зависимостью сcom.ning:
org.asynchttpclient
async-http-client
2.2.0
3. Конфигурация клиента HTTP
Самый простой способ получить HTTP-клиент - использовать классDsl. Статический методasyncHttpClient() возвращает объектAsyncHttpClient:
AsyncHttpClient client = Dsl.asyncHttpClient();
Если нам нужна специальная конфигурация HTTP-клиента, мы можем построить объектAsyncHttpClient с помощью построителяDefaultAsyncHttpClientConfig.Builder:
DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config()
Это дает возможность настроить тайм-ауты, прокси-сервер, HTTP-сертификаты и многое другое:
DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config()
.setConnectTimeout(500)
.setProxyServer(new ProxyServer(...));
AsyncHttpClient client = Dsl.asyncHttpClient(clientBuilder);
После того, как мы настроили и получилиan instance of the HTTP client we can reuse it across out application. Нам не нужно создавать экземпляр для каждого запроса, потому что внутри он создает новые потоки и пулы соединений, что приведет к проблемам с производительностью.
Также важно отметить, чтоonce we’ve finished using the client we should call to close() method to prevent any memory leaks или зависшие ресурсы.
4. Создание HTTP-запроса
Есть два метода, в которых мы можем определить HTTP-запрос, используя AHC:
-
связанный
-
несвязанный
Нет большой разницы между двумя типами запросов с точки зрения производительности. Они представляют только два отдельных API, которые мы можем использовать для определения запроса. A bound request is tied to the HTTP client it was created from and will, by default, use the configuration of that specific client if not specified otherwise.с
Например, при создании связанного запроса флагdisableUrlEncoding считывается из конфигурации HTTP-клиента, а для несвязанного запроса по умолчанию установлено значение false. Это полезно, потому что конфигурацию клиента можно изменить без перекомпиляции всего приложения, используя системные свойства, передаваемые в качестве аргументов виртуальной машины:
java -jar -Dorg.asynchttpclient.disableUrlEncodingForBoundRequests=true
Полный список свойств можно найти в файлеahc-default.properties.
4.1. Связанный запрос
Для создания связанного запроса мы используем вспомогательные методы из классаAsyncHttpClient, которые начинаются с префикса“prepare”. Также мы можем использовать методprepareRequest(), который получает уже созданный объектRequest.
Например, методprepareGet() создаст HTTP-запрос GET:
BoundRequestBuilder getRequest = client.prepareGet("http://www.example.com");
4.2. Несвязанный запрос
Несвязанный запрос можно создать с помощью классаRequestBuilder:
Request getRequest = new RequestBuilder(HttpConstants.Methods.GET)
.setUrl("http://www.example.com")
.build();
или с помощью вспомогательного классаDsl, который фактически используетRequestBuilder для настройки метода HTTP и URL-адреса запроса:
Request getRequest = Dsl.get("http://www.example.com").build()
5. Выполнение HTTP-запросов
Название библиотеки дает нам подсказку о том, как запросы могут быть выполнены. AHC поддерживает как синхронные, так и асинхронные запросы.
Выполнение запроса зависит от его типа. При использовании классаbound request we use the execute() method from the BoundRequestBuilder и когда у нас естьunbound request we’ll execute it using one of the implementations of the executeRequest() method from the AsyncHttpClient interface.
5.1. Синхронно
Библиотека была спроектирована как асинхронная, но при необходимости мы можем имитировать синхронные вызовы, заблокировав объектFuture. Оба методаexecute() иexecuteRequest() возвращают объектListenableFuture<Response>. Этот класс расширяет интерфейс JavaFuture, наследуя методget(), который можно использовать для блокировки текущего потока до тех пор, пока HTTP-запрос не будет завершен и не вернет ответ:
Future responseFuture = boundGetRequest.execute();
responseFuture.get();
Future responseFuture = client.executeRequest(unboundRequest);
responseFuture.get();
Использование синхронных вызовов полезно при попытке отладки частей нашего кода, но не рекомендуется использовать в производственной среде, где асинхронное выполнение приводит к повышению производительности и пропускной способности.
5.2. Асинхронный
Когда мы говорим об асинхронных выполнениях, мы также говорим о слушателях для обработки результатов. Библиотека AHC предоставляет 3 типа слушателей, которые можно использовать для асинхронных HTTP-вызовов:
-
AsyncHandler
-
AsyncCompletionHandler
-
ListenableFuture слушателей
СлушательAsyncHandler предлагает возможность контролировать и обрабатывать HTTP-вызов до его завершения. С его помощью можно обработать серию событий, связанных с вызовом HTTP:
request.execute(new AsyncHandler
ПеречислениеState позволяет нам контролировать обработку HTTP-запроса. ВозвращаяState.ABORT we can stop the processing в определенный момент и используяState.CONTINUE, мы даем завершение обработки.
Важно отметить, чтоAsyncHandler isn’t thread-safe and shouldn’t be reused when executing concurrent requests.
AsyncCompletionHandler наследует все методы интерфейсаAsyncHandler и добавляет вспомогательный методonCompleted(Response) для обработки завершения вызова. Все другие методы прослушивателя переопределяются для возвратаState.CONTINUE, что делает код более читаемым:
request.execute(new AsyncCompletionHandler
ИнтерфейсListenableFuture позволяет нам добавлять слушателей, которые будут запускаться после завершения HTTP-вызова.
Кроме того, давайте выполним код от слушателей - используя другой пул потоков:
ListenableFuture listenableFuture = client
.executeRequest(unboundRequest);
listenableFuture.addListener(() -> {
Response response = listenableFuture.get();
LOG.debug(response.getStatusCode());
}, Executors.newCachedThreadPool());
Помимо возможности добавления слушателей, интерфейсListenableFuture позволяет нам преобразовать ответFuture вCompletableFuture.
7. Заключение
AHC - очень мощная библиотека с множеством интересных функций. Он предлагает очень простой способ настройки HTTP-клиента и возможность выполнения как синхронных, так и асинхронных запросов.
Как всегда доступен исходный код статьиover on GitHub.