Java入门级教程27——ActiveMQ的下载与应用

1.ActiveMQ的下载与使用

1.1 下载与运行

① 下载地址:ActiveMQ (稳定版,适配 JDK8/11/17,低版本 JDK 无法运行高版本编译的程序,会导致 ActiveMQ 启动失败,建议安装ActiveMQ Classic 5.15.0 版本)

② 根据操作系统类型选择性安装

③ 下载解压后,打开文件夹,找到activemq.bat,双击打开,或右击选择以管理员身份运行

④ 运行成功显示

⑤ 运行成功后,在浏览器中访问网址: http://127.0.0.1:8161/admin/
账号和密码都默认为: admin

1.2 修改密码

① 若要修改密码,找到 jetty-realm.properties 文件,右击选择记事本方式打开

② 自定义修改用户名和密码(格式:"admin:密码,用户名")

③ 修改后按Ctrl+S保存,关闭 activemq.bat 运行界面,重新打开

④ 刷新网址,输入新设定的用户名和密码登录

2.点对点文本消息的发送与接收(SpringBoot 整合 ActiveMQ)

2.1 项目准备

2.1.1 启动 ActiveMQ 服务

  • 双击activemq.bat(Windows)/ 执行./activemq start(Linux/Mac)启动服务

  • 验证启动:访问 ActiveMQ 管理控制台 http://127.0.0.1:8161/admin输入用户名密码

2.1.2 配置 ActiveMQ 用户名密码(匹配代码)

为了和代码中的认证信息一致,修改 ActiveMQ 的用户配置,避免匿名访问:

  • 打开 ActiveMQ 安装目录下的conf/activemq.xml

  • <broker>标签内最后添加用户认证插件(直接复制)

    <plugins> <simpleAuthenticationPlugin> <users> <authenticationUser username="hy" password="123456" groups="users,admins"/> </users> </simpleAuthenticationPlugin> </plugins>
  • 保存后重启 ActiveMQ 服务,配置生效。

2.2 实现过程

2.2.1 新建项目

2.2.2 添加Maven依赖

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.hy</groupId>
    <artifactId>mqdemo1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mqdemo1</name>
    <description>mqdemo1</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- JUnit 测试依赖 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- ActiveMQ 核心依赖 -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-core</artifactId>
            <version>5.7.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2.3 具体实现

① 消息生产者(ActiveMqP2PSender.java)

负责向 ActiveMQ 的hy-queue队列发送持久化消息 ,支持循环发送多条消息,消息持久化保证 ActiveMQ 重启后数据不丢失。创建在com.hy.mqdemo1.chapter1包下:

java 复制代码
package com.hy.mqdemo1.chapter1;

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

/**
 * ActiveMQ 点对点模式 - 消息生产者
 * 功能:向hy-queue队列发送持久化文本消息
 */
public class ActiveMqP2PSender {
    // ActiveMQ 连接用户名(与activemq.xml配置一致)
    private static final String USERNAME = "hy";
    // ActiveMQ 连接密码(与activemq.xml配置一致)
    private static final String PASSWORD = "123456";
    // ActiveMQ 通信地址(默认TCP端口:61616,固定写法)
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    // 消息队列名称(生产者和消费者必须一致,否则无法通信)
    private static final String QUEUE_NAME = "hy-queue";

    public void sendMessage(String msg, int sendCount) {
        // 1. 声明JMS核心对象(连接工厂、连接、会话、目的地、生产者)
        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Destination destination = null;
        MessageProducer producer = null;

        try {
            // 2. 创建ActiveMQ连接工厂(传入用户名、密码、通信地址)
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            // 3. 通过工厂创建连接对象
            connection = factory.createConnection();
            // 4. 启动连接(必须启动,否则无法发送/接收消息)
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接:" + connection);

            // 5. 创建会话对象
            // 参数1:transacted - 是否开启事务,false=不开启(点对点模式一般不开启)
            // 参数2:acknowledgeMode - 消息确认模式,AUTO_ACKNOWLEDGE=自动确认
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 6. 创建消息目的地 - 点对点模式使用Queue,指定队列名
            destination = session.createQueue(QUEUE_NAME);
            // 7. 创建消息生产者,绑定到指定队列
            producer = session.createProducer(destination);

            // 8. 设置消息持久化(核心!避免ActiveMQ关闭/重启后消息丢失)
            // DeliveryMode.PERSISTENT=持久化(存文件),NON_PERSISTENT=非持久化(存内存)
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);

            // 9. 循环发送指定数量的消息
            for (int i = 0; i < sendCount; i++) {
                // 创建文本消息(JMS基础消息类型,也支持Map/Object等类型)
                TextMessage textMessage = session.createTextMessage("【第" + (i+1) + "条消息】" + msg);
                // 发送消息到队列
                producer.send(textMessage);
                System.out.println("📤 成功发送消息:" + textMessage.getText());
            }

        } catch (JMSException e) {
            // 捕获JMS异常,打印堆栈信息
            e.printStackTrace();
        } finally {
            // 10. 关闭资源(从后往前关,避免资源泄漏)
            try {
                if (producer != null) producer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
                System.out.println("🔌 成功关闭ActiveMQ连接资源");
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    // 测试主方法 - 运行即可发送消息
    public static void main(String[] args) {
        ActiveMqP2PSender sender = new ActiveMqP2PSender();
        // 发送消息内容:"SpringBoot整合ActiveMQ点对点测试",发送数量:10条
        sender.sendMessage("SpringBoot整合ActiveMQ点对点测试", 10);
    }
}

② 消息消费者(ActiveMqP2PReceiver.java)

负责持续监听 ActiveMQ 的hy-queue队列,通过while(true)保持程序运行,实现消息实时接收,采用监听器模式(异步接收) ,消息到达自动触发处理逻辑。创建在com.hy.mqdemo1.chapter1包下:

java 复制代码
package com.hy.mqdemo1.chapter1;

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

/**
 * ActiveMQ 点对点模式 - 消息消费者
 * 功能:持续监听hy-queue队列,异步接收并处理消息
 */
public class ActiveMqP2PReceiver {
    // 与生产者保持一致的配置(用户名、密码、地址、队列名)
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String QUEUE_NAME = "hy-queue";

    public void receiveMessage() {
        // 1. 声明JMS核心对象
        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Destination destination = null;
        MessageConsumer consumer = null;

        try {
            // 2. 创建连接工厂(与生产者一致)
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            // 3. 创建连接并启动
            connection = factory.createConnection();
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接,开始监听队列:" + QUEUE_NAME);

            // 4. 创建会话(参数与生产者一致,保证通信兼容)
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 5. 绑定到相同的队列(必须和生产者一致)
            destination = session.createQueue(QUEUE_NAME);
            // 6. 创建消息消费者,绑定到指定队列
            consumer = session.createConsumer(destination);

            // 7. 设置消息监听器(异步接收核心)
            // 当队列中有新消息时,自动触发onMessage方法处理消息
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    // 判断消息类型为文本消息(与生产者发送的类型匹配)
                    if (message instanceof TextMessage) {
                        TextMessage textMessage = (TextMessage) message;
                        try {
                            // 解析并打印接收到的消息
                            System.out.println("📥 成功接收消息:" + textMessage.getText());
                        } catch (JMSException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

            // 8. 持续监听 - while(true)保证程序不退出,一直监听队列
            // 实际项目中可通过配置/开关控制,此处为测试简化
            while (true) {
                // 让线程休眠1秒,避免空循环占用CPU
                Thread.sleep(1000);
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 注意:实际监听场景中,消费者一般不主动关闭资源!
            // 此处仅做异常时的资源释放,正常运行时保持连接
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
                System.out.println("🔌 异常关闭ActiveMQ连接资源");
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    // 测试主方法 - 运行即可开始持续监听
    public static void main(String[] args) {
        ActiveMqP2PReceiver receiver = new ActiveMqP2PReceiver();
        receiver.receiveMessage();
    }
}

2.2.4 运行与测试

① 运行 ActiveMqP2PSender.java 文件,控制台打印📤 成功发送消息+🔌 成功关闭连接,说明消息发送成功;

② 打开 ActiveMQ 管理控制台 http://127.0.0.1:8161/admin点击左侧Queues,可看到hy-queue队列的**Messages Enqueued** (入队数)=10,说明消息已存入 ActiveMQ;

③ 运行 ActiveMqP2PReceiver.java 文件,控制台打印✅ 成功获取连接,开始监听队列,随后快速打印📥 成功接收消息,共 10 条;

④ 刷新 ActiveMQ 管理控制台,hy-queue队列的Messages Dequeued (出队数)=10,Messages Pending (待消费数)=0,说明消息全部被消费。

测试持久化(关键验证

  1. 先不启动消费者,直接运行生产者发送 10 条消息;
  2. 关闭 ActiveMQ 服务(执行activemq stop/ 关闭 bat 窗口);
  3. 重新启动 ActiveMQ 服务;
  4. 运行消费者,控制台仍能接收到 10 条消息,说明持久化生效(消息存到了文件,重启后未丢失)。

3.点对点对象消息的发送与接收

实际业务中常需传输自定义对象(如用户信息),ActiveMQ 支持序列化对象消息传输,但需保证对象实现Serializable接口。

3.1 具体实现

① 自定义序列化对象(User)

java 复制代码
package com.hy.mqdemo1.chapter2;

/**
 * 自定义用户类
 * 必须实现java.io.Serializable接口才能通过ActiveMQ传输对象
 */
public class User implements java.io.Serializable {

    private int id;       // 用户ID
    private String name;  // 用户名

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

② 对象消息生产者(P2PSender)

java 复制代码
package com.hy.mqdemo1.chapter2;
import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * ActiveMQ 点对点模式 - 对象消息生产者(沿用统一类名)
 * 功能:发送序列化User对象到object1队列(持久化)
 */
public class P2PSender {
    // 你的ActiveMQ连接配置(hy/123456)
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String QUEUE_NAME = "object1";

    public void sendObjectMessage() {
        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Destination destination = null;
        MessageProducer producer = null;

        try {
            // 创建连接工厂
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接:" + connection);

            // 创建会话+队列
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue(QUEUE_NAME);
            producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 持久化

            // 复用User对象创建逻辑
            User u = new User();
            u.setId(100);
            u.setName("hhhy");

            // 封装为ObjectMessage并发送
            ObjectMessage msgObj = session.createObjectMessage();
            msgObj.setObject(u);
            producer.send(msgObj);
            System.out.println("📤 发送对象消息成功:ID=" + u.getId() + ", 姓名=" + u.getName());

        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源(沿用之前的资源释放逻辑)
            try {
                if (producer != null) producer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
                System.out.println("🔌 成功关闭ActiveMQ连接资源");
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ActiveMqP2PSender sender = new ActiveMqP2PSender();
        sender.sendObjectMessage();
    }
}

③ 对象消息消费者(P2PReceiver)

java 复制代码
package com.hy.mqdemo1.chapter2;
import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * ActiveMQ 点对点模式 - 对象消息消费者(沿用统一类名)
 * 功能:监听object1队列,异步接收并反序列化User对象
 */
public class P2PReceiver {
    // 与生产者一致的配置
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String QUEUE_NAME = "object1";

    public void receiveObjectMessage() {
        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Destination destination = null;
        MessageConsumer consumer = null;

        try {
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接,开始监听队列:" + QUEUE_NAME);

            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue(QUEUE_NAME);
            consumer = session.createConsumer(destination);

            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    try {
                        System.out.println("\n📥 接收到对象消息");
                        User u = (User) ((ObjectMessage) message).getObject();
                        System.out.println("接收到的数据为: " + u.getId() + "," + u.getName());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

            // 保持程序运行(解决闪退问题)
            synchronized (this) {
                this.wait();
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
                System.out.println("🔌 异常关闭ActiveMQ连接资源");
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ActiveMqP2PReceiver receiver = new ActiveMqP2PReceiver();
        receiver.receiveObjectMessage();
    }
}

3.2 运行与测试

3.2.1 运行顺序

  • 启动消费者监听object1队列;
  • 启动生产者,发送包含 User 对象的消息;
  • 消费者控制台输出:接收到的数据为: 100,hhhy

3.2.2 预期输出

4.发布订阅模式基础文本消息收发

实现 "一个生产者 + 两个消费者(邮件 + 短信系统)" 的 Topic 模式通信,体现发布订阅 "一对多" 的核心特性。

4.1 具体实现

① 消息生产者(TopicOrderSender)

java 复制代码
package com.hy.mqdemo1.chapter3;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * Topic模式 - 订单消息生产者
 * 功能:向hy_topic1主题发送文本消息
 */
public class TopicOrderSender {
    // 统一使用你的ActiveMQ配置
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_topic1";

    public void start() {
        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageProducer producer = null;

        try {
            // 1. 创建连接工厂
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            // 2. 创建并启动连接
            connection = factory.createConnection();
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接:" + connection);

            // 3. 创建会话(非事务+自动确认)
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 4. 创建Topic主题(与消费者一致)
            topic = session.createTopic(TOPIC_NAME);
            // 5. 创建生产者
            producer = session.createProducer(topic);

            // 6. 发送文本消息(保持原始消息内容)
            TextMessage textMessage = session.createTextMessage("祝你星途璀璨");
            producer.send(textMessage);
            System.out.println("📤 发送Topic消息完毕:" + textMessage.getText());

        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源(避免泄漏)
            try {
                if (producer != null) producer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicOrderSender sender = new TopicOrderSender();
        sender.start();
    }
}

② 邮件系统消费者(TopicMailReceiver)

java 复制代码
package com.hy.mqdemo1.chapter3;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * Topic模式 - 邮件系统消费者
 * 功能:持续监听hy_topic1主题,接收文本消息
 */
public class TopicMailReceiver {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_topic1";

    public void startMail() {
        System.out.println("📧 邮件系统平台已启动,开始监听Topic:" + TOPIC_NAME);

        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageConsumer consumer = null;

        try {
            // 1. 创建连接工厂
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            // 2. 创建并启动连接
            connection = factory.createConnection();
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接:" + connection);

            // 3. 创建会话
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 4. 绑定Topic
            topic = session.createTopic(TOPIC_NAME);
            // 5. 创建消费者
            consumer = session.createConsumer(topic);

            // 6. 设置消息监听器(异步消费)
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    if (message instanceof TextMessage textMessage) {
                        try {
                            System.out.println("📥 邮件系统平台接收到的消息为:" + textMessage.getText());
                        } catch (JMSException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

            // 保持程序运行(避免主线程退出,核心!)
            synchronized (this) {
                this.wait();
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 异常时关闭资源
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicMailReceiver receiver = new TopicMailReceiver();
        receiver.startMail();
    }
}

③ 短信系统消费者(TopicSMSReceiver)

java 复制代码
package com.hy.mqdemo1.chapter3;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * Topic模式 - 短信系统消费者
 * 功能:持续监听hy_topic1主题,接收文本消息(对应原始SMSReceiverTopic)
 */
public class TopicSMSReceiver {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_topic1";

    public void startSMS() {
        System.out.println("📱 短信系统平台已启动,开始监听Topic:" + TOPIC_NAME);

        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageConsumer consumer = null;

        try {
            // 1. 创建连接工厂
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            // 2. 创建并启动连接
            connection = factory.createConnection();
            connection.start();
            System.out.println("✅ 成功获取ActiveMQ连接:" + connection);

            // 3. 创建会话
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            // 4. 绑定Topic
            topic = session.createTopic(TOPIC_NAME);
            // 5. 创建消费者
            consumer = session.createConsumer(topic);

            // 6. 设置消息监听器(异步消费)
            consumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    if (message instanceof TextMessage textMessage) {
                        try {
                            System.out.println("📥 短信系统平台接收到的消息为:" + textMessage.getText());
                        } catch (JMSException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

            // 保持程序运行(避免主线程退出,核心!)
            synchronized (this) {
                this.wait();
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 异常时关闭资源
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicSMSReceiver receiver = new TopicSMSReceiver();
        receiver.startSMS();
    }
}

4.2 运行与测试

4.2.1 运行顺序

  • 先启动 邮件系统消费者(ActiveMqTopicMailReceiver);
  • 再启动 短信系统消费者(ActiveMqTopicSMSReceiver);
  • 最后启动 生产者(ActiveMqTopicOrderSender)。

4.2.2 预期输出

① 邮件系统控制台:

② 短信系统控制台:

③ 生产者控制台:

④ ActiveMQ ------ Topics 查询:

5.多平台数据分发(MySQL+Redis)

实现通过 Topic 模式将输入的数据同时分发到 MySQL 数据库和 Redis 缓存,模拟实际业务中的数据同步场景。

5.1 添加 Maven 依赖

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.hy</groupId>
    <artifactId>mqdemo1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mqdemo1</name>
    <description>mqdemo1</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- JUnit 测试依赖 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- ActiveMQ 核心依赖 -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-core</artifactId>
            <version>5.7.0</version>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <!-- Redis客户端 -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.3.1</version>
        </dependency>

        <!-- FastJSON(对象序列化) -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.25</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

5.2 具体实现

① 数据库工具类( DBUtil )

java 复制代码
package com.hy.mqdemo1.chapter4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 数据库操作工具类(适配你的MySQL配置)
 */
public class DBUtil {
    // 你的MySQL配置
    private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/mysql2026";
    private static final String DB_USER = "root";
    private static final String DB_PWD = "Hy61573166!!!";

    /**
     * 插入数据到t_classes表
     */
    public void addDatas(String data) {
        System.out.println("🗄️ 开始插入数据库:" + data);
        String sql = "INSERT INTO t_classes(cid, cname, cphone) VALUES (?, ?, ?)";
        Connection conn = null;

        try {
            // 1. 加载驱动并创建连接
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);

            // 2. 解析数据(格式:cid,cname,cphone)
            String[] datas = data.split(",");
            if (datas.length != 3) {
                System.out.println("❌ 数据格式错误,需满足:cid,cname,cphone");
                return;
            }

            // 3. 执行插入
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, Integer.parseInt(datas[0]));
            pstmt.setString(2, datas[1]);
            pstmt.setString(3, datas[2]);
            pstmt.executeUpdate();
            System.out.println("✅ 数据库插入成功");

        } catch (ClassNotFoundException | SQLException e) {
            System.out.println("❌ 数据库操作异常");
            e.printStackTrace();
        } finally {
            // 4. 关闭连接
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

② Redis 消费者(TopicRedisReceiver------监听 Topic 并缓存数据)

java 复制代码
package com.hy.mqdemo1.chapter4;

import com.alibaba.fastjson.JSONObject;
import org.apache.activemq.ActiveMQConnectionFactory;
import redis.clients.jedis.Jedis;

import javax.jms.*;

/**
 * Topic消费者 - Redis缓存平台
 * 功能:监听hy_adddatas主题,将数据缓存到Redis
 */
public class TopicRedisReceiver {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_adddatas";
    // Redis连接(静态初始化)
    private static final Jedis jedis = new Jedis("127.0.0.1", 6379);

    static {
        System.out.println("🔴 Redis连接成功:" + jedis.ping());
    }

    public void startRedisListener() {
        System.out.println("💾 Redis数据缓存平台已启动,监听Topic:" + TOPIC_NAME);

        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageConsumer consumer = null;

        try {
            // 1. 创建ActiveMQ连接
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();

            // 2. 创建会话和消费者
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic(TOPIC_NAME);
            consumer = session.createConsumer(topic);

            // 3. 监听消息并缓存到Redis
            consumer.setMessageListener(message -> {
                if (message instanceof TextMessage textMessage) {
                    try {
                        String data = textMessage.getText();
                        System.out.println("📥 Redis平台接收消息:" + data);

                        // 解析数据并转换为JSON
                        String[] datas = data.split(",");
                        JSONObject json = new JSONObject();
                        json.put("cid", Integer.parseInt(datas[0]));
                        json.put("cname", datas[1]);
                        json.put("cphone", datas[2]);

                        // 缓存到Redis
                        jedis.set("classesdatas", json.toJSONString());
                        System.out.println("✅ Redis缓存成功:" + json.toJSONString());

                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

            // 保持程序运行
            synchronized (this) {
                this.wait();
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
                jedis.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicRedisReceiver receiver = new TopicRedisReceiver();
        receiver.startRedisListener();
    }
}

③ MySQL 消费者(TopicDBReceiver ------ 监听 Topic 并插入数据)

java 复制代码
package com.hy.mqdemo1.chapter4;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * Topic消费者 - MySQL数据库平台
 * 功能:监听hy_adddatas主题,将数据插入数据库
 */
public class TopicDBReceiver {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_adddatas";

    public void startDBListener() {
        System.out.println("🗄️ MySQL数据库平台已启动,监听Topic:" + TOPIC_NAME);

        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageConsumer consumer = null;

        try {
            // 1. 创建ActiveMQ连接
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();

            // 2. 创建会话和消费者
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic(TOPIC_NAME);
            consumer = session.createConsumer(topic);

            // 3. 监听消息并插入数据库
            consumer.setMessageListener(message -> {
                if (message instanceof TextMessage textMessage) {
                    try {
                        String data = textMessage.getText();
                        System.out.println("📥 MySQL平台接收消息:" + data);

                        // 插入数据库
                        DBUtil dbUtil = new DBUtil();
                        dbUtil.addDatas(data);

                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

            // 保持程序运行
            synchronized (this) {
                this.wait();
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicDBReceiver receiver = new TopicDBReceiver();
        receiver.startDBListener();
    }
}

④ 数据生产者(TopicDataSender ------ 控制台输入数据并发送)

java 复制代码
package com.hy.mqdemo1.chapter4;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;
import java.util.Scanner;

/**
 * Topic生产者 - 数据发送端
 * 功能:控制台输入数据,发送到hy_adddatas主题
 */
public class TopicDataSender {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_adddatas";

    public void sendDataMessage() {
        // 1. 控制台输入数据
        System.out.println("请输入数据(格式:cid,cname,cphone):");
        Scanner scanner = new Scanner(System.in);
        String inputData = scanner.nextLine();
        scanner.close();

        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageProducer producer = null;

        try {
            // 2. 创建ActiveMQ连接
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();

            // 3. 创建会话和生产者
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic(TOPIC_NAME);
            producer = session.createProducer(topic);

            // 4. 发送文本消息
            TextMessage textMessage = session.createTextMessage(inputData);
            producer.send(textMessage);
            System.out.println("📤 数据发送成功:" + inputData);

        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (producer != null) producer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicDataSender sender = new TopicDataSender();
        sender.sendDataMessage();
    }
}

5.3 运行与测试

5.3.1 运行顺序

  • 启动 Redis 消费者和 MySQL 消费者;
  • 启动生产者,输入数据(如:100,Java班,13800138000);
  • Redis 控制台显示缓存成功,MySQL 控制台显示插入成功,可查询数据库验证数据。

5.3.2 预期输出

① Redis 消费者控制台:

② MySQL 消费者控制台:

③ 生产者控制台:

④ 其他查询:

6.Topic 模式序列化对象消息传输

实现将数据库查询结果(Classes 对象列表)通过 Topic 发送,并在 Redis 端接收反序列化。

6.1 具体实现

① 序列化对象类(Classes)

java 复制代码
package com.hy.mqdemo1.chapter5;

import java.io.Serializable;

/**
 * 自定义Classes类(必须实现Serializable接口)
 * 对应数据库t_classes表
 */
public class Classes implements Serializable {

    private int cid;       // 班级ID
    private String cname;  // 班级名称
    private String cphone; // 联系电话

    // Getter & Setter
    public int getCid() {
        return cid;
    }

    public void setCid(int cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public String getCphone() {
        return cphone;
    }

    public void setCphone(String cphone) {
        this.cphone = cphone;
    }

    // 重写toString,方便打印
    @Override
    public String toString() {
        return "Classes{cid=" + cid + ", cname='" + cname + "', cphone='" + cphone + "'}";
    }
}

② 数据库查询工具类(扩展)

java 复制代码
package com.hy.mqdemo1.chapter5;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据库查询工具类(查询t_classes表)
 */
public class DBQueryUtil {
    // 你的MySQL配置
    private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/mysql2026";
    private static final String DB_USER = "root";
    private static final String DB_PWD = "Hy61573166!!!";

    /**
     * 查询t_classes表所有数据
     */
    public List<Classes> queryAllClasses() {
        System.out.println("🗄️ 开始查询数据库t_classes表");
        String sql = "SELECT cid, cname, cphone FROM t_classes";
        Connection conn = null;
        List<Classes> classesList = new ArrayList<>();

        try {
            // 1. 加载驱动并创建连接
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);

            // 2. 执行查询
            PreparedStatement pstmt = conn.prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();

            // 3. 封装结果
            while (rs.next()) {
                Classes cls = new Classes();
                cls.setCid(rs.getInt("cid"));
                cls.setCname(rs.getString("cname"));
                cls.setCphone(rs.getString("cphone"));
                classesList.add(cls);
            }
            System.out.println("✅ 数据库查询成功,共" + classesList.size() + "条数据");

        } catch (ClassNotFoundException | SQLException e) {
            System.out.println("❌ 数据库查询异常");
            e.printStackTrace();
        } finally {
            // 4. 关闭连接
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return classesList;
    }
}

③ 对象消息生产者(查询数据库并发送)

java 复制代码
package com.hy.mqdemo1.chapter5;
import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;
import java.io.Serializable;
import java.util.List;

/**
 * Topic生产者 - 发送Classes对象列表
 * 功能:查询数据库,将结果封装为对象消息发送到hy_datas1主题
 */
public class TopicObjectSender {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_datas1";

    public void sendObjectMessage() {
        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageProducer producer = null;

        try {
            // 1. 创建ActiveMQ连接
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();

            // 2. 创建会话和生产者
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic(TOPIC_NAME);
            producer = session.createProducer(topic);

            // 3. 查询数据库获取Classes列表
            DBQueryUtil dbUtil = new DBQueryUtil();
            List<Classes> classesList = dbUtil.queryAllClasses();

            // 4. 创建对象消息并发送
            ObjectMessage objectMessage = session.createObjectMessage();
            objectMessage.setObject((Serializable) classesList);
            producer.send(objectMessage);
            System.out.println("📤 对象消息发送成功:" + classesList);

        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (producer != null) producer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicObjectSender sender = new TopicObjectSender();
        sender.sendObjectMessage();
    }
}

④ 对象消息消费者(Redis 接收并缓存)

java 复制代码
package com.hy.mqdemo1.chapter5;

import com.alibaba.fastjson.JSONArray;
import org.apache.activemq.ActiveMQConnectionFactory;
import redis.clients.jedis.Jedis;

import javax.jms.*;
import java.util.List;

/**
 * Topic消费者 - Redis接收对象消息
 * 功能:监听hy_datas1主题,反序列化Classes列表并缓存到Redis
 */
public class TopicObjectReceiver {
    private static final String USERNAME = "hy";
    private static final String PASSWORD = "123456";
    private static final String BROKER_URL = "tcp://127.0.0.1:61616";
    private static final String TOPIC_NAME = "hy_datas1";
    private static final Jedis jedis = new Jedis("127.0.0.1", 6379);

    static {
        System.out.println("🔴 Redis连接成功:" + jedis.ping());
    }

    public void startObjectListener() {
        System.out.println("💾 Redis对象缓存平台已启动,监听Topic:" + TOPIC_NAME);

        ConnectionFactory factory = null;
        Connection connection = null;
        Session session = null;
        Topic topic = null;
        MessageConsumer consumer = null;

        try {
            // 1. 创建ActiveMQ连接
            factory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKER_URL);
            connection = factory.createConnection();
            connection.start();

            // 2. 创建会话和消费者
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic(TOPIC_NAME);
            consumer = session.createConsumer(topic);

            // 3. 监听对象消息
            consumer.setMessageListener(message -> {
                if (message instanceof ObjectMessage objectMessage) {
                    try {
                        // 反序列化对象列表
                        List<Classes> classesList = (List<Classes>) objectMessage.getObject();
                        System.out.println("📥 Redis接收对象消息:" + classesList);

                        // 转换为JSON并缓存到Redis List
                        String jsonStr = JSONArray.toJSONString(classesList);
                        jedis.lpush("listclasses", jsonStr);
                        System.out.println("✅ Redis对象缓存成功:" + jsonStr);

                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

            // 保持程序运行
            synchronized (this) {
                this.wait();
            }

        } catch (JMSException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (consumer != null) consumer.close();
                if (session != null) session.close();
                if (connection != null) connection.close();
                jedis.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TopicObjectReceiver receiver = new TopicObjectReceiver();
        receiver.startObjectListener();
    }
}

6.2 运行与测试

6.2.1 运行顺序

  • 先在数据库 t_classes 表插入测试数据;
  • 启动 Redis 对象消费者;
  • 启动对象生产者,查询数据库并发送对象消息;
  • 消费者控制台显示接收并缓存成功,可通过 Redis 客户端查询listclasses验证。

6.2.2 预期输出

相关推荐
Irissgwe1 小时前
C&C++内存管理
c语言·开发语言·c++·c++内存管理
雾岛听蓝1 小时前
C文件操作与系统IO
linux·c语言·开发语言·经验分享·笔记·算法
夫唯不争,故无尤也1 小时前
HTTP方法详解:GET、POST、PUT、DELETE
开发语言·windows·python
Joker Zxc2 小时前
【前端基础(Javascript部分)】4、JavaScript的分支语句
开发语言·前端·javascript
小钻风33662 小时前
Optional:告别NullPointerException的优雅方案
开发语言·python
科技块儿2 小时前
多语言技术栈如何共用IP离线库?Java、Python、Go 的加载实践
java·python·tcp/ip
chools2 小时前
一篇文章带你搞懂Java“设计模式”! - - 超长文(涵盖23种)万字总结!【汇总篇】
java·开发语言·设计模式
良逍Ai出海2 小时前
OpenClaw 新手最该先搞懂的 2 套命令
android·java·数据库
6+h2 小时前
【Spring】深度剖析IoC
java·后端·spring