ActiveMQ常用機制(二)

上篇我們已經講完了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();


二、傳遞javabean對象

傳遞一個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");


這樣就可以進入隊列中,然後實現接口,或者通過receive()方法,就可以拿到未被處理的消息,從而保證正確的處理

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