HttpClient使用高级-apache http client方式实现

本文详细介绍了如何自定义RequestHttp和RequestExecutor来实现Apache HttpClient的使用。通过RequestHttp生成HTTP请求客户端,包括获取httpClient和httpProxy,以及连接管理器的创建。重点讨论了连接池的优势,如降低延迟和支持更大并发。RequestExecutor用于执行HTTP请求,通过RequestHttp获取httpClient执行execute()。同时,文章还揭示了连接池的工作原理和释放连接的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、获取接口定义【自定义RequestHttp】

      作用:生成(获取)http请求客户端

1.1获取httpClient    2.获取httpProxy

public interface RequestHttp<H, P> {

  /**
   * 返回httpClient.CloseableHttpClient是apache的一个类
   *
   * @return 返回httpClient
   */
  H getRequestHttpClient();

  /**
   * 返回httpProxy.HttpHost 是apache的一个类
   * @return 返回httpProxy
   */
  P getRequestHttpProxy();

  /**
   * 返回HttpType.
   *
   *JODD_HTTP 
    Jodd提供一个很轻量级、原生的的http客户端,使用起来很简单、方便。它能很方便的发送和接收http消息
 
    HttpClient
    Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议
 
    OK_HTTP
    一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso) 用于替代HttpUrlConnection和Apache HttpClient
 
   */
  HttpType getRequestType();

}

1.2、接口实现

属性:

  private CloseableHttpClient httpClient;
  private HttpHost httpProxy;

方法:

public void initHttp() {
    //首先、从内存中获取
    WxMpConfigStorage configStorage = this.getWxMpConfigStorage();
    ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder();
    //其次、使用默认方式创建
    if (null == apacheHttpClientBuilder) {
      apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
    }
    //最后、设置代理
    apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
      .httpProxyPort(configStorage.getHttpProxyPort())
      .httpProxyUsername(configStorage.getHttpProxyUsername())
      .httpProxyPassword(configStorage.getHttpProxyPassword());

    if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
      this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
    }

    this.httpClient = apacheHttpClientBuilder.build();
  }

1.3、httpClient  管理器

具体创建【httpclient 连接管理器】  DefaultApacheHttpClientBuilder

public interface ApacheHttpClientBuilder {

  /**
   * 构建httpclient实例.
   *
   * @return new instance of CloseableHttpClient
   */
  CloseableHttpClient build();

  /**
   * 代理服务器地址.
   */
  ApacheHttpClientBuilder httpProxyHost(String httpProxyHost);

  /**
   * 代理服务器端口.
   */
  ApacheHttpClientBuilder httpProxyPort(int httpProxyPort);

  /**
   * 代理服务器用户名.
   */
  ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername);

  /**
   * 代理服务器密码.
   */
  ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword);

  /**
   * ssl连接socket工厂.
   */
  ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory);
}

1.4、httpClient  管理器实现类

  1、获取

  // 单例模式,并持有唯一的CloseableHttpClient(仅首次调用创建)

  public static DefaultApacheHttpClientBuilder get() {
    return DefaultApacheHttpClientBuilder.SingletonHolder.INSTANCE;
  }

  // 内部类
  private static class SingletonHolder {
    private static final DefaultApacheHttpClientBuilder INSTANCE = new 
    DefaultApacheHttpClientBuilder();
  }

2.空闲连接控制器

  public static class IdleConnectionMonitorThread extends Thread {
    private final HttpClientConnectionManager connMgr;
    private final int idleConnTimeout;
    private final int checkWaitTime;
    //是否停止
    private volatile boolean shutdown;

    public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) {
      super("IdleConnectionMonitorThread");
      this.connMgr = connMgr;
      this.idleConnTimeout = idleConnTimeout;
      this.checkWaitTime = checkWaitTime;
    }

    @Override
    public void run() {
      try {
        while (!this.shutdown) {
          synchronized (this) {
            wait(this.checkWaitTime);
            this.connMgr.closeExpiredConnections();
            this.connMgr.closeIdleConnections(this.idleConnTimeout,
              TimeUnit.MILLISECONDS);
          }
        }
      } catch (InterruptedException ignore) {
      }
    }

    public void trigger() {
      synchronized (this) {
        notifyAll();
      }
    }

    public void shutdown() {
      this.shutdown = true;
      synchronized (this) {
        notifyAll();
      }
    }
  }

1.5.Http连接池

1、降低延迟:如果不采用连接池,每次连接发起Http请求的时候都会重新建立TCP连接(经历3次握手),用完就会关闭连接(4次挥手),如果采用连接池则减少了这部分时间损耗,别小看这几次握手,本人经过测试发现,基本上3倍的时间延迟

2、支持更大的并发:如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接

1.5.1代码

1、HttpConnectionManager.java连接池管理类,支持https协议

@Component

public class HttpConnectionManager {

    PoolingHttpClientConnectionManager cm = null;
    
    @PostConstruct
    public void init() {
        LayeredConnectionSocketFactory sslsf = null;
        try {
            sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("https", sslsf)
                .register("http", new PlainConnectionSocketFactory())
                .build();
        cm =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        cm.setMaxTotal(200);
        cm.setDefaultMaxPerRoute(20);
    }

    public CloseableHttpClient getHttpClient() {       
        CloseableHttpClient httpClient = HttpClients.custom()
                .setConnectionManager(cm)
                .build();          
        
        /*CloseableHttpClient httpClient = HttpClients.createDefault();//如果不采用连接池就是这种方式获取连接*/
        return httpClient;
    }
}

 

1.5.2、连接池消费类:HaoMaiClient.java

@Component
public class HaoMaiClient {
    @Autowired
    HttpConnectionManager connManager;
    
    public <T> T get(String path,Class<T> clazz){
        CloseableHttpClient httpClient=connManager.getHttpClient();
        HttpGet httpget = new HttpGet(path);
        String json=null;        
        CloseableHttpResponse response=null;
        try {
            response = httpClient.execute(httpget);
            InputStream in=response.getEntity().getContent();
            json=IOUtils.toString(in);
            in.close();
        } catch (UnsupportedOperationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {            
            if(response!=null){
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            }            
        }                
        return JSON.parseObject(json, clazz);
    }

}

1.5.3、原理及注意事项

连接池中连接都是在发起请求的时候建立,并且都是长连接

HaoMaiClient.java中的in.close();作用就是将用完的连接释放,下次请求可以复用,这里特别注意的是,如果不使用in.close();而仅仅使用response.close();结果就是连接会被关闭,并且不能被复用,这样就失去了采用连接池的意义。

连接池释放连接的时候,并不会直接对TCP连接的状态有任何改变,只是维护了两个Set,leased和avaliabled,leased代表被占用的连接集合,avaliabled代表可用的连接的集合,释放连接的时候仅仅是将连接从leased中remove掉了,并把连接放到avaliabled集合中

2、获取接口定义【自定义RequestExecutor

      作用:生成http请求执行

          实现类中有变量RequestHttp<H, P> requestHttp;

          再具体执行过程中,通过requestHttp获取httpClient后执行execute();

           构建协议:HttpGet httpGet = new HttpGet(uri);

            执行请求:CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)

public interface RequestExecutor<T, E> {

  /**
   * 执行http请求.
   *
   * @param uri  uri
   * @param data 数据
   * @return 响应结果
   * @throws WxErrorException 自定义异常
   * @throws IOException      io异常
   */
  T execute(String uri, E data) throws WxErrorException, IOException;


  /**
   * 执行http请求.
   *
   * @param uri      uri
   * @param data     数据
   * @param handler http响应处理器
   * @throws WxErrorException 自定义异常
   * @throws IOException      io异常
   */
  void execute(String uri, E data, ResponseHandler<T> handler) throws WxErrorException, IOException;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

良之才-小良

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值