我爱普洱茶 发表于 2025-1-8 09:24:00

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 通讯场景需求。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: HttpClient