[英]Programmatically enable and disable certain @RabbitListener's in Spring?
I have a class A that publishes event E1.我有一个发布事件 E1 的 A 类。 E1 is consumed by class B in the same application that is annotated with
@RabbitListener
. E1 由 B 类在使用
@RabbitListener
注释的同一应用程序中使用。 B does some things and then publishes event E2 that is consumed by C etc etc (forming a process chain). B 做一些事情,然后发布由 C 等消费的事件 E2(形成一个流程链)。
What I want to do is two things:我想做的是两件事:
RabbitListener's
so that the entire process that is the result of E1 being published is not executed.RabbitListener's
以便不执行作为 E1 发布结果的整个过程。 I only want to assert that A does what it's supposed to and publishes E1.spring.rabbitmq.listener.auto-startup=false
.spring.rabbitmq.listener.auto-startup=false
设法适应了这一点。RabbitListerner
correctly.RabbitListerner
。 But again I don't want C to be called as a side-effect of E2 being published. I know I can probably do this using mocks but preferably I'd like to test the real deal and using the actual components (including sending the message to an actual RabbitMQ instance that in my case is running in Docker).我知道我可能可以使用模拟来做到这一点,但最好我想测试真正的交易并使用实际组件(包括将消息发送到在我的情况下在 Docker 中运行的实际 RabbitMQ 实例)。
Can I achieve this in a nice way in Spring Boot?我可以在 Spring Boot 中以一种很好的方式实现这一目标吗? Or is it perhaps recommended to use
@RabbitListenerTest
and indeed use mocks?或者是否建议使用
@RabbitListenerTest
并确实使用@RabbitListenerTest
?
The @RabbitListener
has id
property: @RabbitListener
有id
属性:
/**
* 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 "";
And that RabbitListenerEndpointRegistry#getListenerContainer(String)
returns MessageListenerContainer
and there you already can control start()/stop()
of individual @RabbitListener
handler.并且
RabbitListenerEndpointRegistry#getListenerContainer(String)
返回MessageListenerContainer
并且您已经可以控制单个@RabbitListener
处理程序的start()/stop()
。
A follow-up idea to the accepted answer is to have some sort of abstract BaseAmqpIntegrationTest
which does the following:接受答案的后续想法是使用某种抽象的
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();
}
This makes it reusable and ensures that all @RabbitListener
s are disabled "by default" and requires each test to explicitly enable the listener(s) that it tests.这使其可重用并确保所有
@RabbitListener
都“默认”禁用,并要求每个测试显式启用它测试的侦听器。 The test sub classes can then simply override getRequiredListenersToStart()
to provide the IDs of the @RabbitListener
s which they require.然后,测试子类可以简单地覆盖
getRequiredListenersToStart()
以提供它们需要的@RabbitListener
的 ID。
PS: Cleaning it up would of course also work: PS:清理它当然也有效:
public abstract class BaseAmqpIntegrationTest {
@AfterEach
protected void cleanUpAfterEach() {
rabbitListenerEndpointRegistry.getListenerContainers()
.forEach(Lifecycle::stop);
}
}
Or a bit more fine-grained:或者更细粒度的:
public abstract class BaseAmqpIntegrationTest {
@AfterEach
protected void cleanUpAfterEach() {
getRequiredListenersToStart().forEach(listener -> rabbitListenerEndpointRegistry.getListenerContainer(listener)
.stop());
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.