我有一个Java富客户端应用程序,它在启动时在远程HornetQ JMS主题上注册持久订阅。 但是,如果服务器重新启动,则连接将丢失,并且只能通过重新启动客户端应用程序来恢复。 这会导致混乱的情况,即没有收到JMS消息,并且在客户端重新启动后,会立即收到大量消息。
恢复连接的简单解决方案是运行计时器以定期检查连接是否仍然有效并尝试重新连接。 或者,服务器可以向客户端发送心跳并尝试重新连接,如果在一段时间后没有收到心跳(如此answer中所述)。
但两者似乎都是这个问题的笨拙方法,因此我想知道是否有更好的解决方案可以找出连接不再可用?
答案 0 :(得分:0)
要获得断开连接的通知,您必须在开始连接之前在ExceptionListener
上注册TopicConnection
。
private void subscribe() throws JMSException {
// get context / create connection and session / etc.
TopicConnection connection = ...
connection.setExceptionListener(this::handleExceptions);
connection.start();
}
在ExceptionListener
中,您可以查看收到的JMSException
的错误代码。 (错误代码是特定于供应商的)
在HornetQ的情况下,在连接丢失后收到错误代码DISCONNECT
。
private static final String HORNETQ_DISCONNECT_ERROR_CODE = "DISCONNECT";
private void handleExceptions(final JMSException jmsException) {
final String errorCode = jmsException.getErrorCode();
if (HORNETQ_DISCONNECT_ERROR_CODE.equals(errorCode)) {
tryConnect();
}
}
然后你可以启动一个自我取消的Timer,它会尝试每隔x秒重新连接一次,直到成功为止。
private static final long SUBSCRIBE_RETRY_TIME_OUT_IN_MILLIS = 60000;
private void tryConnect() {
final Timer timer = new Timer("JMS-Topic-Reconnection-Timer", true);
final TimerTask timerTask = new TimerTask() {
@Override
public void run() {
try {
subscribe();
// cancel the timer, after the subscription succeeds
timer.cancel();
}
catch (final Exception e) {
logger.info("reconnect to jms topic failed: {}", e.getMessage());
}
}
};
timer.schedule(timerTask, SUBSCRIBE_RETRY_TIME_OUT_IN_MILLIS, SUBSCRIBE_RETRY_TIME_OUT_IN_MILLIS);
}