Java Spring集成JMS创建ActiveMQ队列而不是主题
我正在尝试使用ActiveMQ代理,使用Spring集成工具,向两个侦听自动主题的消费者传递消息 以下是我的配置bean(发布者和订阅者之间的共同点): 以下是制作人的菜豆: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
@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
,实际上是一个名为justmyTopic
的主题(正如我可以从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");
}