You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无ActiveMQ Artemis发送权限时非持久化消息无报错问题咨询

问题:无SEND权限时,非持久化消息发送无报错?

我尝试向无SEND权限的队列发送两类消息:

  • 设置producer.setDeliveryMode(DeliveryMode.PERSISTENT)时,控制台正常显示无权限报错;
  • 设置producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT)时,无任何报错提示且消息未发送至队列。

希望两种场景均能触发报错,请问这是ActiveMQ Artemis Broker的特性吗?

相关配置与代码

broker.xml 配置

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<configuration xmlns="urn:activemq"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
               xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
    <core xmlns="urn:activemq:core">
      <name>localhost</name>
      
      <bindings-directory>./data/messaging/bindings</bindings-directory>

      <journal-directory>./data/messaging/journal</journal-directory>

      <large-messages-directory>./data/messaging/largemessages</large-messages-directory>

      <paging-directory>./data/messaging/paging</paging-directory>


      <!-- true to expose ActiveMQ Artemis resources through JMX -->
      <jmx-management-enabled>true</jmx-management-enabled>

      <!-- Acceptors -->
      <acceptors>
         <acceptor name="netty">tcp://localhost:61616</acceptor>
      </acceptors>

      <!-- Other config -->

      <security-settings>
         <!--security for example queue-->
         <security-setting match="exampleQueue">
            <permission roles="amq" type="createDurableQueue"/>
            <permission roles="amq" type="deleteDurableQueue"/>
            <permission roles="amq" type="createNonDurableQueue"/>
            <permission roles="amq" type="deleteNonDurableQueue"/>
            <permission roles="amq" type="consume"/>
            <permission roles="no" type="send"/>
            <permission roles="amq" type="browse"/>
         </security-setting>
         <security-setting match="TestQueue">
            <permission roles="amq" type="createDurableQueue"/>
            <permission roles="amq" type="deleteDurableQueue"/>
            <permission roles="amq" type="createNonDurableQueue"/>
            <permission roles="amq" type="deleteNonDurableQueue"/>
            <permission roles="amq" type="consume"/>
            <permission roles="no" type="send"/>
            <permission roles="amq" type="browse"/>
         </security-setting>
         <security-setting match="TestQueueSecond">
            <permission roles="amq" type="createDurableQueue"/>
            <permission roles="amq" type="deleteDurableQueue"/>
            <permission roles="amq" type="createNonDurableQueue"/>
            <permission roles="amq" type="deleteNonDurableQueue"/>
            <permission roles="no" type="consume"/>
            <permission roles="no" type="send"/>
         </security-setting>
      </security-settings>

      <addresses>
         <address name="exampleQueue">
            <anycast>
               <queue name="exampleQueue"/>
            </anycast>
         </address>
         <address name="TestQueue">
            <anycast>
               <queue name="TestQueue"/>
            </anycast>
         </address>
         <address name="TestQueueSecond">
            <anycast>
               <queue name="TestQueueSecond"/>
            </anycast>
         </address>
      </addresses>
   </core>
</configuration>

Java 生产者代码

@RestController
public class Producer implements Serializable {

    String url = "tcp://localhost:61616";

    @GetMapping("/send")
    public String sendMessage() throws JMSException {

        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
        connectionFactory.setUser("test");
        connectionFactory.setPassword("qwe123");

        Connection connection = connectionFactory.createConnection();
        connection.start();

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        Destination destination = session.createQueue("exampleQueue");

        MessageProducer producer = session.createProducer(destination);
        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

        Message message = session.createTextMessage("BodyTextMessage");
        message.setStringProperty("TEST", "TEST");

        producer.send(message);

        String body = message.getBody(String.class);

        connection.close();

        return body;
    }
}

解答

这确实是ActiveMQ Artemis的默认行为,核心原因在于非持久化消息的发送确认机制差异:

  • 持久化消息默认要求broker返回发送确认(ACK),权限校验失败时,broker会主动返回错误信息,客户端能捕获到该错误;
  • 非持久化消息在默认的Session.AUTO_ACKNOWLEDGE模式下,客户端不会等待broker的确认,消息发送后直接判定为成功,即便broker因权限问题丢弃了消息,客户端也无法感知。

要让非持久化消息也触发权限报错,可通过以下两种方式解决:

方式1:调整Session的确认模式

创建Session时使用Session.CLIENT_ACKNOWLEDGE模式,并在发送消息后手动确认,强制broker返回处理结果:

Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
// ...发送消息逻辑
message.acknowledge();

这种模式下,broker会在完成权限校验等处理后返回确认,权限失败时客户端会收到对应的报错。

方式2:修改broker配置,强制非持久化消息返回确认

在broker.xml的<core>节点下添加配置,让broker对所有非持久化消息都发送确认:

<core>
  <!-- 保留原有配置 -->
  <force-acknowledge-on-non-durable-send>true</force-acknowledge-on-non-durable-send>
</core>

开启该配置后,无论客户端使用哪种确认模式,broker都会返回非持久化消息的处理结果,权限校验失败时客户端即可捕获到错误。

内容的提问来源于stack exchange,提问作者user23253016

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:55:55