【请求超时HttpClien】

HttpComponentsClientHttpRequestFactory 是 Spring 框架中用于配置 RestTemplate 的底层 HTTP 请求工厂的一个实现。它基于 Apache HttpClient,提供了对连接超时、读取超时等参数的细粒度控制。


为什么使用 HttpComponentsClientHttpRequestFactory

默认情况下,Spring 的 RestTemplate 使用的是 SimpleClientHttpRequestFactory,它基于 JDK 的 HttpURLConnection,功能较为基础,不支持一些高级特性(如连接池、超时设置等)。而 HttpComponentsClientHttpRequestFactory 基于 Apache HttpClient,提供了以下优势:

  1. 连接超时和读取超时

    • 可以分别设置连接超时时间和读取超时时间。
    • 避免因网络问题导致请求长时间挂起。
  2. 连接池支持

    • 支持 HTTP 连接池,提升性能,尤其在高并发场景下。
  3. 更丰富的配置选项

    • 支持代理、SSL 配置、重试策略等。

代码示例:如何使用 HttpComponentsClientHttpRequestFactory

以下是完整的代码示例,展示如何通过 HttpComponentsClientHttpRequestFactory 配置 RestTemplate 并设置超时时间:

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public RestTemplate createRestTemplateWithTimeout() {
    // 创建连接管理器(支持连接池)
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    connectionManager.setMaxTotal(200); // 最大连接数
    connectionManager.setDefaultMaxPerRoute(20); // 每个路由的最大连接数

    // 创建 HttpClient
    CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();

    // 创建 HttpComponentsClientHttpRequestFactory
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

    // 设置超时时间
    requestFactory.setConnectTimeout(10000); // 连接超时时间(毫秒)
    requestFactory.setReadTimeout(10000);    // 读取超时时间(毫秒)

    // 创建 RestTemplate
    return new RestTemplate(requestFactory);
}

关键点解析

  1. 连接池配置

    • 使用 PoolingHttpClientConnectionManager 配置连接池。
    • setMaxTotal:设置整个连接池的最大连接数。
    • setDefaultMaxPerRoute:设置每个路由(目标主机)的最大连接数。
  2. 超时设置

    • setConnectTimeout:控制建立连接的最大时间(单位:毫秒)。
    • setReadTimeout:控制从服务器读取响应的最大时间(单位:毫秒)。
  3. HttpClient 定制

    • 使用 HttpClients.custom() 创建自定义的 HttpClient 实例。
    • 可以进一步添加 SSL 配置、代理设置、重试策略等。
  4. 线程安全

    • RestTemplateHttpComponentsClientHttpRequestFactory 都是线程安全的,可以复用实例。

注意事项

  1. 依赖引入
    使用 HttpComponentsClientHttpRequestFactory 需要引入 Apache HttpClient 的依赖。如果你使用 Maven,请在 pom.xml 中添加以下内容:

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version> <!-- 根据需要选择版本 -->
    </dependency>
    
  2. 资源释放

    • 如果你手动创建了 CloseableHttpClient,需要确保在应用关闭时正确释放资源。
    • 可以通过 Spring 的生命周期管理(如 @PreDestroyDisposableBean 接口)来关闭 HttpClient
  3. 默认行为

    • 如果你不显式配置 HttpComponentsClientHttpRequestFactoryRestTemplate 会使用默认的 SimpleClientHttpRequestFactory,它可能无法满足复杂的超时或连接池需求。

结合 RestTemplate 使用

以下是一个完整的示例,展示如何将配置好的 RestTemplate 用于实际请求:

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;

public class PushService {

    private final RestTemplate restTemplate;

    public PushService() {
        this.restTemplate = createRestTemplateWithTimeout();
    }

    public boolean pushTo(DeviceData deviceData, String DTO, String createUrl) {
        log.info(">>>>>> S DeviceId-{}, CntrNumber-{}, time-{}", 
                 deviceData.getDeviceNumber(), deviceData.getCntrNum(), LocalDateTime.now());

        HttpHeaders headers = new HttpHeaders();
        HttpEntity<String> jsonEntity = new HttpEntity<>(DTO, headers);

        boolean isPushResult = false;

        try {
            ResponseEntity<String> response = restTemplate.postForEntity(createUrl, jsonEntity, String.class);

            if (response.getStatusCodeValue() == 200) {
                log.info(">>>  push succeeded -> {}, {}", deviceData.getDeviceNumber(), response.getStatusCodeValue());
                isPushResult = true;
            }
        } catch (Exception e) {
            log.error(" push error -> DeviceId-{}, CntrNumber-{}, time-{}", 
                      deviceData.getDeviceNumber(), deviceData.getCntrNum(), LocalDateTime.now(), e);
        }

        return isPushResult;
    }

    private RestTemplate createRestTemplateWithTimeout() {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(200);
        connectionManager.setDefaultMaxPerRoute(20);

        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(connectionManager)
                .build();

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

        return new RestTemplate(requestFactory);
    }
}

小结

  • HttpComponentsClientHttpRequestFactory 提供了对 RestTemplate 的底层 HTTP 请求的精细控制。
  • 通过设置连接超时和读取超时,可以有效避免请求长时间挂起的问题。
  • 在高并发场景下,建议启用连接池以提升性能。

另外方案

除了使用 HttpComponentsClientHttpRequestFactory 来配置 RestTemplate 实现同步请求并控制超时外,还有其他几种方案可以考虑。每种方法都有其特定的应用场景和优缺点:

1. 使用 SimpleClientHttpRequestFactory

如果你不需要连接池支持,并且对 Apache HttpClient 的依赖有所顾虑,可以直接使用 SimpleClientHttpRequestFactory,它基于 JDK 自带的 HttpURLConnection

import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public RestTemplate createRestTemplateWithTimeout() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(10000); // 连接超时时间(毫秒)
    factory.setReadTimeout(10000);    // 读取超时时间(毫秒)

    return new RestTemplate(factory);
}

优点

  • 不需要额外的库依赖。
  • 对于简单的 HTTP 请求足够使用。

缺点

  • 功能较为基础,缺少高级特性如连接池等。

2. 使用 WebClient (Spring 5+)

WebClient 是 Spring 5 引入的一个非阻塞、响应式的 HTTP 客户端,非常适合构建现代微服务应用。

import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

public Mono<String> pushToTOS(String tosDTO, String createUrl) {
    WebClient webClient = WebClient.builder().build();

    return webClient.post()
            .uri(createUrl)
            .bodyValue(tosDTO)
            .retrieve()
            .bodyToMono(String.class)
            .timeout(Duration.ofSeconds(10)); // 设置超时时间为10秒
}

优点

  • 非阻塞,适合高并发场景。
  • 提供了流式 API,易于链式调用。

缺点

  • 学习曲线较陡峭,尤其是对于习惯同步编程模型的开发者。
  • 需要处理异步结果。

3. 使用 OkHttp

OkHttp 是另一个流行的 HTTP 客户端库,提供了简洁的 API 和强大的功能集,包括连接池、自动重试等。

首先,你需要添加 OkHttp 的依赖到你的项目中:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.x.x</version> <!-- 选择最新版本 -->
</dependency>

然后创建 RestTemplate 实例:

import okhttp3.OkHttpClient;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public RestTemplate createRestTemplateWithTimeout() {
    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .build();

    OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(okHttpClient);

    return new RestTemplate(factory);
}

优点

  • 轻量级,性能优越。
  • 支持 HTTP/2 和 WebSocket 协议。

缺点

  • 需要引入额外的库依赖。

总结

  • 简单且无需连接池,SimpleClientHttpRequestFactory 是一个不错的选择。
  • 对于现代 Web 应用,特别是那些需要高并发处理能力的应用,推荐使用 WebClient
  • OkHttp 的轻量级和高性能,或者有特殊需求(如 HTTP/2 支持),可以选择 OkHttp。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贺公子之数据科学与艺术

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值