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

JBoss EAP 7.2中JMS MDB偶发丢失消息问题求助

JBoss EAP 7.2 MDB半数概率不触发onMessage的问题排查与修复

我在JBoss EAP 7.2上部署了标准Web应用,请求通过Servlet发送消息至JMS队列,再由MDB处理。但约50%的情况下,生产者发送消息后,MDB的onMessage()方法从未被调用,且服务器日志无报错信息。以下是相关配置、代码及排查后的修复方案:


相关配置与代码

JBoss队列配置

<jms-queue name="HIFWebHookQueue" entries="HifWebHookQueue java:jboss/exported/jms/queue/HifWebHookQueue"/>

Servlet生产者代码

@WebServlet(name = "/")
public class MyServlet extends HttpServlet {

    @Inject
    private JMSContext context;

    @Resource(lookup = "java:jboss/exported/jms/queue/HifWebHookQueue")
    private Queue queue;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
     
        JMSProducer producer = context.createProducer();
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        ObjectMessage msg = context.createObjectMessage(evt);  //evt是可序列化POJO
        producer.send(queue,evt);
    }
}

MDB消费者代码

@MessageDriven(name = "WebhookListenerEJB", activationConfig = {
    @ActivationConfigProperty(propertyName="messagingType", propertyValue="javax.jms.MessageListener"),
    @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
    @ActivationConfigProperty(propertyName="destination", propertyValue="java:/jms/queue/HIFWebHookQueue"),
    @ActivationConfigProperty(propertyName="ConnectionFactoryName", propertyValue="ConnectionFactory"),
})
@TransactionManagement(value = TransactionManagementType.CONTAINER)
@TransactionAttribute(value = TransactionAttributeType.REQUIRED)
public class WebhookListenerEJB implements MessageListener {

    public void onMessage(Message message) {
        ObjectMessage msg = (ObjectMessage) message;
        ... 业务处理 ...
        message.acknowledge();
    }
}

发送消息后的JBoss CLI输出

[standalone@localhost:9990 /] /subsystem=messaging-activemq/server=default/jms-queue=HIFWebHookQueue:read-resource(include-runtime=true)
{
    "outcome" => "success",
    "result" => {
        "consumer-count" => 30,
        "dead-letter-address" => "jms.queue.DLQ",
        "delivering-count" => 0,
        "durable" => true,
        "entries" => [
            "HifWebHookQueue",
            "java:jboss/exported/jms/queue/HifWebHookQueue"
        ],
        "expiry-address" => "jms.queue.ExpiryQueue",
        "legacy-entries" => undefined,
        "message-count" => 0L,
        "messages-added" => 1L,
        "paused" => false,
        "queue-address" => "jms.queue.HIFWebHookQueue",
        "scheduled-count" => 0L,
        "selector" => undefined,
        "temporary" => false
    }
}

问题排查与修复步骤

1. 修复Servlet消息发送的代码错误

Servlet里存在低级错误:明明创建了ObjectMessage实例,发送时却直接传了evt对象而非这个消息实例。直接传对象会导致消息格式不符合JMS规范,部分情况下会被Broker静默处理,MDB自然收不到。

修改后的代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response) {
    JMSProducer producer = context.createProducer();
    producer.setDeliveryMode(DeliveryMode.PERSISTENT);
    ObjectMessage msg = context.createObjectMessage(evt);
    // 改为发送创建好的ObjectMessage实例
    producer.send(queue, msg);
}

2. 修正MDB的队列JNDI名称匹配

队列配置的JNDI条目是java:jboss/exported/jms/queue/HifWebHookQueue(注意首字母是小写的Hif),但MDB里配置的destination是java:/jms/queue/HIFWebHookQueue(全大写HIF)。JBoss的JNDI名称是大小写敏感的,这会导致MDB绑定到错误的队列(或者压根没绑定上),消息被其他消费者吃掉或者丢到了别的地方。

调整MDB的activation配置,确保JNDI名称完全匹配:

@ActivationConfigProperty(propertyName="destination", propertyValue="java:jboss/exported/jms/queue/HifWebHookQueue"),

或者统一大小写,把队列配置里的名称改成HIFWebHookQueue,对应的JNDI条目也调整为大写,保持一致即可。

3. 移除MDB中的手动消息确认

MDB用的是容器管理事务(TransactionManagementType.CONTAINER),事务属性是REQUIRED,这种情况下容器会在事务提交时自动确认消息。手动调用message.acknowledge()会干扰容器的事务逻辑,可能导致消息确认异常,引发消费失败却无日志的情况。

直接删除onMessage里的手动确认代码:

public void onMessage(Message message) {
    ObjectMessage msg = (ObjectMessage) message;
    ... 业务处理 ...
    // 删掉这行:message.acknowledge();
}

4. 清理多余的消费者

CLI输出显示consumer-count是30,这明显不正常——默认MDB的并发消费数远低于这个数值。说明存在其他未关闭的消费者(比如测试用的JMS客户端、遗留的消费代码)连接到了这个队列,消息被这些多余的消费者消费了,目标MDB根本没机会拿到消息。

  • 检查应用是否有其他JMS消费逻辑连接到该队列;
  • 重启JBoss服务器,清除残留的消费者连接,之后观察consumer-count是否恢复到MDB的预期并发数(可以通过@ActivationConfigProperty配置maxSession调整,默认一般是15左右)。

5. 启用调试日志排查剩余问题

如果上面的步骤都做完还是有问题,就开启JBoss的JMS调试日志,查看消息发送、路由、消费的完整流程:

在standalone.xml里添加日志配置:

<logger category="org.apache.activemq.artemis">
    <level name="DEBUG"/>
</logger>
<logger category="javax.jms">
    <level name="DEBUG"/>
</logger>

重启服务器后,查看日志就能清楚看到消息到底被路由到哪里了,有没有被目标MDB接收。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 19:45:43