以编程方式启用和禁用 Spring 中的某些 @RabbitListener?

Programmatically enable and disable certain @RabbitListener's in Spring?

我有一个发布事件 E1 的 class A。在用 @RabbitListener 注释的同一应用程序中,E1 由 class B 使用。 B 做一些事情然后发布事件 E2 被 C 等消费(形成一个流程链)。

我想做的是两件事:

  1. 我想在集成测试中测试 A,但在这样做时我想禁用 RabbitListener's 以便不执行作为 E1 发布结果的整个过程。我只想断言 A 做了它应该做的并发布了 E1。我设法通过设置 spring.rabbitmq.listener.auto-startup=false.
  2. 来解决这个问题
  3. 我还想通过将 E1 发布到 RabbitMQ 来在集成测试中测试 B,这样我就可以确信我已经正确配置了 B 的 RabbitListerner。但是我再次不希望 C 被称为 E2 被发布的副作用。

我知道我可能可以使用模拟来做到这一点,但最好我想测试真实的交易并使用实际的组件(包括将消息发送到实际的 RabbitMQ 实例,在我的例子中是 运行在 Docker).

我可以在 Spring 引导中以一种很好的方式实现这一点吗?还是建议使用 @RabbitListenerTest 并确实使用模拟?

@RabbitListenerid 属性:

/**
 * The unique identifier of the container managing for this endpoint.
 * <p>If none is specified an auto-generated one is provided.
 * @return the {@code id} for the container managing for this endpoint.
 * @see org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry#getListenerContainer(String)
 */
String id() default "";

还有 RabbitListenerEndpointRegistry#getListenerContainer(String) returns MessageListenerContainer 并且您已经可以控制 start()/stop() 个人 @RabbitListener 处理程序。

follow-up 的想法是拥有某种抽象 BaseAmqpIntegrationTest,它执行以下操作:

public abstract class BaseAmqpIntegrationTest {

    @Autowired
    protected RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;

    @BeforeEach
    protected void setUpBeforeEach() {
        rabbitListenerEndpointRegistry.getListenerContainers()
                                      .forEach(Lifecycle::stop);

        getRequiredListenersToStart().forEach(listener -> rabbitListenerEndpointRegistry.getListenerContainer(listener)
                                                                                        .start());
    }

    protected abstract List<String> getRequiredListenersToStart();

}

这使其可重用并确保所有 @RabbitListener 都“默认”禁用,并要求每个测试显式启用它测试的侦听器。然后测试子 类 可以简单地覆盖 getRequiredListenersToStart() 以提供他们需要的 @RabbitListeners 的 ID。

PS:清理当然也可以:

public abstract class BaseAmqpIntegrationTest {

    @AfterEach
    protected void cleanUpAfterEach() {
        rabbitListenerEndpointRegistry.getListenerContainers()
                                      .forEach(Lifecycle::stop);
    }

}

或更多 fine-grained:

public abstract class BaseAmqpIntegrationTest {

    @AfterEach
    protected void cleanUpAfterEach() {
        getRequiredListenersToStart().forEach(listener -> rabbitListenerEndpointRegistry.getListenerContainer(listener)
                                                                                        .stop());
    }

}