问题描述
在我的监听器中,当这个 jms 消息被转换为 Message 时
@JmsListener(id = "cis-listener",destination = "${amiga.service.jms.cis-listener.destination-fqdn}",containerFactory = "containerFactoryListener")
public void receiveMessage(Message<Object> event) throws UnkNownMessageException {
...
当 MessageHeaders 被实例化时,这个属性会被生成的 UUID 覆盖:
protected MessageHeaders(@Nullable Map<String,Object> headers,@Nullable UUID id,@Nullable Long timestamp) {
this.headers = (headers != null ? new HashMap<>(headers) : new HashMap<>());
if (id == null) {
this.headers.put(ID,getIdGenerator().generateId());
}
...
是否有一些选项可以重命名我在消息中收到的 id 标头属性以保留该值?
我可以通过使用 javax.jms.Message 更改侦听器接收到的对象来访问此属性,但我更喜欢使用 spring-jms 消息实现。
解决方法
您可以向侦听器适配器添加自定义 JmsHeaderMapper
。
- 将容器工厂
autoStartup
设置为false
。 - 从
JmdListenerContainerEndpointRegistry
(通过 id)获取容器。 - 从容器中获取消息侦听器并将其转换为
AbstractAdaptableMessageListener
。 - 设置自定义标头映射器。
- 启动容器。
您的映射器应该将您的外部 id
标头映射到其他内容。 id
在 spring-messaging 中保留。它可以是 SimpleJmsHeaderMapper
的子类。
您好 Gary Russell 首先感谢您的回复和帮助,很高兴能得到 Spring 部分开发人员的回答,我有疑问。
在您的解决方案中,我不喜欢被迫禁用自动启动。在我们的项目中,我们不强制自动启动,但如果我们需要此属性将被忽略,因为我们在设置自定义标头映射器后强制启动。我们应该在容器启动之前定义其他属性并检查其值。更改容器自动启动属性的含义有点奇怪。
我也对 MessageHeader 定义有疑问。我将 Message 和 MessageHeader 类视为 jms Message 类的包装器/装饰器。我知道定义这两个类是为了使实例化和访问消息和标头属性更容易。 这就是为什么我不明白为什么时间戳和 id 值被覆盖的原因。我认为包装器不应该添加这种逻辑,尤其是在消息标题中接收 id 属性并不罕见时。如果 spring 需要一个 id 来处理消息,那么在创建之前,应该检查属性 id 是否存在并使用其他名称代替 id,与时间戳相同。 这两个属性名称由 spring 保留,但 jms 定义不允许使用。
我不喜欢该解决方案,但我认为我们将被迫更改我们的侦听器以接收 jms 消息,尽管实例化消息来测试它更困难,但我认为这是一个更好的选择。
再次感谢您的时间和帮助。