Java Spring集成JMS创建ActiveMQ队列而不是主题

Java Spring集成JMS创建ActiveMQ队列而不是主题,java,spring-integration,activemq,spring-jms,spring-messaging,Java,Spring Integration,Activemq,Spring Jms,Spring Messaging,我正在尝试使用ActiveMQ代理,使用Spring集成工具,向两个侦听自动主题的消费者传递消息 以下是我的配置bean(发布者和订阅者之间的共同点): 以下是制作人的菜豆: @Bean(name = "jmsOutputChannel") public MessageChannel jmsOutputChannel() { return new PublishSubscribeChannel(); } @Bean(name = "jmsOutputFlow") public Inte

我正在尝试使用ActiveMQ代理,使用Spring集成工具,向两个侦听自动主题的消费者传递消息

以下是我的配置bean(发布者和订阅者之间的共同点):

以下是制作人的菜豆:

@Bean(name = "jmsOutputChannel")
public MessageChannel jmsOutputChannel() {
    return new PublishSubscribeChannel();
}

@Bean(name = "jmsOutputFlow")
public IntegrationFlow jmsOutputFlow() {
    return IntegrationFlows.from(jmsOutputChannel()).handle(Jms.outboundAdapter(connectionFactory())
            .destination("myTopic")
    ).get();
}



private static int counter = 1;

@Scheduled(initialDelay=5000, fixedDelay=2000)
public void send() {
     String s = "Message number " + counter;
     counter++;
     jmsOutputChannel().send(MessageBuilder.withPayload(s).build());
}
我没有使用嵌入式ActiveMQ代理。我在自己的(docker)容器中使用一个代理、一个生产者和两个消费者

我的问题是,当我在
JmsListenerContainerFactory
JmsTemplate
上调用
setPubSubDomain(true)
时,我的“主题”表现为队列:一个消费者打印所有偶数消息,而另一个消费者打印所有奇数消息

事实上,通过访问ActiveMQ web界面,我看到我的“主题”(即在/topics.jsp页面下)被命名为
ActiveMQ.advision.Consumer.Queue.myTopic
ActiveMQ.advision.Producer.Queue.myTopic
,而“myTopic”确实出现在队列页面中(即/queues.jsp)

节点按以下顺序启动:

  • AMQ经纪人
  • 消费者1
  • 消费者2
  • 制作人
创建的第一个“主题”是
ActiveMQ.advision.Consumer.Queue.myTopic
,而生产者主题显然只有在生产者启动之后才会出现

我不是ActiveMQ的专家,所以我的生产者/消费者“主题”被命名为“.Queue”可能只是误导。但是,我确实得到了for队列中描述的语义,而不是主题

我也已经看过了,但是我所有雇佣的频道都是PublishSubscribeChannel类型的

我需要实现的是将所有消息传递给我的所有(可能>2)消费者

更新:我忘了提到,我的
应用程序.properties
文件已经包含
spring.jms.pub sub-domain=true
,以及其他设置

另外,我使用的Spring集成版本是4.3.12.0版本

问题是,我仍然得到RR负载平衡语义,而不是发布-订阅语义。 至于我在@Hassen Bennour提供的中看到的内容,我希望在所有主题的列表中得到一行
ActiveMQ.advision.Producer.Topic.myTopic
和一行
ActiveMQ.advision.Consumer.Topic.myTopic
。不知何故,我认为我没有很好地使用Spring集成库,因此当我想设置一个主题时,我正在设置一个队列

更新2:很抱歉造成混淆
jmsOutputChannel2
实际上是
jmsOutputChannel
在这里,我已经编辑了主要部分。我在代码中使用了第二个“主题”作为检查,生产者可以自己发送消息和接收回复。“主题”名称也不同,因此。。。它完全在一个单独的流程上

通过以下方式更改接收器流,我确实取得了一些进展:

@Bean(name = "jmsInputFlow")
public IntegrationFlow buildReceiverFlow() {        
    //return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(connectionFactory()).destination("myTopic"))
            //.channel("jmsInputChannel").get();
return IntegrationFlows.from(Jms.publishSubscribeChannel(connectionFactory()).destination("myTopic")) //Jms.publishSubscribeChannel() rather than Jms.messageDrivenChannelAdapter()
            .channel("jmsInputChannel").get();
}
这会在代理上生成一个类型为
Consumer.topic.myTopic
的咨询主题,而不是
Consumer.Queue.myTopic
,实际上是一个名为just
myTopic
的主题(正如我可以从topics选项卡中看到的)。但是,一旦生产者启动,就会创建一个
producer.Queue
咨询主题,并且消息会在没有传递的情况下发送到那里

输入流中适配器的选择似乎决定了创建哪种类型的建议使用者主题(从
Jms.messageDrivenChannelAdapter()
切换到
Jms.publishSubscribeChannel()
时主题与队列)。然而,我还没有找到类似于输出流的东西

更新3:由于@Hassen Bennour,问题得以解决。概述:

我在生产者的
Jms.outboundAdapter()中连接了
jmsTemplate()

消费者
Jms.messageDrivenChannelAdapter()
的配置更为复杂:

虽然这可能是最平滑、最灵活的方法,但拥有这样一个bean

@Bean
public Topic topic() {
    return new ActiveMQTopic("myTopic");
}
将连接作为适配器的目标,而不仅仅是字符串


再次感谢。

将spring.jms.pub sub-domain=true添加到application.properties

或将目的地定义为主题,并将目的地(“myTopic”)替换为目的地(topic())

@Bean
public Topic topic() {
    return new ActiveMQTopic("myTopic");
}

物业已经设置好了,我忘了提。我还尝试在调用配置程序后移动
factory.setPubSubDomain(true)
行。我有完全相同的行为。jmsOutputChannel2()。send()向jmsOutputChannel()发送消息??我这边报告“2”是一个错误。实际上,我只是在消息通道
jmsOutputChannel()
本身上直接发送字符串,该通道通过IntegrationFlow链接到
Jms.outboundAdapter()
@Bean(name = "jmsOutputFlow")
public IntegrationFlow jmsOutputFlow() {
    return IntegrationFlows.from(jmsOutputChannel()).handle(Jms.outboundAdapter(jsaTemplate())
            .destination("myTopic")
    ).get();
}
@Bean(name = "jmsInputFlow")
public IntegrationFlow buildReceiverFlow() {        
    return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(
        Jms.container(connectionFactory(),"myTopic")
        .pubSubDomain(true).get()) )
        .channel("jmsInputChannel").get();
}
@Bean
public Topic topic() {
    return new ActiveMQTopic("myTopic");
}
@Bean
public JmsListenerContainerFactory<?> jsaFactory(ConnectionFactory connectionFactory,
        DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    // the configurer will use PubSubDomain from application.properties if defined or false if not
    //so setting it on the factory level need to be set after this
    configurer.configure(factory, connectionFactory);
    factory.setPubSubDomain(true);
    return factory;
}
@Bean(name = "jmsOutputFlow")
public IntegrationFlow jmsOutputFlow() {
    return IntegrationFlows.from(jmsOutputChannel()).handle(Jms.outboundAdapter(jmsTemplate())
            .destination("myTopic")
    ).get();
}

@Bean(name = "jmsInputFlow")
public IntegrationFlow buildReceiverFlow() {        
    return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(
            Jms.container(connectionFactory(),"myTopic")
            .pubSubDomain(true).get()) )
            .channel("jmsInputChannel").get();
}
@Bean
public Topic topic() {
    return new ActiveMQTopic("myTopic");
}