此版本仍在开发中,目前尚不稳定。如需最新稳定版本,请使用 Spring AMQP 4.0.2spring-doc.cadn.net.cn

检测空闲异步消费者

虽然高效,但异步消费者的一个问题在于检测其是否处于空闲状态——用户可能希望在一段时间内没有消息到达时执行某些操作。spring-doc.cadn.net.cn

从版本 1.6 开始,现在可以配置监听器容器在一段时间内没有消息传递时发布一个 ListenerContainerIdleEvent。当容器处于空闲状态时,每 idleEventInterval 毫秒发布一次事件。spring-doc.cadn.net.cn

要配置此功能,请在容器上设置 idleEventInterval。以下示例展示了如何在 XML 和 Java 中实现(适用于 SimpleMessageListenerContainerSimpleRabbitListenerContainerFactory):spring-doc.cadn.net.cn

<rabbit:listener-container connection-factory="connectionFactory"
        ...
        idle-event-interval="60000"
        ...
        >
    <rabbit:listener id="container1" queue-names="foo" ref="myListener" method="handle" />
</rabbit:listener-container>
@Bean
public SimpleMessageListenerContainer(ConnectionFactory connectionFactory) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
    ...
    container.setIdleEventInterval(60000L);
    ...
    return container;
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(rabbitConnectionFactory());
    factory.setIdleEventInterval(60000L);
    ...
    return factory;
}

在这些情况下,每当容器空闲时,每分钟都会发布一次事件。spring-doc.cadn.net.cn

事件消费

您可以通过实现 ApplicationListener 来捕获空闲事件——既可以是通用监听器,也可以是仅接收此特定事件的限定监听器。您还可以使用 @EventListener,该功能在 Spring Framework 4.2 中引入。spring-doc.cadn.net.cn

以下示例将 @RabbitListener@EventListener 合并为一个类。你需要理解的是,应用监听器会接收到所有容器的事件,因此如果你希望根据哪个容器处于空闲状态而采取特定操作,则可能需要检查监听器 ID。你还可以使用 @EventListener condition 来实现此目的。spring-doc.cadn.net.cn

事件具有四个属性:spring-doc.cadn.net.cn

以下示例展示了如何同时使用 @RabbitListener@EventListener 注解来创建监听器:spring-doc.cadn.net.cn

public class Listener {

    @RabbitListener(id="someId", queues="#{queue.name}")
    public String listen(String foo) {
        return foo.toUpperCase();
    }

    @EventListener(condition = "event.listenerId == 'someId'")
    public void onApplicationEvent(ListenerContainerIdleEvent event) {
        ...
    }

}
事件监听器会看到所有容器的事件。因此,在前面的例子中,我们根据监听器 ID 来缩小接收到的事件范围。
如果您希望使用空闲事件来停止监听器容器,则不应在调用监听器的线程上调用 container.stop()。这样做总是会导致延迟并产生不必要的日志消息。相反,您应将该事件转交给另一个线程,由该线程负责停止容器。