Как я могу полностью закрыть RabbitTemplate в Spring Rabbit?

Я написал скрипт, который использует Spring Rabbit для помещения ряда сообщений в очередь Rabbit, используя RabbitTemplate.convertAndSend, а затем завершает работу. Однако соединение Rabbit, по-видимому, поддерживает работу приложения даже после того, как сообщение поставлено в очередь. Я не нашел способа четко указать серверу Rabbit остановиться после того, как сообщения поставлены в очередь.

Лучшее решение, которое я смог придумать, — изменить мои вызовы convertAndSend на convertSendAndReceive, чтобы я знал, что сообщение успешно помещено в очередь, а затем выйдите, используя System.exit(0). Я переключился на convertSendAndReceive, так как оказалось, что convertAndSend происходит в фоновом потоке или что-то в этом роде, поскольку, если я выполню System.exit(0) после выполнения ряда этих вызовов, только первый из них будет успешным.

Обратите внимание, что простое создание RabbitTemplate не приводит к такому поведению; использование его с помощью одного из методов «отправить».

Следующий код иллюстрирует проблему.

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

import static issues.RabbitSettings.*; //Static fields containing my test Rabbit connection info

public class RabbitTemplateShutdownIssue {
    public static void main(String[] args) {
        RabbitTemplate rabbitTemplate = createRabbitTemplate();
        rabbitTemplate.convertAndSend(ROUTING_KEY, "Test"); // Or convertSendAndReceive
        // The app never exits
    }

    private static RabbitTemplate createRabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(getConnectionFactory());
        rabbitTemplate.setExchange(EXCHANGE);
        rabbitTemplate.setMandatory(true);
        return rabbitTemplate;
    }

    private static ConnectionFactory getConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(HOSTNAME);
        connectionFactory.setPublisherConfirms(true);
        connectionFactory.setVirtualHost(VIRTUAL_HOST);
        connectionFactory.setUsername(USERNAME);
        connectionFactory.setPassword(PASSWORD);
        return connectionFactory;
    }
}

Есть ли способ приказать клиенту Rabbit закрыться, в идеале, после того, как все сообщения будут поставлены в очередь?


person M. Justin    schedule 19.08.2016    source источник
comment
Закрыть Spring. Вы используете Spring Beans с ApplicationContext - это PITA, с которым нужно иметь дело, так как вам нужно закрыть все, чтобы не получать исключений. Простое решение? Делай это правильно!   -  person Boris the Spider    schedule 19.08.2016
comment
@BoristheSpider В моем примере нет запущенного контейнера Spring, поэтому Spring не нужно останавливать.   -  person M. Justin    schedule 19.08.2016
comment
Это точно моя точка зрения. (Теперь я вижу, я имел в виду без, а не с)   -  person Boris the Spider    schedule 19.08.2016
comment
@BoristheSpider Похоже, вы отредактировали свой комментарий после того, как я начал писать свой ответ на него, поскольку комментарий, который я видел и на который отвечал, был просто «Выключите Spring». Ваш ответ имеет гораздо больше смысла с этим дополнительным контекстом.   -  person M. Justin    schedule 20.08.2016


Ответы (1)


Если вы разрешите Spring управлять bean-компонентами, вы сможете close() контекст приложения, когда закончите.

Как вы сейчас настроили (без контекста Spring), вы можете вызвать destroy() на фабрике соединений, и все закроется.

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

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

person Gary Russell    schedule 19.08.2016
comment
Справедливости ради следует отметить, что фактический сценарий представляет собой сценарий Groovy, который выполняет некоторую базовую постановку сообщений в очередь и затем завершает работу, а не полноценное производственное приложение. Я просто написал свой пример со статическими методами, так как казалось, что использование Java будет более понятным для аудитории Spring, чем Groovy. - person M. Justin; 19.08.2016
comment
Справедливо. Вам нужен обратный вызов подтверждения в шаблоне, чтобы получить подтверждение того, что кролик получил посылку. - person Gary Russell; 19.08.2016
comment
Метод destroy() на фабрике соединений был именно тем, что я искал. - person M. Justin; 19.08.2016