Клиент JMS, который не завершается - PullRequest
0 голосов
/ 28 ноября 2018

У нас есть клиент 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 голосов
/ 28 ноября 2018

Соответствует ли текущая реализация клиента вашим требованиям?Если это так, я бы не стал его менять.Если текущая реализация клиента не удовлетворяет вашим требованиям, я бы изменил ее.Изменение программного обеспечения, которое работает без проблем и отвечает вашим потребностям (и без явных проблем), просто для того, чтобы придерживаться «наилучшей практики», почти наверняка не лучшая инвестиция ресурсов.

В конечном итоге поведениеПриложение зависит от самого приложения.Я не понимаю, как запуск приложения в качестве службы или выполнение каких-либо других действий, не связанных с приложением, фактически вынуждает его работать и работать должным образом, пока он слушает / ждет сообщений.Было бы ошибкой, если бы приложение было запрограммировано, например, использовать API-интерфейс JMS и создать MessageListener (то есть класс, отвечающий за асинхронный прием сообщений), а затем завершить работу, фактически не ожидая сообщений.Запуск такого приложения в качестве службы, чтобы ОС продолжала перезапускать его после неправильного выхода, не будет хорошим решением.

Лучше всего иметь правильно написанный клиент.Поддерживать его с помощью какого-либо внешнего механизма - плохая практика.

Предоставленный вами пример кода плохо написан и имеет некоторые явные проблемы:

  1. Падение объектов Connection и Sessionвне области, что означает, что они никогда не могут быть должным образом закрыты.В конечном итоге эти объекты будут собраны мусором JVM.Это неправильное управление ресурсами.
  2. Единственная причина, по которой приложение не завершает работу полностью, связана с тем, как реализован клиент ActiveMQ 5.x (т. Е. Открытое соединение блокирует завершение процесса JVM).Эта деталь реализации не является частью публичного договора, предоставляемого JMS API, и поэтому на нее не следует полагаться.Если бы вы использовали другую реализацию клиента JMS, например, клиент JMS ядра ActiveMQ Artemis, приложение будет полностью завершаться, как только выйдет main().

Чтобы исправить это, ваш метод main() должен ждать после создания экземпляра JmsTestWithoutClose.Есть много способов сделать это в Java:

  1. Используйте цикл while с Thread.sleep(), где условие цикла может быть изменено по мере необходимости, чтобы позволить приложению выйти.
  2. Используйте объект, специально разработанный для координации потоков, такой как java.util.concurrent.CountDownLatch.При использовании CountDownLatch метод main() может вызывать await(), а когда приложение завершает обработку сообщений, например, реализация MessageListener может вызывать countDown()
  3. Использование циклического чтения whileввод с консоли и продолжается только при вводе специальной строки (например, exit ).

В любом случае важно, чтобы приложение закрыло все созданные им ресурсы (например, сеансы, соединения и т. д.).

...