Recentemente, usei o HTTPClient e observei o documento oficial: as implementações httpclient devem ser seguras. Recomenda -se que a mesma instância desta classe seja reutilizada para várias execuções de solicitação. A tradução significa: a implementação do HTTPClient é segura para threads e pode reutilizar a mesma instância para executar várias solicitações. Quando encontramos essa descrição, devemos pensar que o HTTPClient precisa ser encapsulado. Como é usado a bota de mola, combinaremos a inicialização da mola para encapsular o httpclient.
1. Solicite o manipulador de repetição (solicitar o processamento da tentativa)
Para fazer com que o mecanismo de exceção personalizado entre em vigor, a interface httprequestretryhandler precisa ser implementada, o código é o seguinte:
importar java.io.ioException; importar java.io.InterruptedioException; importar java.net.unknownhostException; importar javax.net.ssl.ssLexception; importar javax.net.ssl.ssslHandshakeException; importar org.apache.http.httpenclosingRequest; importar org.apache.http.httprequest; importar org.apache.http.nohttpResponseException; importar org.apache.http.client.httprequestretryhandler; importar org.apache.http.client.protocol.httpclientContext; importar org.apache.http.conn.connectTimeoutException; importar org.apache.http.protocol.httpContext; importar org.springframework.beans.factory.annotation.value; importar org.springframework.context.annotation.bean; importar org.springframework.context.annotation.configuration; / *** Descrição: Mecanismo de processamento de nova tentativa do HTTPClient*/ @Configuration public class MyhttPrequestRetryHandler {@Value ("$ {httpclient.config.retrytime}") // aqui é recomendado para usar @configurationProperties (prefix = httpyn) // aqui é recomendado @Bean public httPrequestRetRyHandler httPrequestRetRyHandler () {// solicita a tentativa final int reTryTime = this.retrytime; Retornar novo httPreQuestRetRyHandler () {public boolean RetryRequest (exceção da ioException, int ExecutionCount, contexto httpContext) {// não retrive se mais de retenção máxima; } // O servidor quebra a exceção de conexão do cliente se (Instância de exceção de nohttpResponseException) {return true; } // Tempo limite Timeout RECET IF (Exceção de exceção do interruptorioException) {return true; } // host desconhecido if (instância de exceção do desconhecidoHosTexception) {return false; } // A conexão recusou se (instância de exceção do ConnectTimeOutException) {return false; } // SSL Handshake Exception if (Exceção de exceção de sslexception) {return false; } HttpclientContext clientContext = httpclientContext.adapt (contexto); Solicitação httprequest = clientContext.getRequest (); if (! (solicitar a instância do httpentityEnclosingRequest)) {return true; } retornar false; }}; }} 2. Gerenciador de conexão de pool (Gerenciador de pool de conexão)
PoolingHttpClientConnectionManager é usado para gerenciar o pool de conexão do cliente e pode fornecer serviços para solicitações de vários threads. O código é o seguinte:
importar org.apache.http.config.registry; importar org.apache.http.config.registryBuilder; importar org.apache.http.conn.socket.connectionSocketFactory; importar org.apache.http.conn.socket.layeredconnectionSocketFactory; importar org.apache.http.conn.socket.plainConnectionSocketFactory; importar org.apache.http.conn.ssl.ssslConnectionSocketFactory; importar org.apache.http.impl.conn.poolinghttpclientConnectionManager; importar org.springframework.beans.factory.annotation.value; importar org.springframework.context.annotation.bean; importar org.springframework.context.annotation.configuration; @Configuration public class MyPoolingHttpClientConnectionManager { / *** Número máximo de conexões no pool de conexões* / @Value ("$ {httpclient.config.connmaxtotal}") private int connmaxtotal = 20; / ** * */ @Value ("$ {httpclient.config.maxperroute}") private int maxperroute = 20; / ** * Tempo de sobrevivência da conexão, a unidade é s */ @value ("$ {httpclient.config.timetolive}") private int timetolive = 60; @Bean public poolinghttpclientConnectionManager PoolingClientConnectionManager () {PoolingHttpClientConnectionManager PoolhttpcconnManager = new PoolingHttpClientConnectionManager (60, TimeUnit.Seconds); // Número máximo de conexões PoolHttpcConnManager.Setmaxtotal (this.connmaxtotal); // rota radix poolhttpcconnmanager.setDefaultMaxPerRoute (this.maxperroute); Retornar PoolhttpcconnManager; }} Nota: Quando a instância HTTPClient não é mais necessária e está prestes a ficar fora de escopo, é importante fechar seu gerenciador de conexões para garantir que todas as conexões que o gerente mantém ativo estejam fechadas e liberam os recursos do sistema alocados por essas conexões.
O construtor da classe PoolingHttpClientConnectionManager é o seguinte:
public PoolingHttpClientConnectionManager (Timetolive final, time -unidade final) {this (getDefaulTregistry (), NULL, NULL, NULL, TIMETOLIVE, TUNIT); } Registro estático privado <CnectionsocketFactory> getDefaulTregistry () {return RegistryBuilder. } Existem duas conexões máximas na configuração do PoolingHttpClientConnectionManager, que controlam o número máximo de conexão total e o número máximo de conexão por rota, respectivamente. Se não houver configuração explícita, por padrão, apenas até 2 conexões por rota são permitidas e o número total de conexões não excede 20. Esse valor não é suficiente para muitos aplicativos com alta concorrência. O valor apropriado deve ser definido de acordo com a situação real. A idéia é semelhante ao tamanho do pool de threads. Se todas as solicitações de conexão forem para o mesmo URL, o valor do maxperroute pode ser definido como consistente com o Maxtotal, para que a conexão possa ser reutilizada com mais eficiência
NOTA ESPECIAL: Se você deseja reutilizar uma conexão, deve fazer com que os recursos do sistema ocupe corretamente liberados. O método de liberação é o seguinte:
Se você estiver usando o OutputStream, deve garantir que toda a entidade seja gravada. Se for um inputStream, lembre -se de chamar o InputStream.close () no final. Ou use entityutils.consume (entidade) ou entityutils.ConsumeQuietly (entidade) para tornar a entidade completamente esgotada (o último não joga exceções) para fazer isso. Existe um método de tostragem no entityutils, que também é muito conveniente (o InputStream será fechado automaticamente no final ao chamar esse método, mas no processo de teste real, a conexão não será liberada), mas só pode ser usada se puder ser determinado que a entidade recebida não é particularmente grande. Se toda a entidade não for totalmente consumida, a conexão não poderá ser reutilizada e logo o tempo limite da conexão disponível ou os blocos aqui não será obtido no pool de conexões (porque o estado da conexão sempre será poupado, ou seja, o estado que está sendo usado). Portanto, se você deseja reutilizar a conexão, lembre -se de consumir totalmente a entidade. Enquanto o EOF do fluxo for detectado, o método de liberação do detentor da conexão será automaticamente chamado de processamento.
3. Conexão Mantenha a Estratégia Aliva
A especificação HTTP não especifica quanto tempo uma conexão persistente pode e deve permanecer viva. Alguns servidores HTTP usam cabeçalhos de Keep-alive não padrão para se comunicar aos clientes o período em segundos, quando pretendem manter a conexão no lado do servidor. O httpclient pode usar essas informações. Se o cabeçalho Keep-Alive não existir na resposta, o HTTPClient pressupõe que a conexão possa permanecer ativa indefinidamente. No entanto, muitos servidores HTTP geralmente usados são configurados para excluir conexões persistentes após um período de status inativo, a fim de salvar os recursos do sistema sem notificar o cliente. Se a política padrão estiver muito otimista, pode ser necessário fornecer uma política de manutenção personalizada, o código é o seguinte:
importar org.apache.http.headerelement; importar org.apache.http.headereLementIerator; importar org.apache.http.httpResponse; importar org.apache.http.conn.connectionkeepalivestrategy; importar org.apache.http.message.basicheaderelementIterator; importar org.apache.http.protocol.http; importar org.apache.http.protocol.httpContext; importar org.springframework.beans.factory.annotation.value; importar org.springframework.context.annotation.bean; importar org.springframework.context.annotation.configuration; / *** Descrição: Política de manutenção de conexão* @Author chhliu*/ @configuration public class MyConnectionkeepalivestrategy {@Value ("$ {httpclient.config.keepaliveTime}") private int keeteTETime = 30; @Bean ("ConnectionKeepalivestrategy") public Connectionkeepalivestrategy Connectionkeepalivestrategy () {retorna new Connectionkeepalivestrategy () {public Long GetKeepaliveduration (resposta httproponse, httpContext context) {// Honor-alive 'HeaderElerElementIterator Response.Headeriterator (http.conn_keep_alive)); while (it.hasnext ()) {headerelement ele = it.nextElement (); String param = He.getName (); String value = He.getValue (); if (valor! } catch (númeroFormatexception ignore) {}}} retorna 30 * 1000; }}; }} Nota: As conexões longas não são usadas em todas as situações, especialmente hoje em dia, a maioria dos sistemas é implantada em vários servidores e possui funções de balanceamento de carga. Se mantivermos uma conexão longa ao acessar, uma vez suspenso, isso afetará o cliente. Ao mesmo tempo, não podemos utilizar completamente as características de balanceamento de carga do servidor. Em vez disso, conexões curtas são mais benéficas. Eles precisam ser determinados de acordo com as necessidades específicas, em vez de resumir -as em uma frase.
4. Configuração de proxy httpclient (configuração de proxy)
Usado para configurar o proxy, o código é o seguinte:
importar org.apache.http.httphot; importar org.apache.http.impl.conn.defaultProxyRoutePlanner; importar org.springframework.beans.factory.annotation.value; importar org.springframework.context.annotation.bean; importar org.springframework.context.annotation.configuration; / *** Descrição: httpclient proxy* @author chhliu*/ @configuration public class MyDefaultProxyroutePlanner {// O endereço do host do proxy @Value ("$ {httpclient.config.proxyhost}) private string proxyhost; // o número da porta do proxy @Value ("$ {httpclient.config.proxyport}") private int proxyport = 8080; @Bean Public DefaultProxyroutePlanner DefaultProxyRoutePlanner () {httphoSt proxy = new httpHost (this.proxyhost, thisproxyport); Retornar novo DefaultProxyRoutePlanner (Proxy); }} O HTTPClient não suporta apenas conexões diretas simples, políticas de roteamento complexas e proxy. O HTTPROUTEPLANNER é baseado no contexto HTTP, a política de computação de roteamento cliente a servidor. Geralmente, se não houver proxy, você não precisa definir isso. Existe um conceito muito crítico aqui - Rota: No httpclient, uma rota refere -se a uma linha da máquina do ambiente de corrida-> Host de mecanismo de destino, ou seja, se o host do URL de destino for o mesmo, então a rota é a mesma.
5. RequestConfig
As várias configurações usadas para definir a solicitação, o código é o seguinte:
importar org.apache.http.client.config.requestConfig; importar org.springframework.beans.factory.annotation.value; importar org.springframework.context.annotation.bean; importar org.springframework.context.annotation.configuration; @Configuration public class MyRequestConfig {@Value ("$ {httpclient.config.connecttimeout}") private int ConnectTimeout = 2000; @Value ("$ {httpclient.config.connectrecesttimeout}") private int conectreceStimeout = 2000; @Value ("$ {httpclient.config.sockettimeout}") private int sockettimeout = 2000; @Bean public requestconfig config () {return requestconfig.custom () .setConnectionRequestTimeout (this.ConConCelectTimeout) .SetConnectTimeout (this.ConnectTimeout) .SetSockEtTimeout (this.sockettimeout) .build (); }} RequestConfig é uma configuração da solicitação. Existem três tempos de tempo limite mais importantes. Por padrão, todos os três tempos de tempo limite são 0 (se a configuração da solicitação não estiver definida, os parâmetros padrão serão definidos no getRequestConfig do HTTPClientParamConfig durante a execução). Isso significa espera infinita, o que pode causar facilmente todas as solicitações para bloquear e esperar indefinidamente neste local. Esses três tempos limite são:
um. ConnectionRequestTimeout - Tempo para obter conexão do pool de conexões
Desta vez, define o tempo de tempo limite para recuperar a conexão do pool de conexões gerenciado pelo ConnectionManager. Se não houver conexão disponível no pool de conexões, a solicitação será bloqueada e o tempo máximo para aguardar o ConnectionRequestTimeout. Se não foi atendido, uma exceção do ConnectionPoolTimeoutException será lançada e nenhuma espera mais aguardada é permitida.
b. ConnectTimeout - Tempo de tempo limite da conexão
Desta vez, define o tempo limite para estabelecer uma conexão com o servidor através da rede, ou seja, o tempo de espera da conexão para se conectar ao URL de destino após obter uma conexão no pool de conexão. Ocorre um tempo limite, uma exceção de conexão de tempooutException será lançada.
c. Sockettimeout - Request Timeout Time
Desta vez, define o tempo de tempo limite para os dados de leitura do soquete, ou seja, o tempo necessário para esperar depois de se conectar ao servidor para obter dados de resposta do servidor ou o tempo necessário para obter a resposta após se conectar ao URL anterior. Ocorre um tempo limite e uma exceção de SockettimeoutException será lançada.
6. Instanciar httpClient
O HTTPClient é instanciado pela implementação do FactoryBean, o código é o seguinte:
importar org.apache.http.client.httprequestretryhandler; importar org.apache.http.client.config.requestConfig; importar org.apache.http.impl.conn.connectionkeepalivestrategy; importar org.apache.http.impl.client.closeablehttpclient; importar org.apache.http.impl.client.httpclients; importar org.apache.http.impl.conn.defaultProxyRoutePlanner; importar org.apache.http.impl.conn.poolinghttpclientConnectionManager; importar org.springframework.beans.factory.disposableBean; importar org.springframework.beans.factory.factoryBean; importar org.springframework.beans.factory.initializingBean; importar org.springframework.beans.factory.annotation.autowired; importar org.springframework.tereotype.service; / *** Descrição: encapsulamento do cliente httpclient*/ @Service ("httpclientManagerFactoryBen") Public Class httpClientManagerFactoryBen implementa a fábrica <closeablehttpClient>, a prostares, o objeto de desligamento, o objeto de fábricas*/ privateBean, o objeto de fábrica*/ privateban*/ privateban,/ ** **** @Autowired Private Connectionkeepalivestrategy Connectionkeepalivestrategy; @AUTOCIDED PRIVADO HTTPREQUESTRRETRYHANDLER HTTPREQUESTRRETRYHANDLER; @AUTOWIRED PRIVADO DEFAULTPROXYROUTEPLANNER PROXYROUTTEPLANNER; @AUTowired PoolinghttpClientConnectionManager PoolhttpcconnManager; @Autowired Private requestconfig config; // Ao destruir o contexto, destruir a instância httpclient @Override public void Destroy () lança a exceção { / * * Chamando httpclient.close () fechará primeiro o Gerenciador de conexões e depois liberará todos os recursos ocupados pelo httpclient, * feche todas as conexões que estão em uso ou odios, incluindo o Substeting. Como o gerenciador de conexões que ele usa está fechado aqui, * então, quando você precisa fazer uma solicitação HTTP na próxima vez, você deve renovar um gerenciador de conexão para criar um httpclient, * ou seja, quando você precisa fechar e criar um novo cliente, o gerenciador de conexões não pode ser um singleton. */ if (null! = this.client) {this.client.close (); } } @Override// Initialize the instance public void afterPropertiesSet() throws Exception { /* * It is recommended to use HttpClients.custom to create HttpClientBuilder here, instead of using HttpClientBuilder.create() method to create HttpClientBuilder * From the official documentation, HttpClientBuilder is non-thread-safe, but Httpclients é realmente imutável. O objeto imutável pode não apenas garantir que o estado do objeto não seja alterado, *, mas também pode ser compartilhado por outros threads sem usar o mecanismo de bloqueio */ this.client = httpclients.custom (). SetConnectionManager (PoolhttpConManager) .SetRetReHandler (HttrequestretHandler). .SETROUTEPLANNER (proxyRoutePlanner) .SetDefaulTReCeStConfig (config) .build (); } // Retorna o tipo de instância @Override public CloseableHttpClient getObject () lança exceção {return this.client; } @Override public class <?> GetObjectType () {return (this.client == null? CloseableHttpClient.class: this.client.getclass ()); } // A instância construída é uma singleton@substituir public boolean issingleton () {return true; }}7. Adicione arquivos de configuração
# proxy's host httpclient.config.proxyhost=xxx.xx.xx.xx # proxy port httpclient.config.proxyPort=8080 # connection timeout or exception retry times httpclient.config.retryTime=3 # long connection hold time, unit is s httpclient.config.keepAliveTime=30 # maximum number of Conexões no pool de conexões httpclient.config.connmaxtotal = 20 httpclient.config.maxperroute = 20 # Timeout de conexão, unidade ms httpclient.config.ConnectTimeout = 20 # Timeout de conexão, unidade é MS HTTP TIME TIME httpclient.config.connectionesttimeout = 2000 # tempo limite de meia httpclient.config.sockettimeout = 2000 # tempo de sobrevivência de conexão, unidade s httpclient.config.timetolive = 60
8. Teste
O código de teste é o seguinte:
importar java.io.ioException; importar java.util.concurrent.executorService; importar java.util.concurrent.executores; importar javax.annotation.resource; importar org.apache.http.consts; importar org.apache.http.parseException; importar org.apache.http.client.clientprotocolexception; importar org.apache.http.client.methods.closeablehttpResponse; importar org.apache.http.client.methods.httpget; importar org.apache.http.impl.client.closeablehttpclient; importar org.apache.http.util.entityutils; importar org.junit.test; importar org.junit.runner.runwith; importar org.springframework.boot.test.context.springboottest; importar org.springframework.test.context.junit4.springrunner; @Runwith (springrunner.class) @springboottest classe pública httpclientManagerFactoryBentest {// injete a instância httpclient @Resource (name = "httpclientManagerFactoryBen") Closetável privadohttpClient; @Test public void test () lança clientprotocolexception, ioexception, interruptedException {executorService Service = executores.newfixedThreadpool (2); para (int i = 0; i <10; i ++) {service.subMit (new Runnable () {@Override public void run () {System.out.println ("O thread atual é:"+thread.currentThread (). getName (); htttpentity entity = nuln; Httpget (https: // localhost: 8080/testjson "); System.out.println("======================================================================================; EntityUtils.consumeQuietly(entity);// Release the Conexão} Catch (ClientProtocolexception e) {E.PrintStackTrace (); }); Através das etapas acima, o encapsulamento do HTTPClient é basicamente concluído. Se você precisar ser mais detalhado, poderá melhorar gradualmente o HTTPClient como HttpClientTemplate de acordo com as idéias acima, porque o ClosableHttpClient usa um mecanismo de retorno de chamada internamente, que é semelhante ao JDBCTemplate ou Redistemplate até que o serviço possa ser fornecido na forma de inicialização da mola.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.