ActiveMQ消息持久化
一、什么是持久化消息?
保证消息只被传送一次和成功使用一次.在持久性消息传送至目标时,消息服务将其放入持久性数据存储.如果消息服务由于某种原因导致失败,它可以恢复此消息并将此消息传送至相应的消费者.虽然这样增加了消息传送的开销,但却增加了可靠性.
也可以理解为,当消息生产者将消息成功的发送至MQ之后,如果出现了问题,例如MQ服务器宕机、消费者掉线等等,都能够保证消息消费者能够成功的消费消息,并且只能消费一次,如果消息生产者没有成功发送消息到MQ服务器,那么消费者就不能消费该消息.
二、队列的持久化和非持久化
1、队列的持久化:使用 producer.setDeliveryMode(DeliveryMode.PERSISTENT) 来设置队列的持久化,队列的消息默认的就是持久化
一、生产者代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class JmsQueueProducer { public static final String BROKER_URL = "tcp://192.168.229.129:61616" ; public static final String USERNAME = "admin" ; public static final String PASSWORD = "admin" ; public static final String QUEUE_NAME = "queue01" ; public static final String TEXT_MESSAGE_NAME = "textMessage" ; public static void main(String[] args) throws JMSException { // 1、创建连接工厂对象 ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL); // 2、通过连接工厂获取连接对象 Connection connection = connectionFactory.createConnection(); // 3、启动连接 connection.start(); // 4、通过连接对象获取JSM Session对象 Session session = connection.createSession( false , Session.AUTO_ACKNOWLEDGE); // 5、设置Destination(Destination接口下面有两个子接口,Queue和Topic) Queue queue = session.createQueue(QUEUE_NAME); // 6、创建消息生产者对象 MessageProducer producer = session.createProducer(queue); // 7、设置生产者持久化 producer.setDeliveryMode(DeliveryMode.PERSISTENT); for ( int i = 1 ; i < 4 ; i++) { // 8、创建Message对象 TextMessage textMessage = session.createTextMessage(TEXT_MESSAGE_NAME + i); // 9、发送消息 producer.send(queue, textMessage); } // 释放资源 producer.close(); session.close(); connection.close(); System.out.println( "生产者发送消息至MQ QUEUE......" ); } } |
二、消费者代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public class JmsQueueConsumer{ public static final String BROKER_URL = "tcp://192.168.229.129:61616" ; public static final String USERNAME = "admin" ; public static final String PASSWORD = "admin" ; public static final String QUEUE_NAME = "queue01" ; public static void main(String[] args) throws IOException, JMSException { // 1、创建连接工厂对象 ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL); // 2、通过连接工厂获取连接对象 Connection connection = connectionFactory.createConnection(); // 3、启动连接 connection.start(); // 4、通过连接对象获取JSM Session对象 Session session = connection.createSession( false , Session.AUTO_ACKNOWLEDGE); // 5、创建目的地 Queue queue = session.createQueue(QUEUE_NAME); // 6、创建消费者 MessageConsumer messageConsumer = session.createConsumer(queue); // 7、设置监听的方式来消费消息,是异步非阻塞的方式消费消息 messageConsumer.setMessageListener( new MessageListener() { @Override public void onMessage(Message message) { if (message != null && message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; try { System.out.println( "消费者接收到的消息是:" + textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } } }); // 让主线程不要结束,主线程一旦结束,那么监听消息的线程也会被迫结束,实际开发中我们的程序会一直运行,这一句就不需要了 System.in.read(); // 8、释放资源 messageConsumer.close(); session.close(); connection.close(); } } |
三、启动ActiveMQ,可以看到生产者将消息发送给了队列
四、关闭ActiveMQ,然后重新启动ActiveMQ(模拟服务器宕机),可以看到队列中待处理的消息还在,只是入队的消息不存在了,但是消费者依然可以继续消费消息
2、队列的非持久化
一、生产者代码
1 | 将producer.setDeliveryMode(DeliveryMode.PERSISTENT)替换为producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT) |
二、消费者代码
保持不变
三、开始启动生产者,可以看到队列中情况如下(消费者是可以消费到队列中的消息的)
四、关闭activemq之后,,接着重新启动activemq(模拟宕机后重启),队列中的消息已经清空了,(消费者不能再继续消费队列中的消息)
三、Topic的持久化和非持久化
1、主题的非持久化
topic默认就是非持久化的,在该模式下,如果生产者生产消息的时候,消费者不在线,那么消费者是不能接收到消息的,也就相当于生产者生产了一条废消息
2、主题的持久化
只要消费者向MQ服务器注册过,不管MQ服务器是否宕机,还是消费者是否在线的情况,所有的生产者发布成功的消息,该消费者都能接收到.
一、生产者代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | // 持久化topic生产者 public class JmsTopicProducer { public static final String BROKER_URL = "tcp://192.168.229.129:61616" ; public static final String USERNAME = "admin" ; public static final String PASSWORD = "admin" ; public static final String TOPIC_NAME = "topic01" ; public static final String TOPIC_TEXT_MESSAGE_NAME = "topicTextMessage" ; public static void main(String[] args) throws JMSException { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL); Connection connection = connectionFactory.createConnection(); Session session = connection.createSession( false , Session.AUTO_ACKNOWLEDGE); Topic topic = session.createTopic(TOPIC_NAME); MessageProducer producer = session.createProducer(topic); // 设置持久化topic producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 设置持久化topic之后再,启动连接 connection.start(); // 创建消息 for ( int i = 1 ; i < 4 ; i++) { TextMessage textMessage = session.createTextMessage(TOPIC_TEXT_MESSAGE_NAME + i); producer.send(textMessage); } // 释放资源 producer.close(); session.close(); connection.close(); System.out.println( "发送主题消息成功......" ); } } |
二、消费者代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // 持久化topic消费者 public class JmsTopicConsumer { public static final String BROKER_URL = "tcp://192.168.229.129:61616" ; public static final String USERNAME = "admin" ; public static final String PASSWORD = "admin" ; public static final String TOPIC_NAME = "topic01" ; public static final String TOPIC_TEXT_MESSAGE_NAME = "topicTextMessage" ; public static void main(String[] args) throws JMSException, IOException { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL); Connection connection = connectionFactory.createConnection(); // 设置客户端ID,向MQ服务器注册自己的名称 connection.setClientID( "xiaomaomao" ); Session session = connection.createSession( false , Session.AUTO_ACKNOWLEDGE); Topic topic = session.createTopic(TOPIC_NAME); // 创建一个topic订阅者对象.一参是topic,二参是订阅者名称 TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic, "playWithUs" ); // 创建完了topic对象之后再开启连接 connection.start(); // 设置监听的方式消费消息 topicSubscriber.setMessageListener( new MessageListener() { @Override public void onMessage(Message message) { // 生产者发送的是什么类型的消息,这里就只能消费相同类型的消息 if (message != null && message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; try { System.out.println( "接收到的消息是:" + textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } } }); // 8、释放资源 System.in.read(); topicSubscriber.close(); session.close(); connection.close(); } } |
三、订阅者面板
3、主题注意事项:
一、一定要先运行一次消费者,等于向MQ注册,类似我订阅了这个主题.
二、然后再运行生产者发送消息.
三、之后无论消费者是否在线,都会收到消息.如果不在线的话,下次连接的时候,会把没有收过的消息都接收过来.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?