整合 okhttp

bean 容器

将 OkHttpClient 添加到 bean 容器

tio-boot 整合 okhttp 非常简单,只需要添加一个配置类将 okhttp3.OkHttpClient 放到 bean 容器中即可,配置示例如下

import java.util.concurrent.TimeUnit;

import com.litongjava.jfinal.aop.annotation.ABean;
import com.litongjava.jfinal.aop.annotation.AConfiguration;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;

@AConfiguration
public class OkHttpClientConfig {

  @ABean
  public OkHttpClient config() {
    Builder builder = new OkHttpClient().newBuilder();
    // 连接池
    builder.connectionPool(pool());
    // 连接超时
    builder.connectTimeout(120L, TimeUnit.SECONDS).readTimeout(120L, TimeUnit.SECONDS).build();
    return builder.build();
  }

  private ConnectionPool pool() {
    return new ConnectionPool(200, 5, TimeUnit.MINUTES);
  }
}

为什么要将 OkHttpClient 添加到 bean 容器

OkHttpClient实例放入容器有多个好处,这种做法在开发大型应用时尤其重要。OkHttpClient是一个能够处理 HTTP 请求的高效客户端,具有配置灵活、支持同步阻塞与异步处理 HTTP 请求等特点。以下是将OkHttpClient放入容器中的几个主要理由:

  1. 重用连接和线程池OkHttpClient实例在内部使用了连接池和线程池来优化资源使用和提高性能。通过将其作为单例(或者有限的几个实例)放入容器中,可以确保整个应用共享这些资源,避免了重复创建和销毁带来的开销,从而减少了内存占用和提高了性能。

  2. 统一配置:将OkHttpClient配置在容器中可以让你在一个地方集中管理其配置,如超时设置、连接池大小等。这样做不仅使配置更加集中、易于管理,还能确保整个应用使用的是一致的 HTTP 客户端行为。对于需要调整 HTTP 行为以适应不同环境(开发、测试、生产)的情况,这一点尤其有用。

  3. 便于维护和测试:通过依赖注入管理OkHttpClient,可以更容易地在不同的环境或测试场景下替换或模拟这个客户端。这对于编写单元测试和集成测试尤其重要,因为你可以注入一个配置了不同行为(如模拟服务器响应)的客户端,而不用改变测试代码外的实际代码。

  4. 减少资源泄漏的风险:正确管理OkHttpClient实例(如通过容器确保其生命周期)有助于防止资源泄漏,例如忘记关闭连接。框架层面的管理有助于自动化这一过程,减少因错误使用 API 导致的问题。

  5. 提高开发效率:最后,通过框架自动管理这些依赖项,开发者可以专注于业务逻辑而不是管理底层的 HTTP 通信细节,从而提高开发效率。

总的来说,将OkHttpClient放入容器中是一种最佳实践,它有助于优化应用的性能和资源使用,同时提高了代码的可维护性和测试性。

单例枚举

单例枚举不依赖 bean 容器


import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;

public enum OkHttpClientPool {
  INSTANCE;

  static okhttp3.OkHttpClient.Builder builder;
  static {
    builder = new OkHttpClient().newBuilder();
    // 连接池
    builder.connectionPool(pool());
    // 信任连接
    builder.sslSocketFactory(sslSocketFactory(), x509TrustManager());
    // 连接超时
    builder.connectTimeout(120L, TimeUnit.SECONDS).readTimeout(120L, TimeUnit.SECONDS).build();

  }

  public static OkHttpClient getHttpClient() {
    return builder.build();
  }

  private static ConnectionPool pool() {
    return new ConnectionPool(200, 5, TimeUnit.MINUTES);
  }

  public static X509TrustManager x509TrustManager() {
    return new X509TrustManager() {
      @Override
      public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
      }

      @Override
      public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
      }

      @Override
      public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
      }
    };
  }

  public static SSLSocketFactory sslSocketFactory() {
    try {
      // 信任任何链接
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, new TrustManager[] { x509TrustManager() }, new SecureRandom());
      return sslContext.getSocketFactory();
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (KeyManagementException e) {
      e.printStackTrace();
    }
    return null;
  }

}