ActiveMQ

ActiveMQ

一 、入门概述

二、ActiveMQ安装

官网下载 http://activemq.apache.org/

启动方式

将安装上传到Linux系统后,无需进行任何操作,直接通过命令启动即可

功能 命令
普通启动 ./activemq start
普通停止 ./activemq stop
带日志方式启动 ./activemq start > activemq.log

端口情况

功能 端口
后台管理系统图形化界面 8161
默认进程端口号 61616

启动情况

Linux中查看启动状况

功能 命令
查看MQ是否使用 ps -ef | grep activemq
查看端口是否使用 netstat -anp | grep 61616

Win中通过浏览器查看,通过IP地址 + 端口号 进入, 账号和密码默认都是admin
ActiveMQ_第1张图片
登录成功界面
ActiveMQ_第2张图片

三、Queue队列入门Demo

1 环境配置

1) IEDA2020.1
2) JDK1.8版本
3) Springboot功能
4) 导入依赖
	<dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-all</artifactId>
            <version>5.16.0</version>
     </dependency>

2 队列测试(同步阻塞方式receive())

1)消息生产者编码

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce {
     
	//ActiveMQ地址
    public static final String ACTIVEMQ_URL = "tcp://192.168.146.131:61616";
    //队列名
    public static final String QUEUE_NAME = "queue01";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5 创建消息的生产者
        MessageProducer messageProducer = session.createProducer(queue);
        //6 生产3条消息发送到消息队列里面
        for (int i = 0; i < 3; i++) {
     
            // 7 创建消息
            TextMessage textMessage = session.createTextMessage("发送队列测试消息" + i);
            // 8 通过消息生产者发布
            messageProducer.send(textMessage);
        }
        //9 关闭资源
        messageProducer.close();
        session.close();
        connection.close();
        System.out.println("消息发送到MQ完成");
    }
}
启动类之后,查看网页ActiveMQ_第3张图片
连接不成功解决问题,参考文章: https://blog.csdn.net/weixin_44051038/article/details/111188636

2) 消息消费者代码

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsConsumer {
     

    // 消息接收

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String QUEUE_NAME = "test_queue01";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5 创建消息的消费者
        MessageConsumer consumer = session.createConsumer(queue);
        //6 循环获取消息
        while (true){
     
            TextMessage textMessage = (TextMessage) consumer.receive();
            if (textMessage != null){
     
                System.out.println("消费消息----->" + textMessage.getText());
            }else {
     
                break;
            }
        }
        //7 关闭资源
        consumer.close();
        session.close();
        connection.close();
        System.out.println("消费MQ消息成功");
    }
}
消费者receive()方法
功能 方法
接收不到消息一直等待 receive()
没有消息则在固定时间后停止 receive(long var1)

3)测试结果

控制台显示生产者发送的消息,并且页面发送改变
ActiveMQ_第4张图片

3 队列测试(异步非阻塞方式方式listener)

消息生产者编码同上

消息消费者编码

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;
import java.io.IOException;

public class JmsConsumer {
     

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.131:61616";
    public static final String QUEUE_NAME = "queue01";

    public static void main(String[] args) throws JMSException, IOException {
     
        System.out.println("我是2号消费者");
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地
        Queue queue = session.createQueue(QUEUE_NAME);
        //5 创建消息的消费者
        MessageConsumer consumer = session.createConsumer(queue);
        //6 创建消息监听器
        consumer.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();
                    }
                }
            }
        });
        // 一定要写 不然没有输出
        // 此代码要保证MQ连接成功并且被消费之后,才关闭连接,不然还未执行就已经关闭了
        System.in.read();

        consumer.close();
        session.close();
        connection.close();
        System.out.println("消息接收到MQ完成");
    }
}

4 消费者三大消费情况

序号 启动方式 结果
1 先启动生产者,然后在启动1个消费者 消费者全部消费消息
2 先启动生产者,然后启动1号消费者,成功后在启动2号消费者 1号消费者全部消费,2号消费者未消费任何消息
3 先分别启动1号消费者和2号消费者,然后在启动生产者 全部的消息1号消费者和2号消费者每个一半,而不是每个全都消费一遍

5 JMS开发的基本步骤

ActiveMQ_第5张图片

  1. 创建1个connection factory工厂
  2. 通过connection factory来创建JMS connection
  3. 启动JMS connection
  4. 通过connection创建JMS session
  5. 创建JMS destination
  6. 创建JMS producer 或者 创建JMS message并设置destination
  7. 创建JMS consumer或者是注册一个JMS message listener
  8. 发送或接收JMS message
  9. 关闭所有的JMS资源

6 两种消费方式

方式 描述
同步阻塞方式receive() 订阅者或接收者调用MessageConsumer的receive()方法来接收消息,receive方法在能够接收到消息之前(或超时之前)将一直阻塞
异步非阻塞方式(监听器onMessage) 订阅者或接收者通过MessageConsumer的setMessageListener(MessageListener listener)注册一个消息监听器,

7 点对点消息传递的特点

  1. 每个消息只能有1个消费者,类似于1对1的关系,好比个人快递自己领取自己的

  2. 消息的生产者和消费者之间没有时间上的相关性,无论消费者在生产者发送消息的时候是否处于运行状态,消费者都可以提取消息,好比我们发送短信,发送者发送以后不见得接收者会即收即看

  3. 消息被消费后队列中不会在存储,所有消费者不会消费到已经被消费的消息

四、Topic主题入门Demo

1 发送/订阅消息传递域的特点如下:

  1. 生产者将消息发送到topic中,每个消息可以有多个消费者,属于1:N的关系
  2. 生产者和消费者之间有时间上的相关性,订阅某一个主题的消费者只能消费自他订阅之后发布的消息
  3. 生产者生产时,topic不保存消息,它是不保存消息的不落地,假如无人订阅就去生产,那就是一条废消息,所以一般先启动消费者在启动生产者

2 主题测试

1) 消费者代码

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.io.IOException;

public class JmsConsumer {
     

    // 消息接收
    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String TOPIC_NAME = "topic-test";

    public static void main(String[] args) throws JMSException, IOException {
     
        System.out.println("我是1号消费者");

        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地
        Topic topic = session.createTopic(TOPIC_NAME);
        //5 创建消息的消费者
        MessageConsumer consumer = session.createConsumer(topic);
        //6 消息
        consumer.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();
        consumer.close();
        session.close();
        connection.close();
    }
}

2) 生产者代码

package com.lin.activemqdemo.demo03_topic;

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce {
     

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String TOPIC_NAME = "topic-test";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        // 两个参数 事务 / 签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Topic topic = session.createTopic(TOPIC_NAME);
        //5 创建消息的生产者
        MessageProducer messageProducer = session.createProducer(topic);
        messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
        //6 生产3条消息发送到消息队列里面
        for (int i = 0; i < 3; i++) {
     
            // 7 创建消息
            TextMessage textMessage = session.createTextMessage("topic测试消息" + i);
            // 8 通过消息生产者发布
            messageProducer.send(textMessage);
        }
        //9 关闭资源
        messageProducer.close();
        session.close();
        connection.close();
        System.out.println("TOPIC消息发送到MQ完成");
    }
}

3) 测试步骤

  1. 先启动消费者代码,为1号消费者
  2. 修改消费者代码中的输出文字,然后启动,为2号消费者,这个通过IDEA设置代码可以启动2个进程
  3. 启动生产者代码,
  4. 发现启动之后,1号消费者和2号消费者,接收的消息都是生产者发送的全部消息,而不是一人一半
  5. 当我们通过生产者再次启动发送消息时,发送1号消费者和2号消费者依然能够接收到消息

3 队列VS主题

比较项目 Topic模式对队列 Queue模式队列
工作模式 ”订阅-发布“模式,如果当前没有订阅者,消息将会被丢弃,如果有多个订阅者,那么这些订阅者都会收到消息 “负载均衡”模式,如果当前没有消费者,消息也不会丢弃,如果有多个消费者,那么1条消息只能发送给其中一个消费者,并且要求消费者ack消息
有无状态 无状态 Queue数据默认会在mq服务器上以文字形式保存,比如ActiveMQ一般保存在$AMQ_HOME/data/kr-store/data下面,也可以配置成DB存储
传递完整性 如果没有订阅者,消息会被丢弃 消息不回丢弃
处理效率 由于消息要按照订阅者的数量进行复制,所以处理性能会随着订阅者的增加而明显降低,并且还要结合不同消息协议自身的性能差异 由于1条消息只能发送给1个消费者,所以就算消费者再多,性能也就不会有明显降低,当然不同消息协议的具体性能也是有差异的

五、 JMS规范和落地产品

1 是什么?

Java Message Service(Java消息服务是JavaEE中的一个技术)

Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持Java应用程序开发。在JavaEE中,当两个应用程序使用JMS进行通信时,它们之间斌不是之间相连的,而是通过一个共同的消息收发服务组件关联起来以达到解耦/异步削峰的效果
ActiveMQ_第6张图片

2 MQ消息中间件落地产品

特性 ActiveMQ RabbitMQ Kafka RockerMQ
PRODUCER-COMSUMER 支持 支持 支持 支持
PUBLISH-SUBSCRIBE 支持 支持 支持 支持
REQUEST-REPLY 支持 支持 - 支持
API完整性 低(静态配置)
多语言支持 支持,Java优先 语言无关 支持,Java有限 支持
单机吞吐量 万级 万级 十万级 单机万级
消息延迟 - 微秒级 毫秒级 -
可用性 高(主从) 高(主从) 非常高(分布式)
消息丢失 - 理论上不会丢失 -

3 JMS的组成结构和特点

ActiveMQ_第7张图片

消息设置示例代码

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProducer {
     

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String TOPIC_NAME = "topic-test2";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 创建连接
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地
        Topic topic = session.createTopic(TOPIC_NAME);
        //5 创建消息的生产者
        MessageProducer producer = session.createProducer(topic);
        // 消息头设置
        // 1)可以统一设置消息为非持久化
        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
        // 2)可以统一设置消息优先级
        producer.setPriority(4);
        // 3)可以统一设置过期时间
        //producer.setTimeToLive(1000);
        for (int i = 0; i < 3; i++) {
     
            //文本消息
            TextMessage textMessage = session.createTextMessage("文本消息" + i);
            //单独设置某条消息为队列/主题模式
            //textMessage.setJMSDestination(topic);
            //单独设置某条消息的持久化策略
            //textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
            //单独设置某条消息的过期时间
            //textMessage.setJMSExpiration(1000);
            //单独设置某条消息的优先级
            //textMessage.setJMSPriority(5);
            //单独设置某条消息的id
            //textMessage.setJMSMessageID("1000");
            producer.send(textMessage);

            //map类型
            MapMessage mapMessage = session.createMapMessage();
            mapMessage.setString("hello","world");

            //其它类型....
        }
        // 6 关闭资源
        producer.close();
        session.close();
        connection.close();
        System.out.println("消息发送成功");
    }
}

4 JMS的可靠性ActiveMQ_第8张图片

持久的Queue

持久的Topic

1) 消费者代码
// 主要代码有和上面不一样的

import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.io.IOException;

public class JmsConsumer_Topic_Persist {
     

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String TOPIC_NAME = "topic-persist";

    public static void main(String[] args) throws JMSException, IOException {
     
        System.out.println("我是1号消费者");
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        // 设置订阅者id
        connection.setClientID("1号消费者");
        //3 创建会话seesion
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Topic topic = session.createTopic(TOPIC_NAME);
        TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic,"remark");
        //5 启动
        connection.start();;
        //6 订阅者接收
        Message message = topicSubscriber.receive();
        while (message != null){
     
            TextMessage textMessage = (TextMessage) message;
            System.out.println("收到的持久化topic:" + textMessage.getText());
            //接收消息之后一直监听服务
            message = topicSubscriber.receive();
            //第一次接收到消息之后,4秒之内没有接收到新消息,服务自动停止
            //message = topicSubscriber.receive(4000);
        }
        session.close();
        connection.close();
    }
}
2) 启动者代码
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmvProduce_Topic_Persist {
     

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String TOPIC_NAME = "topic-persist";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        //3 创建会话seesion
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Topic topic = session.createTopic(TOPIC_NAME);
        //5 创建消息的生产者
        MessageProducer messageProducer = session.createProducer(topic);
        messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
        //6 这里在上面设置完持久话在启动
        connection.start();
        //7 生产3条消息发送到消息队列里面
        for (int i = 0; i < 3; i++) {
     
            TextMessage textMessage = session.createTextMessage("topic消息" + i);
            messageProducer.send(textMessage);
        }
        //8 关闭资源
        messageProducer.close();
        session.close();
        connection.close();
        System.out.println("TOPIC消息发送到MQ完成");
    }
}
3) 测试方式
序号 启动方式 结果
1 先启动消费者,订阅主题,然后启动生产者 消息可以正常接收
2 先启动1号消费者,然后启动2号消费者,然后启动生产者 消息可以正常接收
3 先启动1号消费者,订阅之后在关闭,然后启动生产者发送消息,再次启动消费者看是否能收到消息? 1号消费者启动之后之前的消息正常接收
4) 结论
  1. 一定要先运行一次消费者,等于向MQ注册,类似我订阅了这个主题
  2. 然后在运行生产者发送信息
  3. 此时无论消费者是否在线,都会接收到,不在线的话,下次连接的时候,会把没有收到的消息都接收过来

需要注意页面订阅者数量变化,可以查看到当前主题的在线人数和离线人数
ActiveMQ_第9张图片

事务transcation

步骤

  1. 开启消息事务, 在创建session的时候开启
  2. 当消息通过send()方法发送之后,必须要通过 session.commit(); 才能提交成功
  3. 当出现异常时,可以通过 session.rollback(); 进行回滚
生产者开启事务代码示例
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsProduce {
     

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String QUEUE_NAME = "test_queue01";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        //  !!!!!!!!!!!!!!!这是设置事务为 true 开启状态
        Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5 创建消息的生产者
        MessageProducer messageProducer = session.createProducer(queue);
        //6 生产3条消息发送到消息队列里面
        for (int i = 0; i < 3; i++) {
     
            // 7 创建消息
            TextMessage textMessage = session.createTextMessage("发送队列测试消息----" + i);
            // 8 通过消息生产者发布
            messageProducer.send(textMessage);
        }
        //9 关闭资源
        messageProducer.close();
        // 当上面开启事务以后,这里一定要通过commit提交
        session.commit();
        session.close();
        connection.close();
        System.out.println("消息发送到MQ完成");

        try {
     

        }catch (Exception e){
     
            // 如果代码如果任何异常,可以使用rollback进行回滚
            session.rollback();
        }
    }
}
消费者开启事务代码示例

注意: 当消费者开启事务以后,也必须要commit提交,不然这条消息则没有被消费,下次运行消费者代码会再次获取相同的消息,造成非常常见的问题: 消息重复消费

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

public class JmsConsumer {
     

    // 消息接收

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String QUEUE_NAME = "test_queue01";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5 创建消息的消费者
        MessageConsumer consumer = session.createConsumer(queue);
        //6 循环获取消息
        while (true){
     
            TextMessage textMessage = (TextMessage) consumer.receive(1000);
            if (textMessage != null){
     
                System.out.println("消费消息----->" + textMessage.getText());
            }else {
     
                break;
            }
        }
        //7 关闭资源
        consumer.close();
        //这里一定要commit,不然则消息没有被消费,下次运行还会获取相同的消息
        //会造成消息重复消费
        session.commit();
        session.close();
        connection.close();
        System.out.println("消费MQ消息成功");
    }
}

签收acknowledge

描述 代码
常用 自动签收 Session.AUTO_ACKNOWLEDGE=1
常用 手动签收 Session.CLIENT_ACKNOWLEDGE=2
允许部分重复签收 Session.DUPS_OK_ACKNOWLEDGE=3
事务 Session.SESSION_TRANSACTED=0
非事务状态下消费者开启自动签收示例代码
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;

public class JmsConsumer {
     

    // 消息接收

    public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
    public static final String QUEUE_NAME = "test_queue01";

    public static void main(String[] args) throws JMSException {
     
        //1 创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2 通过连接工程,获取连接connection并启动访问
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //3 创建会话seesion
        // 设置签收为自动签收
        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        //4 创建目的地(具体是队列还是主题topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5 创建消息的消费者
        MessageConsumer consumer = session.createConsumer(queue);
        //6 循环获取消息
        while (true){
     
            TextMessage textMessage = (TextMessage) consumer.receive(1000);
            if (textMessage != null){
     
                System.out.println("消费消息----->" + textMessage.getText());
                // 消息一定要确定签收,不然会造成重复消费
                textMessage.acknowledge();
            }else {
     
                break;
            }
        }
        //7 关闭资源
        consumer.close();
        session.close();
        connection.close();
        System.out.println("消费MQ消息成功");
    }
}
事务状态下消费者开启手动签收

测试情况:

事务状态 签收状态 是否commit() 是否调用acknowledge() 结果 结论
开启 自动签收 消息不会重复消费 事务会帮我们进行手动签收
开启 自动签收 消息会重复消费 没有commit则签收不管事

5 点对点模式的总结

点对点模式是基于队列的,生产者发消息队列,消费者从队列接收消息,队列的存在使得消息的异步传输成为可能,和我们平常给朋友发送短信类似

1 如果在Session关闭时有部分消息已被接收到但还没有被签收(ack),那当消费者下次连接到相同的队列时,这些消息还会被再次接收

2 队列可以长久地保存消息知道消费者收到消息,消费者不需要因为担心消息会丢失而时刻和队列保持激活的连接状态,充分体现了异步传输模式的优势

6 发布/订阅模式总结

非持久订阅

JMS Pub/Sub模型定义了如何向一个内容节点发送和订阅消息,这些节点被称作topic

主题可以被认为是消息的传输中介,发布者(publisher)发布消费到主题,订阅者(subscribe)从主题订阅消息

主题使得消息订阅者和消息发布者保持互相独立,不需要接触即可保证消息的传送

持久订阅

客户端首先向MQ注册一个自己的身份ID识别号,当这个客户端处理离线时,生产者会为这个ID保存所有发送到主题的消息,当客户再次连接到MQ时会根据消费者的ID得到所有当自己处理离线时发送到主题的消息

非持久订阅状态下,不能恢复或重新派送一个未签收的消息

持久订阅才能恢复或重新派送一个未签收的消息

六、ActiveMQ的Broker

1 是什么

相当于一个ActiveMQ服务器示例

说白了,Broker其实就是实现了用代码的形式启动ActiveMQ将MQ嵌入到Java代码中,以便随时用随时启动,在用的时候再去启动,这样能节省了资源,也保证了可靠性

2 不同配置文件启动ActiveMQ

启动命令
./bin/activemq start xbean:file:/usr/local/apache-activemq-5.16.0/conf/activemq02.xml

启动示例

3 嵌入式Broker

import org.apache.activemq.broker.BrokerService;

public class EmbedBroker {
     

   public static void main(String[] args) throws Exception {
     
       // 在本机启动一个迷你般的ActiveMQ
       BrokerService brokerService = new BrokerService();
       brokerService.setUseJmx(true);
       // 因为要在本机启动,所以地址为本机
       brokerService.addConnector("tcp://localhost:61616");
       brokerService.start();
   }
}

启动之后可以通过JPS查看进程,然后通过消费者和生产者测试

七、SpringBoot整合ActiveMQ

八、ActiveMQ的传输协议

1) 面试题

  1. 默认的61616端口如何修改
  2. 你生产上的链接协议如何配置的? 使用tcp吗?

2) 官网

3)协议有哪些

序号 名称 使用频率
1 TCP协议 默认
2 New I/0协议 常用
3 AMQP协议
4 stomp协议
5 mqtt协议
6 ws协议
7

4 NIO案例演示

public static void main(String[] args) throws Exception {
// 在本机启动一个迷你般的ActiveMQ
BrokerService brokerService = new BrokerService();
brokerService.setUseJmx(true);
// 因为要在本机启动,所以地址为本机
brokerService.addConnector(“tcp://localhost:61616”);
brokerService.start();
}
}


启动之后可以通过JPS查看进程,然后通过消费者和生产者测试

## 七、SpringBoot整合ActiveMQ

## 八、ActiveMQ的传输协议

### 1) 面试题

1. 默认的61616端口如何修改
2. 你生产上的链接协议如何配置的? 使用tcp吗?

### 2) 官网

### 3)协议有哪些

| 序号 |    名称     | 使用频率 |
| :--: | :---------: | :------: |
|  1   |   TCP协议   |   默认   |
|  2   | New I/0协议 |   常用   |
|  3   |  AMQP协议   |          |
|  4   |  stomp协议  |          |
|  5   |  mqtt协议   |          |
|  6   |   ws协议    |          |
|  7   | ........... |          |

### 4 NIO案例演示



















你可能感兴趣的:(JavaEE)