不终止的 JMS 客户端

JMS client that doesn't terminate

我们有一个 JMS 客户端需要闲置直到它收到一条消息。当它收到一条消息时,它会执行一些功能,然后返回到空闲状态。我的问题是,确保客户熬夜 运行ning 的最佳方法是什么?让 JMS 客户端软件处理这个是好的做法,还是我们需要 运行 软件作为主机上的服务(and/or 做其他事情)?我们目前依赖于 JMS 客户端软件,因为它似乎通过打开的连接保持线程活动,但我不确定这是否是最佳实践。我们使用 ActiveMQ 作为我们的消息代理和客户端软件。

编辑:添加了代码示例

下面是客户端如何使用 JMS 客户端连接保持在线的示例:

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JmsTestWithoutClose implements MessageListener {

    private final Connection connection;
    private final Session session;
    private final MessageConsumer consumer;

    public static void main(String[] args) throws JMSException {
        System.out.println("Starting...");
        JmsTestWithoutClose test = new JmsTestWithoutClose("<username>", "<password>", "tcp://<host>:<port>");
        // if you uncomment the line below, the program will terminate
        // if you keep it commented, the program will NOT terminate
        // test.close();
        System.out.println("Last line of main method...");
    }

    public JmsTestWithoutClose(String username, String password, String url) throws JMSException {
        // create connection and session
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(username, password, url);
        this.connection = factory.createConnection();
        connection.start();
        this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Destination destination = session.createTopic("Topic_Name");
        consumer = session.createConsumer(destination);
        consumer.setMessageListener(this);
    }

    public void close() throws JMSException {
        session.close();
        connection.close();
    }

    @Override
    public void onMessage(Message message) {
        // process the message
    }

}

当前的客户端实现是否满足您的要求?如果是这样,我不会改变它。如果当前的客户端实现 满足您的要求,那么我会更改它。仅仅为了遵守 "best practice" 而更改正常运行并满足您的需求(并且没有明确可预见的问题)的软件几乎肯定不是最好的资源投资。

最终,应用程序的行为取决于应用程序本身。我看不出 运行 应用程序作为服务或在应用程序外部做任何其他事情实际上会迫使它保持正常运行并 运行 正确地同时它 listens/waits 用于消息。如果应用程序被编程,例如,使用 JMS API 并创建一个 MessageListener(即 class 负责异步接收消息)然后退出而不实际等待消息,这将是一个错误。 运行 将这样的应用程序作为服务,以便 OS 在错误退出后继续重新启动它并不是一个好的解决方案。

最好的做法是编写正确的客户端。用一些外部机制支撑它是不好的做法。

您提供的示例代码写得不好,有一些明显的问题:

  1. ConnectionSession 对象超出范围,这意味着它们永远无法正确关闭。最终这些对象将被 JVM 垃圾收集。这是资源管理不当。
  2. 应用程序没有完全终止的唯一原因是 ActiveMQ 5.x 客户端的实现方式(即打开的连接阻止 JVM 进程终止)。此实现细节不是 JMS API 提供的 public 合同的一部分,因此不应依赖。如果您要使用不同的 JMS 客户端实现,例如ActiveMQ Artemis 核心 JMS 客户端,一旦 main() 退出,应用程序 完全终止。

要解决此问题,您的 main() 方法应在创建 JmsTestWithoutClose 实例后等待。在 Java:

中有很多方法可以做到这一点
  1. 使用带有 Thread.sleep()while 循环,其中可以根据需要修改循环的条件以允许应用程序退出。
  2. 使用专为线程协调设计的对象,如 java.util.concurrent.CountDownLatch。例如,使用 CountDownLatch main() 方法可以调用 await() 并且当应用程序完成处理消息时 MessageListener 实现可以调用 countDown()
  3. 使用 while 循环从控制台读取输入,只有在输入特殊字符串时才继续(例如 exit)。

无论如何,应用程序关闭它创建的所有资源(例如会话、连接等)很重要。