如何知道与 JMS 主题的连接何时丢失?

How to know when connection to a JMS Topic is lost?

我有一个 Java 富客户端应用程序,它在启动时在远程 HornetQ JMS 主题上注册持久订阅。 但是,如果服务器重新启动,连接就会丢失,只能通过重新启动客户端应用程序来恢复。 这会导致混乱的情况,即未收到 JMS 消息,并且在客户端重新启动后立即收到大量消息。

恢复连接的一个简单解决方案是 运行 一个定时器来定期检查连接是否仍然有效,否则尝试重新连接。 或者,服务器可以向客户端发送心跳,如果在一段时间后没有收到心跳(如本 answer 中所述),则尝试重新连接。

但是对于这个问题,这两种方法似乎都很笨拙,因此我想知道是否有更好的解决方案来发现连接不再可用?

要在断开连接时收到通知,您必须在开始连接之前在 TopicConnection 上注册一个 ExceptionListener

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();
    }
}

然后你可以启动一个自取消定时器,每隔 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);
}