由于项目中发送请求的客户端非常多,比如apache的httpclient,也用过hutool的httputil,但是spring5之后都是推荐使用webflux进行请求的发送或处理,所以我们将平常的httpclient去掉,引入了spring-webflux,并自己动手构建了一个webclientutil作为请求发送的客户端。在此期间由于是手动构建的util,或多或少都有可能会写出一些bug,其中我们使用wenclient调用外部互联网接口时,由于对方是https连接,所以请求会失败因为没有安装证书,这时有两个处理方式一个是在spring项目中安装请求接口地址的证书,第二点就是跳过SSL证书验证,于是我们在util中加了一个方法构建一个可信任的证书用于跳过SSL验证,在经过多次请求发现服务器宕机了,打开日志发现是堆内存溢出,经过排除法发现不调用跳过SSL证书的方法就不会导致内存增加。

导致内存溢出的方法

public WebClientUtil trustSSL(){
  SslContext sslContext = SslContextBuilder.forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();
  httpClient = httpClient.secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
  return this;
} 

由于创建SslContext包含静态变量而WebClientUtil又是手动new导致webclientutil不会被回收。

改造

可以通过springboot启动时将其注入为bean即可,保持单例后续直接使用。

创建bean

@Bean
public ConnectionProvider connectionProvider(){
  return ConnectionProvider.builder("connection-provider")
    // 最大连接数 默认为处理器数量*2
    .maxConnections(500)
    // 默认等待队列等于maxConnections*2
    .pendingAcquireMaxCount(1000)
    // 最大空闲时间
    .maxIdleTime(Duration.ofSeconds(120))
    // 连接最大生命周期
    .maxLifeTime(Duration.ofSeconds(60))
    .build();
}

改造后的工具方法

public WebClientUtil trustSSL(){
  SslContext sslContext = SpringUtil.getBean("sslContext");
  httpClient = httpClient.secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
  return this;
}