欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot中RestTemplate配置HttpClient連接池詳解

 更新時(shí)間:2023年11月18日 09:11:26   作者:morris131  
這篇文章主要介紹了springboot中RestTemplate配置HttpClient連接池詳解,這些Http連接工具,使用起來(lái)都比較復(fù)雜,如果項(xiàng)目中使用的是Spring框架,可以使用Spring自帶的RestTemplate來(lái)進(jìn)行Http連接請(qǐng)求,需要的朋友可以參考下

RestTemplate配置HttpClient連接池

在Java開(kāi)發(fā)中,訪問(wèn)第三方HTTP協(xié)議的網(wǎng)絡(luò)接口,通常使用的連接工具為JDK自帶的HttpURLConnection、HttpClient(現(xiàn)在應(yīng)該稱之為HttpComponents)和OKHttp。

這些Http連接工具,使用起來(lái)都比較復(fù)雜,如果項(xiàng)目中使用的是Spring框架,可以使用Spring自帶的RestTemplate來(lái)進(jìn)行Http連接請(qǐng)求。

RestTemplate底層默認(rèn)的連接方式是Java中的HttpURLConnection,可以使用ClientHttpRequestFactory來(lái)指定底層使用不同的HTTP連接方式。

RestTemplate中默認(rèn)的連接方式

RestTemplate中默認(rèn)使用的是SimpleClientHttpRequestFactory,我們這里手動(dòng)創(chuàng)建SimpleClientHttpRequestFactory可以指定連接的超時(shí)時(shí)間,讀數(shù)據(jù)的超時(shí)時(shí)間。

package com.morris.user.demo;

import com.morris.user.entity.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * restTemplate+httpUrlConnection
 */
@Slf4j
public class RestTemplateDemo1 {

    public static void main(String[] args) {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(3000);
        factory.setReadTimeout(5000);
        RestTemplate restTemplate = new RestTemplate(factory);
        Order[] orders = restTemplate.getForObject("http://127.0.0.1:8020/order/findOrderByUserId?userId=", Order[].class, 1);
        log.info("orders :{}", orders);
    }

}

SimpleClientHttpRequestFactory底層在創(chuàng)建請(qǐng)求的時(shí)候使用的就是HttpURLConnection。

org.springframework.http.client.SimpleClientHttpRequestFactory#createRequest

public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
    prepareConnection(connection, httpMethod.name());

    if (this.bufferRequestBody) {
        return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
    }
    else {
        return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
    }
}

RestTemplate與HttpClient的結(jié)合

只需要在構(gòu)造RestTemplate實(shí)例時(shí)傳入HttpComponentsClientHttpRequestFactory對(duì)象即可。

package com.morris.user.demo;

import com.morris.user.entity.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * RestTemplate+HttpClient
 */
@Slf4j
public class RestTemplateDemo2 {

    public static void main(String[] args) {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        RestTemplate restTemplate = new RestTemplate(factory);
        Order[] orders = restTemplate.getForObject("http://127.0.0.1:8020/order/findOrderByUserId?userId=", Order[].class, 1);
        log.info("orders :{}", orders);
    }

}

HttpComponentsClientHttpRequestFactory底層在創(chuàng)建請(qǐng)求時(shí)使用了HttpClient。

org.springframework.http.client.HttpComponentsClientHttpRequestFactory#createRequest

public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
    HttpClient client = getHttpClient();

    HttpUriRequest httpRequest = createHttpUriRequest(httpMethod, uri);
    postProcessHttpRequest(httpRequest);
    HttpContext context = createHttpContext(httpMethod, uri);
    if (context == null) {
        context = HttpClientContext.create();
    }

    // Request configuration not set in the context
    if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
        // Use request configuration given by the user, when available
        RequestConfig config = null;
        if (httpRequest instanceof Configurable) {
            config = ((Configurable) httpRequest).getConfig();
        }
        if (config == null) {
            config = createRequestConfig(client);
        }
        if (config != null) {
            context.setAttribute(HttpClientContext.REQUEST_CONFIG, config);
        }
    }

    if (this.bufferRequestBody) {
        return new HttpComponentsClientHttpRequest(client, httpRequest, context);
    }
    else {
        return new HttpComponentsStreamingClientHttpRequest(client, httpRequest, context);
    }
}

RestTemplate與HttpClient的在生產(chǎn)環(huán)境使用的最佳實(shí)踐

在構(gòu)建HttpClient時(shí),經(jīng)常需要配置很多信息,例如RequestTimeout、ConnectTimeout、SocketTimeout、代理、是否允許重定向、連接池等信息。

在HttpClient,對(duì)這些參數(shù)進(jìn)行配置需要使用到RequestConfig類的一個(gè)內(nèi)部類Builder。

這里將這些常用的配置抽取出來(lái)放到配置文件中:

package com.morris.user.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;


@EnableConfigurationProperties(HttpClientConfig.class)
@ConditionalOnClass(RestTemplate.class)
@Configuration
@Slf4j
public class RestTemplateAutoConfiguration {

    @Resource
    private HttpClientConfig httpClientConfig;

    @Bean
    @ConditionalOnClass(CloseableHttpClient.class)
    public RestTemplate httpClientRestTemplate(ClientHttpRequestFactory clientHttpRequestFactory){
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    @ConditionalOnClass(CloseableHttpClient.class)
    public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setHttpClient(httpClient);
        clientHttpRequestFactory.setConnectTimeout(httpClientConfig.getRequest().getConnectTimeout());
        clientHttpRequestFactory.setReadTimeout(httpClientConfig.getRequest().getReadTimeout());
        clientHttpRequestFactory.setConnectionRequestTimeout(httpClientConfig.getRequest().getConnectionRequestTimeout());
        clientHttpRequestFactory.setBufferRequestBody(httpClientConfig.getRequest().isBufferRequestBody());
        return clientHttpRequestFactory;
    }

    @Bean
    @Primary
    @ConditionalOnClass(CloseableHttpClient.class)
    public HttpClient httpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        try {
            // 設(shè)置信任SSL訪問(wèn)
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
            httpClientBuilder.setSSLContext(sslContext);
            // 任何主機(jī)都不會(huì)拋出SSLException異常
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    // 注冊(cè)HTTP和HTTPS請(qǐng)求
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory).build();

            // 使用Httpclient連接池的方式配置
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            poolingHttpClientConnectionManager.setMaxTotal(httpClientConfig.getPool().getMaxTotalConnect());
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientConfig.getPool().getMaxConnectPerRoute());
            poolingHttpClientConnectionManager.setValidateAfterInactivity(httpClientConfig.getPool().getValidateAfterInactivity());

            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientConfig.getPool().getRetryTimes(), true));
            httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy());
            return httpClientBuilder.build();
        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
            log.error("初始化HTTP連接池出錯(cuò)", e);
            throw e;
        }
    }

    /**
     * 配置長(zhǎng)連接保持策略
     * @return ConnectionKeepAliveStrategy
     */
    public ConnectionKeepAliveStrategy connectionKeepAliveStrategy(){
        return (response, context) -> {
            // Honor 'keep-alive' header
            HeaderElementIterator it = new BasicHeaderElementIterator(
                    response.headerIterator(HTTP.CONN_KEEP_ALIVE));
            while (it.hasNext()) {
                HeaderElement he = it.nextElement();
                String param = he.getName();
                String value = he.getValue();
                if (value != null && "timeout".equalsIgnoreCase(param)) {
                    try {
                        return Long.parseLong(value) * 1000;
                    } catch(NumberFormatException error) {
                        log.error("解析長(zhǎng)連接過(guò)期時(shí)間異常", error);
                    }
                }
            }
            HttpHost target = (HttpHost) context.getAttribute(HttpClientContext.HTTP_TARGET_HOST);
            //如果請(qǐng)求目標(biāo)地址,單獨(dú)配置了長(zhǎng)連接保持時(shí)間,使用該配置
            Optional<Map.Entry<String, Integer>> any = Optional.ofNullable(httpClientConfig.getPool().getKeepAliveTargetHost()).orElseGet(HashMap::new)
                    .entrySet().stream().filter(
                            e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny();
            //否則使用默認(rèn)長(zhǎng)連接保持時(shí)間
            return any.map(en -> en.getValue() * 1000L).orElse(httpClientConfig.getPool().getKeepAliveTime() * 1000L);
        };
    }

}

到此這篇關(guān)于springboot中RestTemplate配置HttpClient連接池詳解的文章就介紹到這了,更多相關(guān)RestTemplate配置HttpClient連接池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java微信公眾號(hào)開(kāi)發(fā)(搭建本地測(cè)試環(huán)境)

    java微信公眾號(hào)開(kāi)發(fā)(搭建本地測(cè)試環(huán)境)

    這篇文章主要介紹了java微信公眾號(hào)開(kāi)發(fā),主要內(nèi)容有測(cè)試公眾號(hào)與本地測(cè)試環(huán)境搭建,需要的朋友可以參考下
    2015-12-12
  • 用SpringMVC編寫一個(gè)HelloWorld的詳細(xì)過(guò)程

    用SpringMVC編寫一個(gè)HelloWorld的詳細(xì)過(guò)程

    SpringMVC是Spring的一個(gè)后續(xù)產(chǎn)品,是Spring的一個(gè)子項(xiàng)目<BR>SpringMVC?是?Spring?為表述層開(kāi)發(fā)提供的一整套完備的解決方案,本文我們將用SpringMVC編寫一個(gè)HelloWorld,文中有詳細(xì)的編寫過(guò)程,需要的朋友可以參考下
    2023-08-08
  • Java引用隊(duì)列和虛引用實(shí)例分析

    Java引用隊(duì)列和虛引用實(shí)例分析

    這篇文章主要介紹了Java引用隊(duì)列和虛引用,結(jié)合實(shí)例形式分析了java引用隊(duì)列和虛引用相關(guān)概念、原理與使用方法,需要的朋友可以參考下
    2019-08-08
  • java.lang.Void類源碼解析

    java.lang.Void類源碼解析

    這篇文章主要介紹了java.lang.Void類源碼解析的相關(guān)內(nèi)容,對(duì)源碼中的部分內(nèi)容進(jìn)行解釋,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10
  • JAVA之讀取properties時(shí)路徑的注意問(wèn)題

    JAVA之讀取properties時(shí)路徑的注意問(wèn)題

    這篇文章主要介紹了JAVA之讀取properties時(shí)路徑的注意問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • springboot實(shí)現(xiàn)發(fā)送QQ郵箱

    springboot實(shí)現(xiàn)發(fā)送QQ郵箱

    這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)發(fā)送QQ郵箱,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • SpringMVC互聯(lián)網(wǎng)軟件架構(gòu)REST使用詳解

    SpringMVC互聯(lián)網(wǎng)軟件架構(gòu)REST使用詳解

    這篇文章主要為大家詳細(xì)介紹了SpringMVC互聯(lián)網(wǎng)軟件架構(gòu)REST的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Java中synchronized鎖升級(jí)的過(guò)程

    Java中synchronized鎖升級(jí)的過(guò)程

    本文主要介紹了Java中synchronized鎖升級(jí)的過(guò)程,synchronized相對(duì)于早期的synchronized做出了優(yōu)化,從以前的加鎖就是重量級(jí)鎖優(yōu)化成了有一個(gè)鎖升級(jí)的過(guò),下文詳細(xì)內(nèi)容需要的小伙伴可以參考一下
    2022-05-05
  • Java 中的 BufferedReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java 中的 BufferedReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    BufferedReader 是緩沖字符輸入流。它繼承于Reader。接下來(lái)通過(guò)本文給大家介紹BufferedReader的相關(guān)知識(shí),需要的朋友參考下吧
    2017-05-05
  • idea2023創(chuàng)建JavaWeb教程之右鍵沒(méi)有Servlet的問(wèn)題解決

    idea2023創(chuàng)建JavaWeb教程之右鍵沒(méi)有Servlet的問(wèn)題解決

    最近在寫一個(gè)javaweb項(xiàng)目,但是在IDEA中創(chuàng)建好項(xiàng)目后,在搭建結(jié)構(gòu)的時(shí)候創(chuàng)建servlet文件去沒(méi)有選項(xiàng),所以這里給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于idea2023創(chuàng)建JavaWeb教程之右鍵沒(méi)有Servlet問(wèn)題的解決方法,需要的朋友可以參考下
    2023-10-10

最新評(píng)論