httpclient实现http连接池

HTTP连接池是一种优化网络通信性能的技术,通过复用已建立的TCP连接减少重复握手开销,提升资源利用率。以下是关键要点:

核心原理与优势

  1. 连接复用机制

    • 维护活跃连接队列,避免每次请求重复TCP三次握手/SSL协商,降低延迟。
    • 典型场景:高频短请求(如API调用)性能提升可达300%。
  2. 资源控制能力

    • 限制最大连接数防止服务端过载,支持动态扩容应对流量峰值。
    • 内置连接有效性检测与自动重试,增强健壮性。

HttpClientConfig 配置中,使用了 Apache HttpClient 的 PoolingHttpClientConnectionManager 作为连接池管理器。其连接释放规则主要由以下几个方面决定:

1. 连接的生命周期

  • 空闲连接:连接池会自动管理空闲连接。当连接长时间未被使用时,连接池可以关闭这些空闲连接以释放资源。
  • 过期连接:如果服务器关闭了连接(比如 Keep-Alive 超时),连接池会检测到并清理这些已失效的连接。

2. 连接释放的时机

  • 请求完成后:当你通过 CloseableHttpClient 执行完一次 HTTP 请求后,连接不会被关闭,而是被"归还"到连接池中,供下次复用。
  • 显式关闭:如果你手动调用了 CloseableHttpResponse.close(),会释放底层连接到连接池。
  • 连接池自动清理:连接池会定期清理已过期或空闲时间过长的连接(需要在应用中显式调用 closeExpiredConnections() 和 closeIdleConnections(),或者通过后台线程自动清理)。

3. 相关参数

  • setMaxTotal(50):连接池最大连接数为 50。
  • setDefaultMaxPerRoute(20):每个路由(目标主机)最大连接数为 20。
  • (可选)RequestConfig 的超时设置(如连接超时、请求超时、读取超时)会影响连接的生命周期,但不会直接导致连接被关闭,只是影响请求的超时行为。

4. 连接池释放的最佳实践

  • 及时关闭响应:每次请求后,务必关闭 CloseableHttpResponse,否则连接不会被归还到池中,可能导致连接泄漏。
  • 定期清理:可以通过定时任务调用 PoolingHttpClientConnectionManager 的 closeExpiredConnections() 和 closeIdleConnections(long idleTime, TimeUnit t) 方法,清理无效连接。

1、引入pom

XML 复制代码
     <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.14</version>
        </dependency>

2、监控连接池情况

java 复制代码
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class HttpClientPoolMonitor {

    @Resource
    private PoolingHttpClientConnectionManager manager;

    @Scheduled(fixedRate = 5000)
    public void reportStats() {
        int total = manager.getTotalStats().getLeased() + manager.getTotalStats().getAvailable();
        System.out.println("[HttpClientPool] Leased: " + manager.getTotalStats().getLeased()
                + ", Available: " + manager.getTotalStats().getAvailable()
                + ", Max: " + manager.getMaxTotal()
                + ", Total: " + total);
        int a = 0;
    }
} 

在HttpClient连接池中,这些参数分别表示以下含义:

  1. Leased‌:当前正在被使用的连接数量,反映活跃连接状态
  2. Available‌:连接池中可立即复用的空闲连接数量
  3. Max‌:连接池允许创建的最大连接总数(maxTotal),控制总体资源消耗
  4. Total‌:当前连接池中连接总数(Leased + Available),反映实际连接占用情况

连接池的关键工作机制:

  • 当Leased达到Max时,新请求需要等待可用连接
  • Available连接会被优先复用,减少新建连接开销
  • 合理设置Max值需要平衡并发需求和系统资源

3、连接池配置

java 复制代码
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class HttpClientConfig {

    @Bean
    public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager() {
        PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
        manager.setMaxTotal(50); // 最大连接数
        manager.setDefaultMaxPerRoute(20); // 每个路由最大连接数
        return manager;
    }

 /*   @Bean
    public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager manager) {
        return HttpClients.custom()
                .setConnectionManager(manager)
                .build();
    }*/

//设置超时时间

    @Bean
    public CloseableHttpClient httpClient(PoolingHttpClientConnectionManager manager) {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(2000)
                .setConnectionRequestTimeout(2000)
                .setSocketTimeout(2000)
                .build();

        return HttpClients.custom()
                .setConnectionManager(manager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }
} 

4、demo

java 复制代码
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Date;

@Service
public class HttpClientDemoService {

    @Resource
    private CloseableHttpClient httpClient;

    public String doGet(String url) {
        try {
            HttpGet request = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuilder result = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
                return result.toString();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
//超时设置
public String doGet2(String url) {
    try {
        // 设置超时时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)      // 连接超时,单位毫秒
                .setConnectionRequestTimeout(3000) // 从连接池获取连接超时
                .setSocketTimeout(10000)      // 读取超时
                .build();

        HttpGet request = new HttpGet(url);
        request.setConfig(requestConfig);

        try (CloseableHttpResponse response = httpClient.execute(request)) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
            return result.toString();
        }
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

    @Scheduled(fixedRate = 50)
    public void scheduledTask() {
       // System.out.println("new Date() = " + new Date());


       // System.out.println("a + new Date() = " + a + new Date());

    for (int i = 0; i < 10; i++) {
        new Thread(this::callHTttp).start();
    }


    }

    public void callHTttp(){
        String url = "http://127.0.0.1:8080/api/producer/send?message=HelloWorld!";
        url = "https://devapi.qweather.com/v7/weather/3d?location=北京&key=YOUR_KEY";
        url = "http://127.0.0.1:7700/openApi/test";
        String a =  doGet(url);
        System.out.println("a = " +a);
    }
} 

5、定时调用http

java 复制代码
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}


import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
public class TestController {

    public String test(){
        return "hello world";
    }
    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/api/producer/send")
    public String send() {
        return "Message sent!";
    }

    @Scheduled(fixedRate = 5000)
    public void scheduledTask() {
        String url = "http://127.0.0.1:8080/api/producer/send?message=Hello, World!";
        //String result = restTemplate.getForObject(url, String.class);
        //System.out.println("HTTP GET Response: " + result);
    }
}
相关推荐
qq_3863226921 分钟前
华为网路设备学习-25(路由器OSPF - 特性专题 二)
网络·学习·华为
听风lighting1 小时前
WebServer实现:muduo库的主丛Reactor架构
linux·运维·网络·c++·socket·webserver
Yolanda_20221 小时前
语音相关-浏览器的自动播放策略研究和websocket研究
websocket·网络协议·microsoft
chirrupy_hamal2 小时前
为什么主动关闭 TCP 连接的一方需要 TIME_WAIT 状态?
网络·tcp
Xの哲學2 小时前
hostapd状态机解析
linux·网络·算法·wireless
Clownseven3 小时前
云计算与5G:如何利用5G网络优化云平台的性能
网络·5g·云计算
码里看花‌4 小时前
网络编程简介与Netty实战:从入门到高性能Echo服务器
运维·服务器·网络
2501_916013744 小时前
iOS应用启动时间优化:通过多工具协作提升iOS App性能表现
websocket·网络协议·tcp/ip·http·网络安全·https·udp
光电大美美-见合八方中国芯5 小时前
【平面波导外腔激光器专题系列】用于干涉光纤传感的低噪声平面波导外腔激光器
网络·人工智能·科技·平面·性能优化·信息与通信