簡體   English   中英

Spring Integration JMS創建ActiveMQ隊列而不是主題

[英]Spring Integration JMS creating ActiveMQ queue instead of topic

我正在嘗試使用ActiveMQ代理使用Spring Integration工具將消息傳遞給正在偵聽自動主題的兩個消費者。

這是我的配置Bean(發布者和訂閱者之間的共同點):

@Value("${spring.activemq.broker-url}")
String brokerUrl;

@Value("${spring.activemq.user}")
String userName;

@Value("${spring.activemq.password}")
String password;

@Bean
public ConnectionFactory connectionFactory() {
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
    connectionFactory.setBrokerURL(brokerUrl);
    connectionFactory.setUserName(userName);
    connectionFactory.setPassword(password);
    return connectionFactory;
}

@Bean
public JmsListenerContainerFactory<?> jsaFactory(ConnectionFactory connectionFactory,
        DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setPubSubDomain(true); //!!
    configurer.configure(factory, connectionFactory);
    return factory;
}

@Bean
public JmsTemplate jmsTemplate() {
    JmsTemplate template = new JmsTemplate();
    template.setConnectionFactory(connectionFactory());
    template.setPubSubDomain(true); //!!
    return template;
}

這是供消費者使用的豆類:

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

@Bean(name = "jmsInputFlow")
public IntegrationFlow buildReceiverFlow() {        
    return IntegrationFlows.from(Jms.messageDrivenChannelAdapter(connectionFactory()).destination("myTopic"))
            .channel("jmsInputChannel").get();
}

//Consumes the message.
@ServiceActivator(inputChannel="jmsInputChannel")
public void receive(String msg){
    System.out.println("Received Message: " + msg);
}

這些是生產者的豆子:

@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)容器中使用了一個經紀人,一個生產者和兩個消費者。

我的問題是,雖然我同時在JmsListenerContainerFactoryJmsTemplate上調用了setPubSubDomain(true) ,但我的“主題”卻表現為隊列:一個使用者打印所有的偶數消息,而另一個使用者打印所有的奇數消息。

實際上,通過訪問ActiveMQ Web界面,我看到我的“主題”(即/topics.jsp頁面下)分別命名為ActiveMQ.Advisory.Consumer.Queue.myTopicActiveMQ.Advisory.Producer.Queue.myTopic , “ myTopic”確實出現在隊列頁面(即/queues.jsp)中。

節點按以下順序啟動:

  • AMQ經紀人
  • 消費者1
  • 消費者2
  • 制片人

創建的第一個“主題”是ActiveMQ.Advisory.Consumer.Queue.myTopic ,而生產者顯然只有在生產者開始之后才出現。

我不是ActiveMQ的專家,所以我的生產者/消費者“主題”被命名為“ .Queue”的事實可能會引起誤解。 但是,我確實獲得了官方ActiveMQ文檔中描述的隊列而不是主題所描述的語義。

我也已經看過這個問題 ,但是我所有受雇的頻道都已經屬於PublishSubscribeChannel類型。

我需要實現的是將所有消息傳遞給我的所有(可能> 2個)消費者。

更新:我忘了提一下,我的application.properties文件已經包含spring.jms.pub-sub-domain=true以及其他設置。

另外,我正在使用的Spring Integration版本是4.3.12.RELEASE。

問題是,我仍然獲得了RR負載平衡的語義,而不是發布-訂閱的語義。 至於我在@Hassen Bennour提供的鏈接中看到的內容,我希望在所有主題列表中都有一個ActiveMQ.Advisory.Producer.Topic.myTopicActiveMQ.Advisory.Consumer.Topic.myTopic行。 我以某種方式認為我沒有很好地使用Spring Integration庫,因此,當我要設置主題時,我正在設置隊列。

更新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的咨詢主題,並且實際上只是一個名為myTopic (正如我從主題選項卡中看到的)。 但是,一旦生產者啟動,就會創建一個Producer.Queue咨詢主題,並在不傳遞消息的情況下將消息發送到那里。

在輸入流中選擇適配器似乎決定了要創建哪種類型的咨詢消費者主題Jms.publishSubscribeChannel()Jms.messageDrivenChannelAdapter()切換到Jms.publishSubscribeChannel()時,主題與隊列)。 但是,我無法找到類似於輸出流的東西。

更新3 :由於@Hassen Bennour,問題已解決。 概括:

我有線的jmsTemplate()在生產者的Jms.outboundAdapter()

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

使用者Jms.messageDrivenChannelAdapter()配置更為復雜:

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

盡管可能是最流暢,最靈活的方法,但是擁有這樣的bean ...

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

有線作為適配器的目標,而不僅僅是字符串。

再次感謝。

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

要么

@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;
}

ActiveMQ.Advisory.Consumer.Queue.myTopic是名為myTopic的隊列的咨詢主題,請在此處閱讀有關咨詢的http://activemq.apache.org/advisory-message.html

更新:

如下更新您的定義

@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();
}

或將“目標”定義為主題,並用“目標”(topic())替換“目標”(“ myTopic”)

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM