初學RabbitMQ之HelloWorld

最近工作任務有點輕,且剛到新公司,接觸到了RabbitMQ,覺得該消息代理很神奇,想先入個門,結果還出了一個糗事:因爲本人比較菜,又想學RabbitMQ,結果找公司架構問了一個很弱智的問題—讓他幫我介紹一個入門級的學習RabbitMQ的blog,結果對方只發來一句:詳情請見官網http://www.rabbitmq.com/,後來補充了一句,學新技術,找官網……
好吧,閒話不多說,開始我們的HelloWorld吧!

材料準備:
1.本地安裝好Erlang環境
2.本地安裝好RabbitMQ服務器
3.本地Maven web 空項目一個

開始:
1.找到pom.xml文件,加入下面依賴

<!-- RabbitMQ -->
<dependency>
      <groupId>com.rabbitmq</groupId>
      <artifactId>amqp-client</artifactId>
      <version>3.0.4</version>
</dependency>

思考: 爲什麼要加入這段依賴?
回答(不一定準確): RabbitMQ是基於Erlang開發的,對於一些重要的開發語言(Python | Java | Ruby | PHP | C# | Javascript | Go)都有相應的驅動和客戶端, 我們使用的是java開發,故先要獲取java RabbitMQ客戶端,上面那段便是java RabbitMQ的maven依賴配置

2.
由於生產者和消費者都是咱們自己寫的應用程序,且和隊列有關,而且需要和隊列進行通信,故在代碼結構上可以抽象出一個抽象類:AbstractApplication用來抽象生產者和消費者一些共同的操作,代碼如下:
抽象類:AbstractApplication.java

public abstract class AbstractApplication {

    protected Channel channel;
    protected Connection connection;
    protected String appName;//隊列名稱
    protected String name;//生產者或者消費者名稱

    public AbstractApplication (String appName ,String name) throws IOException {
        this.appName = appName;
        this.name = name;

        // 創建connection工廠
        ConnectionFactory factory = new ConnectionFactory();

        // MQ服務器主機名
        factory.setHost("localhost");
//      System.out.println(factory.getPort());

        // 創建connection
        this.connection = factory.newConnection();

        // 創建channel
        this.channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(appName, false, false, false, null);
    }

    /**
     * 關閉channel和connection。並非必須,因爲隱含是自動調用的。 
     * @throws IOException
     */
     public void close() throws IOException{
         this.channel.close();
         this.connection.close();
     }
}

注: 上面那段代碼是不是和SessionFactory有點像呢… -.-

3.開始寫我們的生產者程序了,要給隊列發消息嘛,不過在生產者生產消息之前,得先加點依賴包進去(Apache Common Lang,方便把可序列化的java對象轉換爲byte[],加不加沒啥關係,可忽略)

<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>

生產者: MsgProducer.java

public class MsgProducer extends AbstractApplication {

    public MsgProducer(String appName, String name) throws IOException {
        super(appName, name);
        System.out.println("*******消息生產者被創建******");
    }

    public void sendMessage (Serializable object) throws IOException {
        this.channel.basicPublish("", appName,null,SerializationUtils.serialize(object));
    }
}

注: 這樣我們的生產者就產生了,可以給appName隊列發消息啦,可是一個人是不是有點孤單,趕緊加入一個消費者吧 o(∩_∩)o

4.加入消費者之前,先想下是不是可以把消費者作爲一個線程呢,一有消息我就給消費掉,不給浪費的機會,有想法就趕緊行動
消費者: MsgConsumer.java

public class MsgConsumer extends AbstractApplication implements Runnable, Consumer {

    public MsgConsumer(String appName, String name) throws IOException {
        super(appName, name);
        this.channel.basicQos(1);
        System.out.println("*******消息消費者被創建******");
    }

    public void handleConsumeOk(String consumerTag) {
        System.out.println("=====消費者 "+ consumerTag + "已經註冊=====");
    }

    public void handleCancelOk(String consumerTag) {
    }

    public void handleCancel(String consumerTag) throws IOException {

    }

    /**
     * 當有消息可消費時,回調此方法
     */
    public void handleDelivery(String arg0, Envelope arg1,
            BasicProperties arg2, byte[] arg3) throws IOException {
        Map<String, Integer> map = (HashMap<String, Integer>)SerializationUtils.deserialize(arg3);
        System.out.println("消息個數: " + map.get("MsgNum") + " 已經被接收");
    }

    public void handleShutdownSignal(String consumerTag,
            ShutdownSignalException sig) {

    }

    public void handleRecoverOk(String consumerTag) {

    }

    public void run() {
        try {
            // 開始消費消息, 並自動告知已經消費
            channel.basicConsume(appName, true, this);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

其中Consumer是com.rabbitmq.client包下的一個接口,這是官方解釋:
Interface for application callback objects to receive notifications and messages from a queue by subscription.(該接口是給咱們這些application使用的,當隊列有消息來時,可以回調該對象的方法),其中最重要的回調方法是:handleDelivery,當隊列有消息來時,回調該方法處理消息

5.好了,生產者和消費者都有了,咱們來測測這個Hello World到底能不能Hello了
測試類: Main.java

public class Main {

    public Main () throws IOException {

        // 啓動一個消費者線程
        MsgConsumer consumer = new MsgConsumer("F_QUEUE", "consumer");
        Thread consumerThread = new Thread(consumer);
        consumerThread.start();

        // 創建一個生產者
        MsgProducer producer = new MsgProducer("F_QUEUE", "producer");

        for (int index = 0; index < 1000; index++) {
            HashMap<String, Integer> msgMap = new HashMap<String, Integer>();
            msgMap.put("MsgNum", index);
            producer.sendMessage(msgMap);
            System.out.println("生產者生產了 :" + index + " 個消息");
        }
    }

    public static void main(String[] args) throws IOException {
        new Main();
    }
}

注: 先搞一個消費者在隊列上監聽着,一旦生產出來消息了,立即回調MsgConsumer.java中的回調方法處理掉,下面是我電腦上的部分輸出哦,因爲有多線程,故看到的結果可能不太一樣,只要消費掉消息就是ok的
這裏寫圖片描述

題外話: 這是第一次寫這麼長的blog,而且剛學RabbitMQ,有不對的懇請各位大俠指出,小弟先謝過啦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章