我有一个 EJB 模块,它必须通过 TemporaryQueue 与另一个模块中的 MDB 同步交换消息。EJB 容器(在我的例子中是 Glassfish 4.0)假设事务环境,我是否必须使用 BEAN 管理的事务并使用 UserTransaction 对象表示事务的开始和结束。
我的代码大纲是这样的:
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CommunicationJMSUtils {
@Resource
private UserTransaction ut;
@Inject
private JMSContext context;
@Resource(lookup = "jms/DestinationQueue")
private Queue destination;
private static final long JMS_COMMUNICATION_TIMEOUT = 5000;
public Map<String, String> getClientordersData(String id) throws JMSException {
try {
MapMessage mm = context.createMapMessage();
ut.begin();
TemporaryQueue replyQueue = context.createTemporaryQueue();
mm.setJMSReplyTo(replyQueue);
mm.setStringProperty(<...>);
<...>
mm.setString(<...>);
<...>
context.createProducer().send(destination, mm);
ut.commit();
ut.begin();
ObjectMessage om = (ObjectMessage) context.createConsumer(replyQueue).receive(JMS_COMMUNICATION_TIMEOUT);
ut.commit();
if (om != null) {
return om.getBody(Map.class);
} else {
throw new JMSException("Failed to receive reply within " + JMS_COMMUNICATION_TIMEOUT);
}
} catch (NotSupportedException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException | SystemException ex) {
<...>
}
}
}
第一个问题是该代码(接收部分)有时会因异常而失败
MQJMSRA_DS4001: _checkDestination:Temporary Destination not owned by parent connectionId=1760697170479431168
尽管显然 TemporaryQueue 是使用相同的 JMSContext 创建的。
第二个问题是这段代码的“脆弱性”。如果我将 context.createMapMessage() 放在第一个事务中或将 TemporaryQueue 创建移出第一个事务,则此代码段肯定会失败。
不幸的是,JMS 教程/文档并没有真正涵盖那个特定的用例。在 Java EE 中使用 JMS 2.0 实现 JMS 请求/响应模式的正确方法是什么?