ActiveMQ 生產者和消費者demo

喝水會長肉發表於2021-12-07

生產者程式碼

package org.mule.util.ansyLog;
 
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
 
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQSession;
import org.apache.activemq.pool.PooledConnectionFactory;
 
/**
 * JMS訊息生產者
 * @author 
 * java學習交流:737251827  進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
 */
public class JMSProducer implements ExceptionListener{
	
	//設定連線的最大連線數
	public final static int DEFAULT_MAX_CONNECTIONS=5;
	private int maxConnections = DEFAULT_MAX_CONNECTIONS;
	//設定每個連線中使用的最大活動會話數
	private int maximumActiveSessionPerConnection = DEFAULT_MAXIMUM_ACTIVE_SESSION_PER_CONNECTION;
	public final static int DEFAULT_MAXIMUM_ACTIVE_SESSION_PER_CONNECTION=300;
	//執行緒池數量
	private int threadPoolSize = DEFAULT_THREAD_POOL_SIZE;
	public final static int DEFAULT_THREAD_POOL_SIZE=50;
	//強制使用同步返回資料的格式
	private boolean useAsyncSendForJMS = DEFAULT_USE_ASYNC_SEND_FOR_JMS;
	public final static boolean DEFAULT_USE_ASYNC_SEND_FOR_JMS=true;
	//是否持久化訊息
	private boolean isPersistent = DEFAULT_IS_PERSISTENT;
	public final static boolean DEFAULT_IS_PERSISTENT=true; 
	
	//連線地址
	private String brokerUrl;
 
	private String userName;
 
	private String password;
 
	private ExecutorService threadPool;
 
	private PooledConnectionFactory connectionFactory;
 
	public JMSProducer(String brokerUrl, String userName, String password) {
		this(brokerUrl, userName, password, DEFAULT_MAX_CONNECTIONS, DEFAULT_MAXIMUM_ACTIVE_SESSION_PER_CONNECTION, DEFAULT_THREAD_POOL_SIZE, DEFAULT_USE_ASYNC_SEND_FOR_JMS, DEFAULT_IS_PERSISTENT);
	}
	
	public JMSProducer(String brokerUrl, String userName, String password, int maxConnections, int maximumActiveSessionPerConnection, int threadPoolSize,boolean useAsyncSendForJMS, boolean isPersistent) {
		this.useAsyncSendForJMS = useAsyncSendForJMS;
		this.isPersistent = isPersistent;
		this.brokerUrl = brokerUrl;
		this.userName = userName;
		this.password = password;
		this.maxConnections = maxConnections;
		this.maximumActiveSessionPerConnection = maximumActiveSessionPerConnection;
		this.threadPoolSize = threadPoolSize;
		init();
	}
	  
	private void init() {
		//設定JAVA執行緒池
		this.threadPool = Executors.newFixedThreadPool(this.threadPoolSize);
		//ActiveMQ的連線工廠
		ActiveMQConnectionFactory actualConnectionFactory = new ActiveMQConnectionFactory(this.userName, this.password, this.brokerUrl);
		actualConnectionFactory.setUseAsyncSend(this.useAsyncSendForJMS);
		//Active中的連線池工廠
		this.connectionFactory = new PooledConnectionFactory(actualConnectionFactory);
		this.connectionFactory.setCreateConnectionOnStartup(true);
		this.connectionFactory.setMaxConnections(this.maxConnections);
		this.connectionFactory.setMaximumActiveSessionPerConnection(this.maximumActiveSessionPerConnection);
	}
	
	
	/**
	 * 執行傳送訊息的具體方法
	 * @param queue
	 * @param map
	 */
	public void send(final String queue, final Map<String, Object> map) {
		//直接使用執行緒池來執行具體的呼叫
		this.threadPool.execute(new Runnable(){
			@Override
			public void run() {
				try {
					sendMsg(queue,map);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	/**
	 * 執行傳送訊息的具體方法
	 * @param queue
	 * @param map
	 */
	public void send(final String queue, final String message) {
		//直接使用執行緒池來執行具體的呼叫
		this.threadPool.execute(new Runnable(){
			@Override
			public void run() {
				try {
					sendMsg(queue,message);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * 真正的執行訊息傳送
	 * @param queue
	 * @param map
	 * @throws Exception
	 */
	private void sendMsg(String queue, String msg) throws Exception {
		
		Connection connection = null;
		Session session = null;
		try {
			//從連線池工廠中獲取一個連線
			connection = this.connectionFactory.createConnection();
			/*createSession(boolean transacted,int acknowledgeMode)
			  transacted - indicates whether the session is transacted acknowledgeMode - indicates whether the consumer or the client 
			  will acknowledge any messages it receives; ignored if the session is transacted. 
			  Legal values are Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE.
			 */
			//false 參數列示 為非事務型訊息,後面的參數列示訊息的確認型別
//			session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
			session = connection.createSession(Boolean.TRUE, ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE);
			//true 開啟事務,需要客戶端確認
//			session = connection.createSession(Boolean.TRUE, Session.CLIENT_ACKNOWLEDGE);
			//Destination is superinterface of Queue
			//PTP訊息方式     
			Destination destination = session.createQueue(queue);
			//Creates a MessageProducer to send messages to the specified destination
			MessageProducer producer = session.createProducer(destination);
			//set delevery mode
			producer.setDeliveryMode(this.isPersistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
			//map convert to javax message
			TextMessage message = session.createTextMessage(msg);
			producer.send(message);
			session.commit();
		} finally {
			closeSession(session);
			closeConnection(connection);
		}
	}
	/**
	 * 真正的執行訊息傳送
	 * @param queue
	 * @param map
	 * @throws Exception
     * java學習交流:737251827  進入可領取學習資源及對十年開發經驗大佬提問,免費解答!
	 */
	private void sendMsg(String queue, Map<String, Object> map) throws Exception {
		
		Connection connection = null;
		Session session = null;
		try {
			//從連線池工廠中獲取一個連線
			connection = this.connectionFactory.createConnection();
			//false 參數列示 為非事務型訊息,後面的參數列示訊息的確認型別
			session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
			//PTP訊息方式     
			Destination destination = session.createQueue(queue);
			//Creates a MessageProducer to send messages to the specified destination
			MessageProducer producer = session.createProducer(destination);
			//set delevery mode
			producer.setDeliveryMode(this.isPersistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
			//map convert to javax message
			Message message = getMessage(session, map);
			producer.send(message);
		} finally {
			closeSession(session);
			closeConnection(connection);
		}
	}
	
	private Message getMessage(Session session, Map<String, Object> map) throws JMSException {
		MapMessage message = session.createMapMessage();
		if (map != null && !map.isEmpty()) {
			Set<String> keys = map.keySet();
			for (String key : keys) {
				message.setObject(key, map.get(key));
			}
		}
		return message;
	}
	
	private void closeSession(Session session) {
		try {
			if (session != null) {
				session.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	private void closeConnection(Connection connection) {
		try {
			if (connection != null) {
				connection.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void onException(JMSException e) {
		e.printStackTrace();
	}


消費者程式碼,這裡只貼出main方法裡的內容

       // ConnectionFactory :連線工廠,JMS 用它建立連線
        ConnectionFactory connectionFactory;
        // Connection :JMS 客戶端到JMS Provider 的連線
//        Connection connection = null;
        // Session: 一個傳送或接收訊息的執行緒
        Session session;
        // Destination :訊息的目的地;訊息傳送給誰.
        Destination destination;
        // 消費者,訊息接收者
        MessageConsumer consumer = null;
        connectionFactory = new ActiveMQConnectionFactory(
        		USERNAME,PASSWORD,ACTIVE_URL);
        try {
            // 構造從工廠得到連線物件
            connection = connectionFactory.createConnection();
            // 啟動
            connection.start();
            // 獲取操作連線
            session = connection.createSession(Boolean.FALSE,
                    Session.AUTO_ACKNOWLEDGE);
            // 獲取session注意引數值xingbo.xu-queue是一個伺服器的queue,須在在ActiveMq的console配置
            destination = session.createQueue(QUEUE_NAME_LOG);
            consumer = session.createConsumer(destination);
            while (true) {
            	TextMessage message = (TextMessage) consumer.receive();
                if (null != message) {
                    System.out.println("--------------------"+message.getText());
                    JSONObject json = (JSONObject) JSON.parse(message.getText());
                    //儲存到資料庫
                    System.out.println(json.getString("inPro"));
                    message.acknowledge(); 
           } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();


這裡是基於queue的,支援事務,並且持久化的。

 

JMS訊息確認機制

 

 JMS訊息只有在被確認之後,才認為已經被成功地消費了。訊息的成功消費通常包含三個階段:客戶接收訊息、客戶處理訊息和訊息被確認。在事務性會話中,當一個事務被提交的時候,確認自動發生。在非事務性會話中,訊息何時被確認取決於建立會話時的應答模式(acknowledgement mode)。該引數有以下三個可選值:

 

 Session.AUTO_ACKNOWLEDGE。當客戶成功的從receive方法返回的時候,或者從MessageListener.onMessage方法成功返回的時候,會話自動確認客戶收到的訊息。

 

 Session.CLIENT_ACKNOWLEDGE。 客戶通過訊息的acknowledge方法確認訊息。需要注意的是,在這種模式中,確認是在會話層上進行:確認一個被消費的訊息將自動確認所有已被會話消 費的訊息。例如,如果一個訊息消費者消費了10個訊息,然後確認第5個訊息,那麼所有10個訊息都被確認。

 

 Session.DUPS_ACKNOWLEDGE。 該選擇只是會話遲鈍第確認訊息的提交。如果JMS provider失敗,那麼可能會導致一些重複的訊息。如果是重複的訊息,那麼JMS provider必須把訊息頭的JMSRedelivered欄位設定為true。

 

ActiveMQ訊息確認機制

 

 ActiveMQSession,實現了JMS的session,QueueSession, TopicSession

 

 ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE 每條訊息都必須顯式呼叫acknowledge方法確認訊息。

 

 

訊息永續性

JMS 支援以下兩種訊息提交模式:

 

 DeliveryMode.PERSISTENT  指示JMS provider持久儲存訊息,以保證訊息不會因為JMS provider的失敗而丟失。 訊息持久化在硬碟中,ActiveMQ持久化有三種方式:AMQ、KahaDB、JDBC。

 

 DeliveryMode.NON_PERSISTENT  不要求JMS provider持久儲存訊息,訊息存放在記憶體中,讀寫速度快,在JMS服務停止後訊息會消失,沒有持久化到硬碟。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70010294/viewspace-2846195/,如需轉載,請註明出處,否則將追究法律責任。

相關文章