JMS與MDB

          上一篇文章講了實體bean,瞭解了實體Bean的在工作流程中的使用,這篇文章我們來看一下消息驅動bean的使用。我們先來了解一下JMS.

         JMS是Java的消息服務,JMS的客戶端之間可以通過JMS服務進行異步的消息傳輸。JMS支持兩種消息模型:Point-to-Point(P2P)和Publish/Subscribe(Pub/Sub),即點對點和發佈訂閱模型。

P2P

        在P2P模型中,有下列概念:消息隊列(Queue)、發送者(Sender)、接收者(Receiver)。每個消息都被髮送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留着消息,直到它們被消費或超時。

       l  每個消息只有一個消費者(Consumer)(即一旦被消費,消息就不再在消息隊列中)

       l  發送者和接收者之間在時間上沒有依賴性,也就是說當發送者發送了消息之後,不管接收者有沒有正在運行,它不會影響到消息被髮送到隊列。

       l  接收者在成功接收消息之後需向隊列應答成功

       如果你希望發送的每個消息都應該被成功處理的話,那麼你需要P2P模型。

Pub/Sub

         在Pub/Sub模型中,有下列概念: 主題(Topic)、發佈者(Publisher)、訂閱者(Subscriber)。客戶端將消息發送到主題。多個發佈者將消息發送到Topic,系統將這些消息傳遞給多個訂閱者。

        l  每個消息可以有多個消費者

        l  發佈者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須創建一個訂閱之後,才能消費發佈者的消息,而且,爲了消費消息,訂閱者必須保持運行的狀態。

        當然,爲了緩和這種嚴格的時間相關性,JMS允許訂閱者創建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發佈者的消息。

         如果你希望發送的消息可以不被做任何處理、或者被一個消費者處理、或者可以被多個消費者處理的話,那麼可以採用Pub/Sub模型。

消息的消費

        在JMS中,消息的產生和消費是異步的。對於消費來說,JMS的消費者可以通過兩種方式來消費消息。

        l  同步 – 訂閱者或接收者調用receive方法來接收消息,receive方法在能夠接收到消息之前(或超時之前)將一直阻塞。

        l  異步 – 訂閱者或接收者可以註冊爲一個消息監聽器。當消息到達之後,系統自動調用監聽器的onMessage方法。

JMS編程模型

Connection Factory

        創建Connection對象的工廠,針對兩種不同的JMS消息模型,分別有QueueConnectionFactory和TopicConnectionFactory兩種。可以通過JNDI來查找ConnectionFactory對象。

Destination

       Destination的意思是消息生產者的消息發送目標或者說消息消費者的消息來源。對於消息生產者來說,它的Destination是某個隊列(Queue)或某個主題(Topic);對於消息消費者來說,它的Destination也是某個隊列或主題(即消息來源)。

       所以,Destination實際上就是兩種類型的對象:Queue、Topic。可以通過JNDI來查找Destination。

Connection

        Connection表示在客戶端和JMS系統之間建立的鏈接(對TCP/IPsocket的包裝)。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-DrivenBean)就是一種MessageListener。

        對客戶端來說,message-drivenbean(消息驅動bean)就是異步消息的消費者。當消息到達之後,由容器負責調用MDB。客戶端發送消息到destination,MDB作爲一個MessageListener接收消息。

       下邊我們通過一個例子來了解一下消息驅動bean的使用。

        我們建立一個ejb項目,然後建立一個SmsSendMessage類,並實現MessageListener接口,並實現方法onMessage方法,當有消息發送到容器後,容器會自動的調用onMessage方法處理消息。

 

package com.tgb.message;

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/myqneue")
})
public class SmsSendMessage implements MessageListener {
	//當有消息的時候,容器會自動調用onMessage方法。
	@Override
	public void onMessage(Message message) {
		  try {  
	            TextMessage textMessage = (TextMessage)message;  
	            System.out.println("MyMDBBean被調用了!【"+textMessage.getText()+"】");  
	        } catch (JMSException e) {  
	            e.printStackTrace();  
	        }  
	}
}

        然後我們在建立一個客戶端,用來發送消息,代碼如下,

package com.tgb.jms;

import java.util.Properties;

import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class JmsClient {
	public static void main(String[] args) {
		Properties props = new Properties();
		props.setProperty("java.naming.factory.initial",
				"org.jnp.interfaces.NamingContextFactory");
		props.setProperty("java.naming.provider.url", "localhost:1099");

		try {
			// 建立上下文
			InitialContext ctx = new InitialContext(props);
			// 獲取ConnectionFactory對象
			QueueConnectionFactory factory = (QueueConnectionFactory) ctx
					.lookup("ConnectionFactory");
			// 創建QueueConnection對象
			QueueConnection connection = factory.createQueueConnection();
			// 創建QueueSession對象,第一個參數表示事務自動提交,第二個參數標識一旦消息被正確送達,將自動發回響應
			QueueSession session = connection.createQueueSession(false,
					QueueSession.AUTO_ACKNOWLEDGE);
			// 獲得Destination對象
			//這裏的queue/myqneue 就是我們在消息處理類的註解中的Destination的值 ( 此處這樣寫,如果不做其他的配置,可能會有問題)
			Queue queue = (Queue) ctx.lookup("queue/myqneue");
			// 創建文本消息
			TextMessage msg = session.createTextMessage("世界,你好");
			// 創建發送者
			QueueSender sender = session.createSender(queue);
			// 發送消息
			sender.send(msg);
			// 關閉會話
			session.close();
		} catch (NamingException e) {
			System.out.println(e.toString());
			e.printStackTrace();
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			System.out.println(e.toString());
			e.printStackTrace();
		}

	}

}

        這樣我們會看到控制檯打印出如下信息, 說明我們的消息發送到了Destination,並由容器進行了處理。

         消息驅動bean是一個異步消息使用者。當JMS消息到達時,容器激發消息驅動bean。消息驅動bean既沒有本地接口也沒有組件接口。消息驅動bean實例是一個消息驅動bean類的實例。

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