轉自:http://www.iteye.com/topic/609285
1、P2P模型
在P2P模型中,有下列概念:消息隊列(Queue)、發送者(Sender)、接收者(Receiver)。每個消息都被髮送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留着消息,直到它們被消費或超時。
每個消息只有一個消費者(Consumer)(即一旦被消費,消息就不再在消息隊列中)
發送者和接收者之間在時間上沒有依賴性,也就是說當發送者發送了消息之後,不管接收者有沒有正在運行,它不會影響到消息被髮送到隊列。
接收者在成功接收消息之後需向隊列應答成功
如果你希望發送的每個消息都應該被成功處理的話,那麼你需要P2P模型。
舉例:
//註冊消息監聽器,當有消息發送過來的時候會調用onMessage方法(實現MessageListener 接口)
- import javax.ejb.ActivationConfigProperty;
- import javax.ejb.MessageDriven;
- import javax.jms.JMSException;
- import javax.jms.Message;
- import javax.jms.MessageListener;
- import javax.jms.TextMessage;
- @MessageDriven(activationConfig={
- @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"),
- @ActivationConfigProperty(propertyName="destination", propertyValue="queue/myqueue")
- }
- )
- public class QueueMessageBean implements MessageListener {
- public void onMessage(Message msg) {
- //共有下面幾種消息類型
- //1 Text
- //2 Map
- //3 Object
- //4 stream
- //5 byte
- TextMessage txtMsg = (TextMessage)msg;
- String s = "";
- try {
- s = txtMsg.getText();
- } catch (JMSException e) {
- e.printStackTrace();
- }
- System.out.println("QueueMessageBean接收到了消息:" + s);
- }
- }
- //客戶端調用
- import javax.jms.Message;
- import javax.jms.MessageProducer;
- import javax.jms.Queue;
- import javax.jms.QueueConnection;
- import javax.jms.QueueConnectionFactory;
- import javax.jms.QueueSession;
- import javax.naming.InitialContext;
- public class Test {
- public static void main(String[] args) throws Exception {
- InitialContext ctx = new InitialContext();
- //獲得QueueConnectionFactory對象
- QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
- //創建QueueConnection對像
- QueueConnection connection = factory.createQueueConnection();
- //創建會話
- //arg1:與事物有關,true表示最後提交,false表示自動提交
- //arg2:表示消息向中間件發送確認通知,這裏採用的是自動通知的類型
- QueueSession session = (QueueSession) connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
- //取得destination
- Queue queue = (Queue) ctx.lookup("queue/myqueue");
- //消息生產者
- MessageProducer sender = session.createProducer(queue);
- //定義消息
- Message msg = session.createTextMessage("消息來了");
- //發送消息
- sender.send(queue, msg);
- session.close();
- connection.close();
- }
- }
2、Pub/Sub模式
在Pub/Sub模型中,有下列概念: 主題(Topic)、發佈者(Publisher)、訂閱者(Subscriber)。客戶端將消息發送到主題。多個發佈者將消息發送到Topic,系統將這些消息傳遞給多個訂閱者。
每個消息可以有多個消費者
發佈者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須創建一個訂閱之後,才能消費發佈者的消息,而且,爲了消費消息,訂閱者必須保持運行的狀態。
當然,爲了緩和這種嚴格的時間相關性,JMS允許訂閱者創建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發佈者的消息。
如果你希望發送的消息可以不被做任何處理、或者被一個消費者處理、或者可以被多個消費者處理的話,那麼可以採用Pub/Sub模型。
//註冊消息監聽器,當有消息發送過來的時候會調用onMessage方法(實現MessageListener 接口)
- import javax.ejb.ActivationConfigProperty;
- import javax.ejb.MessageDriven;
- import javax.jms.JMSException;
- import javax.jms.Message;
- import javax.jms.MessageListener;
- import javax.jms.TextMessage;
- @MessageDriven(activationConfig={
- @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Topic"),
- @ActivationConfigProperty(propertyName="destination", propertyValue="topic/myTopic")
- }
- )
- public class TopicMessageBean implements MessageListener {
- public void onMessage(Message msg) {
- //共有下面幾種消息類型
- //1 Text
- //2 Map
- //3 Object
- //4 stream
- //5 byte
- TextMessage txtMsg = (TextMessage)msg;
- String s = "";
- try {
- s = txtMsg.getText();
- } catch (JMSException e) {
- e.printStackTrace();
- }
- System.out.println("TopicMessageBean接收到了消息:" + s);
- }
- }
- //客戶端測試
- import javax.jms.MessageProducer;
- import javax.jms.Topic;
- import javax.jms.TopicConnection;
- import javax.jms.TopicConnectionFactory;
- import javax.jms.TopicSession;
- import javax.naming.InitialContext;
- public class Test {
- public static void main(String[] args) throws Exception {
- InitialContext ctx = new InitialContext();
- //獲得QueueConnectionFactory對象
- TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");
- //創建QueueConnection對像
- TopicConnection connection = factory.createTopicConnection();
- //創建會話
- //arg1:與事物有關,true表示最後提交,false表示自動提交
- //arg2:表示消息向中間件發送確認通知,這裏採用的是自動通知的類型
- TopicSession session = (TopicSession) connection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
- //取得destination
- Topic queue = (Topic) ctx.lookup("topic/myTopic");
- //消息生產者
- MessageProducer publisher = session.createProducer(queue);
- //定義消息
- Message msg = session.createTextMessage("消息來了");
- //發送消息
- publisher.send(queue, msg);
- session.close();
- connection.close();
- }
- }
二種模型的實現結果:對於p2p模型的每個消息只能有一個消費者 如果我們定義二個消息接受者的Bean那麼只能有一端會接收到消息。當你把部署在Jboss中的消息接收Bean去掉以後,然後發送消息 此時消息在隊列中,一旦你重新部署他會立刻就接收到剛剛發送的消息所以它沒有時間的依賴性, pub/sub模型可以有多個消費者 在這個模型中如果我們定義多個接收消息的Bean當我們在客戶端發送消息的時候二個bean都會接收到消息,所以他有多個消費者 但是如果你把Jboss部署中的消息接收bean去掉之後,發送消息。然後在重新部署,那麼消息也無法接收到,所以說他有時間的依賴性。
//代碼中幾個概念的理解
Connection Factory
創建Connection對象的工廠,針對兩種不同的JMS消息模型,分別有QueueConnectionFactory和TopicConnectionFactory兩種。可以通過JNDI來查找ConnectionFactory對象。
Destination
Destination的意思是消息生產者的消息發送目標或者說消息消費者的消息來源。對於消息生產者來說,它的Destination是某個隊列(Queue)或某個主題(Topic);對於消息消費者來說,它的Destination也是某個隊列或主題(即消息來源)。
所以,Destination實際上就是兩種類型的對象:Queue、Topic。
可以通過JNDI來查找Destination。
Connection:
Connection表示在客戶端和JMS系統之間建立的鏈接(對TCP/IP socket的包裝)。Connection可以產生一個或多個Session。跟ConnectionFactory一樣,Connection也有兩種類型:QueueConnection和TopicConnection。
Session:
Session是我們操作消息的接口。可以通過session創建生產者、消費者、消息等。Session提供了事務的功能。當我們需要使用session發送/接收多個消息時,可以將這些發送/接收動作放到一個事務中。同樣,也分QueueSession和TopicSession。
消息生產者:
消息生產者由Session創建,並用於將消息發送到Destination。同樣,消息生產者分兩種類型:QueueSender和TopicPublisher。可以調用消息生產者的方法(send或publish方法)發送消息!
消息消費者:
消息消費者由Session創建,用於接收被髮送到Destination的消息。兩種類型:QueueReceiver和TopicSubscriber。可分別通過session的createReceiver(Queue)或createSubscriber(Topic)來創建。當然,也可以通過session的createDurableSubscriber方法來創建持久化的訂閱者。
MessageListener:
消息監聽器。如果註冊了消息監聽器,一旦消息到達,將自動調用監聽器的onMessage方法。EJB中的MDB(Message-Driven Bean)就是一種MessageListener。
MDB介紹:
對客戶端來說,message-driven bean就是異步消息的消費者。當消息到達之後,由容器負責調用MDB。客戶端發送消息到destination,MDB作爲一個MessageListener接收消息。