返回

Spring WebClient 如何避免 Apache HttpClient 5 内存泄漏?

java

Spring WebClient 中如何避免 Apache HttpClient 5 内存泄漏

问题:Apache HttpClient 5 内存泄漏

在升级 Spring Boot 应用程序后,我们使用 Spring 的新 WebClient,发现“idle-connection-evictor”线程存在内存泄漏,导致 WebappClassloader 无法 GC。这是由 Apache HttpClient 5(异步)创建的。

原因:缺少资源清理

内存泄漏是由未正确关闭 Apache HttpClient 5 的 CloseableHttpAsyncClient 引起的。Spring WebClient 缺乏关闭机制,导致资源未释放。

解决方案:手动关闭资源

为了避免内存泄漏,需要手动关闭 CloseableHttpAsyncClient。这是通过使用 try-with-resource 语句或显式调用 close() 方法实现的。

此外,HttpComponentsClientHttpConnector 提供了一个 close() 方法来释放资源。确保在不再需要 WebClient 时调用此方法。

最佳实践:使用 Bean 注入

将 HttpComponentsClientHttpConnector 注册为 Bean 是一个最佳做法。这允许在 Bean 生命周期结束时自动关闭它。这可以通过在 Spring 上下文中使用 @Bean 注解实现。

代码更新

以下是更新的代码,已应用上述解决方案:

@Bean
public CloseableHttpAsyncClient httpAsyncClient() {
    return HttpAsyncClients.custom()
        .setConnectionManager(connManager)
        .evictIdleConnections(TimeValue.ofSeconds(60))
        .build();
}

@Bean
public HttpComponentsClientHttpConnector clientConnector(CloseableHttpAsyncClient httpAsyncClient) {
    return new HttpComponentsClientHttpConnector(httpAsyncClient);
}

public WebClient build() {
    final ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
        buildOAuth2AuthorizedClientManager());

    return WebClient.builder()
        .clientConnector(clientConnector)
        .apply(oauth2Client.oauth2Configuration())
        .build();
}

结论

通过遵循这些步骤,可以避免在 Spring WebClient 中使用 Apache HttpClient 5 造成的内存泄漏。正确关闭资源和使用 Bean 注入有助于确保资源的适当释放和应用程序的稳定运行。

常见问题解答

1. 为什么 Spring WebClient 不提供关闭方法?

Spring WebClient 是一个反应式客户端,设计为无状态的。它不持有对基础连接的引用,因此不提供关闭方法。

2. 我可以使用 try-with-resource 语句来关闭 CloseableHttpAsyncClient 吗?

是的,使用 try-with-resource 语句是一种简单有效的方法,可以确保在代码块执行完成后关闭 CloseableHttpAsyncClient。

3. HttpComponentsClientHttpConnector 是否实现了关闭方法?

是的,HttpComponentsClientHttpConnector 提供了一个 close() 方法来释放资源。在不再需要 WebClient 时调用此方法非常重要。

4. 将 HttpComponentsClientHttpConnector 注册为 Bean 有什么好处?

将 HttpComponentsClientHttpConnector 注册为 Bean 可以确保它在 Bean 生命周期结束时自动关闭。这是一种避免内存泄漏的最佳实践。

5. 除了内存泄漏,还有哪些其他影响?

如果不关闭资源,除了内存泄漏外,还会导致其他问题,例如性能下降和不稳定的应用程序行为。