【问题标题】:Can we select JmsTemplate dynamically on the basis of MessageHeaders while using outbound jms adapter?在使用outbound jms适配器时,我们可以根据MessageHeaders动态选择JmsTemplate吗?
【发布时间】:2021-11-29 15:04:18
【问题描述】:

我创建了 2 个jmsTemplate Bean 以便能够相应地处理向Solace QueueSolace Topic 发送消息,现在当我在下面的exampleChannel 上传递消息时,我想如果MessageHandler 可以动态选择 jmsTemplate ?如果我用MessageHeader 传递消息,可以说destinationType=Topic/Queue

下面是配置

    @Autowired
    @Qualifier("topic")
    private JmsTemplate jmsTemplate;
    
    @Autowired
    @Qualifier("queue")
    private JmsTemplate jmsTemplate1;

    @Bean
    @ServiceActivator(inputChannel = "exampleMessageChannel" )
    public MessageHandler archiveOutboundHandler() {

        /*
         I need to select between jmsTemplate & jmsTemplate1 on the basis on header 
         information. 
         **/
        JmsSendingMessageHandler messageHandler = new JmsSendingMessageHandler(jmsTemplete);
        messageHandler.setDestinationExpression(new FunctionExpression<Message<?>>(m->m.getHeaders().get("destination")));
        return messageHandler;
    }

有可能吗?或者有更好的方法吗?

更新 1:

@Artem 建议将destinationExpression 的实现更改为返回Destination 后,我这样做了

    @Bean
    @ServiceActivator(inputChannel = "outMessageChannel" )
    public MessageHandler archiveOutboundHandler() {
        JmsSendingMessageHandler messageHandler = new JmsSendingMessageHandler(jmsTemplate);
        messageHandler.setDestinationExpression(new FunctionExpression<Message<?>>(message -> {
            if((Objects.equals(message.getHeaders().get("destinationType"), "topic"))){
               return (Topic) () -> (String) message.getHeaders().get("destination");
            }else{
                return (Queue) () -> (String) message.getHeaders().get("destination");
            }
        }));
        return messageHandler;
    }

我遇到了异常

$$Lambda$821/1572602632 cannot be cast to com.solacesystems.jms.SolDestination)

更新 2

我能够使用JndiDestinationResolver解析目的地

正如 Artem 建议使用 BeanFactoryDestinationResolver 那样,我无法使用它,因为目的地太多,BeanFactoryDestinationResolver 需要为每个目的地创建特定的 bean。

我已经配置了JndiDestinationResolver,所以我只需要注入DestinationResolver 来解析目的地。

下面是sn-p,

@Autowired
private JmsTemplate jmsTemplate;

@Autowired
private DestinationResolver destinationResolver;

@Bean
@ServiceActivator(inputChannel = "exampleChannel" )
public MessageHandler jmsOutboundHandler() {
    
    JmsSendingMessageHandler messageHandler = new JmsSendingMessageHandler(jmsTemplate);
    messageHandler.setDestinationExpression(new FunctionExpression<Message<?>>(message -> {
        if(message.getHeaders().get("dest_type").equals("topic")){
               return destinationResolver.resolveDestinationName(null,(String) message.getHeaders().get("dest"),true);
            
        }else{
               return destinationResolver.resolveDestinationName(null,(String) message.getHeaders().get("dest"),false);
        }
    }));
    return messageHandler;
}

感谢所有输入,我将提出 GH 问题以在 DynamicJmsTemplate 中包含 pubsub 功能

【问题讨论】:

  • 为什么需要不同的JmsTemplate 实例?它是一个无状态组件,可以为不同的用例共享。因此,您可以简单地生产到队列以及主题。请用两个不同的JmsTemplate 实例详细说明您的情况
  • 我正在查看一些 spring 文档,默认情况下 spring 使用 pubsub 作为 false,如果我们想发送关于需要设置为 'true' 的主题的消息,这就是我创建 2 个 bean 的原因对于主题和其他队列,你能告诉我我们如何使用相同的实例,以便它在队列和主题上产生

标签: spring-integration spring-jms


【解决方案1】:

我明白你的意思了。

它的逻辑是这样的:

protected Destination resolveDestinationName(Session session, String destinationName) throws JMSException {
    return getDestinationResolver().resolveDestinationName(session, destinationName, isPubSubDomain());
}

默认的DynamicDestinationResolver 是这样的:

if (pubSubDomain) {
        return resolveTopic(session, destinationName);
    }
    else {
        return resolveQueue(session, destinationName);
    }

作为一种解决方法,请考虑将您的destinationExpression 评估为javax.jms.Destination 实例,而不是它们的普通名称。这样您就不会被绑定到 pubSubDomain 属性。

还有一个 BeanFactoryDestinationResolver 用于将提供的名称解析为来自应用程序上下文的 Destination bean。

同时,我要求您提出一个 GH 问题,以将 pubSubDomain 支持添加到 DynamicJmsTemplate API 中。因此,您将能够根据JmsSendingMessageHandler 中的表达式评估来确定pubSubDomain

【讨论】:

  • 谢谢阿特姆!我已经用更改编辑了问题,似乎我缺少基础知识
  • cast ?不,它不能这么容易施放。您确实创建了SolDestination 的实例。或在该表达式内容中或在发送到此端点之前预先进行。如果 Solace 允许我们这样做,考虑为这些目的地提供豆子可能会更好。我将这种方法与 WebSphere 中的 BeanFactoryDestinationResolver 结合起来用于对抗其 JNDI。
  • 感谢您的输入,使用BeanFactoryDestinationResolver 对我来说是不可行的,因为我没有使用静态配置,BeanFactoryDestinationResolver 需要为所有这些目标创建特定的 bean。相反,我已经在使用JndiDestinationResolver,所以我使用它来解决添加了相同的目标的sn-p。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多