22

在我对 rabbit-mq 的(有限)经验中,如果您为尚不存在的队列创建新的侦听器,则会自动创建队列。我正在尝试将 Spring AMQP 项目与 rabbit-mq 一起使用来设置侦听器,但我得到了一个错误。这是我的 xml 配置:

<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.

从堆栈跟踪中可以看出,队列是在“被动”模式下创建的——谁能指出我将如何不使用被动模式创建队列,所以我看不到这个错误?还是我错过了其他东西?

4

5 回答 5

25

较旧的线程,但这仍然在 Google 上显示得相当高,所以这里有一些更新的信息:

2015-11-23

从带有 Spring-Messaging 和Spring-Amqp 1.4.5.RELEASESpring-Rabbit 1.4.5.RELEASE的Spring 4.2.x开始,通过 @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.*");
    }
}

一些可以提供帮助的资源和文档:

  1. 弹簧注解
  2. 为队列/绑定支持声明/配置 RabbitMQ
  3. 直接交换绑定(当路由密钥无关紧要时)

注意:看起来我错过了一个版本——从Spring AMQP 1.5开始,事情变得更加容易,因为您可以在侦听器处声明完整的绑定!

于 2015-11-23T19:10:23.433 回答
11

似乎可以解决我的问题的是添加管理员。这是我的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>
于 2013-05-04T17:32:55.640 回答
7

Spring Boot 2.1.6Spring 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));
    }
}
于 2019-07-03T17:15:14.867 回答
4

你可以在你的连接标签之后,但在监听器之前添加这个:

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

不幸的是,根据 XSD 模式,被动属性(上面列出的)无效。但是,在我见过的每个 queue_declare 实现中,passive 都是一个有效的 queue_declare 参数。我很好奇这是否可行,或者他们是否计划在未来支持它。

以下是队列声明选项的完整列表: http ://www.rabbitmq.com/amqp-0-9-1-reference.html#class.queue

这里是 spring rabbit 模式的完整 XSD(包括注释): http ://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd

于 2013-05-04T06:03:01.523 回答
0

如果之前您使用的是 <1.6 的 spring-rabbit 版本,而现在您升级到该版本或更高版本并且您发现您的队列没有被创建,那么您很可能缺少 RabbitAdmin bean。以前的版本在上下文中似乎不需要,但 1.6 及之后的版本

于 2022-01-12T11:08:29.487 回答