You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebClient线程未停止致应用关闭内存泄漏问题求助

WebClient 应用停止时Netty线程未关闭导致内存泄漏问题

我的应用中有一个端点通过WebClient调用3个REST API,运行时可正常获取所有接口响应,但在本地停止应用时出现内存泄漏相关错误,错误日志如下:

o.a.c.loader.WebappClassLoaderBase       : The web application [ROOT] appears to have started a thread named [reactor-http-nio-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method)
 sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(WindowsSelectorImpl.java:296)
 sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(WindowsSelectorImpl.java:278)
 sun.nio.ch.WindowsSelectorImpl.doSelect(WindowsSelectorImpl.java:159)
 sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
 sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
 io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
 io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:883)
 io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:526)
 io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
 io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
 io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
 java.lang.Thread.run(Thread.java:750)

该错误共出现4次,推测与WebClient的调用逻辑相关。以下是其中一个端点的调用代码:

public Void makeRestCall(Request request) {
    URI endpoint = UriComponentsBuilder.fromUriString("url").build().encode().toUri();
    return webClient.post().uri(endpoint).contentType(MediaType.APPLICATION_JSON)
            .bodyValue(request)
            .retrieve()
            .onStatus(HttpStatus::is4xxClientError,
                    stringResponse -> stringResponse.bodyToMono(Fault.class).flatMap(
                            pojoResponse -> stringResponse.createException().flatMap(ex -> Mono.error(
                                    new HttpClientErrorException(ex.getStatusCode(), "Field: " + pojoResponse.getErrors().get(0)
                                            .getSourceProperty() + " - Error: " + pojoResponse.getErrors().get(0).getMessageID() )))))
            .onStatus(HttpStatus::is5xxServerError,
                    stringResponse -> stringResponse.bodyToMono(Fault.class).flatMap(
                            pojoResponse -> stringResponse.createException().flatMap(ex -> Mono.error(
                                    new HttpClientErrorException(ex.getStatusCode(), pojoResponse.getMessage())))))
            .toBodilessEntity().block().getBody();
}

不确定问题原因,是否需要手动关闭WebClient?原以为Spring容器会自动处理,恳请协助解决。


问题原因

WebClient默认依赖Netty作为底层HTTP客户端,调用block()会触发Netty创建NIO线程池(如日志中的reactor-http-nio-1)。如果WebClient不是Spring托管的Bean,或底层Netty资源未配置销毁逻辑,Spring容器停止时无法自动关闭这些线程,导致线程残留引发内存泄漏告警。

解决步骤

  1. 确保WebClient为Spring托管Bean
    不要手动实例化WebClient,通过WebClient.Builder创建并注入:

    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder.build();
    }
    

    此方式下Spring会在容器销毁时自动处理WebClient的资源释放。

  2. 配置Netty资源的自动销毁逻辑
    若使用自定义HttpClient,需指定销毁方法让Spring自动清理Netty线程池:

    @Bean(destroyMethod = "dispose")
    public HttpClient httpClient() {
        return HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .doOnConnected(conn -> 
                    conn.addHandlerLast(new ReadTimeoutHandler(5))
                        .addHandlerLast(new WriteTimeoutHandler(5)));
    }
    
    @Bean
    public WebClient webClient(HttpClient httpClient) {
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }
    

    通过destroyMethod = "dispose",Spring会在容器关闭时调用HttpClient的销毁方法,关闭Netty线程资源。

  3. 规范响应式调用方式
    你的代码使用block()将响应式调用转为同步,易导致线程资源脱离Spring管理。如果是Spring WebFlux应用,建议全程使用响应式编程(返回Mono<Void>而非直接block);如果是Spring MVC应用,确保WebClient Bean被正确管理的同时,避免不必要的同步阻塞。

结论

无需手动关闭WebClient,但必须保证它是Spring托管的Bean,且底层Netty资源配置了正确的销毁逻辑。仅当使用自定义HttpClient时,需通过destroyMethod指定资源清理方式,让Spring自动完成线程池的关闭。

内容的提问来源于stack exchange,提问作者JavaJo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 04:25:19