Недавно я использовал httpclient и посмотрел официальный документ: Ожидается, что реализации HTTPClient будут безопасными. Рекомендуется, чтобы один и тот же экземпляр этого класса использовался для многочисленных выполнений запросов. Перевод означает: реализация httpclient безопасна и может повторно использовать один и тот же экземпляр для выполнения нескольких запросов. Когда мы сталкиваемся с этим описанием, мы должны подумать, что httpclient необходимо инкапсулировать. Поскольку он используется пружинной загрузкой, мы будем комбинировать пружинный загрузок, чтобы инкапсулировать httpclient.
1. Запросить обработчик повторения (запрос повторной обработки)
Для того, чтобы сделать индивидуальный механизм исключений вступить в силу, необходимо реализовать интерфейс httprequestryhandler, этот код выглядит следующим образом:
импортировать java.io.ioexception; Импорт java.io.ErentertedioException; Импорт java.net.unknownhostexception; импортировать javax.net.ssl.sslexception; Импорт javax.net.ssl.sslhandshakeexception; Import org.apache.http.httpenclosingRequest; импорт org.apache.http.httprequest; Импорт org.apache.http.nohttpresponseexception; Import org.apache.http.client.httprequestretryhandler; Import org.apache.http.client.protocol.httpclientContext; Import org.apache.http.conn.connecttimeoutexception; Import org.apache.http.protocol.httpcontext; Импорт org.springframework.beans.factory.annotation.value; Импорт org.springframework.context.annotation.bean; Импорт org.springframework.context.annotation.configuration; / *** Описание: Механизм обработки обработки httpclient*/ @configuration public class myhttprequestretryhandler {@value ("$ {httpclient.config.retrytime}") // Вот рекомендуется использовать @configurationperties (prefix = "httpclient.configtritity of infiletritire. Втрит; @Bean public httprequestretryhandler httprequestretryhandler () {// запросить повторный финал int rtrytime = this.retrytime; Вернуть новый httprequestretryhandler () {public boolean retryrequest (исключение ioexception, int executioncount, httpcontext context) {// Не повторно повторно, если не будет превышает максимальный счет, если число повторных повторений превышает restrytime, запрос больше не будет повторно повторно, если (выполнение } // Сервер нарушает исключение подключения клиента, если (Exception Incemberof nohttpresponseexception) {return true; } // Time Out Timeout retry if (Exception InstanceOf refruptOexception) {return true; } // Неизвестный хост if (exception exanceof antownhostexception) {return false; } // Подключение отказано if (exception exantef ancectimeoutexception) {return false; } // SSL Handshake Exception if (Exception InstactOf Sslexception) {return false; } HttpclientContext clientContext = httpclientContext.adapt (context); Httprequest request = clientContext.getRequest (); if (! (Запросить экземпляр httpentityenclosingRequest)) {return true; } вернуть false; }}; }} 2. Менеджер объединения соединений (управление пулом соединений)
PoolingHttpClientConnectionManager используется для управления пулом соединений клиента и может предоставлять услуги для запросов из нескольких потоков. Код заключается в следующем:
Импорт org.apache.http.config.registry; Импорт org.apache.http.config.registrybuilder; Import org.apache.http.conn.socket.connectionsocketCactory; Импорт org.apache.http.conn.socket.layeredConnectionsocketCactory; Import org.apache.http.conn.socket.plainconnectionsockectectory; Import org.apache.http.conn.ssl.sslconnectionsockectectory; Import org.apache.http.impl.conn.poolinghttpclientConnectionManager; Импорт org.springframework.beans.factory.annotation.value; Импорт org.springframework.context.annotation.bean; Импорт org.springframework.context.annotation.configuration; @Configuration public class mypoolinghttpclientconnectionmanager { / *** Максимальное количество соединений в пуле соединений* / @value ("$ {httpclient.config.connmaxtotal}") private int connmaxtotal = 20; / ** * */ @value ("$ {httpclient.config.maxperroute}") private int maxperroute = 20; / ** * Время выживания подключения, единица s */ @value ("$ {httpclient.config.timetolive}") private int timetolive = 60; @Bean public poolinghttpclientconnectionmanager poolingclientconnectionmanager () {poolinghttpclientconnectionmanager poolhttpcconnmanager = новый PoolinghttpclientConnectionManager (60, TimeUnit.seconds); // максимальное количество соединений Poolhttpcconnmanager.setmaxtotal (this.connmaxtotal); // маршрут Radix poolhttpcconnmanager.setDefaultmaxPerroute (this.maxperroute); return poolhttpcconnmanager; }} ПРИМЕЧАНИЕ. Когда экземпляр HTTPClient больше не нужен и собирается быть вне сферы действия, важно закрыть диспетчер подключений, чтобы гарантировать, что все подключения, которые управляется активным, закрыты и освобождают системные ресурсы, выделенные этими подключениями.
Конструктор приведенного выше класса PoolinghttpclientConnectionManager заключается в следующем:
public poolinghttpclientConnectionManager (Final Long Timetolive, Final TimeUnit tunit) {this (getDefaultRegistry (), нулевая, нулевая, нулевая, временная, тунит); } Частный статический реестр <nectictionSocketCastory> getDefaulTregistry () {return RegistryBuilder. <ConnectionSocketCastcorty> create () .register ("http", plainconnectionsocketfactory.getSocketFactory ()) .register ("https", sslconcectoctory.getocketCocketCoxtoctory ()). } В конфигурации PoolingHttpClientConconnectionManager существует два максимальных соединения, которые управляют общим максимальным номером подключения и максимальным номером подключения на маршрут соответственно. Если нет явных настройки, по умолчанию разрешено только до 2 соединений на маршрут, и общее количество соединений не превышает 20. Это значение недостаточно для многих приложений с высокой параллелизмом. Соответствующее значение должно быть установлено в соответствии с фактической ситуацией. Идея похожа на размер пула потоков. Если все запросы на подключение к одному и тому же URL -адресу, значение MaxPerroute может быть установлено, чтобы соответствовать Maxtotal, чтобы соединение было более эффективно повторно используется
Специальное примечание: если вы хотите повторно использовать соединение, вы должны сделать системные ресурсы, которые он занимает правильно выпущенным. Метод выпуска выглядит следующим образом:
Если вы используете outputStream, вы должны убедиться, что вся сущность записана. Если это входная сеть, вы должны помнить, чтобы вызовать inputstream.close () в конце. Или используйте EntityUtils.consume (Entity) или Entityutils.consumequietly (Entity), чтобы сделать сущность полностью истощенной (последний не бросает исключения), чтобы сделать это. Существует метод ToString в EntityUtils, который также очень удобен (входная сеть будет автоматически закрыто в конце при вызове этого метода, но в процессе фактического тестирования соединение не будет выпущено), но его можно использовать только в том случае, если можно определить, что принятая объект не особенно велика. Если весь объект не будет полностью потреблен, соединение не может быть использовано повторно, и вскоре доступное время ожидания или блоки подключения здесь не будет получено в пуле соединений (поскольку состояние соединения всегда будет избавлено, то есть состояние, которое используется). Поэтому, если вы хотите повторно использовать связь, вы должны помнить, чтобы поглотить объект полностью. Пока обнаруживается EOF потока, метод ReleaseConnection подключения будет автоматически призван к обработке.
3. Стратегия подключения
Спецификация HTTP не указывает, как долго может и должно оставаться живым. Некоторые HTTP-серверы используют нестандартные заголовки, чтобы общаться с клиентами в период в секундах, когда они намерены сохранить соединение на стороне сервера. Httpclient может использовать эту информацию. Если заголовок Keep-Alive не существует в ответе, HttpClient предполагает, что соединение может оставаться активным на неопределенный срок. Тем не менее, многие используемые HTTP -серверы, как правило, настроены для удаления постоянных соединений после периода неактивного статуса, чтобы сохранить системные ресурсы без уведомления клиента. Если политика по умолчанию слишком оптимистична, вам может потребоваться предоставить пользовательскую политику Keep-Alive, этот код заключается в следующем:
Импорт org.apache.http.headerelement; Импорт org.apache.http.headerelementiterator; Импорт org.apache.http.httpresponse; Import org.apache.http.conn.connectionkeepalalivestrategy; Импорт org.apache.http.message.basicheaderelementiterator; Импорт org.apache.http.protocol.http; Import org.apache.http.protocol.httpcontext; Импорт org.springframework.beans.factory.annotation.value; Импорт org.springframework.context.annotation.bean; Импорт org.springframework.context.annotation.configuration; / *** Описание: Политика подключения* @author chhliu*/ @configuration public class myconnection keeplevestrategy {@value ("$ {httpclient.config.keepaliveTime}") private int jeftiveTime = 30; @Bean ("connectionkeepalivestrategy") public Connectionkeepestrategy connectionkeepalivestrategy () {return new ConnectAcePectRategrategy () {public long getakeakeAlviveuration (httpresponse, httpcontextextex response.headeriterator (http.conn_keep_alive)); while (it.hasnext ()) {hearerelement he = it.nextelement (); String param = he.getName (); String value = he.getValue (); if (value! = null && param.equalsignorecase ("timeout")) {try {return long.parselong (value) * 1000; } catch (numberFormateXception игнорировать) {}}} return 30 * 1000; }}; }} ПРИМЕЧАНИЕ. Длинные соединения не используются во всех ситуациях, особенно в настоящее время, большинство систем развернуты на нескольких серверах и имеют функции балансировки нагрузки. Если мы сохраним длинное соединение при доступе, после того, как этот сервер будет приостановлен, он повлияет на клиента. В то же время мы не можем полностью использовать характеристики балансировки нагрузки сервера. Вместо этого короткие соединения более полезны. Они должны быть определены в соответствии с конкретными потребностями, а не суммировать их в одном предложении.
4. Конфигурация прокси HTTPClient (конфигурация прокси)
Используется для настройки прокси, код выглядит следующим образом:
Импорт org.apache.http.httphost; Импорт org.apache.http.impl.conn.defaultproxyrouteplanner; Импорт org.springframework.beans.factory.annotation.value; Импорт org.springframework.context.annotation.bean; Импорт org.springframework.context.annotation.configuration; / *** Описание: httpclient proxy* @author chhliu*/ @configuration public class mydefaultproxyrouteplanner {// Адрес хоста прокси @value ("$ {httpclient.config.proxyhost}") Private String Proxyhost; // номер порта прокси @value ("$ {httpclient.config.proxyport}") private int proxyport = 8080; @Bean public DefaultProxyRoutePlanner defaultProxyRoutePlanner () {httphost proxy = new httphost (this.proxyhost, this.proxyport); вернуть новый defaultProxyRoutePlanner (прокси); }} HttpClient не только поддерживает простые прямые соединения, сложные политики маршрутизации и оформление. Httprouteplanner основан на контексте HTTP, вычислительной политике маршрутизации клиента на сервер. Как правило, если нет прокси, вам не нужно устанавливать эту вещь. Здесь есть очень важная концепция - маршрут: в httpclient маршрут относится к линии целевого машинного хоста, то есть, если хост целевого URL одинаково, то их маршрут такой же.
5. requestConfig
Различные конфигурации, используемые для установки запроса, код выглядит следующим образом:
Import org.apache.http.client.config.requestconfig; Импорт org.springframework.beans.factory.annotation.value; Импорт org.springframework.context.annotation.bean; Импорт org.springframework.context.annotation.configuration; @Configuration public class myrequestconfig {@value ("$ {httpclient.config.connecttimeout}") private int connecttimeout = 2000; @Value ("$ {httpclient.config.connectrecevesttime}") private int connectRectesttimeout = 2000; @Value ("$ {httpclient.config.sockettimeout}") private int sockettimeout = 2000; @Bean public requestConfig config () {return requestConfig.custom () .setConnectionRequestTimeout (this.ConnectRecteMecteTimeout) .SetConnectTimeout (this.ConnectTimeOut) .setSocketTimeout (this.sockettimeout) .build (); }} RequestConfig - это какая -то конфигурация запроса. Есть три времени, которые более важны. По умолчанию все три временных времени - 0 (если конфигурация запроса не установлена, параметры по умолчанию будут установлены в httpclientparamconfig's getRequestConfig во время выполнения). Это означает бесконечное ожидание, которое может легко привести к тому, что все запросы блокируют и ждать бесконечно в этом месте. Эти три тайм -ауты:
а ConnectionRequestTimeout - время для получения подключения из пула соединений
На этот раз определяет время ожидания для получения соединения из пула соединений, управляемого ConnectionManager. Если в пуле подключения нет доступного соединения, запрос будет заблокирован, и максимальное время ожидания ConnectionRequestTimeout. Если это не было обслуживано, исключение ConnectionPooltimeOutException выброшено, и дальнейшее ожидание не допускается.
беременный ConnectTimeout - время ожидания
На этот раз определяет тайм -аут для установления соединения с сервером через сеть, то есть время ожидания соединения для подключения к целевому URL -адресу после получения соединения в пуле подключения. Поискает тайм -аут, будет брошено исключение ConnectimeOutexception.
в Sockettimeout - время аута
На этот раз определяет время ожидания данных для чтения сокетов, то есть время, необходимое для ожидания после подключения к серверу для получения данных ответа с сервера, или время, необходимое для получения ответа после подключения к предыдущему URL. Происходит тайм -аут, и будет брошено исключение Sockettimeoutexception.
6. Смоторий httpclient
HttpClient создается созданием заводской фабрики, код заключается в следующем:
Import org.apache.http.client.httprequestretryhandler; Import org.apache.http.client.config.requestconfig; Импорт org.apache.http.impl.conn.connectionkeeparevestrategy; Import org.apache.http.impl.client.closablehttpclient; импорт org.apache.http.impl.client.httpclients; Импорт org.apache.http.impl.conn.defaultproxyrouteplanner; Import org.apache.http.impl.conn.poolinghttpclientConnectionManager; Импорт org.springframework.beans.factory.disposablebean; Импорт org.springframework.beans.factory.factorybean; Импорт org.springframework.beans.factory.initializebean; Импорт org.springframework.beans.factory.annotation.autowired; Импорт org.springframework.stereotype.service; / **! @Autowired private connectionkeepevestrategy connectionkeepevestrategy; @Autowired private httprequestretryhandler httprequestretryhandler; @Autowired private defaultproxyrouteplanner proxyrouteplanner; @Autowired Private PoolinghttpclientConnectionManager Poolhttpcconnmanager; @Autowired private requestConfig config; // При уничтожении контекста уничтожение экземпляра httpclient @override public void destress () бросает исключение { / * * Вызов httpclient.close () сначала отключит менеджер подключения, а затем отпустит все ресурсы, занятые httpclient, * Закройте все соединения, которые используются или проводятся, включая лежащие в основе соревнование. Поскольку менеджер соединений, который он использует, закрыт здесь, * поэтому, когда вам придется сделать HTTP -запрос в следующий раз, вам нужно продлить менеджер подключения для создания HTTPClient, * то есть, когда вам нужно закрыть и создать нового клиента, диспетчер подключений не может быть синглтоном. */ if (null! = this.client) {this.client.close (); }} @Переопределить // инициализировать экземпляр public void efpropertiesset () throws exception {/ * * * * * * * * * * * * * * * * * * * Несоответствующий, но httpclients действительно имитабель. The immutable object can not only ensure that the state of the object is not changed, * but also can be shared by other threads without using the lock mechanism*/ this.client = HttpClients.custom().setConnectionManager(poolHttpcConnManager) .setRetryHandler(httpRequestRetryHandler) .setKeepAliveStrategy(connectionKeepAliveStrategy) .setRoutePlanner (proxyrouteplanner) .setDeftRequestConfig (config) .build (); } // возвращает тип экземпляра @Override public QualeableHttpClient getObject (), который вызывает exception {return this.client; } @Override public class <?> GetObjectType () {return (this.client == null? Qualeablehttpclient.class: this.client.getClass ()); } // Встроенный экземпляр - это Singleton@Replide public boolean issingleton () {return true; }}7. Добавить файлы конфигурации
# HOST Proxy httpclient.config.proxyhost = xxx.xx.xx.xx # proxy port httpclient.config.proxyport = 8080 # время подключения или времена повторного периода исключения. В пуле подключений httpclient.config.connmaxtotal = 20 httpclient.config.maxperroute = 20 # Тайм -аут подключения, единица ms httpclient.config.connecttimeout = 20 # Тайм -аут подключения, единица httpclient.config.connecttimeout = 20 # Запрос подключения, единица httpclient.config.connecttimeout = 20 #. httpclient.config.connectrectesttimeout = 2000 # Timeout Sock Timeout httpclient.config.sockettimeout = 2000 # Время выживания подключения, блок s httpclient.config.timetolive = 60
8. тест
Тестовый код заключается в следующем:
импортировать java.io.ioexception; импортировать java.util.concurrent.executorservice; импортировать java.util.concurrent.executors; Импорт javax.annotation.resource; Импорт org.apache.http.consts; Импорт org.apache.http.parseexception; Импорт org.apache.http.client.clientprotocolexception; Импорт org.apache.http.client.methods.closablehttpresponse; Импорт org.apache.http.client.methods.httpget; Import org.apache.http.impl.client.closablehttpclient; Импорт org.apache.http.util.entityutils; Импорт org.junit.test; Импорт org.junit.runner.runwith; Импорт org.springframework.boot.test.context.springboottest; Import org.springframework.test.context.junit4.springrunner; @Runwith (springrunner.class) @springboottest public class httpclientmanagerfactorybentest {// inject httpclient экземпляр @resource (name = "httpclientmagerfactoryben") private closablehttpclient Client; @Test public void test () Throws ClientProtocolexception, ioException, прерывание {receectorservice service = executors.newfixedthreadpool (2); for (int i = 0; i <10; i ++) {service.submit (new runnable () {@override public void run () {System.out.println («Текущий поток:»+thread.currentThread (). getName ()); httpentity entity = nul Httpget ("https: // localhost: 8080/testjson"); System.out.println ("=================================================================================================== Connection} Catch (ClientProtocolexception e) {e.printstacktrace (); }); Через вышеуказанные этапы инкапсуляция HTTPClient в основном завершена. Если вам нужно быть более подробным, вы можете постепенно улучшить HTTPClient как httpClientTemplate в соответствии с вышеуказанными идеями, потому что ClosableHttpClient использует механизм обратного вызова внутри, что похоже на JDBCTemplate или Redistemplate, пока служба не может быть предоставлен в форме стартера Spring Boot.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.