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);
    }
}
相关推荐
sakoba3 小时前
Docker学习其二(容器卷,Docker网络,Compose)
运维·网络·学习·docker·容器·基础
惜.己5 小时前
appium中urllib3.exceptions.LocationValueError: No host specified. 的错误解决办法
网络·appium
吉凶以情迁5 小时前
window服务相关问题探索 go语言服务开发探索调试
linux·服务器·开发语言·网络·golang
专注VB编程开发20年5 小时前
UDP受限广播地址255.255.255.255的通信机制详解
网络·udp·智能路由器
189228048616 小时前
NX947NX955美光固态闪存NX962NX966
大数据·服务器·网络·人工智能·科技
Sadsvit7 小时前
Linux 进程管理与计划任务
linux·服务器·网络
一碗白开水一8 小时前
【模型细节】FPN经典网络模型 (Feature Pyramid Networks)详解及其变形优化
网络·人工智能·pytorch·深度学习·计算机视觉
什么都想学的阿超8 小时前
【网络与爬虫 38】Apify全栈指南:从0到1构建企业级自动化爬虫平台
网络·爬虫·自动化
D-海漠9 小时前
安全光幕Muting功能程序逻辑设计
服务器·网络·人工智能
都给我10 小时前
可计算存储(Computational Storage)与DPU(Data Processing Unit)的技术特点对比及实际应用场景分析
运维·服务器·网络·云计算