From 4119ecc25be18106fe7594a473c4f37ca180f690 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Tue, 20 Jan 2026 11:34:18 +0000 Subject: [PATCH] Refine solution to clear Netty channel attribute Closes gh-36158 --- .../reactive/ReactorClientHttpConnector.java | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/reactive/ReactorClientHttpConnector.java b/spring-web/src/main/java/org/springframework/http/client/reactive/ReactorClientHttpConnector.java index ad7eed9bce0..ee81b325e7b 100644 --- a/spring-web/src/main/java/org/springframework/http/client/reactive/ReactorClientHttpConnector.java +++ b/spring-web/src/main/java/org/springframework/http/client/reactive/ReactorClientHttpConnector.java @@ -21,15 +21,13 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -import io.netty.channel.Channel; -import io.netty.util.Attribute; import io.netty.util.AttributeKey; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; +import reactor.netty.Connection; import reactor.netty.NettyOutbound; -import reactor.netty.channel.ChannelOperations; import reactor.netty.http.client.HttpClient; import reactor.netty.http.client.HttpClientRequest; import reactor.netty.resources.ConnectionProvider; @@ -163,17 +161,14 @@ public class ReactorClientHttpConnector implements ClientHttpConnector, SmartLif .request(io.netty.handler.codec.http.HttpMethod.valueOf(method.name())); requestSender = setUri(requestSender, uri); - AtomicReference channelRef = new AtomicReference<>(); AtomicReference responseRef = new AtomicReference<>(); return requestSender - .send((request, outbound) -> { - channelRef.set(((ChannelOperations) request).channel()); - return requestCallback.apply(adaptRequest(method, uri, request, outbound)); - }) + .send((request, outbound) -> requestCallback.apply(adaptRequest(method, uri, request, outbound))) .responseConnection((response, connection) -> { ReactorClientHttpResponse clientResponse = new ReactorClientHttpResponse(response, connection); responseRef.set(clientResponse); + clearChannelAttribute(connection); return Mono.just((ClientHttpResponse) clientResponse); }) .next() @@ -182,15 +177,6 @@ public class ReactorClientHttpConnector implements ClientHttpConnector, SmartLif if (response != null) { response.releaseAfterCancel(method); } - }) - .doOnTerminate(() -> { - Channel channel = channelRef.get(); - if (channel != null) { - Attribute> attribute = channel.attr(ATTRIBUTES_KEY); - if (attribute != null) { - attribute.set(null); - } - } }); } @@ -212,6 +198,15 @@ public class ReactorClientHttpConnector implements ClientHttpConnector, SmartLif return new ReactorClientHttpRequest(method, uri, request, nettyOutbound); } + private static void clearChannelAttribute(Connection connection) { + connection.onTerminate().subscribe( + aVoid -> {}, ex -> clearAttribute(connection), () -> clearAttribute(connection)); + } + + private static void clearAttribute(Connection connection) { + connection.channel().attr(ATTRIBUTES_KEY).set(null); + } + @Override public void start() {