2015年12月30日 星期三

Message Queue Intro & Spring RabbitMQ Example

http://villebez.logdown.com/posts/2015/12/21/message-queue-intro-spring-rabbitmq-example
進入這次主題之前,先讓大家認識
什麼是 Message Queue, Wikipedia.
在電腦科學中,訊息佇列(英語:Message queue)是一種行程間通信或同一行程的不同執行緒間的通信方式,軟體的貯列用來處理一系列的輸入,通常是來自使用者。訊息佇列提供了非同步的通信協定,也就是說:訊息的傳送者和接收者不需要同時與訊息佇列互交。訊息會儲存在佇列中,直到接收者取回它。
訊息佇列(Message Queue,簡稱MQ),從字面意思上看,本質是個佇列,FIFO先入先出,只不過佇列中存放的內容是message而已。其主要用途:不同行程Process/執行緒Thread之間通信。
最初起源于金融系統,用於在分散式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。
訊息中介軟體主要用於元件之間的解耦,訊息的發送者無需知道訊息使用者的存在,反之亦然。
接著要準備這次的環境,下載安裝server,RabbitMQ
RabbitMQ Server Commands,詳見手冊
基本上windows上安裝方式就是下一步、下一步就好了,
安裝完可以連看看RabbitMQ Management Page,輸入default user
Management Page就不詳述了,自己玩玩看吧。
http://localhost:15672/
default username/password:guest/guest
server安裝完後就可以進入這次的主題
其實Spring AMQP管網已經有兩個簡易範例了,一個是純Java,一個是使用Spring的方式
我是使用Spring的方式,做些微調整,並記錄下須注意的地方
首先New Gradle Project,設定dependencies
dependencies {
compile 'org.springframework.amqp:spring-rabbit:1.5.3.RELEASE'
}
Spring Context Config (applicationContext.xml)

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">

    <rabbit:connection-factory id="connectionFactory"
        host="127.0.0.1" port="5672" username="guest" password="guest" />

    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
        exchange="myExchange" />
 
    <rabbit:admin connection-factory="connectionFactory" />

  <rabbit:queue name="myQueue" />

    <rabbit:fanout-exchange name="myExchange">
        <rabbit:bindings>
            <rabbit:binding queue="myQueue" />
        </rabbit:bindings>
    </rabbit:fanout-exchange>

    <rabbit:listener-container id="rabbitMQContainer"
        connection-factory="connectionFactory" auto-startup="false">
        <rabbit:listener ref="messageHandler" queue-names="myQueue" />
    </rabbit:listener-container>

    <bean id="messageHandler" class="MessageHandler"/>
</beans>


注意設定xmlns:rabbit以及xsi:schemaLocation (http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd)
auto-startup預設為true,也就是spring載入後consumer listener就會啟動並且keep alive
與官網做法不同rabbit:listener沒有設定method屬性,後面說明

Message Handler
public class MessageHandler implements MessageListener {
    public void onMessage(Message message) {
        System.out.println(message);
    }
}
這裡跟官網用法不同,是去實作org.springframework.amqp.core.MessageListener
所以Spring Content Config並沒有設定rabbit:listener的method屬性,
好處是可以拿到更多Message的資訊,不是只有Body的字串,
要用哪種方式沒有對錯,單看需求而定!!
Output Message Object
(Body:'Test'; ID:null; Content:text/plain; Headers:{}; Exchange:myExchange; RoutingKey:; Reply:null; DeliveryMode:PERSISTENT; DeliveryTag:1)
Main
public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        AmqpTemplate amqpTemplate = ctx.getBean("amqpTemplate", AmqpTemplate.class);
        amqpTemplate.convertAndSend("Test");
}