簡體   English   中英

如何在兩個應用程序之間發布/訂閱JMS消息?

[英]How to publish/subscribe JMS message between two applications?

我有兩個Java獨立應用程序。 我想從一個應用程序發送消息,並由兩個客戶端異步接收消息:一個客戶端與發送者位於同一應用程序中。 另一個在不同的應用程序中。 兩者都與ActiveMQ代理連接。 但是我只能看到第一個客戶端收到了消息,而另一個沒有收到消息。 通過JMS連接兩個應用程序的一般方法是什么? 我認為對於JMS,我必須有一些不清楚的概念。 我環顧四周,但不知道如何設置Spring bean配置文件以在兩個Java應用程序之間發布/訂閱消息。

這是我在第一個應用程序中的發送者的Bean配置文件,也是在同一應用程序中的第一個偵聽器的Bean:

<bean id="customerMessageSender" class="com.example.message.CustomerStatusSender">
    <property name="jmsTemplate" ref="jsmTemplateBean" />
    <property name="topic" ref="topicBean" />
</bean>

<bean id="jsmTemplateBean" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactoryBean"/>
    <property name="pubSubDomain" value="true"/>
</bean>

<bean id="topicBean" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="CustomerStatusTopic" />
</bean>

<bean id="connectionFactoryBean" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="tcp://localhost:61616" />
</bean>

<bean id="customerStatusListener" class="com.example.message.CustomerStatusListener" />


<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactoryBean" />
    <property name="destination" ref="topicBean" />
    <property name="messageListener" ref="customerStatusListener" />
</bean>

這是第二個偵聽器的Bean配置文件,該文件位於另一個應用程序中:

<bean id="topicBean" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="CustomerStatusTopic" />
</bean>

<bean id="connectionFactoryBean" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="tcp://localhost:61616" />
</bean>

<bean id="anotherCustomerStatusListener" class="com.mydomain.jms.CustomerStatusMessageListener" />

<bean id="listenerContainer"
    class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="connectionFactoryBean" />
    <property name="destination" ref="topicBean" />
    <property name="messageListener" ref="anotherCustomerStatusListener" />
</bean> 

如您所見, customerStatusListener bean和anotherCustomerStatusListener bean都訂閱topicBean 但是,只有第一個偵聽器會收到消息,因為它與發送者在同一個應用程序中,而第二個則沒有。 通過JMS連接兩個Java應用程序,以便可以在兩個單獨的應用程序之間發送/接收消息的一般原理是什么?

編輯:我不能在第一個XML文件中添加以下偵聽器bean,因為類CustomerStatusMessageListener在另一個應用程序中,因此在第一個(發送者)應用程序的類路徑中不可見。

<bean id="anotherCustomerStatusListener" class="com.mydomain.jms.CustomerStatusMessageListener" />

再次編輯:以下是第二個應用程序中的第二個偵聽器,它與第一個應用程序是分開的。 它包含一個實例化偵聽器bean的main方法(jms-beans.xml是上面列出的第二個偵聽器的bean配置文件)。

public class CustomerStatusMessageListener implements MessageListener {
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println("Subscriber 2 got you! The message is: "
                        + ((TextMessage) message).getText());
            } catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        } else {
            throw new IllegalArgumentException(
                    "Message must be of type TextMessage");
        }
    }

    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("jms-beans.xml");
        CustomerStatusMessageListener messageListener = (CustomerStatusMessageListener) context.getBean("anotherCustomerStatusListener");
        context.close();
    }
}

您對JMS的理解是正確的。 如果您希望兩個偵聽器都收到相同的消息,則可以通過主題來實現。 一個偵聽器是否與發送者在同一虛擬機上運行而另一個偵聽器不在同一虛擬機上運行則無關緊要。 沒有看到您的代碼,您的Spring配置看起來也正確。 剩下的事情需要檢查:

  • 兩個偵聽器是否都在同一主機上運行? 也就是說, localhost是其中一個偵聽器的位置,而另一個偵聽器的位置是不同的位置嗎?
  • 發送消息時,第二個偵聽器是否正在運行? 如果發送消息時您的第二個偵聽器未處於活動狀態,則它將看不到它是否稍后開始,除非您使用的是持久性主題並且您的訂戶已至少連接到代理一次。

根據您的評論,第二項是您遇到問題的地方。

博客文章介紹了如何設置持久性主題(如果需要消息通過代理重新啟動來持久化,則持久化消息)。 基本上,將此配置添加到您的消息偵聽器:

<property name="subscriptionDurable" value="true">
<property name="clientId" value="Some_unique_id">
<property name="durableSubscriptionName" value="Some_unique_id">

每個訂戶的客戶端ID和持久訂閱名稱必須不同,因此您的第一個偵聽器將具有以下內容:

<bean id="listenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactoryBean" />
        <property name="destination" ref="topicBean" />
        <property name="messageListener" ref="anotherCustomerStatusListener" />
        <property name="subscriptionDurable" value="true">
        <property name="clientId" value="listener1">
        <property name="durableSubscriptionName" value="listener1">
</bean> 

第二個應該具有:

      <bean id="listenerContainer"
           class="org.springframework.jms.listener.DefaultMessageListenerContainer">
           <property name="connectionFactory" ref="connectionFactoryBean" />
           <property name="destination" ref="topicBean" />
           <property name="messageListener" ref="anotherCustomerStatusListener" />
           <property name="subscriptionDurable" value="true">
           <property name="clientId" value="listener2">
           <property name="durableSubscriptionName" value="listener2">
       </bean> 

請注意,您必須至少啟動一次第二個偵聽器才能在代理中注冊自己,以便代理知道其clientId並為其存儲消息,但是您可以將其關閉並稍后啟動以獲取在其丟失的任何消息。下。

如果您的偵聽器在高容量系統上長時間處於關閉狀態,則代理將為其存儲所有消息,這最終可能會填滿磁盤或使代理變慢。 請參閱ActiveMQ文檔以自動刪除持久消息

暫無
暫無

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

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