繁体   English   中英

具有空队列名称的 Spring-amqp 正在等待声明

[英]Spring-amqp with empty queue name is awaiting_declaration

我想创建一个空名称的队列,以便可以通过 RabbitMQ 生成名称 -

var queue = QueueBuilder
    .durable("")
    .exclusive()
    .autoDelete().build

var binding = BindingBuilder.bind(queue).to(exchange).with(bindingKey).noargs();
Declarables d = new Declarables(queue, binding);

但随后调用 getActualName 返回: spring.gen-vuiRwjOmRkihAE8C72rbmw_awaiting_declaration

d.getDeclarablesByType(Queue.class).get(0).getActualName();

而在 rabbitMQ 中,名称是: amq.gen-wpaYnybu9vOdD5v2ej66IQ

在 spring-amqp 核心中,队列构造函数声明:

    public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete,
            @Nullable Map<String, Object> arguments) {
    
        super(arguments);
        Assert.notNull(name, "'name' cannot be null");
        this.name = name;
        this.actualName = StringUtils.hasText(name) ? name
                : (Base64UrlNamingStrategy.DEFAULT.generateName() 
+ "_awaiting_declaration");
        this.durable = durable;
        this.exclusive = exclusive;
        this.autoDelete = autoDelete;
    }

为什么 spring Queue 使用 Base64UrlNamingStrategy 并在我们想要 rabbitMQ 名称时添加“awaiting_declaration”? 我们如何获得 rabbitMQ 名称而不是 spring 生成的名称?

队列定义: https://github.com/spring-projects/spring-amqp/blob/d4e0f5c366a7ffae073f608c3766c82064cab3d1/spring-amqp/src/main/java/org/springframework/amqp/core/Queue.java#L98

这个用例的原因是队列上的竞争条件:“当自动删除或独占队列使用众所周知的(静态)名称时,如果客户端断开连接并立即重新连接,RabbitMQ 节点之间将出现自然竞争条件这将删除此类队列并恢复将尝试重新声明它们的客户端。这可能导致客户端连接恢复失败或异常,并造成不必要的混乱或影响应用程序可用性。

https://www.rabbitmq.com/queues.html#properties

Spring 建议使用可能导致竞争条件的基于代理的队列: https://docs.spring.io/spring-amqp/docs/current/reference/html/#containers-and-broker-named-queues

编辑:我们不是自己启动连接,而是管理 bean 在 d.setAdminsThatShouldDelcare(admin) 之后启动它

    public Declarables someEventsDeclarables(
    @Qualifier("rabbitAdmin") RabbitAdmin admin,
    @Qualifier("AmqpExchange") Exchange exchange
) {
    final var bindingKey = somePrefix +".*." +someSuffix
    final var cfg = new OurEventsDeclarables(
        exchange,
        "", // no queue name - RabbitMq generates it
        bindingKey,
        true
    );

    final var declarables = cfg.declarables();
    for (Declarable d : declarables.getDeclarables()) {
        d.setAdminsThatShouldDeclare(admin);
        admin.declareQueue();
    }
    return declarables;
}

运行使用队列结果的集成测试

org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$DeclarationException: Failed to declare queue(s):[spring.gen-QUh8ffN0TimELGG_kF1wFw_awaiting_declaration]

目前尚不清楚您对该Queue object 做了什么以及在哪里做了什么。您必须在应用程序上下文中有一个RabbitAdmin bean。 以及所有那些Declarable实例也必须声明为 beans。 然后当应用程序上下文启动时, RabbitAdmin获取所有可声明的 bean Declarable针对代理声明它们。 Queue的进一步逻辑是这样的:

DeclareOk declareOk = channel.queueDeclare(queue.getName(), queue.isDurable(),
                            queue.isExclusive(), queue.isAutoDelete(), queue.getArguments());
if (StringUtils.hasText(declareOk.getQueue())) {
    queue.setActualName(declareOk.getQueue());
}

仅仅为这些类型创建变量不会启动与代理的任何连接来执行对象创建和它们之间的绑定。

您正在使用admin.declareQueue() (并丢弃其结果)而不是admin.declareQueue(Queue queue)

第一种方法只是声明一个名为 queue 的代理; 实际名称的更新需要Queue object(因此它可以更新名称)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM