ActiveMQ 原理與應用

在介紹activemq之前,先簡單介紹JMS,它是J2EE的13個規範之一,提供的是消息中間件的規範。

  

  JMS包括以下基本構件:

   連接工廠,是客戶用來創建連接的對象,ActiveMQ提供的是ActiveMQConnectionFactory;

   連接connection;

   會話session,是發送和接收消息的上下文,用於創建消息生產者,消息消費者,相比rocketMQ會話session是提供事務性的;

   目的地destination,指定生產消息的目的地和消費消息的來源對象;

   生產者、消費者,由會話創建的對象,顧名思義。

 

  消息通信機制

   點對點模式,每個消息只有1個消費者,它的目的地稱爲queue隊列;

   發佈/訂閱模式,每個消息可以有多個消費者,而且訂閱一個主題的消費者,只能消費自它訂閱之後發佈的消息。

 

  消息確認機制

   Session.AUTO_ACKNOWLEDGE,直接使用receive方法。
   Session.CLIENT_ACKNOWLEDGE,通過消息的acknowledge 方法確認消息。
   Session.DUPS_ACKNOWLEDGE,該選擇只是會話遲鈍第確認消息的提交。如果JMS provider 失敗,那麼可能會導致一些重複的消息。如果是重複的消息,那麼JMS provider 必須把消息頭的JMSRedelivered 字段設置爲true。

package com.java.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

/**
 * 消息生產者
 * @author xing.liu
 *
 */
public class JMSProducer {

	private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默認的連接用戶名
	private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默認的連接密碼
	private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默認的連接地址
	private static final int SENDNUM=10; // 發送的消息數量
	
	public static void main(String[] args) {
		
		ConnectionFactory connectionFactory; // 連接工廠
		Connection connection = null; // 連接
		Session session; // 會話 接受或者發送消息的線程
		Destination destination; // 消息的目的地
		MessageProducer messageProducer; // 消息生產者
		
		// 實例化連接工廠
		connectionFactory=new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL);
		
		try {
			connection=connectionFactory.createConnection(); // 通過連接工廠獲取連接
			connection.start(); // 啓動連接
			// 創建Session,第一個參數是開啓事務true,第二個參數是消息確認機制屬性
			session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);  
			destination=session.createQueue("FirstQueue1"); // 創建消息隊列
			messageProducer=session.createProducer(destination); // 創建消息生產者
			sendMessage(session, messageProducer); // 發送消息
			session.commit();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally{
			if(connection!=null){
				try {
					connection.close();
				} catch (JMSException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 發送消息
	 * @param session
	 * @param messageProducer
	 * @throws Exception
	 */
	public static void sendMessage(Session session,MessageProducer messageProducer)throws Exception{
		for(int i=0;i<JMSProducer.SENDNUM;i++){
			TextMessage message=session.createTextMessage("ActiveMQ 發送的消息"+i);
			System.out.println("發送消息:"+"ActiveMQ 發送的消息"+i);
			messageProducer.send(message);
		}
	}
}

 

  原理很多,但是把原理映射在實踐中,就更容易懂了。一起看看下面的這個小例子,通過代碼回想原理,最後運行顯示到控制檯上,驗證結論。

  新建一個普通Java Project,引進activemq的jar包,build到項目中。新建生產者producer、消費者consumer,如下:

 

package com.java.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

/**
 * 消息消費者
 * @author xing.liu
 *
 */
public class JMSConsumer {

	private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默認的連接用戶名
	private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默認的連接密碼
	private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默認的連接地址
	
	public static void main(String[] args) {
		ConnectionFactory connectionFactory; // 連接工廠
		Connection connection = null; // 連接
		Session session; // 會話 接受或者發送消息的線程
		Destination destination; // 消息的目的地
		MessageConsumer messageConsumer; // 消息的消費者
		
		// 實例化連接工廠
		connectionFactory=new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL);
				
		try {
			connection=connectionFactory.createConnection();  // 通過連接工廠獲取連接
			connection.start(); // 啓動連接
			session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 創建Session
			destination=session.createQueue("FirstQueue1");  // 創建連接的消息隊列
			messageConsumer=session.createConsumer(destination); // 創建消息消費者
			while(true){
				TextMessage textMessage=(TextMessage)messageConsumer.receive(100000);
				if(textMessage!=null){
					System.out.println("收到的消息:"+textMessage.getText());
				}else{
					break;
				}
			}
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
}

這個demo是簡單的點對點模式下,目的地對象是queue隊列,代碼中可以看出session.createQueue;從代碼中可以聯想到上邊的原理,也是簡而易懂。messageConsumer.receive(100000)這使用的是receive模式,這種模式讓消費者consumer不斷的問producer要消息,很亂的。

  

  安裝了ActiveMQ服務器,在瀏覽器打開後臺監控,地址 http://127.0.0.1:8161/admin/

可以在Queues中看到消息未被消費的條數,已消費的條數。後臺監控系統都是一樣的,類似rocketMQ,我就不介紹了,多點點就能明白。

 

  所以生產中我們常用的是監聽listener模式,看看下邊這個帶監聽的consumer:

package com.java.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

/**
 * 消息消費者
 * @author xing
 *
 */
public class JMSConsumer2 {

	private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默認的連接用戶名
	private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默認的連接密碼
	private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默認的連接地址
	
	public static void main(String[] args) {
		ConnectionFactory connectionFactory; // 連接工廠
		Connection connection = null; // 連接
		Session session; // 會話 接受或者發送消息的線程
		Destination destination; // 消息的目的地
		MessageConsumer messageConsumer; // 消息的消費者
		
		// 實例化連接工廠
		connectionFactory=new ActiveMQConnectionFactory(JMSConsumer2.USERNAME, JMSConsumer2.PASSWORD, JMSConsumer2.BROKEURL);
				
		try {
			connection=connectionFactory.createConnection();  // 通過連接工廠獲取連接
			connection.start(); // 啓動連接
			session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 創建Session
			destination=session.createQueue("FirstQueue1");  // 創建連接的消息隊列
			messageConsumer=session.createConsumer(destination); // 創建消息消費者
			messageConsumer.setMessageListener(new Listener()); // 註冊消息監聽
		} catch (JMSException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
}
package com.java.activemq;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
 * 消息監聽
 * @author xing
 *
 */
public class Listener implements MessageListener{

	@Override
	public void onMessage(Message message) {
		try {
			System.out.println("收到的消息:"+((TextMessage)message).getText());
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}

這種消息監聽模式,只是多一個註冊消息監聽messageConsumer.setMessageListener(new Listener());

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