HttpClient

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

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容