上篇我們已經講完了ActiveMQ的基本使用,這篇文章用來講講ActiveMQ常用的幾種機制 ActiveMQ的基本使用
一、發送消息的數據類型
上面的代碼演示,全部都是發送字符串,但是ActiveMQ支持哪些數據呢?
大家可以看一下 javax.jms.Message 這個接口,只要是這個接口的數據,都可以被髮送。
或者這樣看起來有點麻煩,那麼看到上面的代碼,創建消息,是通過session這個對象來創建的,那我們來看一下這裏有哪些可以被創建的呢?
//純字符串的數據
session.createTextMessage();
//序列化的對象
session.createObjectMessage();
//流,可以用來傳遞文件等
session.createStreamMessage();
//用來傳遞字節
session.createBytesMessage();
//這個方法創建出來的就是一個map,可以把它當作map來用,當你看了它的一些方法,你就懂了
session.createMapMessage();
//這個方法,拿到的是javax.jms.Message,是所有message的接口
session.createMessage();
傳遞一個java對象,可能是最多的使用方式了,而且這種數據接收與使用都方便,那麼,下面的代碼就來演示下如何發送一個java對象
當然了,這個對象必須序列化,也就是實現Serializable接口
//通過這個方法,可以把一個對象發送出去,當然,這個對象需要序列化,因爲一切在網絡在傳輸的,都是字節
ObjectMessage obj = session.createObjectMessage();
for(int i = 0 ; i < 100 ; i ++){
Person p = new Person(i,"名字");
obj.setObject(p);
producer.send(obj);
}
那麼在接收端要怎麼接收這個對象呢?
//實現一個消息的監聽器
//實現這個監聽器後,以後只要有消息,就會通過這個監聽器接收到
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
//同樣的,強轉爲ObjectMessage,然後拿到對象,強轉爲Person
Person p = (Person) ((ObjectMessage)message).getObject();
System.out.println(p);
} catch (JMSException e) {
e.printStackTrace();
}
}
});
三、保證消息的成功處理
消息發送成功後,接收端接收到了消息。然後進行處理,但是可能由於某種原因,高併發也好,IO阻塞也好,反正這條消息在接收端處理失敗了。而點對點的特性是一條消息,只會被一個接收端給接收,只要接收端A接收成功了,接收端B,就不可能接收到這條消息,如果是一些普通的消息還好,但是如果是一些很重要的消息,比如說用戶的支付訂單,用戶的退款,這些與金錢相關的,是必須保證成功的,那麼這個時候要怎麼處理呢?
我們可以使用 CLIENT_ACKNOWLEDGE 模式
之前其實就有提到當創建一個session的時候,需要指定其事務,及消息的處理模式,當時使用的是
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
AUTO_ACKNOWLEDGE
這一個代碼的是,當消息發送給接收端之後,就自動確認成功了,而不管接收端有沒有處理成功,而一旦確認成功後,就會把隊列裏面的消息給清除掉,避免下一個接收端接收到同樣的消息。
那麼,它還有另外一個模式,那就是 CLIENT_ACKNOWLEDGE
這行要寫在接收端裏面,不是寫在發送端的
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
這行代碼以後,如果接收端不確認消息,那麼activemq將會把這條消息一直保留,直到有一個接收端確定了消息。
那麼要怎麼確認消息呢?
在接收端接收到消息的時候,調用javax.jms.Message的acknowledge方法
@Override
public void onMessage(Message message) {
try {
//獲取到接收的數據
String text = ((TextMessage)message).getText();
System.out.println(text);
//確認接收,併成功處理了消息
message.acknowledge();
} catch (JMSException e) {
e.printStackTrace();
}
}
這樣,當消息處理成功之後,確認消息,如果不確定,activemq將會發給下一個接收端處理
注意:只在點對點中有效,訂閱模式,即使不確認,也不會保存消息
四、避免消息隊列的併發JMQ設計出來的原因,就是用來避免併發的,和溝通兩個系統之間的交互。
//實現一個消息的監聽器
//實現這個監聽器後,以後只要有消息,就會通過這個監聽器接收到
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
//獲取到接收的數據
String text = ((TextMessage)message).getText();
System.out.println(text);
//確認接收,併成功處理了消息
message.acknowledge();
} catch (JMSException e) {
e.printStackTrace();
}
}
});
之前的代碼裏面,實現了一個監聽器,監聽消息的傳遞,這樣只要每有一個消息,都會即時的傳遞到程序中。
但是,這樣的處理,在高併發的時候,因爲它是被動接收,並沒有考慮到程序的處理能力,可能會壓跨系統,那要怎麼辦呢?
答案就是把被動變爲主動,當程序有着處理消息的能力時,主動去接收一條消息進行處理
實現的代碼如下:
if(當程序有能力處理){//當程序有能力處理時接收
Message receive = consumer.receive();
//這個可以設置超時時間,超過則不等待消息
recieve.receive(10000);
//其實receive是一個阻塞式方法,一定會拿到值的
if(null != receive){
String text = ((TextMessage)receive).getText();
receive.acknowledge();
System.out.println(text);
}else{
//沒有值嘛
//
}
}
通過上面的代碼,就可以讓程序自已判斷,自己是否有能力接收這條消息,如果不能接收,那就給別的接收端接收,或者等自己有能力處理的時候接收
五、消息有效期的管理
這樣的場景也是有的,一條消息的有效時間,當發送一條消息的時候,可能希望這條消息在指定的時間被處理,如果超過了指定的時間,那麼這條消息就失效了,就不需要進行處理了,那麼我們可以使用ActiveMQ的設置有效期來實現
代碼如下:
TextMessage msg = session.createTextMessage("哈哈");
for(int i = 0 ; i < 100 ; i ++){
//設置該消息的超時時間
producer.setTimeToLive(i * 1000);
producer.send(msg);
}
這裏每一條消息的有效期都是不同的,打開ip:8161/admin/就可以查看到,裏面的消息越來越少了。
過期的消息是不會被接收到的。
過期的消息會從隊列中清除,並存儲到ActiveMQ.DLQ這個隊列裏面,這個稍後會解釋。
五、過期消息,處理失敗的消息如何處理
過期的、處理失敗的消息,將會被ActiveMQ置入“ActiveMQ.DLQ”這個隊列中。
這個隊列是ActiveMQ自動創建的。
如果需要查看這些未被處理的消息,可以進入這個隊列中查看
//指定一個目的地,也就是一個隊列的位置
destination = session.createQueue("ActiveMQ.DLQ");