activeMQ详解一 activeMQ和JMS规范

一、activeMQ是什么?
ActiveMQ 是完全基于 JMS 规范实现的一个消息中间件产品。是 Apache 开源基金会研发的消息中间件。ActiveMQ主要应用在分布式系统架构中,帮助构建高可用、高性能、可伸缩的企业级面向消息服务的系统
ActiveMQ 特性:
1)多语言和协议编写客户端
语言:java/C/C++/C#/Ruby/Perl/Python/PHP
协议 :openwire/stomp/REST/ws/notification/XMPP/AMQP
2)完全支持 jms1.1 和 J2ee1.4 规范
3) 对 spring 的支持,ActiveMQ 可以很容易内嵌到 spring模块中
文件下载和运行
这里使用windows版本进行演示
下载压缩包并解压 apache-activemq-5.13.0
在bin\win64目录下activemq.bat即可启动mq
mq 的监控端口是8161 通过locahost:8161可以访问控制台
默认登录账号密码 admin/admin
在这里插入图片描述
二、通过JMS规范来了解ActiveMQ
JMS 定义
Java 消息服务(Java Message Service)是 java 平台中关于面向消息中间件的 API,用于在两个应用程序之间,或者分布式系统中发送消息,进行异步通信。JMS 是一个与具体平台无关的 API,绝大多数 MOM(Message Oriented Middleware)(面向消息中间件)提供商都对 JMS 提供了支持。
什么是 MOM
MOM 是面向消息的中间件,使用消息传送提供者来协调消息传送操作。MOM 需要提供 API 和管理工具。客户端使用 api 调用,把消息发送到由提供者管理的目的地。在发送消息之后,客户端会继续执行其他工作,并且在接收方收到这个消息确认之前,提供者一直保留该消息。
MOM 的特点
1)消息异步接收,发送者不需要等待消息接受者响应
2) 消息可靠接收,确保消息在中间件可靠保存。只有接收方收到后才删除消息

Java 消息传送服务规范最初的开发目的是为了使 Java应用程序能够访问现有 MOM 系统。引入该规范之后,它已被许多现有的 MOM 供应商采用,并且已经凭借自身的功能实现为异步消息传送系统。
JMS 的体系结构
在这里插入图片描述
收发消息示例代码
发送消息代码

public class JmsSender {
        public static void main(String[] args) throws JMSException {
                ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
                		"admin",
                		"admin",
                		"tcp://127.0.0.1:61616");
                
                //JMS 客户端到JMS Provider 的连接
                Connection connection = connectionFactory.createConnection();
                
                connection.start();
                
                // Session: 一个发送或接收消息的线程
                Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
                // Destination :消息的目的地;消息发送给谁.
                // 获取session注意参数值my-queue是Queue的名字
                Destination destination = session.createQueue("my-queue111");
                // MessageProducer:消息生产者13582811738
                MessageProducer producer = session.createProducer(destination);
                //设置不持久化  如果不持久化 消息 mq重启后 及时消息没有被消费 也会丢失。设置为持久化的消息mq重启后 消息不会消失。
                producer.setDeliveryMode(DeliveryMode.PERSISTENT);
                
                TextMessage message = session.createTextMessage("Hello ActiveMQ!");
                //通过消息生产者发出消息
                producer.send(message);
                
                //发送一条消息
                sendMsg(session, producer);
                sendMsg(session, producer);
                sendMsg(session, producer);
                
                //对于事务型的消息只有commit()之后才会整整提交到服务器。让消费者消费。
                session.commit();
                connection.close();
        }

执行代码可以在控制台看到 queue my-queue111中有一条待消费的消息
在这里插入图片描述
接受消息代码

public class JmsReceiver {
        public static void main(String[] args) throws JMSException {
                // ConnectionFactory :连接工厂,JMS 用它创建连接
                ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
                                ActiveMQConnection.DEFAULT_USER,
                                ActiveMQConnection.DEFAULT_PASSWORD,
                                "tcp://mysql2:61616");
                //JMS 客户端到JMS Provider 的连接
                Connection connection = connectionFactory.createConnection();
                connection.start();
                // Session: 一个发送或接收消息的线程
                Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
                // Destination :消息的目的地;消息发送给谁.
                Destination destination = session.createQueue("my-queue111");
                // 消费者,消息接收者
                MessageConsumer consumer = session.createConsumer(destination);
               while (true) {
                        TextMessage message = (TextMessage) consumer.receive();
                        System.out.println(message);
                        //事务性会话rollback 后消息还在队列中。 或者不执行commit 直接 close 消息也依然存在再队列中
                        //session.commit();;
                } 
                	//session.close();
                	//connection.close();
        }
}

执行后可以看到消费了消息
在这里插入图片描述
消息接收还可以使用listener监听的方式 如下:

public static void run() throws Exception {
    QueueConnection connection = null;
    QueueSession session = null;
    try {
        // 创建链接工厂
        QueueConnectionFactory factory = new 			    ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, BROKER_URL);
        // 通过工厂创建一个连接
        connection = factory.createQueueConnection();
        // 启动连接
        connection.start();
        // 创建一个session会话
        session = connection.createQueueSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
        // 创建一个消息队列
        Queue queue = session.createQueue(TARGET);
        // 创建消息制作者
        javax.jms.QueueReceiver receiver = session.createReceiver(queue);
        
        receiver.setMessageListener(new MessageListener() { 
            public void onMessage(Message msg) { 
            	System.out.println(msg);
                if (msg != null) {
                    MapMessage map = (MapMessage) msg;
                    try {
                        System.out.println(map.getLong("time") + "接收#" + map.getString("text"));
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            } 
        }); 
        // 休眠100ms再关闭
        Thread.sleep(1000 * 10000); 
        
        // 提交会话
        session.commit();
        
    } catch (Exception e) {
        throw e;
    } finally {
        // 关闭释放资源
        if (session != null) {
            session.close();
        }
        if (connection != null) {
            connection.close();
        }
    }
}

详细了解jms标准
1、提供两种消息传递域:点对点和发布订阅
点对点(queue)方式特点
1 )每个消息只能被一个人消费,
2)消息的生产者和消费者没有时间上的相关性。就是说消息发送的时候不用关心消费者的状态(在线\离线),而消费者接收消息的时候也不用关心发送者的状态。只要消息发送成功,消费者上线的时候就能收到并完成消费
发布订阅方式的特点
1)每个消息可能有多个消费者 ,类似于群聊中我发送一条消息可以被群里所有人看到。
2)消费者和生产者有时间相关性,订阅一个主题的消费者只能消费它订阅之后发布的消息。
3)JMS支持持久订阅,持久订阅允许消费者消费它再未激活状态时(持久订阅的主题)发送的消息。
2、消息结构组成
JMS 消息由几部分组成:消息头、属性、消息体
消息头:包含消息的识别信息和路由信息
比如:
JMSDestination 消息发送的目的地,queue或者topic)
JMSDeliveryMode 传送模式。持久模式和非持久模式
JMSPriority 消息优先级(优先级分为 10 个级别,从 0(最低)到 9(最高). 如果不设定优先级,默认级别是 4。需要注意的是,JMS provider 并不一定保证按照优先级的顺序提交消息)
JMSMessageID 唯一识别每个消息的标识

属性:按类型可以分为应用设置的属性,标准属性和消息中间件定义的属性
应用设置的属性: 比如通过如下代码添加的属性

 Message.setStringProperty(“key”,”value”)

接收端可以通过getStringProperty(“key”)来获取属性
JMS 定义的属性:使用“JMSX”作为属性名的前缀,通过下面这段代码可以返回所有连接 JMSX 属性的名字
在这里插入图片描述
JMS provider 特定的属性 由mq提供者自定义的属性

消息体:就是我们需要传递的消息内容
JMS API 定义了 5 种消息格式
在这里插入图片描述
3、持久订阅
持久订阅的概念:消费者关注一个主题之后,每次消费者的状态由未激活变为激活时,会接收到该消费者在未激活时主题中的消息。类似群聊,我加入一个群后每次上线的时候回收到,离线起见群里的消息。
两个特点:
1)非持久订阅和持久订阅都是针对 发布订阅来说的和 点对点无关。
2)当 Broker 发送消息给订阅者时,如果订阅者处于 未激活状态状态:持久订阅者可以收到消息,而非持久订阅者则收不到消息。Broker 需要为持久订阅者保存消息;如果持久订阅者订阅的消息太多则会溢出

4、可靠性机制:
理论上来说,我们需要保证消息中间件上的消息,只有被消费者确认过以后才会被删除。相当于我们寄一个快递出去,收件人没有收到快递,就认为这个包裹还是属于待签收状态,这样才能保证包裹能够安全达到收件人手里。消息中间件也是一样,消息的消费通常包含 3 个阶段:客户接收消息、客户处理消息、消息被确认。
事务性会话和非事务性会话 通过connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE); 第一个参数,为true标识事务性会话,否则为非事务性会话。

JMS Session 接口提供了 commit 和 rollback 方法,提交意味着生产的所有消息被发送,消费的所有消息被确认;事务回滚意味着生产的所有消息被销毁,消费的所有消息被恢复并重新接收。commit 或 rollback 方法一旦被调用,一个事务就结束了,而另一个事务被开始。关闭事务性会话将回滚其中的事务。

在事务状态下进行发送操作,消息并未真正投递到中间件,而只有进行 session.commit 操作之后,消息才会发送到中间件,再转发到适当的消费者进行处理。如果是调用rollback 操作,则表明,当前事务期间内所发送的消息都取消掉。
在消费端事务性会话中,消息的确认是自动进行的,commit()执行以后消息自动确认。消费端如果调用了 rollback 或者没有调用commit 直接close则已经接受到的消息仍然存在在队列中。

在非事务型会话中,消 息 何 时 被 确 认 取 决 于 创 建 会 话 时 的 应 答 模 式(acknowledgement mode). 应答模式有三个选项
Session.AUTO_ACKNOWLEDGE
当客户成功的从 receive 方法返回的时候,或者从MessageListenner.onMessage 方法成功返回的时候,会话自动确认客户收到消息
Session.CLIENT_ACKNOWLEDGE
客户通过调用消息的 acknowledge 方法确认消息。在这种模式中,确认是在会话层上进行,确认一个被消费的消息将自动确认所有已被会话消费的消息。列如,如果一个消息消费者消费了 10 个消息,然后确认了第 5 个消息,那么 0~5 的消息都会被确认
Session.DUPS_ACKNOWLEDGE
消息延迟确认。指定消息提供者在消息接收者没有确认时,重新发送消息,这种模式不在乎接受者收到重复的消息.

5.消息 的 持久化存储
消息的持久化存储也是保证可靠性最重要的机制之一,也就是消息发送到 Broker 上以后,如果 broker 出现故障宕机了,那么存储在 broker 上的消息不应该丢失。消息的持久化通过发送者 来设置:producer.setDeliveryMode(DeliveryMode.PERSISTENT);

猜你喜欢

转载自blog.csdn.net/zhangxm_qz/article/details/87968476