SoapUI中MQQueueConnection读取JMS队列的技术问题咨询
解决SoapUI中JMS读取最新消息及超时阻塞问题
我来帮你搞定这两个棘手的问题,下面结合你的场景给出修改后的代码和详细解释:
问题1:读取队列最新消息
默认的MQQueueReceiver是按FIFO顺序读取最早的消息,要拿到队列里的最新消息,我们可以通过**消息浏览器(QueueBrowser)**遍历队列,定位到最后一条消息的ID,再通过这个ID精准接收这条最新消息,确保拿到队列最末尾的内容。
问题2:设置超时避免SoapUI挂起
你原来的代码里receive(1000000)设置了1000秒的超时,这跟无限阻塞没区别。我们需要把超时时间改短(比如5秒),同时在receive返回null(无消息或超时)时做针对性处理,避免空指针异常和程序挂死。
修改后的完整Groovy代码
import com.eviware.soapui.impl.wsdl.submit.transports.jms.JMSConnectionHolder import com.eviware.soapui.impl.wsdl.submit.transports.jms.util.HermesUtils import com.eviware.soapui.impl.wsdl.submit.transports.jms.JMSEndpoint import hermes.Hermes import javax.jms.* import javax.jms.JMSException; import javax.jms.Session; import com.ibm.jms.JMSMessage; import com.ibm.jms.JMSTextMessage; import com.ibm.mq.jms.JMSC; import com.ibm.mq.jms.MQQueue; import com.ibm.mq.jms.MQQueueConnection; import com.ibm.mq.jms.MQQueueConnectionFactory; import com.ibm.mq.jms.MQQueueReceiver; import com.ibm.mq.jms.MQQueueSender; import com.ibm.mq.jms.MQQueueSession; // 初始化接收消息的属性 context.testCase.testSteps["Properties"].setPropertyValue("receivedMessage","") try { MQQueueConnectionFactory cf = new MQQueueConnectionFactory(); // MQ连接配置 cf.setHostName("agdevesb01"); cf.setPort(14141); cf.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP); // 用常量替代硬编码,更清晰 cf.setQueueManager("AGDEV1T1"); cf.setChannel("CLIENTS.CARRIER"); MQQueueConnection connection = (MQQueueConnection) cf.createQueueConnection(); MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); MQQueue queue = (MQQueue) session.createQueue("queue:///QUEUE_NAME"); // 启动连接 connection.start(); // ========== 解决问题1:获取最新消息 ========== String latestMessageId = null; QueueBrowser browser = session.createBrowser(queue); Enumeration msgEnum = browser.getEnumeration(); // 遍历所有消息,记录最后一条的MessageID while (msgEnum.hasMoreElements()) { JMSMessage msg = (JMSMessage) msgEnum.nextElement(); latestMessageId = msg.getJMSMessageID(); } browser.close(); // 关闭浏览器 JMSMessage receivedMessage = null; if (latestMessageId != null) { // 通过MessageID精准接收最新消息 MQQueueReceiver receiver = (MQQueueReceiver) session.createReceiver(queue, "JMSMessageID='" + latestMessageId + "'"); // ========== 解决问题2:设置5秒超时 ========== receivedMessage = (JMSMessage) receiver.receive(5000); receiver.close(); } // 处理接收结果 if (receivedMessage != null) { log.info "Received latest message: " + receivedMessage context.testCase.testSteps["Properties"].setPropertyValue("receivedMessage", receivedMessage.toString()) } else { log.info "No messages found in queue or timeout reached" context.testCase.testSteps["Properties"].setPropertyValue("receivedMessage", "NO_MESSAGE") } // 关闭资源 session.close(); connection.close(); log.info "SUCCESS" } catch (JMSException jmsex) { log.error "JMS Exception occurred: " + jmsex.getMessage(), jmsex } catch (Exception ex) { log.error "Unexpected error occurred: " + ex.getMessage(), ex }
关键修改点说明
获取最新消息
- 用
QueueBrowser遍历队列所有消息,记录最后一条的JMSMessageID - 创建接收者时使用消息选择器
"JMSMessageID='" + latestMessageId + "'",精准定位最新消息 - 注:如果队列消息量极大,遍历可能有性能损耗,这种场景可以考虑调整MQ队列属性或采用其他消费模式,常规场景下这个方案足够好用
- 用
超时与阻塞处理
- 将
receive超时时间改为5000(5秒),你可以根据实际业务需求调整这个数值 - 增加了
receivedMessage为null的判断,避免空指针异常,同时输出明确日志 - 队列无消息或超时后,程序会正常收尾,不会导致SoapUI挂起
- 将
其他优化
- 用
JMSC.MQJMS_TP_CLIENT_MQ_TCPIP常量替代硬编码的1,提升代码可读性 - 异常日志改用
log.error并打印堆栈,方便排查问题 - 移除了无用的
MQQueueSender代码,简化逻辑
- 用
内容的提问来源于stack exchange,提问作者Sagar Wadhwa
相关产品推荐
相关产品推荐

