給女朋友講ActiveMQ是啥?

歐陽思海發表於2019-08-20

1 ActiveMQ是啥

ActiveMQ 就是一個訊息中介軟體,市面上現在有很多的訊息中介軟體開源產品,比如,RocketMQ、RabbitMQ、Kafka等。

拿一個簡單的比喻來說,訊息中介軟體就是一箇中轉站,在程式中加的一箇中轉站,有了這樣一個類似快遞的儲存站點,可以大大的減輕物流的壓力,而對應到程式中,也就是減輕了程式的壓力。

另外不得不說的是,ActiveMQ是遵從 JMS 規範的訊息中介軟體,那麼什麼是 JMS 規範呢?

JMS 規範

JMS是java的訊息服務,JMS的客戶端之間可以通過JMS服務進行非同步的訊息傳輸。

訊息模型

  • Point-to-Point(P2P),點對點
  • P2P模式圖

圖片.png

如上圖,有幾個需要了解的概念,傳送者、接收者、訊息佇列

在點對點模型中,一般訊息由傳送者將訊息傳送到訊息佇列中,然後,接收者從訊息佇列中消費訊息,訊息被消費者消費之後,訊息就不存在了。

  • Publish/Subscribe(Pub/Sub),釋出訂閱模型
  • Pub/Sub模式圖

如上圖,有下面幾個概念,主題、釋出者、訂閱者

釋出訂閱模型中,釋出者通常將訊息釋出到主題(topic)中,然後,訂閱者通過訂閱主題來消費訊息,與 P2P 模型不同的是,釋出訂閱模型的訊息是可以被多次消費的!

兩種模式的區別

1、P2P在傳送者和接收者之間沒有時間上的依賴性,也就是說傳送者傳送了訊息之後,不管接收者有沒有執行,不會影響訊息傳送到佇列,而Pub/Sub模式有時間上的依賴性,消費者必須先訂閱主題,才能夠消費訊息。
2、P2P模式的每個訊息只能有一個消費者,消費完了訊息就不存在了,Pub/Sub模式可以有多個消費者。

2 為什麼需要使用訊息中介軟體

到這裡我就不得不講一個小故事了!

小明、小李和小白都是在一個專案組的 Java 開發人員,但是呢,他們的團隊比較小,只有幾個開發人員,而他們正在開發一個專案,這個專案比較龐大,所以,專案負責人就考慮到專案進度,給他們每個人都分一個模組單獨開發,這樣就能夠加快專案的進度了。

圖片.png

然而,萬萬沒有想到的是,當專案開發到一定階段的時候,小明、小李和小白各自負責的模組都需要專案呼叫資料了,但是呢,現在問題來了,每次小白小明需要資料的時候,小明總是要改介面來滿足小白的需求,而且還會擔心小明的系統會不會出問題,如果出了問題就呼叫不了怎麼辦?這樣就總是耽誤專案的進度,小李那邊也是出現了這種問題!

圖片.png

於是,小明就想了個辦法,如果在各個模組之間再加一個模組,用來處理資料,比如一個佇列來存資料,每次就把資料丟到那個模組中去,這樣就不用擔心那個問題啦。小明是不是很聰明!

其實,小明沒有做足夠的調查,他說的這個模組,就是 ActiveMQ 的作用所在啦。

也就是降低模組與模組之間的耦合度,達到解耦的目的!

然後,他們又遇到了一個問題,他們在開發一個使用者註冊模組的時候,是先註冊,然後寫入資料庫,然後再傳送郵件或者簡訊通知使用者,但是,他們發現這樣的系統速度很慢!

後來,他們發現了訊息中介軟體後,改造了一下,變成了下面的模式。

他們也發現了,這就是訊息中介軟體帶來的非同步執行的優勢!
系統速度槓槓的!

後來,小明、小李和小白開發的系統呢上線了,但是,公司業快速發展,當流量大的時候,系統的資料呼叫總是負荷不了,出現當機的問題,沒辦法,只能再改程式碼了!

他們靈機一動,前面都用了訊息中介軟體了,但是沒有發現另外一個功能,我們可以加入訊息中介軟體,控制每次消費訊息的數量,保證系統不會當機,剩下的訊息在系統流量小的時候再定時執行不就可以了。簡直不要太好!

小明、小李和小白經過這個系統的開發,終於明白了訊息中介軟體的優勢了!

3 安裝使用

3.1 下載

到下面的官網地址下載,包括linux和Windows的不同版本。

3.2 解壓使用

windows使用方法

首先,解壓到一個自己的目錄,ActiveMQ目錄如下;

進入到對應的 bin 目錄;

裡面有一個 activemq 的可執行檔案,開啟 cmd,執行:activemq start

成功啟動了!

關閉;

activemq stop
linux 使用方法

解壓到指定目錄;

sudo tar zxvf activemq-x.x.x-bin.tar.gz

進入到 bin 目錄,執行下面命令;

./activemq start

關閉;

./activemq stop
後臺管理介面

啟動成功之後,可以輸出http://localhost:8161/admin/檢視 ActiveMQ 的後臺管理介面,使用者名稱和密碼都為 admin

ok,到這裡,ActiveMQ的安裝和基本使用應該沒有問題了,接下來,我們使用 ActiveMQ 的 Java API 從一個入門例項開始講起!

4 ActiveMQ入門程式

4.1 前提條件

在開始之前,先申明一下需要的 Java 環境的配置,相關配置自行解決哦!

  • Java JDK1.7 以上
  • Maven 3.0 以上
  • 開發工具 IDEA

4.2 帶你入門

step1:匯入 Maven 相關依賴;

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.10.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-all</artifactId>
            <version>5.15.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
    </dependencies>

step2:建立傳送端類;

/**
 * @ClassName JmsSender
 * @Description
 * @Author 歐陽思海
 * @Date 2019/8/13 16:39
 * @Version 1.0
 **/
public class JmsSender {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = null;
        try {
            connection = connectionFactory.createConnection();
            connection.start();

            Session session = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);
            Destination destination = session.createQueue("queue");
            MessageProducer producer = session.createProducer(destination);
            TextMessage textMessage = session.createTextMessage("hello activemq");
            producer.send(textMessage);

            //session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

上面的程式碼建立了一個訊息傳送者,步驟如下:
1、建立ActiveMQ實現的JMS規範的實現類ActiveMQConnectionFactory的物件connectionFactory ,並且給定引數ActiveMQ的服務地址;
2、由connectionFactory呼叫方法createConnection建立連線connection物件;
3、由connection物件呼叫createSession方法建立session會話物件;
4、有了session物件之後,就可以傳送者、佇列或者主題了,這裡建立佇列,session.createQueue("queue"),並給定了佇列名稱為queue
5、session物件通過方法createProducer建立生產者,並且建立訊息session.createTextMessage("hello activemq")
6、生產者呼叫send的方法傳送訊息,producer.send(textMessage)

通過上面的步驟就可以將訊息傳送到佇列中了,接著只要等待消費者消費訊息即可,訊息消費後,訊息就消失了。

通過上面的講解,也將JMS的主要的介面都概括了,包括:ConnectionFactory(連線工廠)、Session(會話)、Connection(連線)

step3:建立消費端類;

/**
 * @ClassName JmsReceiver
 * @Description
 * @Author 歐陽思海
 * @Date 2019/8/13 16:47
 * @Version 1.0
 **/
public class JmsReceiver {
    public static void main(String[] args) {
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = null;
        try {
            //建立連線
            connection = connectionFactory.createConnection();
            connection.start();

            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);

            //建立佇列(如果佇列已經存在則不會建立,queue是佇列名稱)
            //destination表示目的地
            Destination destination = session.createQueue("queue");
            //建立訊息接收者
            MessageConsumer consumer = session.createConsumer(destination);

            TextMessage textMessage = (TextMessage) consumer.receive();
            System.out.println(textMessage.getText());
            session.commit();
            session.close();
        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消費者和生產者的差別不大,前面的建立工廠、建立連線、建立會話物件和生產者一樣,區別在於,session.createConsumer(destination)通過session建立消費者,然後,呼叫receive方法接受訊息。

執行傳送端,檢視後臺管理介面,點選 Queues 選項,發現有一個入隊的訊息,並且沒有出佇列

執行接收端

再檢視後臺管理介面,訊息被消費了;

5 ActiveMQ整合Spring

這一部分花了挺多時間琢磨的,首先是應為在實際的開發中,我們整合Spring來開發專案是最多的一種方式,這一塊如果可以學透的話,對於專案開發是非常有好處的,出於這個出發點,儘可能的把相關的知識講解的全面一些。

首先,這一部分分為以下三個部分來講解。

  • 不使用 Spring 配置檔案方式
  • 使用 Spring 配置檔案方式
  • 註解方式(0配置)

5.1 前提條件

  1. JDK 1.7 以上
  2. Maven 3.0 以上
  3. Spring 4.3.1 ,或者以上版本
  4. ActiveMQ 5.15.9 目前最新穩定版本

專案結構
這次搭建的專案是一個子模組聚合的專案,結構如下;

這個聚合的專案分為生產者(Producer)消費者(Consumer)兩個子模組。

匯入 Maven 依賴

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.10.RELEASE</spring.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.activemq</groupId>
                <artifactId>activemq-all</artifactId>
                <version>5.15.9</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jms</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
                <version>2.6.2</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
溫馨提示
由於我這裡使用的是子模組聚合的方式,所以,如果你不是這種方式的專案,直接給出各個依賴的版本在你的專案中即可!

5.2 不使用 Spring 配置檔案方式

這一節的講解中,我們將採用不使用 Spring 的配置檔案的方式,Maven 的相關依賴在上面已經給出,請參考上一節的內容。

生產者(Producer)

首先,我們來看一下生產者端,生產者端主要負責傳送訊息到 Broker 中,傳送的目的地(Destination)可以分為佇列(Queue)主題(Topic),下面,我們就看看如何不採用 Spring 配置檔案的方式傳送訊息

public static void main(String[] args) {
        ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = null;
        try {
            connection = cf.createConnection();
            connection.start();

            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
            Queue destination = session.createQueue("queue2");

            JmsQueueSenderWithNotXml jmsQueueSender = new JmsQueueSenderWithNotXml();
            jmsQueueSender.setConnectionFactory(cf);
            jmsQueueSender.setQueue(destination);
            jmsQueueSender.simpleSend();
            jmsQueueSender.sendWithConversion();
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

    private JmsTemplate jmsTemplate;
    private Queue queue;

    public void setConnectionFactory(ConnectionFactory cf) {
        this.jmsTemplate = new JmsTemplate(cf);
    }

    public void setQueue(Queue queue) {
        this.queue = queue;
    }

    /*
     * @Author 歐陽思海
     * @Description  傳送簡單訊息
     * @Date 15:45 2019/8/16
     * @Param []
     * @return void
     **/
    public void simpleSend() {
        this.jmsTemplate.send(this.queue, new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
                return session.createTextMessage("hello queue world");
            }
        });
        System.out.println("傳送成功!");
    }

    /*
     * @Author 歐陽思海
     * @Description  傳送map型別的訊息
     * @Date 15:46 2019/8/16
     * @Param []
     * @return void
     **/
    public void sendWithConversion() {
        Map map = new HashMap();
        map.put("Name", "sihai");
        map.put("Age", new Integer(18));
        jmsTemplate.convertAndSend("Queue3", map, new MessagePostProcessor() {
            public Message postProcessMessage(Message message) throws JMSException {
                message.setIntProperty("num", 189);
                message.setJMSCorrelationID("00001");
                return message;
            }
        });
        System.out.println("傳送成功!");
    }

step1:上面是生產者端的所有程式碼示例,在這個示例中,我們首先通過下面的程式碼設定好ConnectionFactory 和Queue,並且呼叫JmsTemplateSpring提供的工具類提供兩個傳送訊息的方法 。

    private JmsTemplate jmsTemplate;
    private Queue queue;

    public void setConnectionFactory(ConnectionFactory cf) {
        this.jmsTemplate = new JmsTemplate(cf);
    }

    public void setQueue(Queue queue) {
        this.queue = queue;
    }

    /*
     * @Author 歐陽思海
     * @Description  傳送簡單訊息
     * @Date 15:45 2019/8/16
     * @Param []
     * @return void
     **/
    public void simpleSend() {
        this.jmsTemplate.send(this.queue, new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
                return session.createTextMessage("hello queue world");
            }
        });
        System.out.println("傳送成功!");
    }

    /*
     * @Author 歐陽思海
     * @Description  傳送map型別的訊息
     * @Date 15:46 2019/8/16
     * @Param []
     * @return void
     **/
    public void sendWithConversion() {
        Map map = new HashMap();
        map.put("Name", "sihai");
        map.put("Age", new Integer(18));
        jmsTemplate.convertAndSend("Queue3", map, new MessagePostProcessor() {
            public Message postProcessMessage(Message message) throws JMSException {
                message.setIntProperty("num", 189);
                message.setJMSCorrelationID("00001");
                return message;
            }
        });
        System.out.println("傳送成功!");
    }

step2:使用Main方法,設定ConnectionFactory和Queue物件,接著,呼叫傳送方法傳送訊息。

public static void main(String[] args) {
        ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
        Connection connection = null;
        try {
            connection = cf.createConnection();
            connection.start();

            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
            Queue destination = session.createQueue("queue2");

            JmsQueueSenderWithNotXml jmsQueueSender = new JmsQueueSenderWithNotXml();
            jmsQueueSender.setConnectionFactory(cf);
            jmsQueueSender.setQueue(destination);
            jmsQueueSender.simpleSend();
            jmsQueueSender.sendWithConversion();
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

step2:接著,我們執行上面的程式碼,輸出下面結果,再看一下ActiveMQ的控制檯,看看有沒有訊息傳送成功。

發現有一條掛起的訊息和入佇列的訊息,說明傳送成功!

消費者(Consumer)

對於消費者,在這一節先不展開講解,可以先參考上面的入門程式的消費端的程式碼消費訊息,接下來的方式再講解消費端的消費訊息。

5.3 使用 Spring 配置檔案方式

上面一節中,講解了不使用 Spring 配置的方式如何傳送訊息,主要是想讓大家瞭解一下其中的原理,這一節中,將使用 Spring 配置的方式講解,這種方式在實際的開發中還是用的比較多的。

生產者(Producer)

既然是配置檔案的方式,那麼,首先,不得不講如何進行xml配置了。

step1:xml配置檔案

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/jms https://www.springframework.org/schema/jms/spring-jms.xsd">

    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
        <property name="connectionFactory">
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">
                <property name="brokerURL">
                    <value>tcp://localhost:61616</value>
                </property>
            </bean>
        </property>
        <property name="maxConnections" value="50"/>
    </bean>

    <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg index="0" value="spring-queue"/>
    </bean>

    <!--<bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg index="0" value="spring-topic"/>
    </bean>-->

    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="destination"/>
        <property name="messageConverter">
            <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
        </property>
    </bean>

</beans>

在上面的配置中,首先,需要配置connectionFactory(對應不使用配置的connectionFactory物件),然後,需要配置destination(對應不使用配置的destination),在這裡使用的是向佇列傳送訊息,也可以使用主題(Topic),最後,配置 Spring 提供的jmsTemplate模板類。

step2:使用Main方法執行

public static void main(String[] args) {
        ApplicationContext application = new FileSystemXmlApplicationContext("G:\\ideaproject\\activemq\\Producer\\src\\main\\resources\\service-jms.xml");
        JmsTemplate jmsTemplate = (JmsTemplate) application.getBean("jmsTemplate");
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            jmsTemplate.send((session) -> {
                TextMessage textMessage = session.createTextMessage();
                textMessage.setText("first message" + finalI);
                return textMessage;
            });
        }
    }

在上面的程式碼中,呼叫了JmsTemplatesend方法傳送訊息。執行之後,就成功傳送訊息了,這種方式還是簡潔不少的。

溫馨提示
上面我使用的是FileSystemXmlApplicationContext獲取xml配置檔案,除此之外,你也可以使用ClassPathXmlApplicationContext來獲取。
消費者(Consumer)

在上一節中,沒有講解消費者,在這一節中,將重點講解。

step1:首先,我們還是需要配置xml檔案

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:amq="http://activemq.apache.org/schema/core"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd">

    <!--連線工廠-->
    <bean id="connectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
        <property name="connectionFactory">
            <bean class="org.apache.activemq.ActiveMQConnectionFactory">
                <property name="brokerURL">
                    <value>tcp://localhost:61616</value>
                </property>
            </bean>
        </property>
        <property name="maxConnections" value="50"/>
    </bean>

    <!--配置佇列-->
    <bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg index="0" value="queue2"/>
    </bean>

<!--    配置主題(topic)-->
    <!-- <bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
         <constructor-arg index="0" value="spring-topic"/>
     </bean>-->

    <!--配置spring的jms模板-->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="destination"/>
        <property name="messageConverter">
            <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
        </property>
    </bean>

    <!-- 訊息監聽器 -->
    <!--<bean id="messageListener" class="com.sihai.activemq.listener.MyMessageListener"/>-->
    <bean id="messageListener" class="com.sihai.activemq.listener.MySessionAwareMessageListener"></bean>

    <!--jta事務-->
    <!--<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>-->

    <!-- 訊息監聽器容器 -->
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="messageListener"/>
        <!--配置本地資源事務-->
        <!--<property name="sessionTransacted" value="true"/>-->
        <!--配置jta事務-->
        <!--<property name="transactionManager" ref="transactionManager"/>-->
    </bean>

    <!--&lt;!&ndash; 監聽註解支援 &ndash;&gt;
    <jms:annotation-driven />-->

</beans>

最前面的配置和生產者是一樣的,需要配置connectionFactory(對應不使用配置的connectionFactory物件),然後,需要配置destination(對應不使用配置的destination)。

區別在於,消費者端需要配置一個訊息監聽器容器,如下。

<!-- 訊息監聽器 -->
    <!--<bean id="messageListener" class="com.sihai.activemq.listener.MyMessageListener"/>-->
    <bean id="messageListener" class="com.sihai.activemq.listener.MySessionAwareMessageListener"></bean>

    <!--jta事務-->
    <!--<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>-->

    <!-- 訊息監聽器容器 -->
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="messageListener"/>
        <!--配置本地資源事務-->
        <!--<property name="sessionTransacted" value="true"/>-->
        <!--配置jta事務-->
        <!--<property name="transactionManager" ref="transactionManager"/>-->
    </bean>

那麼這個怎麼配置呢?請接著看。

step2:訊息監聽器容器配置
首先,我們需要寫一個類,實現MessageListener介面,然後實現一個名為onMessage的方法,通過這個方法就可以監聽是否有訊息,有訊息就消費

/**
 * @ClassName MyMessageListener
 * @Description 訊息消費監聽器實現
 * @Author 歐陽思海
 * @Date 2019/8/13 20:39
 * @Version 1.0
 **/
@Component
public class MyMessageListener implements MessageListener {

    @Override
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }
            catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }
    }
}

如此,配置就完成了。

step3:啟動spring容器,執行。

/*
     * @Author 歐陽思海
     * @Description  xml配置方式獲取訊息
     * @Date 18:09 2019/8/16
     * @Param []
     * @return void
     **/
    @Test
    public void test_01() throws IOException {
        ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("G:\\ideaproject\\activemq\\Consumer\\src\\main\\resources\\service-jms.xml");
        /*JmsTemplate jmsTemplate = (JmsTemplate) application.getBean("jmsTemplate");
        String msg = (String) jmsTemplate.receiveAndConvert();
        System.out.println(msg);*/
        System.in.read();
    }

在上面的程式碼中,System.in.read(),這個作用就是一直等待,有訊息就消費。

step4:開啟訊息監聽器事務
在訊息處理的過程中是可以開啟事務的,如果出現處理失敗的情況,就會回滾。在訊息監聽容器當中可以配置一個屬性是sessionTransacted的本地事務,如果valuetrue,就代表開啟本地事務。具體配置如下:

<!-- 訊息監聽器容器 -->
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="messageListener"/>
        <!--配置本地資源事務-->
        <property name="sessionTransacted" value="true"/>        
    </bean>
訊息監聽器容器

上面的消費者的講解中,其實,最重要的就是訊息監聽器容器配置了,這一部分,我們就詳細的講解一下訊息監聽器容器的配置方法。

1 實現MessageListener介面
這種方式就是上面的例項使用的方式,先看看這個介面。

public interface MessageListener {
    void onMessage(Message var1);
}

這個介面很簡單,只有一個方法onMessage,通過拿到Message引數讀取訊息,這裡就不再多說了。

2 實現SessionAwareMessageListener介面
這個介面平時很少用到,但是,其實是有這個介面可以實現的,這個介面和上面的MessageListener介面有點不一樣,這個介面是Spring提供的。

public interface SessionAwareMessageListener<M extends Message> {
    void onMessage(M var1, Session var2) throws JMSException;
}

另外,你可以看到,這個介面提供的是一個泛型介面,可以是M extends Message這個型別,同時,實現的方式onMessage,還多了一個Session引數,可以在獲取訊息的同時處理Session

使用例項

/**
 * @ClassName MySessionAwareMessageListener
 * @Description 實現SessionAwareMessageListener的訊息監聽器
 * @Author 歐陽思海
 * @Date 2019/8/16 16:02
 * @Version 1.0
 **/
public class MySessionAwareMessageListener implements SessionAwareMessageListener {
    @Override
    public void onMessage(Message message, Session session) throws JMSException {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }
            catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }
    }
}

5.4 註解方式(0配置)

前面已經介紹了兩種方式,分別是不使用xml配置方式使用xml配置的方式,但是,由於現在微服務的興起,約定優於配置是現在的一種趨勢,所以,在這一節中,我們使用註解的方式來處理。

生產者(Producer)

由於使用註解的方式,所以,我們不再需要xml配置檔案了,但是,我們可以參照上面的xml的配置方式來配置註解的方式。

step1:首先,我們需要一個 Java 配置類,如下;

/**
 * @ClassName ProducerConfig
 * @Description 不用xml的配置類
 * @Author 歐陽思海
 * @Date 2019/8/16 17:41
 * @Version 1.0
 **/
@Configuration
public class ProducerConfig {

    @Bean
    //配置ConnectionFactory用於生成connection
    public ActiveMQConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory activeMQConnectionFactory
                = new ActiveMQConnectionFactory("tcp://localhost:61616");
        return activeMQConnectionFactory;
    }

    @Bean
    //註冊SingleConnectionFactory,這個spring的一個包裝工廠 用於管理真正的ConnectionFactory
    public SingleConnectionFactory singleConnectionFactory(ActiveMQConnectionFactory activeMQconnectionFactory) {
        SingleConnectionFactory connectionFactory = new SingleConnectionFactory();
        //設定目標工廠
        connectionFactory.setTargetConnectionFactory(activeMQconnectionFactory);
        return connectionFactory;
    }

    @Bean
    //配置生產者,jmsTemplate
    public JmsTemplate jmsTemplate(SingleConnectionFactory connectionFactory) {
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(connectionFactory);
        return jmsTemplate;
    }

    /**
     * 配置佇列目的的: 根據測試需要配置其中一個
     * 1.佇列  點對點 queue
     * 2.主題  一對多  topic
     */
    @Bean //
    public ActiveMQQueue queueDestination() {
        ActiveMQQueue activeMQQueue = new ActiveMQQueue("queue-anno");
        return activeMQQueue;
    }

    @Bean
    public ActiveMQTopic topicDestination() {
        ActiveMQTopic activeMQTopic = new ActiveMQTopic("topic-anno");
        return activeMQTopic;
    }
}

上面的配置的每一個方法就對應xml配置的每一個節點,對應起來配置會比較簡單,每一個方法都使用了@Bean這個註解,類上使用Configuration,將這些配置加入到 spring 容器中。

step2:啟動 spring 容器,傳送訊息;

/**
 * @ClassName JmsSenderWithAnnotation
 * @Description 註解傳送方式
 * @Author 歐陽思海
 * @Date 2019/8/16 18:04
 * @Version 1.0
 **/
public class JmsSenderWithAnnotation {

    /*
     * @Author 歐陽思海
     * @Description  測試點對點
     * @Date 18:05 2019/8/16
     * @Param []
     * @return void
     **/
    @Test
    public void testActiveMqAnnotation() {
        AnnotationConfigApplicationContext aContext =
                new AnnotationConfigApplicationContext(ProducerConfig.class);

        //獲得傳送者的模板物件
        JmsTemplate jmsTemplate = aContext.getBean(JmsTemplate.class);
        Destination bean = (Destination) aContext.getBean("queueDestination");

        //傳送訊息
        jmsTemplate.send(bean, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText("activemq message for queue");
                return message;
            }
        });
    }

    /*
     * @Author 歐陽思海
     * @Description  測試topic傳送
     * @Date 18:06 2019/8/16
     * @Param []
     * @return void
     **/
    @Test
    public void testActiveMqAnnotation2() {
        AnnotationConfigApplicationContext aContext =
                new AnnotationConfigApplicationContext(ProducerConfig.class);
        //獲得傳送者的模板物件
        JmsTemplate jmsTemplate = aContext.getBean(JmsTemplate.class);

        Destination bean = (Destination) aContext.getBean("topicDestination");

        //傳送訊息
        jmsTemplate.send(bean, new MessageCreator() {
            @Override
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText("activemq message for topic");
                return message;
            }
        });
    }
}

分別執行這兩個測試,檢視ActiveMQ控制檯,發現Queue和Topic都有一條訊息傳送成功;

消費者(Consumer)

消費者的大概也差不多,跟xml的配置一樣,多的也是訊息監聽容器的配置,來看看;

step1:首先,Java 配置類

**
 * @ClassName ConsumerConfig
 * @Description 不用xml的配置類
 * @Author 歐陽思海
 * @Date 2019/8/16 17:44
 * @Version 1.0
 **/
@ComponentScan(basePackages = {"com.sihai"})
@EnableJms
@Configuration
public class ConsumerConfig {

    @Bean
    //配置ConnectionFactory用於生成connection
    public ActiveMQConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory activeMQConnectionFactory
                = new ActiveMQConnectionFactory("tcp://localhost:61616");
        return activeMQConnectionFactory;
    }

    @Bean
    //註冊SingleConnectionFactory,這個spring的一個包裝工廠 用於管理真正的ConnectionFactory
    public SingleConnectionFactory singleConnectionFactory(ActiveMQConnectionFactory activeMQconnectionFactory) {
        SingleConnectionFactory connectionFactory = new SingleConnectionFactory();
        //設定目標工廠
        connectionFactory.setTargetConnectionFactory(activeMQconnectionFactory);
        return connectionFactory;
    }


    /*在xml當中的如下配置 效果相同
     * <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
     *        <property name="connectionFactory" ref="connectionFactory" />
     *        <property name="destination" ref="topicDestination" />
     *        <property name="messageListener" ref="itemListenerMessage" />
     *    </bean>
     **/
    @Bean
    public DefaultMessageListenerContainer jmsListenerContainerFactory(SingleConnectionFactory singleConnectionFactory, MyMessageListener myMessageListener, Destination destination) {
        //建立容器
        DefaultMessageListenerContainer jmsContainer = new DefaultMessageListenerContainer();
        //設定監聽器
        jmsContainer.setMessageListener(myMessageListener);
        //設定連線工廠
        jmsContainer.setConnectionFactory(singleConnectionFactory);
        //設定監聽目的地的名字/也可以直接設定物件目的地
        jmsContainer.setDestination(destination);
        return jmsContainer;
    }

    /**
     * 1.佇列  點對點 queue
     * 2.主題  一對多  topic
     */
    @Bean
    public ActiveMQQueue queueDestination() {
        ActiveMQQueue activeMQQueue = new ActiveMQQueue("queue-anno");
        return activeMQQueue;
    }

    /*@Bean
    public ActiveMQTopic topicDestination() {
        ActiveMQTopic activeMQTopic = new ActiveMQTopic("topic-anno");
        return activeMQTopic;
    }*/
}

其中只有一個訊息監聽容器的配置是和生產者的配置不同的訊息監聽容器的配置需要配置訊息監聽器、連線工廠和目的地(Destination)

 /*在xml當中的如下配置 效果相同
     * <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
     *        <property name="connectionFactory" ref="connectionFactory" />
     *        <property name="destination" ref="topicDestination" />
     *        <property name="messageListener" ref="itemListenerMessage" />
     *    </bean>
     **/
    @Bean
    public DefaultMessageListenerContainer jmsListenerContainerFactory(SingleConnectionFactory singleConnectionFactory, MyMessageListener myMessageListener, Destination destination) {
        //建立容器
        DefaultMessageListenerContainer jmsContainer = new DefaultMessageListenerContainer();
        //設定監聽器
        jmsContainer.setMessageListener(myMessageListener);
        //設定連線工廠
        jmsContainer.setConnectionFactory(singleConnectionFactory);
        //設定監聽目的地的名字/也可以直接設定物件目的地
        jmsContainer.setDestination(destination);
        return jmsContainer;
    }

step2:訊息監聽器

/**
 * @ClassName MyMessageListener
 * @Description 訊息消費監聽器實現
 * @Author 歐陽思海
 * @Date 2019/8/13 20:39
 * @Version 1.0
 **/
@Component
public class MyMessageListener implements MessageListener {

    @Override
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }
            catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }
    }
}

這個前面已經講過了,這裡就不再累贅了,但是,這裡我需要講的是訊息監聽器註解方式的配置,如下。

step3:訊息監聽器註解方式的配置方法

/**
 * @ClassName JmsAnnotation
 * @Description 註解方式監聽
 * @Author 歐陽思海
 * @Date 2019/8/16 17:01
 * @Version 1.0
 **/
@Component
@EnableJms
public class JmsAnnotation {

    @JmsListener(destination = "queue-anno")
    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }
            catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }
    }
}

你會發現,在訊息監聽器的類上面需要兩個配置@Component和@EnableJms,用於標記這是一個訊息監聽器,另外,在onMessage方法上,需要一個@JmsListener(destination = "queue-anno")註解,可以標記需要哪個destination

注意:如果採用註解的訊息監聽,那麼需要修改Java類的訊息監聽的容器的配置,否則會出現問題

step4:訊息監聽容器配置更改

 /*在xml當中的如下配置 效果相同
     * <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
     *        <property name="connectionFactory" ref="connectionFactory" />
     *        <property name="destination" ref="topicDestination" />
     *        <property name="messageListener" ref="itemListenerMessage" />
     *    </bean>
     **/
    @Bean
    public DefaultMessageListenerContainer jmsListenerContainerFactory(SingleConnectionFactory singleConnectionFactory, MyMessageListener myMessageListener, Destination destination) {
        //建立容器
        DefaultMessageListenerContainer jmsContainer = new DefaultMessageListenerContainer();
        //設定監聽器
        jmsContainer.setMessageListener(myMessageListener);
        //設定連線工廠
        jmsContainer.setConnectionFactory(singleConnectionFactory);
        //設定監聽目的地的名字/也可以直接設定物件目的地
        jmsContainer.setDestination(destination);
        return jmsContainer;
    }

改為

 @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory());
//        factory.setDestinationResolver(destinationResolver());
        factory.setSessionTransacted(true);
        factory.setConcurrency("3-10");
        return factory;
    }

上面的修改會發現,實現介面的監聽器使用的是DefaultMessageListenerContainer,而註解的方式使用的是DefaultJmsListenerContainerFactory,所以,這裡需要特別注意。

此時,訊息監聽器是註解的方式的Java配置類就是下面這樣的。

/**
 * @ClassName ConsumerConfig
 * @Description 不用xml的配置類
 * @Author 歐陽思海
 * @Date 2019/8/16 17:44
 * @Version 1.0
 **/
@ComponentScan(basePackages = {"com.sihai"})
@EnableJms
@Configuration
public class ConsumerConfig {

    @Bean
    //配置ConnectionFactory用於生成connection
    public ActiveMQConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory activeMQConnectionFactory
                = new ActiveMQConnectionFactory("tcp://localhost:61616");
        return activeMQConnectionFactory;
    }

    @Bean
    //註冊SingleConnectionFactory,這個spring的一個包裝工廠 用於管理真正的ConnectionFactory
    public SingleConnectionFactory singleConnectionFactory(ActiveMQConnectionFactory activeMQconnectionFactory) {
        SingleConnectionFactory connectionFactory = new SingleConnectionFactory();
        //設定目標工廠
        connectionFactory.setTargetConnectionFactory(activeMQconnectionFactory);
        return connectionFactory;
    }

    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory());
//        factory.setDestinationResolver(destinationResolver());
        factory.setSessionTransacted(true);
        factory.setConcurrency("3-10");
        return factory;
    }

    /**
     * 1.佇列  點對點 queue
     * 2.主題  一對多  topic
     */
    @Bean
    public ActiveMQQueue queueDestination() {
        ActiveMQQueue activeMQQueue = new ActiveMQQueue("queue-anno");
        return activeMQQueue;
    }

    /*@Bean
    public ActiveMQTopic topicDestination() {
        ActiveMQTopic activeMQTopic = new ActiveMQTopic("topic-anno");
        return activeMQTopic;
    }*/
}

step5:啟動容器,消費訊息

/**
 * @ClassName SpringSender
 * @Description
 * @Author 歐陽思海
 * @Date 2019/8/13 17:22
 * @Version 1.0
 **/
public class SpringReceiver {
    /*
     * @Author 歐陽思海
     * @Description  xml配置方式獲取訊息
     * @Date 18:09 2019/8/16
     * @Param []
     * @return void
     **/
    @Test
    public void test_01() throws IOException {
        ApplicationContext application = new FileSystemXmlApplicationContext("G:\\ideaproject\\activemq\\Consumer\\src\\main\\resources\\service-jms.xml");
        /*JmsTemplate jmsTemplate = (JmsTemplate) application.getBean("jmsTemplate");
        String msg = (String) jmsTemplate.receiveAndConvert();
        System.out.println(msg);*/
        System.in.read();
    }

    /*
     * @Author 歐陽思海
     * @Description  註解方式獲取訊息
     * @Date 18:10 2019/8/16
     * @Param []
     * @return void
     **/
    @Test
    public void test_02() throws IOException {
        AnnotationConfigApplicationContext aContext =
                new AnnotationConfigApplicationContext(ConsumerConfig.class);
        /*JmsTemplate jmsTemplate = (JmsTemplate) application.getBean("jmsTemplate");
        String msg = (String) jmsTemplate.receiveAndConvert();
        System.out.println(msg);*/
        System.in.read();
    }
}

終於,到這裡把ActiveMQ整合Spring的全部內容就講述完結了,這一部分講了三個部分,分別是:

  • 不使用 Spring 配置檔案方式
  • 使用 Spring 配置檔案方式
  • 註解方式(0配置)

6 ActiveMQ支援的傳輸協議

6.1 預設協議介紹

在ActiveMQ中支援的協議還是挺多的,這也是ActiveMQ的一個特點之一,例如,預設支援AMQP、MQTT、OpenWire、STOMP、WebSocket,這些預設的協議的配置都是在activemq.xml配置檔案中的。

        <transportConnectors>
            
            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        </transportConnectors>

注意:上面的每種協議的埠都必須是不一樣的。

6.2 其他協議

除了上面的協議外,還支援這些協議:TCP、UDP 、NIO、SSL、Http(s)、vm

那麼如何使用這些協議呢?

只需要在上面的activemq.xml配置檔案中的transportConnectors節點新增就可以,例如,新增 nio協議

        <transportConnectors>
            <!-- 新增協議 -->
            <transportConnector name="nio" uri="nio://0.0.0.0:61619"/>
            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
            <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
            <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        </transportConnectors>

其他協議的新增方法也是相似的!

6.3 簡化配置

在ActiveMQ中還有一種更加簡單的配置方法,在uri中可以使用 auto 來簡化配置,ActiveMQ將監聽器埠的訊息自動適配相應的協議。

<transportConnector name="auto" uri="auto://0.0.0.0:61619"/>

如果需要更加安全,還可以在此基礎上新增ssl協議。

<transportConnector name="auto+ssl" uri="auto+ssl://0.0.0.0:61619"/>

如果還想要提高傳輸的效能,可以配合上面的nio協議,提高網路效能。

<transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61619"/>

7 ActiveMQ的持久化儲存機制

持久化的作用是什麼呢?

作用主要是為避免系統以外當機而導致訊息丟失,在ActiveMQ中支援多種持久化機制,比如,JDBC、AMQ、KahaDB、LevelDB,下面簡單介紹一下這幾種機制。

  • JDBC:基於資料庫儲存的方式,可以儲存在Mysql等資料庫中,這種機制的效能瓶頸在Mysql等資料庫,所以其效能是不太好的。

配置方法
activemq.xml配置檔案中配置,這裡我們使用Mysql進行配置。

step1:修改persistenceAdapter節點

<persistenceAdapter>
            <jdbcPersistenceAdapter dataSource="#mysqlDataSource" createTablesOnStartup="true"/>
            <!--<kahaDB directory="${activemq.data}/kahadb"/>-->
        </persistenceAdapter>

其中,dataSource="#mysqlDataSource"是資料來源引用。

step2:配置Mysql資料來源

<bean id="mysqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

這就是spring的配置方式。

step3:匯入資料庫連線池、驅動等Jar包
在ActiveMQ的目錄中有一個lib目錄,是存放jar包的目錄。

將下面幾個Jar放入。

step4:啟動ActiveMQ,檢視結果
啟動之後,開啟mysql資料庫,發現生成了三張資料表。

這樣就成功了,每次生成訊息之後,就會將訊息的資訊儲存到這三張表中,消費之後,再刪除資訊。

  • AMQ:基於檔案儲存,這種方式會把訊息寫入日誌檔案,並且是順序儲存方式,這種方式比JDBC方式要好,缺點是:會為每個Destination建立索引,佔用大量磁碟空間。

配置方法
activemq.xml配置檔案中配置,更加詳細引數請參考:https://activemq.apache.org/a...

<broker brokerName="broker" persistent="true" useShutdownHook="false">
    <persistenceAdapter>
      <amqPersistenceAdapter directory="資料儲存目錄" maxFileLength="32mb"/>
    </persistenceAdapter>
  </broker>
  • KahaDB:這個5.4版本之後出現的預設的持久化方式,與AMQ很相似,不同的是隻為Destination建立一個索引。

配置方法
activemq.xml配置檔案中配置,更加詳細引數請參考:https://activemq.apache.org/k...

<broker brokerName="broker">
    <persistenceAdapter>
      <kahaDB directory="資料儲存目錄" journalMaxFileLength="32mb"/>
    </persistenceAdapter>
 </broker>
  • LevelDB:5.6版本後推出的新的持久化方式。這種比KahaDB更快,跟KahaDB類似,但是不是用自定義B數實現。但是需要注意的是,目前官網已經不推薦使用這種方式,而是推薦使用KahaDB。

配置方法
activemq.xml配置檔案中配置,更加詳細的引數請參考:https://activemq.apache.org/l...

<broker brokerName="broker" ... >
    ...
    <persistenceAdapter>
      <levelDB directory="資料儲存目錄"/>
    </persistenceAdapter>
    ...
  </broker>

8 ActiveMQ網路連線支援

Broker的網路配置主要有三種配置方法,分別是靜態配置、動態配置和主從配置。

8.1 靜態配置

靜態傳輸提供了一種硬編碼機制,可以使用URI列表發現其他連線。使用此發現機制的連線將嘗試連線到列表中的所有URI,直到成功為止。

在activemq.xml配置檔案中配置。

<networkConnectors>
            <networkConnector uri="static:(tcp://localhoat:61616)"/>
        </networkConnectors>

配置語法

static:(uri1,uri2,uri3,…)?options

舉例

static:(tcp://localhost:61616,tcp://remotehost:61617?trace=false,vm://localbroker)?initialReconnectDelay=100

uri的屬性說明

8.2 動態配置

在activemq.xml配置檔案中配置。

<networkConnectors>
      <networkConnector uri="multicast://default"/>
    </networkConnectors>

8.3 主從配置

Master-Slave模型是非常常見的,主從模型主要是為了防止一個網路節點出現問題而提出的,提高了穩定性。

在ActiveMQ中也是可配置的,我們可以在activemq.xml配置檔案中進行相關配置。

<networkConnectors>
  <networkConnector uri="masterslave:(tcp://host1:61616,tcp://host2:61616,tcp://..)"/>
</networkConnectors>

注意:Master-Slave方式的第一個url需要是master,其他是slave。

另外,NetworkConnector 節點還有其他屬性可以配置,具體詳情可以檢視官網:https://activemq.apache.org/n...

8.4 容錯的客戶端連線方法

在前面的客戶端連線ActiveMQ的時候只是使用一個簡單的url進行連線。

ActiveMQConnectionFactory activeMQConnectionFactory
                = new ActiveMQConnectionFactory("tcp://localhost:61616");

但是,這種方式會出現一個問題,一旦這臺ActiveMQ當機了,就連線不上了,所以,有另外一種容錯的方式,當一臺出現當機,可以連線上其他的機器,這樣就不會出現問題了。

ActiveMQConnectionFactory activeMQConnectionFactory
                = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616,tcp://remotehost:61616)");

其他屬性引數請參考:https://activemq.apache.org/f...

相關文章