Use of TcpClient extensible per connection
Closes gh-25889
This commit is contained in:
parent
43f595f80e
commit
76eb5e6e2c
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.messaging.simp.stomp;
|
package org.springframework.messaging.simp.stomp;
|
||||||
|
|
||||||
import org.springframework.messaging.tcp.TcpConnectionHandler;
|
|
||||||
import org.springframework.util.concurrent.ListenableFuture;
|
import org.springframework.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -30,7 +29,7 @@ import org.springframework.util.concurrent.ListenableFuture;
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
*/
|
*/
|
||||||
public interface ConnectionHandlingStompSession extends StompSession, TcpConnectionHandler<byte[]> {
|
public interface ConnectionHandlingStompSession extends StompSession, StompTcpConnectionHandler<byte[]> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a future that will complete when the session is ready for use.
|
* Return a future that will complete when the session is ready for use.
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,13 @@ public class DefaultStompSession implements ConnectionHandlingStompSession {
|
||||||
return this.sessionId;
|
return this.sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StompHeaderAccessor getConnectHeaders() {
|
||||||
|
StompHeaderAccessor accessor = createHeaderAccessor(StompCommand.CONNECT);
|
||||||
|
accessor.addNativeHeaders(this.connectHeaders);
|
||||||
|
return accessor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the configured session handler.
|
* Return the configured session handler.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||||
import org.springframework.messaging.support.MessageHeaderInitializer;
|
import org.springframework.messaging.support.MessageHeaderInitializer;
|
||||||
import org.springframework.messaging.tcp.FixedIntervalReconnectStrategy;
|
import org.springframework.messaging.tcp.FixedIntervalReconnectStrategy;
|
||||||
import org.springframework.messaging.tcp.TcpConnection;
|
import org.springframework.messaging.tcp.TcpConnection;
|
||||||
import org.springframework.messaging.tcp.TcpConnectionHandler;
|
|
||||||
import org.springframework.messaging.tcp.TcpOperations;
|
import org.springframework.messaging.tcp.TcpOperations;
|
||||||
import org.springframework.messaging.tcp.reactor.ReactorNettyCodec;
|
import org.springframework.messaging.tcp.reactor.ReactorNettyCodec;
|
||||||
import org.springframework.messaging.tcp.reactor.ReactorNettyTcpClient;
|
import org.springframework.messaging.tcp.reactor.ReactorNettyTcpClient;
|
||||||
|
|
@ -141,7 +140,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
|
|
||||||
private final DefaultStats stats = new DefaultStats();
|
private final DefaultStats stats = new DefaultStats();
|
||||||
|
|
||||||
private final Map<String, StompConnectionHandler> connectionHandlers = new ConcurrentHashMap<>();
|
private final Map<String, RelayConnectionHandler> connectionHandlers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private TaskScheduler taskScheduler;
|
private TaskScheduler taskScheduler;
|
||||||
|
|
@ -451,7 +450,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
logger.debug("Forwarding " + accessor.getShortLogMessage(EMPTY_PAYLOAD));
|
logger.debug("Forwarding " + accessor.getShortLogMessage(EMPTY_PAYLOAD));
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemStompConnectionHandler handler = new SystemStompConnectionHandler(accessor);
|
SystemSessionConnectionHandler handler = new SystemSessionConnectionHandler(accessor);
|
||||||
this.connectionHandlers.put(handler.getSessionId(), handler);
|
this.connectionHandlers.put(handler.getSessionId(), handler);
|
||||||
|
|
||||||
this.stats.incrementConnectCount();
|
this.stats.incrementConnectCount();
|
||||||
|
|
@ -495,7 +494,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
throw new MessageDeliveryException("Message broker not active. Consider subscribing to " +
|
throw new MessageDeliveryException("Message broker not active. Consider subscribing to " +
|
||||||
"receive BrokerAvailabilityEvent's from an ApplicationListener Spring bean.");
|
"receive BrokerAvailabilityEvent's from an ApplicationListener Spring bean.");
|
||||||
}
|
}
|
||||||
StompConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
RelayConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
handler.sendStompErrorFrameToClient("Broker not available.");
|
handler.sendStompErrorFrameToClient("Broker not available.");
|
||||||
handler.clearConnection();
|
handler.clearConnection();
|
||||||
|
|
@ -562,14 +561,14 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
if (getVirtualHost() != null) {
|
if (getVirtualHost() != null) {
|
||||||
stompAccessor.setHost(getVirtualHost());
|
stompAccessor.setHost(getVirtualHost());
|
||||||
}
|
}
|
||||||
StompConnectionHandler handler = new StompConnectionHandler(sessionId, stompAccessor);
|
RelayConnectionHandler handler = new RelayConnectionHandler(sessionId, stompAccessor);
|
||||||
this.connectionHandlers.put(sessionId, handler);
|
this.connectionHandlers.put(sessionId, handler);
|
||||||
this.stats.incrementConnectCount();
|
this.stats.incrementConnectCount();
|
||||||
Assert.state(this.tcpClient != null, "No TCP client available");
|
Assert.state(this.tcpClient != null, "No TCP client available");
|
||||||
this.tcpClient.connect(handler);
|
this.tcpClient.connect(handler);
|
||||||
}
|
}
|
||||||
else if (StompCommand.DISCONNECT.equals(command)) {
|
else if (StompCommand.DISCONNECT.equals(command)) {
|
||||||
StompConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
RelayConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Ignoring DISCONNECT in session " + sessionId + ". Connection already cleaned up.");
|
logger.debug("Ignoring DISCONNECT in session " + sessionId + ". Connection already cleaned up.");
|
||||||
|
|
@ -580,7 +579,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
handler.forward(message, stompAccessor);
|
handler.forward(message, stompAccessor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
StompConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
RelayConnectionHandler handler = this.connectionHandlers.get(sessionId);
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("No TCP connection for session " + sessionId + " in " + message);
|
logger.debug("No TCP connection for session " + sessionId + " in " + message);
|
||||||
|
|
@ -611,7 +610,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class StompConnectionHandler implements TcpConnectionHandler<byte[]> {
|
private class RelayConnectionHandler implements StompTcpConnectionHandler<byte[]> {
|
||||||
|
|
||||||
private final String sessionId;
|
private final String sessionId;
|
||||||
|
|
||||||
|
|
@ -634,11 +633,11 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
private long clientSendMessageTimestamp;
|
private long clientSendMessageTimestamp;
|
||||||
|
|
||||||
|
|
||||||
protected StompConnectionHandler(String sessionId, StompHeaderAccessor connectHeaders) {
|
protected RelayConnectionHandler(String sessionId, StompHeaderAccessor connectHeaders) {
|
||||||
this(sessionId, connectHeaders, true);
|
this(sessionId, connectHeaders, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StompConnectionHandler(String sessionId, StompHeaderAccessor connectHeaders, boolean isClientSession) {
|
private RelayConnectionHandler(String sessionId, StompHeaderAccessor connectHeaders, boolean isClientSession) {
|
||||||
Assert.notNull(sessionId, "'sessionId' must not be null");
|
Assert.notNull(sessionId, "'sessionId' must not be null");
|
||||||
Assert.notNull(connectHeaders, "'connectHeaders' must not be null");
|
Assert.notNull(connectHeaders, "'connectHeaders' must not be null");
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
|
|
@ -662,6 +661,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
return this.sessionId;
|
return this.sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public StompHeaderAccessor getConnectHeaders() {
|
public StompHeaderAccessor getConnectHeaders() {
|
||||||
return this.connectHeaders;
|
return this.connectHeaders;
|
||||||
}
|
}
|
||||||
|
|
@ -968,9 +968,9 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class SystemStompConnectionHandler extends StompConnectionHandler {
|
private class SystemSessionConnectionHandler extends RelayConnectionHandler {
|
||||||
|
|
||||||
public SystemStompConnectionHandler(StompHeaderAccessor connectHeaders) {
|
public SystemSessionConnectionHandler(StompHeaderAccessor connectHeaders) {
|
||||||
super(SYSTEM_SESSION_ID, connectHeaders, false);
|
super(SYSTEM_SESSION_ID, connectHeaders, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1099,7 +1099,7 @@ public class StompBrokerRelayMessageHandler extends AbstractBrokerMessageHandler
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
for (StompConnectionHandler handler : connectionHandlers.values()) {
|
for (RelayConnectionHandler handler : connectionHandlers.values()) {
|
||||||
handler.updateClientSendMessageCount(now);
|
handler.updateClientSendMessageCount(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.messaging.simp.stomp;
|
||||||
|
|
||||||
|
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||||
|
import org.springframework.messaging.tcp.TcpConnectionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TcpConnectionHandler} for use with STOMP connections, exposing
|
||||||
|
* further information about the connection.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 5.3
|
||||||
|
* @param <P> the type of payload for inbound and outbound messages
|
||||||
|
*/
|
||||||
|
public interface StompTcpConnectionHandler<P> extends TcpConnectionHandler<P> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link SimpMessageHeaderAccessor#getSessionId() sessionId}
|
||||||
|
* associated with the STOMP connection.
|
||||||
|
*/
|
||||||
|
String getSessionId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the headers that will be sent in the STOMP CONNECT frame.
|
||||||
|
*/
|
||||||
|
StompHeaderAccessor getConnectHeaders();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -186,7 +186,7 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||||
return handleShuttingDownConnectFailure(handler);
|
return handleShuttingDownConnectFailure(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Void> connectMono = this.tcpClient
|
Mono<Void> connectMono = extendTcpClient(this.tcpClient, handler)
|
||||||
.handle(new ReactorNettyHandler(handler))
|
.handle(new ReactorNettyHandler(handler))
|
||||||
.connect()
|
.connect()
|
||||||
.doOnError(handler::afterConnectFailure)
|
.doOnError(handler::afterConnectFailure)
|
||||||
|
|
@ -195,6 +195,19 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||||
return new MonoToListenableFutureAdapter<>(connectMono);
|
return new MonoToListenableFutureAdapter<>(connectMono);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an opportunity to initialize the {@link TcpClient} for the given
|
||||||
|
* {@link TcpConnectionHandler} which may implement sub-interfaces such as
|
||||||
|
* {@link org.springframework.messaging.simp.stomp.StompTcpConnectionHandler}
|
||||||
|
* that expose further information.
|
||||||
|
* @param tcpClient the candidate TcpClient
|
||||||
|
* @param handler the handler for the TCP connection
|
||||||
|
* @return the same handler or an updated instance
|
||||||
|
*/
|
||||||
|
protected TcpClient extendTcpClient(TcpClient tcpClient, TcpConnectionHandler<P> handler) {
|
||||||
|
return tcpClient;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Void> connect(TcpConnectionHandler<P> handler, ReconnectStrategy strategy) {
|
public ListenableFuture<Void> connect(TcpConnectionHandler<P> handler, ReconnectStrategy strategy) {
|
||||||
Assert.notNull(handler, "TcpConnectionHandler is required");
|
Assert.notNull(handler, "TcpConnectionHandler is required");
|
||||||
|
|
@ -207,7 +220,7 @@ public class ReactorNettyTcpClient<P> implements TcpOperations<P> {
|
||||||
// Report first connect to the ListenableFuture
|
// Report first connect to the ListenableFuture
|
||||||
CompletableFuture<Void> connectFuture = new CompletableFuture<>();
|
CompletableFuture<Void> connectFuture = new CompletableFuture<>();
|
||||||
|
|
||||||
this.tcpClient
|
extendTcpClient(this.tcpClient, handler)
|
||||||
.handle(new ReactorNettyHandler(handler))
|
.handle(new ReactorNettyHandler(handler))
|
||||||
.connect()
|
.connect()
|
||||||
.doOnNext(conn -> connectFuture.complete(null))
|
.doOnNext(conn -> connectFuture.complete(null))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue