java - Spring Integration DSL Tcp:如何防止在客户端拒绝连接的过多日志记录
问题描述
我使客户端和服务器都能够等待彼此连接,因此它们可以以任何顺序独立启动。这里描述的解决方案正是这样做的,开箱即用,但客户端不断将大量堆栈跟踪打印到我们的日志中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 反应是再次打印 :) 那是我最初没有注意到的,异常被记录了两次。第二个日志可以通过使用自定义错误消息处理程序来防止,但不是第一个。
调用默认 Java的TcpNetClientConnectionFactory.createSocket()
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
。
HeartbeatClientConfig(仅相关位):
@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 上提供了完整的项目源代码,这里是相关的 commit。
推荐阅读
- python - 将数据更新到多个 Table -> MultipleObjectsReturned at /client/update-client
- python - 如何在python中使用url抓取特定html表(使用类)的数据?
- python - 如何将文件创建/修改文件复制到新文件
- python - 如何在内部类中调用上层类的变量?
- c++ - 代码崩溃。虽然将 c char 数组传递给使用 std::string 捕获的函数
- flutter - 在“状态”中添加“小部件”作为字段时出错
” 飘飘然的课堂 - mysql - 编写一个可以使用 2 个数据库的应用程序?
- android - 在 Android Studio 中构建应用程序时出现 Gradle 错误
- c# - zkemKeeper 无法在 c# 桌面应用程序中触发事件
- .net - 如何获取对象属性及其值的真实列表