HttpComponentsClientHttpRequestFactory
是 Spring 框架中用于配置 RestTemplate
的底层 HTTP 请求工厂的一个实现。它基于 Apache HttpClient,提供了对连接超时、读取超时等参数的细粒度控制。
为什么使用 HttpComponentsClientHttpRequestFactory
?
默认情况下,Spring 的 RestTemplate
使用的是 SimpleClientHttpRequestFactory
,它基于 JDK 的 HttpURLConnection
,功能较为基础,不支持一些高级特性(如连接池、超时设置等)。而 HttpComponentsClientHttpRequestFactory
基于 Apache HttpClient,提供了以下优势:
-
连接超时和读取超时:
- 可以分别设置连接超时时间和读取超时时间。
- 避免因网络问题导致请求长时间挂起。
-
连接池支持:
- 支持 HTTP 连接池,提升性能,尤其在高并发场景下。
-
更丰富的配置选项:
- 支持代理、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);
}
关键点解析
-
连接池配置:
- 使用
PoolingHttpClientConnectionManager
配置连接池。 setMaxTotal
:设置整个连接池的最大连接数。setDefaultMaxPerRoute
:设置每个路由(目标主机)的最大连接数。
- 使用
-
超时设置:
setConnectTimeout
:控制建立连接的最大时间(单位:毫秒)。setReadTimeout
:控制从服务器读取响应的最大时间(单位:毫秒)。
-
HttpClient 定制:
- 使用
HttpClients.custom()
创建自定义的HttpClient
实例。 - 可以进一步添加 SSL 配置、代理设置、重试策略等。
- 使用
-
线程安全:
RestTemplate
和HttpComponentsClientHttpRequestFactory
都是线程安全的,可以复用实例。
注意事项
-
依赖引入:
使用HttpComponentsClientHttpRequestFactory
需要引入 Apache HttpClient 的依赖。如果你使用 Maven,请在pom.xml
中添加以下内容:<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> <!-- 根据需要选择版本 --> </dependency>
-
资源释放:
- 如果你手动创建了
CloseableHttpClient
,需要确保在应用关闭时正确释放资源。 - 可以通过 Spring 的生命周期管理(如
@PreDestroy
或DisposableBean
接口)来关闭HttpClient
。
- 如果你手动创建了
-
默认行为:
- 如果你不显式配置
HttpComponentsClientHttpRequestFactory
,RestTemplate
会使用默认的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。