不终止的JMS客户端

时间:2018-11-28 02:06:42

标签: java jms activemq

我们有一个JMS客户端,它需要闲置直到收到消息。收到消息后,它将执行一些功能,然后返回到空闲状态。我的问题是,确保客户端正常运行的最佳方法是什么?是让JMS客户端软件处理此问题的好习惯,还是我们需要在主机上将软件作为服务运行(和/或执行其他操作)?当前,我们依靠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
    }

}

1 个答案:

答案 0 :(得分:1)

当前的客户端实现是否满足您的要求?如果是这样,我不会改变它。如果当前的客户端实现不能满足您的要求,那么我将对其进行更改。仅仅为了遵循“最佳实践”而更改可以正常工作并满足您的需求(并且没有明显可预见的问题)的软件几乎肯定不是最佳的资源投资。

最终,应用程序的行为取决于应用程序本身。我看不到将应用程序作为服务运行或在应用程序外部执行任何其他操作实际上如何迫使它在侦听/等待消息时保持正常运行。如果对应用程序进行了编程,例如使用JMS API并创建MessageListener(即负责异步接收消息的类),然后退出而不实际等待消息,则将是一个错误。将这样的应用程序作为服务运行,以使操作系统在错误退出后继续重新启动它不是一个好的解决方案。

拥有适当的书面客户是最佳实践。用某种外部机制来支持它是一个坏习惯。

您提供的示例代码编写得很差,并且存在一些明显的问题:

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

要解决此问题,您的main()方法应在创建JmsTestWithoutClose实例后等待。用Java有很多方法可以做到这一点:

  1. while循环与Thread.sleep()一起使用,可以根据需要修改循环的条件以允许应用程序退出。
  2. 使用专门用于线程协调的对象,例如java.util.concurrent.CountDownLatch。使用CountDownLatch的{​​{1}}方法可以调用main(),并且当应用程序完成消息处理后,await()实现可以例如调用MessageListener
  3. 使用countDown()循环从控制台读取输入,并且仅在输入特殊字符串(例如 exit )时才继续。

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