我让客户端和服务器都能够等待彼此连接,因此可以按任何顺序独立启动它们。解决方案described here正是如此,开箱即用,但是客户端继续使用java.net.ConnectException: Connection refused: connect
将大量堆栈跟踪打印到我们的日志中,然后是46行长堆栈跟踪,直到服务器启动并且连接发生。这不太理想。
我的问题是:如何应用我的自定义逻辑来微调记录和何时记录。
到目前为止,我发现日志是由org.springframework.integration.handler.LoggingHandler
打印的。这可以作为一种错误通道,并始终在那里调度错误。我无法找到这一套的位置,所以我可以用我自己的实现替换它。我设法配置了我自己的默认错误通道,但该通道是与预配置的LoggingHandler通道一起添加的,而不是替换它。
另一种方法可能是在发送第一条消息时设置更长的超时。我也在努力解决这个问题。我试图在outboundGateway
上设置它,就像.handle(Tcp.outboundGateway(clientConnectionFactory).remoteTimeout(1_000_000L))
但是没有任何效果。
好的,解决了。
问题不是真的在LoggingHandler
或任何错误通道,但如果服务器没有立即准备好org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.createSocket()
抛出异常,然后TcpOutboundGateway
以旧式方式记录此异常;然后才将错误发送到errorChannel
,在那里它可以作出反应;并且默认的SI反应是再次打印:)这是我最初没有注意到的,异常被记录两次。可以使用自定义错误消息处理程序而不是第一个日志来阻止第二个日志。
TcpNetClientConnectionFactory.createSocket()
调用默认的Java的createSocket(),并且没有设置超时的选项。如果收件人未准备好,则方法调用几乎立即失败。请参阅JDK的增强请求JDK-4414843。
可能的解决方案是覆盖TcpNetClientConnectionFactory.createSocket()
以重复连接到服务器的尝试,直到它成功。
WaitingTcpNetClientConnectionFactory
public class WaitingTcpNetClientConnectionFactory extends TcpNetClientConnectionFactory {
private final SocketConnectionListener socketConnectionListener;
private final int waitBetweenAttemptsInMs;
private final Logger log = LogManager.getLogger();
public WaitingTcpNetClientConnectionFactory(
String host, int port,
int waitBetweenAttemptsInMs,
SocketConnectionListener socketConnectionListener) {
super(host, port);
this.waitBetweenAttemptsInMs = waitBetweenAttemptsInMs;
this.socketConnectionListener = socketConnectionListener;
}
@Override
protected Socket createSocket(String host, int port) throws IOException {
Socket socket = null;
while (socket == null) {
try {
socket = super.createSocket(host, port);
socketConnectionListener.onConnectionOpen();
} catch (ConnectException ce) {
socketConnectionListener.onConnectionFailure();
log.warn("server " + host + ":" + port + " is not ready yet ..waiting");
try {
Thread.sleep(waitBetweenAttemptsInMs);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IOException("interrupted while wating between connection attempts", ie);
}
}
}
return socket;
}
}
作为额外奖励,我还设置成功或失败,提供SocketConnectionListener
,我自己的自定义界面,因此应用程序的其他部分可以与它同步;例如,等待流式传输,直到服务器/对等节点准备就绪。
使用WaitingTcpNetClientConnectionFactory
与TcpNetClientConnectionFactory
相同。
Heartbeat ClientConfig(仅相关位):
@Bean
public TcpNetClientConnectionFactory clientConnectionFactory(
ConnectionStatus connectionStatus) {
TcpNetClientConnectionFactory connectionFactory = new WaitingTcpNetClientConnectionFactory("localhost", 7777, 2000, connectionStatus);
connectionFactory.setSerializer(new ByteArrayLengthHeaderSerializer());
connectionFactory.setDeserializer(new ByteArrayLengthHeaderSerializer());
return connectionFactory;
}
现在它只是打印:
INFO [ main] o.b.e.d.s.h.client.HeartbeatClientRun : Started HeartbeatClientRun in 1.042 seconds (JVM running for 1.44)
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
WARN [ask-scheduler-1] h.c.WaitingTcpNetClientConnectionFactory : server localhost:7777 is not ready yet ..waiting
像往常一样,我的git,here is the relevant commit上有完整的项目资源。