HttpClient
简介
HttpClient是Apache HttpComponents项目中的一个接口。用于发送HTTP请求和接收HTTP响应。
CloseableHttpClient是HttpClient接口的一个具体实现类,提供了自动管理连接资源的功能,包括连接的创建、使用和关闭。HttpClient 4.5 之后新增的功能。CloseableHttpClient本身是线程安全的。
实现原理
由于HttpClient组件源码用了大量设计模式,设计模式如果看不懂,解读源码就比较费劲,因此我们通过分析设计模式角度,结合关键代码来解析整个原理的实现。
工厂模式(简化对象创建)
HttpClients类是创建CloseableHttpClient的入口,主要由HttpClients.createDefault()方法创建默认客户端和HttpClients.custom()允许用户配置超时、拦截器、代理等细节,
package org.apache.http.impl.client;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
public class HttpClients {
private HttpClients() {
}
public static HttpClientBuilder custom() {
return HttpClientBuilder.create();
}
public static CloseableHttpClient createDefault() {
return HttpClientBuilder.create().build();
}
public static CloseableHttpClient createSystem() {
return HttpClientBuilder.create().useSystemProperties().build();
}
public static CloseableHttpClient createMinimal() {
return new MinimalHttpClient(new PoolingHttpClientConnectionManager());
}
public static CloseableHttpClient createMinimal(HttpClientConnectionManager connManager) {
return new MinimalHttpClient(connManager);
}
}
建造者模式(灵活配置客户端)
从HttpClients类的代码看,HttpClients.custom()返回的是一个HttpClientBuilder对象,支持链式调用配置选项。
装饰器模式(动态扩展功能)
CloseableHttpClient 支持通过拦截器对请求和响应进行增强功能,例如日志记录、认证、缓存等。拦截器本质上是对原有请求/响应处理逻辑的装饰。
HttpClients构建CloseableHttpClient添加拦截增强示例代码如下
CloseableHttpClient httpClient = HttpClients.custom()
.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
System.out.println("请求 URI: " + request.getRequestLine().getUri());
})
.addInterceptorFirst((HttpResponseInterceptor) (response, context) -> {
System.out.println("响应状态: " + response.getStatusLine().getStatusCode());
})
.build();
HttpClientBuilder类添加拦截器增强功能相关代码如下
public final HttpClientBuilder addInterceptorFirst(HttpResponseInterceptor itcp) {
if (itcp == null) {
return this;
} else {
if (this.responseFirst == null) {
this.responseFirst = new LinkedList();
}
this.responseFirst.addFirst(itcp);
return this;
}
}
public final HttpClientBuilder addInterceptorLast(HttpResponseInterceptor itcp) {
if (itcp == null) {
return this;
} else {
if (this.responseLast == null) {
this.responseLast = new LinkedList();
}
this.responseLast.addLast(itcp);
return this;
}
}
策略模式(支持不同行为策略)
比如配置不同的重试策略,将行为的实现和逻辑分离,便于扩展或切换不同策略,提高灵活性。
HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(3, true);
CloseableHttpClient httpClient = HttpClients.custom()
.setRetryHandler(retryHandler)
.build();
单例模式(高效管理共享资源)
连接池管理器(PoolingHttpClientConnectionManager)常被设计为单例,以便多个线程共享相同的连接池实例:
java
复制代码
private static final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
public static CloseableHttpClient createClient() {
return HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
}
- 确保连接池资源的统一管理,避免重复创建。
- 提高资源利用率,降低系统开销。
责任链模式(分阶段处理请求和响应)
ClientExecChain接口
public interface ClientExecChain {
CloseableHttpResponse execute(HttpRoute var1, HttpRequestWrapper var2, HttpClientContext var3, HttpExecutionAware var4) throws IOException, HttpException;
}
HttpClientBuilder.build()方法简化示例代码
public class DefaultHttpClientBuilder {
public CloseableHttpClient build() {
HttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
// 最终处理器:MainClientExec
ClientExecChain mainExec = new MainClientExec(connManager);
// 第二个处理器:RedirectExec
ClientExecChain redirectExec = new RedirectExec(mainExec);
// 第一个处理器:RetryExec
ClientExecChain retryExec = new RetryExec(redirectExec, new DefaultHttpRequestRetryHandler());
// 组装完成的责任链起点
return new InternalHttpClient(retryExec, connManager);
}
}
模板方法模式(定义固定流程,允许定制化)
CloseableHttpClient抽象类中execute()
固定的执行流程
- 模板方法是 execute():
- 对 HTTP 请求进行参数校验。
- 转换请求对象(如 HttpUriRequest -> HttpRequest)。
- 调用具体实现方法 doExecute()。
- 子类只需要实现 doExecute() 方法即可完成具体的请求发送逻辑,具体的字类InternalHttpClient类实现doExecute()方法通过责任链模式处理各种逻辑,如重试、重定向和连接管理。
public abstract class CloseableHttpClient implements HttpClient, Closeable {
// 抽象方法:由子类实现实际的请求发送逻辑
protected abstract CloseableHttpResponse doExecute(
HttpHost target, HttpRequest request, HttpContext context) throws IOException;
// 模板方法:对外暴露的执行方法
public CloseableHttpResponse execute(HttpUriRequest request) throws IOException {
return execute(request, (HttpContext) null);
}
public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException, ClientProtocolException {
Args.notNull(request, "HTTP request");//参数校验
return this.doExecute(determineTarget(request), request, context);//转换请求对象
}
public CloseableHttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException {
Args.notNull(request, "HTTP request"); // 参数校验
return doExecute(target, request, context); // 调用抽象方法
}
}
代理模式(管理底层资源和代理请求)
HttpRoutePlanner接口,DefaultRoutePlanner类 实现HttpRoutePlanner接口,DefaultProxyRoutePlanner 和 SystemDefaultRoutePlanner 继承 DefaultRoutePlanner 类。
- 静态代理
DefaultProxyRoutePlanner 静态代理,所有请求都通过固定的代理服务器转发。
HttpHost proxy = new HttpHost("proxy.example.com", 8080); // 配置代理服务器
CloseableHttpClient httpClient = HttpClients.custom()
.setRoutePlanner(new DefaultProxyRoutePlanner(proxy)) // 设置静态代理
.build();
HttpGet request = new HttpGet("http://example.com");
CloseableHttpResponse response = httpClient.execute(request);
System.out.println(EntityUtils.toString(response.getEntity()));
- 动态代理
DefaultRoutePlanner 或 SystemDefaultRoutePlanner 根据目标主机或系统设置动态选择代理。
当创建 SystemDefaultRoutePlanner 时,会指定一个 ProxySelector 对象:示例代码如下
ProxySelector selector = ProxySelector.getDefault();
SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(selector);
在 SystemDefaultRoutePlanner.determineProxy() 方法中,会调用 ProxySelector.select(),返回一组代理(可能是多个,遍历代理列表,按照优先级选出合适的代理。动态选择代理,示例代码如下
@Override
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
if (target == null) {
throw new IllegalArgumentException("Target host is null");
}
// 使用目标主机的 URI 创建请求
URI targetURI = URI.create(target.toURI());
List<Proxy> proxies = proxySelector.select(targetURI); // 调用 ProxySelector
Proxy proxy = chooseProxy(proxies);
if (proxy == null || proxy.type() == Proxy.Type.DIRECT) {
return null; // 无代理,直接连接
}
if (proxy.type() == Proxy.Type.HTTP) {
InetSocketAddress address = (InetSocketAddress) proxy.address();
return new HttpHost(address.getHostString(), address.getPort());
} else {
throw new HttpException("Unsupported proxy type: " + proxy.type());
}
}
总结
使用多种设计模式的结合使得 CloseableHttpClient具备高扩展性、灵活性和性能优势,能够满足各种复杂的 HTTP 通信场景需求。
原文链接:HttpClient
暂无评论内容