如要学习请跳转原文,原文地址:ActiveMQ学习总结 - 吊儿郎当小少年 - 博客园 (cnblogs.com)。
使用场景比对:常见的消息中间件对比(详细版)_常用消息中间件有什么区别-CSDN博客
点对点消息传递
- 每个消息只有一个消费者(Consumer)(即一旦被消费,消息就不再在消息队列中)
- 发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列
- 接收者在成功接收消息之后需向队列应答成功,如果你希望发送的每个消息都应该被成功处理的话,那么你需要P2P模式。
package com.namejr.Web_JRBackstage.serviceImpl; import com.namejr.Web_JRBackstage.base.PublicUtilHelper; import org.apache.activemq.ActiveMQConnectionFactory; import org.springframework.stereotype.Component; import javax.jms.*; @Component public class ActivemqServiceImpl { private String tcpPathUrl="tcp://localhost:61616"; private String queueName="testQueue1"; public void testRunning(){ Runnable tempTask1= () -> { try{ startServiceRunByPointToPoint(); }catch (Exception err){ err.printStackTrace(); } }; PublicUtilHelper.tempExecutor.execute(tempTask1); Runnable tempTask2= () -> { try{ startClientRunByPointToPoint(); }catch (Exception err){ err.printStackTrace(); } }; PublicUtilHelper.tempExecutor.execute(tempTask2); } // 模拟消息发送者--点对点 private void startServiceRunByPointToPoint() throws Exception{ // 第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(tcpPathUrl); // 第二步:使用ConnectionFactory对象创建一个Connection对象。 Connection connection = factory.createConnection(); // 第三步:开启连接,调用Connection对象的start方法。 connection.start(); // 第四步:使用Connection对象创建一个Session对象。 //第一个参数:是否开启事务。true:开启事务,第二个参数忽略。 //第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个Queue对象。 //参数:队列的名称。 Destination destination = session.createQueue(queueName); // 第六步:使用Session对象创建一个Producer对象。 MessageProducer producer = session.createProducer(destination);
/** 设置持久化
* PERSISTENT:指示JMS provider持久保存消息,以保证消息不会因为JMS provider的失败而丢失
* NON_PERSISTENT:不要求JMS provider持久保存消息 */
//producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
int runIndex=20; // 模拟不断发送消息 do{ // 第七步:创建一个Message对象,创建一个TextMessage对象。 TextMessage textMessage = session.createTextMessage("模拟消息发送:发送到第" + runIndex+"条消息。"); // 第八步:使用Producer对象发送消息。 producer.send(textMessage); runIndex--; Thread.sleep(2000); }while (runIndex>0); // 第九步:关闭资源。 producer.close(); session.close(); connection.close(); } // 模拟消息消费者--点对点 private void startClientRunByPointToPoint() throws Exception{ // 第一步:创建一个ConnectionFactory对象。 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(tcpPathUrl); // 第二步:从ConnectionFactory对象中获得一个Connection对象。 Connection connection = factory.createConnection(); // 第三步:开启连接。调用Connection对象的start方法。 connection.start(); // 第四步:使用Connection对象创建一个Session对象。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session对象创建一个Destination对象。和发送端保持一致queue,并且队列的名称一致。 Queue queue = session.createQueue(queueName); // 第六步:使用Session对象创建一个Consumer对象。 MessageConsumer consumer = session.createConsumer(queue); // 第七步:接收消息。 consumer.setMessageListener(message -> { TextMessage textMessage = (TextMessage) message; boolean closeFlag=false; try { //取消息的内容 String text = textMessage.getText(); System.out.println("接收到消息:"+text); if(text.contains("发送到第5条消息。")){ closeFlag=true; } } catch (JMSException terr) { terr.printStackTrace(); } finally { if(closeFlag){ // 第九步:关闭资源 try{ consumer.close(); session.close(); connection.close(); }catch (Exception terr){ terr.printStackTrace(); } } } }); } }
发布/订阅消息传递
每个消息可以有多个消费者
发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。 如果你希望发送的消息可以不被做任何处理、或者被一个消息者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型
消息的消费
在JMS中,消息的产生和消息是异步的。对于消费来说,JMS的消息者可以通过两种方式来消费消息。
同步:订阅者或接收者调用receive方法来接收消息,receive方法在能够接收到消息之前(或超时之前)将一直阻塞。
异步:订阅者或接收者可以注册为一个消息监听器。当消息到达之后,系统自动调用监听器的onMessage方法。
import com.namejr.Web_JRBackstage.base.PublicUtilHelper; import org.apache.activemq.ActiveMQConnectionFactory; import org.springframework.stereotype.Component; import javax.jms.*; import java.util.Random; @Component public class ActivemqServiceImpl { private String tcpPathUrl="tcp://localhost:61616"; private String queueName="testQueue1"; private String topicName="testTopic1"; public void testRunning(){ Runnable tempTask1= () -> { try{ startServiceRunByPublishAndSubscribe(); }catch (Exception err){ err.printStackTrace(); } }; PublicUtilHelper.tempExecutor.execute(tempTask1); Runnable tempTask2= () -> { try{ startClientRunByPublishAndSubscribe1(); }catch (Exception err){ err.printStackTrace(); } }; PublicUtilHelper.tempExecutor.execute(tempTask2); Runnable tempTask3= () -> { try{ startClientRunByPublishAndSubscribe2(); }catch (Exception err){ err.printStackTrace(); } }; PublicUtilHelper.tempExecutor.execute(tempTask3); } // 模拟消息发送者--发布订阅 private void startServiceRunByPublishAndSubscribe() throws Exception{ //第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。 // brokerURL服务器的ip及端口号 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(tcpPathUrl); // 第二步:使用ConnectionFactory对象创建一个Connection对象。 Connection connection = factory.createConnection(); // 第三步:开启连接,调用Connection对象的start方法。 connection.start(); // 第四步:使用Connection对象创建一个Session对象。 // 第一个参数:是否开启事务。true:开启事务,第二个参数忽略。 // 第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。
/** 消息的签收情形分两种:
带事务的session:如果session带有事务,并且事务成功提交,则消息被自动签收。如果事务回滚,则消息会被再次传送。
不带事务的session:不带事务的session的签收方式,取决于session的配置。Activemq支持一下三种模式:
Session.AUTO_ACKNOWLEDGE 消息自动签收
Session.CLIENT_ACKNOWLEDGE 客戶端调用acknowledge方法手动签收。textMessage.acknowledge();//手动签收
Session.DUPS_OK_ACKNOWLEDGE 不是必须签收,消息可能会重复发送。在第二次重新传送消息的时候,消息只有在被确认之后,才认为已经被成功地消费了。
消息的成功消费通常包含三个阶段:客户接收消息、客户处理消息和消息被确认。 在事务性会话中,当一个事务被提交的时候,确认自动发生。在非事务性会话中,消息何时被确认取决于创建会话时的应答模式(acknowledgement mode)。
*/
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session对象创建一个Destination对象(topic、queue),此处创建一个topic对象。 // 参数:话题的名称。 Destination destination = session.createTopic(topicName); // 第六步:使用Session对象创建一个Producer对象。 MessageProducer producer = session.createProducer(destination); int runIndex=20; // 模拟不断发送消息 do{ // 第七步:创建一个Message对象,创建一个TextMessage对象。 TextMessage textMessage = session.createTextMessage("模拟消息发送:发送到第" + runIndex+"条消息。"); // 第八步:使用Producer对象发送消息。 producer.send(textMessage); runIndex--; Thread.sleep(500); }while (runIndex>0); // 第九步:关闭资源。 producer.close(); session.close(); connection.close(); } // 模拟消息消费者--发布订阅 private void startClientRunByPublishAndSubscribe1() throws Exception{ //第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。 // brokerURL服务器的ip及端口号 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(tcpPathUrl); // 第二步:使用ConnectionFactory对象创建一个Connection对象。 Connection connection = factory.createConnection(); // 第三步:开启连接,调用Connection对象的start方法。 connection.start(); //connection.setClientID(UUID.randomUUID().toString()); // 指定唯一id // 第四步:使用Connection对象创建一个Session对象。 // 第一个参数:是否开启事务。true:开启事务,第二个参数忽略。 // 第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session对象创建一个Destination对象。和发送端保持一致topic,并且话题的名称一致。 Topic topic = session.createTopic(topicName); // 第六步:使用Session对象创建一个Consumer对象。 MessageConsumer consumer = session.createConsumer(topic); // 第七步:接收消息。 consumer.setMessageListener(message -> { TextMessage textMessage = (TextMessage) message; boolean closeFlag=false; try { //取消息的内容 String text = textMessage.getText(); System.out.println("第一个消费者接收到消息:"+text); if(text.contains("发送到第1条消息。")){ closeFlag=true; } Random tempRandom=new Random(); int tempSleepVal=tempRandom.nextInt(2000); Thread.sleep(tempSleepVal); } catch (Exception terr) { terr.printStackTrace(); } finally { if(closeFlag){ // 第九步:关闭资源 try{ consumer.close(); session.close(); connection.close(); }catch (Exception terr){ terr.printStackTrace(); } } } }); } // 模拟消息消费者--发布订阅 private void startClientRunByPublishAndSubscribe2() throws Exception{ //第一步:创建ConnectionFactory对象,需要指定服务端ip及端口号。 // brokerURL服务器的ip及端口号 ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(tcpPathUrl); // 第二步:使用ConnectionFactory对象创建一个Connection对象。 Connection connection = factory.createConnection(); // 第三步:开启连接,调用Connection对象的start方法。 connection.start(); //connection.setClientID(UUID.randomUUID().toString()); // 指定唯一id // 第四步:使用Connection对象创建一个Session对象。 // 第一个参数:是否开启事务。true:开启事务,第二个参数忽略。 // 第二个参数:当第一个参数为false时,才有意义。消息的应答模式。1、自动应答2、手动应答。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session对象创建一个Destination对象。和发送端保持一致topic,并且话题的名称一致。 Topic topic = session.createTopic(topicName); // 第六步:使用Session对象创建一个Consumer对象。 MessageConsumer consumer = session.createConsumer(topic); // 第七步:接收消息。 consumer.setMessageListener(message -> { TextMessage textMessage = (TextMessage) message; boolean closeFlag=false; try { //取消息的内容 String text = textMessage.getText(); System.out.println("第二个消费者接收到消息:"+text); if(text.contains("发送到第1条消息。")){ closeFlag=true; } Random tempRandom=new Random(); int tempSleepVal=tempRandom.nextInt(1500); Thread.sleep(tempSleepVal); } catch (Exception terr) { terr.printStackTrace(); } finally { if(closeFlag){ // 第九步:关闭资源 try{ consumer.close(); session.close(); connection.close(); }catch (Exception terr){ terr.printStackTrace(); } } } }); } }
待续。。。
浙公网安备 33010602011771号