TomEE无法向ActiveMQ Artemis发送消息但可接收,求解决方案
问题描述
我正在配置TomEE向ActiveMQ Artemis发送消息:通过ActiveMQ Artemis控制台发送的消息可被MDB接收,但在ActiveMQ Classic下正常运行的无状态服务无法向ActiveMQ Artemis发送消息,且日志无任何错误。
TomEE配置片段
<Resource id="MyJmsConnectionFactory" class-name="org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory" constructor="uri,username,password" type="jakarta.jms.ConnectionFactory"> uri=tcp://localhost:61617?needClientAuth=false;sslEnabled=true;trustAll=true;verifyHost=false;wantClientAuth=false;needClientAuth=false username=admin password=admin </Resource> <Resource id="TESTQ" class-name="org.apache.activemq.artemis.api.jms.ActiveMQJMSClient" constructor="name" factory-name="createQueue" type="jakarta.jms.Queue"> name=TESTQ </Resource> <Container id="mdb" type="MESSAGE"> InstanceLimit = -1 ResourceAdapter = MyJmsResourceAdapter ActivationSpecClass = org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec </Container>
无状态服务注入点
@Stateless @Path("/RestTest") public class RestTest { @Resource(name = "MyJmsConnectionFactory") private ConnectionFactory _connectionFactory ; @Resource(name = "TESTQ") private Queue testq ; ..... }
依赖jar包
artemis-jakarta-client-all-2.29.0.jarartemis-jakarta-ra-2.29.0.jarartemis-jakarta-service-extensions-2.29.0.jarOpenEjbTransactionManagerJakarta.jar(适配Jakarta规范的自定义修改版本)
已尝试操作
- 关闭SSL改用普通TCP连接
- 在TomEE 8中使用javax相关类
以上操作均仅MDB能正常工作,无状态服务发送消息问题依旧。
Artemis日志信息
2023-07-21 10:27:21,334 DEBUG
[org.apache.activemq.artemis.core.server.impl.ServerSessionImpl]
Routing result for CoreMessage[messageID=1538,durable=true,userID=b414a064-27d2-11ee-8e7d-00059a3c7a00,priority=4,
timestamp=Fri Jul 21 10:27:21 EDT 2023,expiration=0, durable=true, address=TESTQ,size=1376,
properties=TypedProperties[__AMQ_CID=b40955c1-27d2-11ee-8e7d-00059a3c7a00,_AMQ_ROUTING_TYPE=1
,_AMQ_DUPL_ID=7e335005-1538-488d-ac5e-0f54ebc01ec8,
_HQ_DUPL_ID=7e335005-1538-488d-ac5e-0f54ebc01ec8]]@1370468351 = OK
服务器显示消息路由成功,但控制台无生产者信息,消息也未出现在队列中。
解决方案
1. 排查事务提交逻辑
从Artemis日志来看,服务器已完成消息路由,但队列中无消息,大概率是事务未提交导致消息被回滚:
- 若使用容器管理事务(默认),确保发送消息的方法没有触发事务回滚的逻辑(如未捕获的异常)。
- 尝试给发送消息的方法添加
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW),强制开启独立事务,避免受原有事务上下文影响:@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void sendMessage() { // 消息发送逻辑 } - 若手动管理事务,需显式调用
commit()方法:UserTransaction ut = InitialContext.doLookup("java:comp/UserTransaction"); ut.begin(); try { // 发送消息逻辑 ut.commit(); } catch (Exception e) { ut.rollback(); e.printStackTrace(); }
2. 调整连接工厂配置
暂时改用非XA连接工厂排除XA事务干扰,将ActiveMQXAConnectionFactory替换为ActiveMQConnectionFactory:
<Resource id="MyJmsConnectionFactory" class-name="org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory" constructor="uri,username,password" type="jakarta.jms.ConnectionFactory"> uri=tcp://localhost:61617?needClientAuth=false;sslEnabled=true;trustAll=true;verifyHost=false;wantClientAuth=false;needClientAuth=false username=admin password=admin </Resource>
测试是否能正常发送消息,若正常则说明问题出在XA事务的协调上。
3. 修正队列资源配置
Artemis的ActiveMQJMSClient.createQueue方法支持传入address和name两个参数,原配置仅指定name可能导致消息发送到错误的地址。修改队列配置:
<Resource id="TESTQ" class-name="org.apache.activemq.artemis.api.jms.ActiveMQJMSClient" constructor="address,name" factory-name="createQueue" type="jakarta.jms.Queue"> address=TESTQ name=TESTQ </Resource>
同时通过Artemis控制台确认TESTQ队列已正确创建,且地址与配置一致。
4. 校验事务管理器适配
自定义的OpenEjbTransactionManagerJakarta.jar可能存在Jakarta事务规范适配问题:
- 尝试移除该jar包,使用TomEE原生事务管理器(若不需要XA事务)。
- 若必须使用XA事务,确保该jar包正确实现了Jakarta Transactions API,特别是XA资源的注册与事务协调逻辑。
5. 开启TomEE JMS日志排查
在TomEE的conf/logging.properties中添加日志配置,捕获JMS发送过程的详细日志:
org.apache.openejb.jms.level = FINE org.apache.activemq.artemis.jms.level = FINE java.util.logging.ConsoleHandler.level = FINE
查看TomEE日志,确认消息发送时是否有隐藏的异常或事务回滚信息。
内容的提问来源于stack exchange,提问作者user18896654353

