From 9f1332c7166eaf817f9f80306fd2b0b4f842c6fe 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 | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 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 102162ba743..ae7adb59355 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,14 +21,12 @@ 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 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; @@ -166,17 +164,15 @@ 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) -> { - responseRef.set(new ReactorClientHttpResponse(response, connection)); - return Mono.just((ClientHttpResponse) responseRef.get()); + ReactorClientHttpResponse clientResponse = new ReactorClientHttpResponse(response, connection); + responseRef.set(clientResponse); + clearChannelAttribute(connection); + return Mono.just((ClientHttpResponse) clientResponse); }) .next() .doOnCancel(() -> { @@ -184,15 +180,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); - } - } }); } @@ -214,6 +201,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() {