点击上方Java资料社区,选择“置顶公众号”
优质文章,第一时间送达
引言
续上篇 "ActiveMQ基础"概念文章,本文将结合上篇理论概念用代码方式进行了解学习,如果您是第一次阅读的读者建议先阅读上篇文章;
本文先不使用springBoot集成整合activeMQ,首先使用原生的JMSAPI进行开发,让大家能够了解底层JMS中的一些组件,如果单纯的用springBoot已封装好的直接开发,那么就失去了学习的初衷;
JMS的基本组件
ConnectionFactory:用来创建Conncetion的工厂类,分别有两种不同的JMS模型,TopicConnectionFactory和QueueConnectionFactory接口,还有一种ActiveMQ的实现ActiveMQConnectionFactory,参数1和参数2为账号密码,参数3是与activeMQ通讯地址;
Connection:用来客户端与JMS建立连接,能够产生一个或者多个Session,上面一样,它也分别有两种类型QueueConnection与TopicConnection还有一个activeMQ的实现ActiveMQConnection;
Session:用来操作消息的接口,可以创建生产者、消费者、消息、(目的地、来源Destination),同样Session还能提供事务功能,使用发送/接收消息时候,可以将这些动作放到一个事务中执行,同样也分QueueSession和TopicSession两种类型;参数1为是否开启事务,参数2为应答方式(具体可看上篇文章,本文顶部有跳转链接);
Destination:目的地也叫来源,对于生产者来说是消息发往的队列目的地,对于消费者来说是消息的来源,可以通过Session创建指定目的地或来源的队列地址;
Message:JMS中的消息类型,有5种不同的类型分别为TextMessage(文本类型String)、MapMessage(MAP类型Key-Value)、ObjectMessage(任意类型)、BytesMessage(字节类型Byte)、StreamMessage(流类型)通过生产者或者消费者组件进行发送与接收;
MessageProducer:消息生产者,也是通过Session创建,send方法进行消息发送还可以通过setDeliveryMode方法设置是否对消息开启持久化,开启之后消息将会保存到本地,即使ActiveMQ挂掉或者停止,下次启动时消息依然会存在;
MessageConsumer:消息消费者,同样是由Session创建,receive方法进行接收消息;
搭建Maven项目
Pom:
<groupId>com_activeMQgroupId> <artifactId>demoartifactId> <version>1.0-SNAPSHOTversion> <dependencies> <dependency> <groupId>org.apache.activemqgroupId> <artifactId>activemq-coreartifactId> <version>5.7.0version> dependency> dependencies>project>
新建P2P点对点包创建生产者与消费者类
(生产者)Producter:
public class Producter { public static void main(String[] args) throws JMSException { // 它创建连接工厂 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, "tcp://127.0.0.1:61616"); // 创建连接 Connection connection = connectionFactory.createConnection(); //启动连接 connection.start(); //创建会话工厂 参数1:是否开启事务 参数2:消息确认应答方式 Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 创建队列 参数为目的地队列 Destination destination = session.createQueue("my-queue"); // 创建消息生产者 MessageProducer producer = session.createProducer(destination); // 设置不持久化 producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // 发送一条消息 for (int i = 1; i <= 5; i++) { //发送消息 sendMsg(session, producer, "activeMQ第"+i+"条消息"); } System.out.println("消息发送完毕"); //关闭连接 connection.close(); } /** * 在指定的会话上,通过指定的消息生产者发出一条消息 */ public static void sendMsg(Session session, MessageProducer producer, String i) throws JMSException { // 创建一条文本消息 TextMessage message = session.createTextMessage(i); /*//创建字节数消息 BytesMessage message1 = session.createBytesMessage(); message1.writeBoolean(false); //创建MAP消息 MapMessage message2 = session.createMapMessage(); message2.setBoolean("result",false); //创建Object类型消息 ObjectMessage message3 = session.createObjectMessage(); message3.setObject("Object");//任意类型*/ // 通过消息生产者发出消息 producer.send(message); }}
(消费者)JmsReceiver:
public class JmsReceiver { public static void main(String[] args) throws JMSException { // ConnectionFactory :连接工厂,JMS 用它创建连接 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, "tcp://127.0.0.1:61616"); // JMS 客户端到JMS Provider 的连接 Connection connection = connectionFactory.createConnection(); connection.start(); // Session:一个发送或接收消息的线程 Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // Destination :消息的目的地;消息发送给谁. // 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置 Destination destination = session.createQueue("my-queue"); // 消费者,消息接收者 MessageConsumer consumer = session.createConsumer(destination); while (true) { TextMessage message = (TextMessage) consumer.receive(); if (null != message) { System.out.println("收到消息:" + message.getText()); } else break; } session.close(); connection.close(); }}
大家一定要仔细阅读一下以上JSM组件介绍,再结合上方代码方便更好的理解;
首先我们先跑一下代码,先启动activeMQ进程(上篇文章已讲解安装、启动、后台介绍,可在本文顶端链接跳转或关注公众号);
刚启动我们队列里面并没有消息,所以是空的,那么我们使用上面代码进行生产消息发送到队列;
发送完毕,我们刷新一下activeMQ的后台页面:
我们发现刚刚生产的消息被成功发入队列,Name对于的是目的地地址,第二个为消费者数量,三个为入列数也就是生产者发入队列的消息数量,第四个为出列数也就是消费者消费掉的消息数量,因为我们暂时还没有启动消费者服务所以为0;
我们再启动一下消费者再看看会是怎样的情况;
消费者服务刚启动就成功将队列中的消息获取到,我们再看一下ActiveMQ后台变化:
可以发现消费者数、出列数由刚刚的0变成1和5,1代表消费者数量,5代表5条消息已被消费;
看完上方代码运行结果我们可以发现消息队列就如我们上篇文章所讲,生产者向队列中发送消息,消费者即使非运行状态也不会影响到生产者的正常运行,他们之间并没有时间的依赖,只要消费者一旦正常运行即可从队列中取到消息;
新建发布/订阅TOP包,创建发布者与订阅者者类
(发布者)TOPSend:
public class TOPSend { private static String BROKERURL = "tcp://127.0.0.1:61616"; private static String TOPIC = "my-topic"; public static void main(String[] args) throws JMSException { System.out.println("生产者已经启动...."); // 创建ActiveMQConnectionFactory 会话工厂 ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory( ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, BROKERURL); Connection connection = activeMQConnectionFactory.createConnection(); // 启动JMS 连接 connection.start(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer producer = session.createProducer(null); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); send(producer, session); System.out.println("发送成功!"); connection.close(); } static public void send(MessageProducer producer, Session session) throws JMSException { for (int i = 1; i <= 5; i++) { System.out.println("我是消息" + i); TextMessage textMessage = session.createTextMessage("我是消息" + i); Destination destination = session.createTopic(TOPIC); producer.send(destination, textMessage); } }}
(订阅者)TopReceiver:
public class TopReceiver { private static String BROKERURL = "tcp://127.0.0.1:61616"; private static String TOPIC = "my-topic"; public static void main(String[] args) throws JMSException { System.out.println("消费点启动..."); // 创建ActiveMQConnectionFactory 会话工厂 ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory( ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, BROKERURL); Connection connection = activeMQConnectionFactory.createConnection(); // 启动JMS 连接 connection.start(); // 不开消息启事物,消息主要发送消费者,则表示消息已经签收 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 创建一个队列 Topic topic = session.createTopic(TOPIC); MessageConsumer consumer = session.createConsumer(topic); // consumer.setMessageListener(new MsgListener()); while (true) { TextMessage textMessage = (TextMessage) consumer.receive(); if (textMessage != null) { System.out.println("接受到消息:" + textMessage.getText()); // textMessage.acknowledge();// 手动签收 // session.commit(); } else { break; } } connection.close(); }}
这里注意一下:发布订阅模式与点对点模式有所不同,因为发布订阅模式是有时间依赖的,如果生产者将消息发出去了而消费者非正常运行状态是取不到消息的,消费者如果想取到消息必须先向主题中进行订阅才能取到主题中的消息,所以在启动流程的时候如果按照点对点的顺序,先启动生产者后启动消费者是无法获取到消息,所以应该先启动消费者对该主题进行订阅,再启动生产者将消息生产进行发布才可以获取到消息,具体可以根据上篇文章的概念图来理解:
那么我们运行来看一下:
既然是发布与订阅一对多,那我们就启动两个消费者
两个消费者启动完毕,我们可以看到是没有收到任何消息的...
但是发现在消费者启动后,activeMQ后台Topcis页面中就有了该主题,并且消费者数量为2,表示消费者已经订阅该主题(其他的主题是ActiveMQ系统的不用管),我们再继续启动一下生产者发布消息;
生产者已启动并发布了消息...我们再回看一下两个消费者的情况:
两个消费者成功将消息获取,并且ActiveMQ后台页面也有所变化;
有读者可能会有疑问,我明明只生产了5条消息为什么出列数量为10呢,原因是因为我们有两个消费者,而发布订阅模式则是一对多的关系所以被两个消费者消费,出列数量自然是10;
源码:关注公众号回复[mq004]
今天先到这里,下篇会推出springBoot集成activeMQ使用更便捷的方式开发,如果有什么不懂的地方欢迎关注公众号在后台添加我微信或者我拉你进交流群大家一起交流学习!
如果大家觉得有用 请分享出去 让更多人看到! 予人玫瑰手有余香![52f3dd35a602381df8a814518a84ff6c.gif](https://i-blog.csdnimg.cn/blog_migrate/7cb3ee23d0d2b9ae9230beac189a0d3f.gif)
1. ActiveMQ基础概念
2. springBoot发送邮件
3. springBoot整合Log4j2
4. springBoot整合i18n国际化
5. springBoot配置SSL搭建HTTPS
6. springBoot定时备份数据邮件通知
7. springBoot数据访问整合mybatis
8. springBoot数据访问整合swagger2