最近工作任務有點輕,且剛到新公司,接觸到了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,有不對的懇請各位大俠指出,小弟先謝過啦!