Как получить Spring RabbitMQ для создания новой очереди?

В моем (ограниченном) опыте с rabbit-mq, ​​если вы создаете нового слушателя для очереди, которая еще не существует, очередь создается автоматически. Я пытаюсь использовать проект Spring AMQP с rabbit-mq, ​​чтобы настроить прослушиватель, и вместо этого получаю ошибку. Это мой xml config:

<rabbit:connection-factory id="rabbitConnectionFactory" host="172.16.45.1" username="test" password="password" />

<rabbit:listener-container connection-factory="rabbitConnectionFactory"  >
    <rabbit:listener ref="testQueueListener" queue-names="test" />
</rabbit:listener-container>

<bean id="testQueueListener" class="com.levelsbeyond.rabbit.TestQueueListener"> 
</bean>

Я получаю это в своих журналах RabbitMq:

=ERROR REPORT==== 3-May-2013::23:17:24 ===
connection <0.1652.0>, channel 1 - soft error:
{amqp_error,not_found,"no queue 'test' in vhost '/'",'queue.declare'}

И аналогичная ошибка AMQP:

2013-05-03 23:17:24,059 ERROR [org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer] (SimpleAsyncTaskExecutor-1) - Consumer received fatal exception on startup
org.springframework.amqp.rabbit.listener.FatalListenerStartupException: Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.

Кажется, из трассировки стека создается очередь в "пассивном" режиме. Может ли кто-нибудь указать, как я буду создавать очередь, не используя пассивный режим, чтобы я не видел эту ошибку? Или я пропущу что-то еще?

Ответ 1

Что, по-видимому, решило мою проблему, это добавить администратора. Вот мой xml:

<rabbit:listener-container connection-factory="rabbitConnectionFactory"  >
    <rabbit:listener ref="orderQueueListener" queues="test.order" />
</rabbit:listener-container>

<rabbit:queue name="test.order"></rabbit:queue>

<rabbit:admin id="amqpAdmin" connection-factory="rabbitConnectionFactory"/>

<bean id="orderQueueListener" class="com.levelsbeyond.rabbit.OrderQueueListener">   
</bean>

Ответ 2

Пожилой поток, но это все еще очень хорошо проявляется в Google, поэтому здесь появилась более новая информация:

2015-11-23

Так как Spring 4.2.x с Spring -Messaging и Spring -Amqp 1.4.5.RELEASE и Spring -Rabbit 1.4.5.RELEASE, объявление обменов, очередей и привязок стало очень простым с помощью класса @Configuration некоторые аннотации:

@EnableRabbit
@Configuration
@PropertySources({
    @PropertySource("classpath:rabbitMq.properties")
})
public class RabbitMqConfig {    
    private static final Logger logger = LoggerFactory.getLogger(RabbitMqConfig.class);

    @Value("${rabbitmq.host}")
    private String host;

    @Value("${rabbitmq.port:5672}")
    private int port;

    @Value("${rabbitmq.username}")
    private String username;

    @Value("${rabbitmq.password}")
    private String password;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host, port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);

        logger.info("Creating connection factory with: " + username + "@" + host + ":" + port);

        return connectionFactory;
    }

    /**
     * Required for executing adminstration functions against an AMQP Broker
     */
    @Bean
    public AmqpAdmin amqpAdmin() {
        return new RabbitAdmin(connectionFactory());
    }

    /**
     * This queue will be declared. This means it will be created if it does not exist. Once declared, you can do something
     * like the following:
     * 
     * @RabbitListener(queues = "#{@myDurableQueue}")
     * @Transactional
     * public void handleMyDurableQueueMessage(CustomDurableDto myMessage) {
     *    // Anything you want! This can also return a non-void which will queue it back in to the queue attached to @RabbitListener
     * }
     */
    @Bean
    public Queue myDurableQueue() {
        // This queue has the following properties:
        // name: my_durable
        // durable: true
        // exclusive: false
        // auto_delete: false
        return new Queue("my_durable", true, false, false);
    }

    /**
     * The following is a complete declaration of an exchange, a queue and a exchange-queue binding
     */
    @Bean
    public TopicExchange emailExchange() {
        return new TopicExchange("email", true, false);
    }

    @Bean
    public Queue inboundEmailQueue() {
        return new Queue("email_inbound", true, false, false);
    }

    @Bean
    public Binding inboundEmailExchangeBinding() {
        // Important part is the routing key -- this is just an example
        return BindingBuilder.bind(inboundEmailQueue()).to(emailExchange()).with("from.*");
    }
}

Некоторые источники и документация, которые помогут:

Примечание. Похоже, я пропустил версию - начиная с Spring AMQP 1.5, все становится еще проще, так как вы можете объявить полное связывание прямо у слушателя

Ответ 3

Вы можете добавить это после своего тега подключения, но перед слушателем:

<rabbit:queue name="test" auto-delete="true" durable="false" passive="false" />

К сожалению, согласно схеме XSD пассивный атрибут (указанный выше) недействителен. Однако в каждой реализации queue_declare, которую я видел, пассивный был действительным параметром queue_declare. Мне интересно узнать, будет ли это работать, или планируют ли они в будущем поддерживать его.

Вот полный список вариантов объявления очереди: http://www.rabbitmq.com/amqp-0-9-1-reference.html#class.queue

И вот полный XSD для кроличьей схемы spring (с включенными комментариями): http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd

Ответ 4

Начиная с Spring Boot 2.1.6 и Spring AMQP 2.1.7, вы можете создавать очереди во время запуска, если они не существуют с этим:

@Component
public class QueueConfig {

    private AmqpAdmin amqpAdmin;

    public QueueConfig(AmqpAdmin amqpAdmin) {
        this.amqpAdmin = amqpAdmin;
    }

    @PostConstruct
    public void createQueues() {
        amqpAdmin.declareQueue(new Queue("queue_one", true));
        amqpAdmin.declareQueue(new Queue("queue_two", true));
    }
}