HttpClient 连接池

本文介绍如何通过配置RestTemplate使用HTTP长连接及连接池技术提高应用性能。包括不同类型的ClientHttpRequestFactory实现方式,以及使用HttpClient和OkHttp实现连接池的具体步骤。

1.HTTP长连接、短连接

        HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。

        HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:Connection:keep-alive.在使用长连接的情况下,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

2. HttpClient 连接池

                HttpClient 连接池是一种复用 HTTP 连接的技术,旨在减少每次请求时建立和关闭连接的开销。通过连接池,可以显著提高 HTTP 请求的效率,尤其是在高并发场景下。

3. HTTP客户端

场景推荐框架特点
高并发、低延迟需求Apache HttpClient提供强大的连接池支持,适合复杂的 HTTP 请求逻辑
异步非阻塞请求Spring WebClient基于 Reactor 的响应式编程模型,支持异步非阻塞操作
简单的 RESTful 调用RestTemplate易于使用,但已被标记为过时(推荐迁移到 WebClient)
轻量级 HTTP 客户端OkHttp支持同步和异步调用,简单易用
原生 HTTP 客户端Java 11 HttpClientJDK 自带的 HTTP 客户端,支持异步和同步调用
声明式 HTTP 客户端Feign基于注解的声明式 HTTP 客户端,适合微服务间通信

4. RestTemplate 

1.构造函数

  • RestTemplate() //无参
  • RestTemplate(List> messageConverters) //messageConverters转换实现类
  • RestTemplate(ClientHttpRequestFactory requestFactory) //客户端连接工厂

2.ClientHttpRequestFactory实现

1.SimpleClientHttpRequestFactory

        SimpleClientHttpRequestFactory(封装URLConnection)//默认的超时时间设置为-1,若出现服务器宕机的情况,该连接将永远不会被释放。

 // 创建 SimpleClientHttpRequestFactory 实例
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        
// 设置连接和读取超时时间(可选)
requestFactory.setConnectTimeout(10000); // 10秒连接超时
requestFactory.setReadTimeout(10000); // 10秒读取超时

2.HttpComponentsClientHttpRequestFactory

        HttpComponentsClientHttpRequestFactory (封装HttpClient)

HttpComponentsClientHttpRequestFactory  factory = new HttpComponentsClientHttpRequestFactory(httpClient());
factory.setReadTimeout(10000);
factory.setConnectTimeout(10000);

3.OkHttp3ClientHttpRequestFactory

        OkHttp3ClientHttpRequestFactory (封装OKHttp)

OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(okHttpClient());
factory.setReadTimeout(10000);
factory.setConnectTimeout(10000);

5.连接池

包名描述
org.apache.httpcomponents:httpclient用于 Apache HttpClient
com.squareup.okhttp3:okhttp用于 OkHttp
spring-boot-starter-webflux用于 WebClient
io.github.openfeign:feign-core用于 Feign

1. Apache HttpClient 连接池

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
</dependency>

        RestTemplate连接线程池,需要使用其他的 HTTP 库(默认使用的是 JDK 自己的),比如 HttpComponents、Netty、OkHttp。

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(httpRequestFactory());
    }

    @Bean
    public ClientHttpRequestFactory httpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();


        // 创建连接池管理器
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        // 设置最大连接数
        connectionManager.setMaxTotal(200); // 默认值:20
        // 设置每个路由的最大连接数
        connectionManager.setDefaultMaxPerRoute(50); // 默认值:2
        // 为特定路由设置最大连接数
        connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("localhost", 8080)), 100);
 


        //路由是对maxTotal的细分
        connectionManager.setDefaultMaxPerRoute(100);
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(30000)  //返回数据的超时时间
                .setConnectTimeout(10000) //连接上服务器的超时时间
                .setConnectionRequestTimeout(1000) //从连接池中获取连接的超时时间
                .build();
        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .build();
    }
}

2. OkHttp 连接池

<dependency>
   <groupId>com.squareup.okhttp3</groupId>
   <artifactId>okhttp</artifactId>
</dependency>

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
        return new RestTemplate(requestFactory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(okHttpClient());
        factory.setReadTimeout(10000);
        factory.setConnectTimeout(10000);
        return factory;
    }
    @Bean
    public OkHttpClient okHttpClient() {
        // 设置连接池参数,最大空闲连接数200,空闲连接存活时间10s
        ConnectionPool connectionPool = new ConnectionPool(200, 10, TimeUnit.SECONDS);
        OkHttpClient okHttpClient = new OkHttpClient.Builder().
                retryOnConnectionFailure(false)
                .connectionPool(connectionPool)
                .connectTimeout(3, TimeUnit.SECONDS)
                .readTimeout(3, TimeUnit.SECONDS)
                .writeTimeout(3, TimeUnit.SECONDS).build();
        return okHttpClient;
    }
}

3.Spring WebClient 连接池

引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
/**
WebClient连接池
**/
@Configuration
public class WebClientConfig {
 
    @Bean
    public WebClient webClient() {
 // 配置连接池
        ConnectionProvider connectionProvider = ConnectionProvider.builder("webClientConnectionPool")
                .maxConnections(100) // 最大连接数
                .pendingAcquireTimeout(Duration.ofSeconds(30)) // 获取连接的超时时间
                .maxIdleTime(Duration.ofMinutes(5)) // 空闲连接的最大存活时间
                .maxLifeTime(Duration.ofMinutes(30)) // 连接的最大生命周期
                .build();

 
        // 配置HTTP客户端
        HttpClient httpClient = HttpClient.create(provider)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .responseTimeout(Duration.ofSeconds(5))
                .doOnConnected(conn ->
                        conn.addHandlerLast(new ReadTimeoutHandler(5))
                                .addHandlerLast(new WriteTimeoutHandler(5)));
 
        // 构建WebClient实例
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .baseUrl("https://echo.apifox.com")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                // 添加请求日志记录功能
                .filter(ExchangeFilterFunction.ofRequestProcessor(
                        clientRequest -> {
                            log.debug("Request: {} {}",
                                    clientRequest.method(),
                                    clientRequest.url());
                            return Mono.just(clientRequest);
                        }
                ))
                // 添加响应日志记录功能
                .filter(ExchangeFilterFunction.ofResponseProcessor(
                        clientResponse -> {
                            log.debug("Response status: {}",
                                    clientResponse.statusCode());
                            return Mono.just(clientResponse);
                        }
                ))
                .build();
    }
}

4. Feign 连接池

引入依赖

<dependency>
   <groupId>io.github.openfeign</groupId>
   <artifactId>feign-core</artifactId>
</dependency>
@Configuration
public class FeignHttpClientPoolConfig {

    @Bean
    public Client feignClient() {
        // 创建连接池管理器
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

        // 设置最大连接数
        connectionManager.setMaxTotal(200); // 默认值:20

        // 设置每个路由的最大连接数
        connectionManager.setDefaultMaxPerRoute(50); // 默认值:2

        // 为特定路由设置最大连接数(例如 localhost:8080)
        connectionManager.setMaxPerRoute(new HttpRoute(new HttpHost("localhost", 8080)), 100);

        // 配置请求参数
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000) // 连接超时时间(单位:毫秒)
                .setSocketTimeout(10000) // 响应超时时间(单位:毫秒)
                .setConnectionRequestTimeout(2000) // 从连接池获取连接的超时时间(单位:毫秒)
                .build();

        // 创建 HttpClient
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .evictIdleConnections(30, TimeUnit.SECONDS) // 清理空闲连接(单位:秒)
                .evictExpiredConnections() // 清理过期连接
                .build();

        // 返回 Feign 的 Apache HttpClient 实现
        return new feign.httpclient.ApacheHttpClient(httpClient);
    }
}

5.java 11 HttpClient 连接池

@Configuration
public class Java11HttpClientConfig {

    @Bean
    public ExecutorService executorService() {
        // 创建固定大小的线程池,并设置自定义线程工厂以命名线程
        ThreadFactory threadFactory = r -> {
            Thread t = new Thread(r, "http-client-thread");
            t.setDaemon(true); // 设置为守护线程
            return t;
        };

        return Executors.newFixedThreadPool(10, threadFactory);
    }

    @Bean
    public HttpClient httpClientPool(ExecutorService executorService) {
        // 配置 Java 11 HttpClient
        return HttpClient.newBuilder()
                .executor(executorService)
                .connectTimeout(java.time.Duration.ofSeconds(5)) // 连接超时时间
                .version(HttpClient.Version.HTTP_2) // 使用 HTTP/2 协议
                .followRedirects(HttpClient.Redirect.ALWAYS) // 自动处理重定向
                .build();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值