Spring中获取JMSMessageID的方法及会话创建合理性咨询
获取JMS发送消息的MessageID及会话管理问题
首先,你遇到的核心问题是:默认的jmsTemplate.send通过lambda创建消息时,无法直接拿到MessageID——这是因为JMS Provider只有在消息实际被发送后,才会为消息分配MessageID,而lambda内部的消息对象在返回时还没完成这个赋值过程。
你自己找到的方案虽然能拿到MessageID,但手动创建Session的做法并不合理,原因很简单:JMS的Connection和Session是重量级资源,频繁手动创建且不妥善关闭的话,会导致资源泄漏,还会浪费连接池的复用能力(如果你的配置里用了连接池的话)。
正确的解决方案:利用JmsTemplate.execute()方法
JmsTemplate本身提供了execute方法,它会帮你管理Session的创建、复用和销毁,同时允许你在同一个Session上下文里完成消息创建、发送和MessageID获取的操作。示例代码如下:
// 利用execute方法在JmsTemplate管理的Session中操作 String messageId = jmsTemplate.execute(session -> { // 在JmsTemplate的Session中创建消息 TextMessage message = session.createTextMessage(msg); // 发送消息(复用同一个Session) jmsTemplate.send("COM.YA.ADAPTER.AFM.TEST.OUT", s -> message); // 发送后即可获取到有效的MessageID return message.getJMSMessageID(); }, false); // 第二个参数:是否需要事务,根据业务场景调整(true=事务性,false=非事务性) // 之后用拿到的messageId接收响应 TextMessage textMessage = (TextMessage) jmsTemplate.receiveSelected( "COM.YA.ADAPTER.AFM.TEST.IN", "JMSCorrelationID='" + messageId + "'" );
为什么手动创建Session不可取?
- 资源泄漏风险:你手动创建的
Connection和Session如果没有显式调用close(),会一直占用资源,时间长了可能耗尽连接池的可用连接。 - 性能损耗:JmsTemplate默认会复用Connection和Session(尤其是在使用连接池时),手动创建会打破这种复用机制,增加资源创建销毁的开销。
- 上下文不一致:手动创建的Session和JmsTemplate内部使用的Session可能不属于同一个上下文,可能引发意想不到的JMS规范问题。
额外提示:JMSCorrelationID的最佳实践
如果你的场景是请求响应模式,其实可以提前生成一个UUID作为CorrelationID,不需要依赖MessageID,这样能避免等待MessageID的环节:
String correlationId = UUID.randomUUID().toString(); jmsTemplate.send("COM.YA.ADAPTER.AFM.TEST.OUT", session -> { TextMessage message = session.createTextMessage(msg); message.setJMSCorrelationID(correlationId); return message; }); // 直接用提前生成的correlationId接收响应 TextMessage textMessage = (TextMessage) jmsTemplate.receiveSelected( "COM.YA.ADAPTER.AFM.TEST.IN", "JMSCorrelationID='" + correlationId + "'" );
当然,这取决于你的系统约定,如果必须用MessageID作为CorrelationID,前面的execute方案就完全适用。
内容的提问来源于stack exchange,提问作者ttt
相关产品推荐
相关产品推荐

