简介

ActiveMQ 是 Apache 提供的消息中间件。

它在 Java 生态里很常见,尤其是传统企业系统、老项目改造、JMS 规范相关系统中出现得比较多。

简单理解:


生产者 | v ActiveMQ Broker | v 消费者

ActiveMQ 最常见的使用方式是 JMS。

JMS 全称是 Java Message Service,它是一套 Java 消息服务 API 规范。

ActiveMQ 和 JMS 的关系可以类比成:


JMS 是规范 ActiveMQ 是实现

一句话概括:


ActiveMQ 是 Java 生态里经典的 JMS 消息中间件,适合异步处理、系统解耦、任务队列和发布订阅场景。

ActiveMQ 解决什么问题

一个业务动作经常会带出很多后续动作。

比如订单创建成功后:


扣库存 发短信 发邮件 写日志 生成物流任务 同步积分

如果全部同步执行,接口会变慢。

如果短信服务异常,订单接口也可能被影响。

使用 ActiveMQ 后,可以拆成:


订单服务 | v 发送订单消息 | v ActiveMQ | +--> 库存服务消费消息 +--> 短信服务消费消息 +--> 邮件服务消费消息 +--> 日志服务消费消息

常见作用:

  • 异步处理
  • 系统解耦
  • 削峰填谷
  • 任务分发
  • 发布订阅
  • 消息重试和失败兜底

ActiveMQ Classic 和 Artemis

ActiveMQ 需要先区分两条线:

名称 说明
ActiveMQ Classic 传统 ActiveMQ 5.x / 6.x 线,老项目和 JMS 系统常见
ActiveMQ Artemis 新一代消息 Broker,性能和架构更现代

简单理解:


ActiveMQ Classic:经典 JMS Broker ActiveMQ Artemis:新一代多协议、高性能 Broker

如果是维护老系统,经常会遇到 ActiveMQ Classic。

如果是新系统选型,并且明确要用 Apache ActiveMQ 体系,Artemis 更值得优先评估。

本文示例以 ActiveMQ Classic + Spring Boot JMS 为主,因为它更贴近日常 Java 老系统和企业项目集成场景。

ActiveMQ 和 RabbitMQ 的区别

对比项 ActiveMQ RabbitMQ
常见协议 JMS、OpenWire、STOMP、AMQP、MQTT AMQP 为主,也支持多协议
Java 规范关系 JMS 体系很强 不以 JMS 为核心
核心模型 Queue / Topic Exchange / Queue / Binding
路由能力 JMS 模型更直接 Exchange 路由更灵活
常见场景 传统企业系统、JMS 项目 微服务消息、灵活路由、事件分发

ActiveMQ 更像:


Queue / Topic 模型清晰,适合 JMS 项目。

RabbitMQ 更像:


Exchange + Routing Key 更灵活,适合复杂路由。

JMS 核心概念

概念 说明
ConnectionFactory 连接工厂
Connection 客户端到 Broker 的连接
Session 会话,负责生产、消费、确认、事务
Destination 目的地,Queue 或 Topic
Queue 点对点队列
Topic 发布订阅主题
MessageProducer 消息生产者
MessageConsumer 消息消费者
Message 消息对象

整体流程:


ConnectionFactory | v Connection | v Session | +--> MessageProducer -> Destination | +--> MessageConsumer <- Destination

Queue 点对点模式

Queue 是点对点模式。

特点:


一条消息只会被一个消费者处理。

示例:


order.queue | +--> consumer-1 +--> consumer-2

如果 order.queue 有 10 条消息,两个消费者会竞争消费。

每条消息最终只会被其中一个消费者处理。

适合:

  • 订单处理
  • 短信发送
  • 邮件发送
  • 报表生成
  • 后台任务

Topic 发布订阅模式

Topic 是发布订阅模式。

特点:


一条消息可以被多个订阅者收到。

示例:


order.topic | +--> sms-consumer +--> email-consumer +--> log-consumer

订单支付成功消息发送到 order.topic 后,短信、邮件、日志服务都能收到。

适合:

  • 业务事件广播
  • 通知消息
  • 日志订阅
  • 缓存刷新

Topic 持久订阅和非持久订阅

Topic 需要注意订阅方式。

类型 离线期间消息是否保留 说明
非持久订阅 不保留 消费者在线时才能收到
持久订阅 保留 消费者离线后再上线也能收到

非持久订阅适合临时通知。

持久订阅适合关键业务事件。

持久订阅通常需要设置唯一的 clientId 和订阅名。

Docker 启动 ActiveMQ Classic

本地学习可以使用 Docker。

不同镜像维护方式不同,实际项目以团队镜像仓库或官方发布包为准。

示例:


docker run -d \ --name activemq-classic \ -p 61616:61616 \ -p 8161:8161 \ apache/activemq-classic:latest

端口说明:

端口 作用
61616 JMS / OpenWire 连接端口
8161 Web 管理控制台

管理后台:


http://localhost:8161/admin

常见默认账号:


admin / admin

如果镜像没有提供默认账号,需要查看镜像说明或自定义配置。

原生 JMS 依赖

Spring Boot 3 使用 jakarta.jms 包名。

如果使用 ActiveMQ Classic 6 或 Jakarta 体系,可以选择 Jakarta 版本客户端。


<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-client-jakarta</artifactId> <version>${activemq.version}</version> </dependency>

如果是老项目,可能仍然使用 javax.jms 和 ActiveMQ 5.x 客户端。


<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-client</artifactId> <version>${activemq.version}</version> </dependency>

包名差异:


老项目:javax.jms.* 新项目:jakarta.jms.*

原生 JMS:发送 Queue 消息


package com.example.activemq.raw; import jakarta.jms.Connection; import jakarta.jms.ConnectionFactory; import jakarta.jms.DeliveryMode; import jakarta.jms.Destination; import jakarta.jms.MessageProducer; import jakarta.jms.Session; import jakarta.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class RawQueueProducer { private static final String BROKER_URL = "tcp://localhost:61616"; private static final String QUEUE_NAME = "order.queue"; public static void main(String[] args) throws Exception { ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL); try (Connection connection = factory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)) { Destination destination = session.createQueue(QUEUE_NAME); MessageProducer producer = session.createProducer(destination); producer.setDeliveryMode(DeliveryMode.PERSISTENT); TextMessage message = session.createTextMessage("订单创建成功"); message.setStringProperty("bizType", "order"); message.setStringProperty("messageId", "msg-1001"); producer.send(message); System.out.println("消息已发送:" + message.getText()); } } }

说明:


Session.AUTO_ACKNOWLEDGE:自动确认 DeliveryMode.PERSISTENT:持久化消息 createQueue:创建 Queue 目的地

原生 JMS:消费 Queue 消息


package com.example.activemq.raw; import jakarta.jms.Connection; import jakarta.jms.ConnectionFactory; import jakarta.jms.MessageConsumer; import jakarta.jms.Session; import jakarta.jms.TextMessage; import org.apache.activemq.ActiveMQConnectionFactory; public class RawQueueConsumer { private static final String BROKER_URL = "tcp://localhost:61616"; private static final String QUEUE_NAME = "order.queue"; public static void main(String[] args) throws Exception { ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL); Connection connection = factory.createConnection(); Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); MessageConsumer consumer = session.createConsumer(session.createQueue(QUEUE_NAME)); connection.start(); consumer.setMessageListener(message -> { try { if (message instanceof TextMessage textMessage) { System.out.println("收到消息:" + textMessage.getText()); } message.acknowledge(); } catch (Exception e) { throw new RuntimeException(e); } }); System.out.println("消费者已启动"); Thread.currentThread().join(); } }

CLIENT_ACKNOWLEDGE 表示客户端手动确认。

注意:


JMS 的 acknowledge() 可能确认当前 Session 中已消费的一批消息。

如果需要更强的边界控制,可以考虑事务会话。

JMS 确认模式

JMS 常见确认模式:

模式 说明
AUTO_ACKNOWLEDGE 监听器正常返回后自动确认
CLIENT_ACKNOWLEDGE 客户端调用 acknowledge() 确认
DUPS_OK_ACKNOWLEDGE 允许延迟确认,可能出现重复
SESSION_TRANSACTED 使用事务提交或回滚

AUTO_ACKNOWLEDGE 使用简单。

关键业务更常见的是事务或手动确认。

JMS 事务

创建事务会话:


Session session = connection.createSession(true, Session.SESSION_TRANSACTED);

处理成功:


session.commit();

处理失败:


session.rollback();

示例:


MessageConsumer consumer = session.createConsumer(session.createQueue("order.queue")); TextMessage message = (TextMessage) consumer.receive(); try { System.out.println("处理消息:" + message.getText()); // 执行业务逻辑 session.commit(); } catch (Exception e) { session.rollback(); }

事务回滚后,消息会重新投递。

Spring Boot 依赖

Spring Boot 集成 ActiveMQ Classic:


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

如果选择 Artemis:


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

Classic 和 Artemis 不建议在同一个应用里混用。

application.yml

ActiveMQ Classic 示例:


spring: activemq: broker-url: tcp://localhost:61616 user: admin password: admin jms: listener: acknowledge-mode: auto

如果需要连接池,可以配置连接池依赖和对应参数。

不同 Spring Boot 版本对连接池自动配置细节略有差异,实际项目以当前版本文档为准。

开启 JMS 注解

使用 @JmsListener 需要开启 JMS 注解支持。


package com.example.activemq.config; import org.springframework.context.annotation.Configuration; import org.springframework.jms.annotation.EnableJms; @Configuration @EnableJms public class JmsConfig { }

消息对象


package com.example.activemq.order; import java.math.BigDecimal; import java.time.LocalDateTime; public record OrderCreatedMessage( Long orderId, String orderNo, Long userId, BigDecimal amount, LocalDateTime createdAt ) { }

JSON 消息转换器

业务系统里更常用 JSON,而不是 Java 原生对象序列化。


package com.example.activemq.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.support.converter.MappingJackson2MessageConverter; import org.springframework.jms.support.converter.MessageConverter; import org.springframework.jms.support.converter.MessageType; @Configuration public class JmsMessageConfig { @Bean public MessageConverter jacksonJmsMessageConverter() { MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); converter.setTargetType(MessageType.TEXT); converter.setTypeIdPropertyName("_type"); return converter; } }

Queue 实战:订单消息

常量:


package com.example.activemq.config; public class ActiveMqDestinations { public static final String ORDER_QUEUE = "order.queue"; public static final String NOTICE_TOPIC = "notice.topic"; private ActiveMqDestinations() { } }

生产者:


package com.example.activemq.order; import com.example.activemq.config.ActiveMqDestinations; import org.springframework.jms.core.JmsTemplate; import org.springframework.stereotype.Service; @Service public class OrderMessageProducer { private final JmsTemplate jmsTemplate; public OrderMessageProducer(JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; } public void sendOrderCreated(OrderCreatedMessage message) { jmsTemplate.convertAndSend(ActiveMqDestinations.ORDER_QUEUE, message); } }

消费者:


package com.example.activemq.order; import com.example.activemq.config.ActiveMqDestinations; import org.springframework.jms.annotation.JmsListener; import org.springframework.stereotype.Component; @Component public class OrderMessageConsumer { @JmsListener(destination = ActiveMqDestinations.ORDER_QUEUE) public void handle(OrderCreatedMessage message) { System.out.println("收到订单消息:" + message); // 执行业务逻辑:扣库存、发通知、写日志等 } }

Controller:


package com.example.activemq.order; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; import java.time.LocalDateTime; @RestController @RequestMapping("/api/orders") public class OrderController { private final OrderMessageProducer producer; public OrderController(OrderMessageProducer producer) { this.producer = producer; } @PostMapping public String createOrder() { OrderCreatedMessage message = new OrderCreatedMessage( 1001L, "O202606300001", 2001L, new BigDecimal("99.80"), LocalDateTime.now() ); producer.sendOrderCreated(message); return "订单消息已发送"; } }

访问:


POST http://localhost:8080/api/orders

同时支持 Queue 和 Topic

JmsTemplate 有一个关键属性:


pubSubDomain

含义:


false:Queue 模式 true:Topic 模式

如果一个项目同时使用 Queue 和 Topic,可以分别创建两个模板。


package com.example.activemq.config; import jakarta.jms.ConnectionFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.core.JmsTemplate; @Configuration public class JmsTemplateConfig { @Bean public JmsTemplate queueJmsTemplate(ConnectionFactory connectionFactory) { JmsTemplate template = new JmsTemplate(connectionFactory); template.setPubSubDomain(false); return template; } @Bean public JmsTemplate topicJmsTemplate(ConnectionFactory connectionFactory) { JmsTemplate template = new JmsTemplate(connectionFactory); template.setPubSubDomain(true); return template; } @Bean public DefaultJmsListenerContainerFactory topicListenerContainerFactory( ConnectionFactory connectionFactory ) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setPubSubDomain(true); return factory; } }

Topic 实战:广播通知

生产者:


package com.example.activemq.notice; import com.example.activemq.config.ActiveMqDestinations; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jms.core.JmsTemplate; import org.springframework.stereotype.Service; @Service public class NoticeProducer { private final JmsTemplate topicJmsTemplate; public NoticeProducer(@Qualifier("topicJmsTemplate") JmsTemplate topicJmsTemplate) { this.topicJmsTemplate = topicJmsTemplate; } public void publish(String content) { topicJmsTemplate.convertAndSend(ActiveMqDestinations.NOTICE_TOPIC, content); } }

短信消费者:


package com.example.activemq.notice; import com.example.activemq.config.ActiveMqDestinations; import org.springframework.jms.annotation.JmsListener; import org.springframework.stereotype.Component; @Component public class SmsNoticeConsumer { @JmsListener( destination = ActiveMqDestinations.NOTICE_TOPIC, containerFactory = "topicListenerContainerFactory" ) public void handle(String message) { System.out.println("短信服务收到通知:" + message); } }

邮件消费者:


package com.example.activemq.notice; import com.example.activemq.config.ActiveMqDestinations; import org.springframework.jms.annotation.JmsListener; import org.springframework.stereotype.Component; @Component public class EmailNoticeConsumer { @JmsListener( destination = ActiveMqDestinations.NOTICE_TOPIC, containerFactory = "topicListenerContainerFactory" ) public void handle(String message) { System.out.println("邮件服务收到通知:" + message); } }

一条 Topic 消息会被两个消费者都收到。

Topic 持久订阅 Demo

非持久订阅只接收在线期间的 Topic 消息。

持久订阅需要设置 clientId 和订阅名。


@Bean public DefaultJmsListenerContainerFactory durableTopicListenerContainerFactory( ConnectionFactory connectionFactory ) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setPubSubDomain(true); factory.setSubscriptionDurable(true); factory.setClientId("notice-service-01"); return factory; }

监听:


@JmsListener( destination = ActiveMqDestinations.NOTICE_TOPIC, subscription = "notice-service-subscription", containerFactory = "durableTopicListenerContainerFactory" ) public void handleDurableTopic(String message) { System.out.println("持久订阅收到通知:" + message); }

持久订阅注意点:


同一个 broker 上 clientId 需要唯一 同一个 clientId + subscription 代表同一个持久订阅

消息选择器

消息选择器可以按消息属性过滤。

发送:


jmsTemplate.convertAndSend("order.queue", message, jmsMessage -> { jmsMessage.setStringProperty("bizType", "order"); jmsMessage.setStringProperty("level", "important"); return jmsMessage; });

消费:


@JmsListener( destination = "order.queue", selector = "bizType = 'order' AND level = 'important'" ) public void handleImportantOrder(OrderCreatedMessage message) { System.out.println("收到重要订单消息:" + message); }

选择器适合按少量稳定属性过滤。

如果路由规则很复杂,通常更适合拆分队列或 Topic。

延迟消息

ActiveMQ Classic 支持调度消息。

常见属性:

属性 作用
AMQ_SCHEDULED_DELAY 延迟多久投递
AMQ_SCHEDULED_PERIOD 重复投递周期
AMQ_SCHEDULED_REPEAT 重复次数
AMQ_SCHEDULED_CRON Cron 表达式

发送延迟消息:


import org.apache.activemq.ScheduledMessage; jmsTemplate.convertAndSend("order.timeout.queue", message, jmsMessage -> { jmsMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 30 * 60 * 1000L); return jmsMessage; });

表示 30 分钟后投递。

Broker 需要开启 scheduler 支持。

死信队列

ActiveMQ Classic 默认有死信队列。

常见默认名称:


ActiveMQ.DLQ

消息可能进入死信队列的常见原因:

  • 消费者重复失败
  • 消息过期
  • 消息被回滚多次
  • 达到最大重投递次数

ActiveMQ 常见处理链路:


消费者处理失败 | v Session rollback 或监听器抛异常 | v Broker 重新投递 | v 超过最大重投递次数 | v 进入 DLQ

死信队列适合:

  • 保留异常消息
  • 后台补偿处理
  • 人工排查
  • 告警通知

Redelivery 重投递

ActiveMQ 客户端可以设置重投递策略。


import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.activemq.RedeliveryPolicy; ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616"); RedeliveryPolicy policy = new RedeliveryPolicy(); policy.setMaximumRedeliveries(3); policy.setInitialRedeliveryDelay(1000); policy.setRedeliveryDelay(2000); policy.setUseExponentialBackOff(true); policy.setBackOffMultiplier(2.0); factory.setRedeliveryPolicy(policy);

含义:

配置 说明
maximumRedeliveries 最大重投递次数
initialRedeliveryDelay 首次重投递延迟
redeliveryDelay 重投递间隔
useExponentialBackOff 是否指数退避
backOffMultiplier 退避倍数

重投递次数耗尽后,消息通常会进入 DLQ。

Spring 事务消费

Spring JMS 可以使用事务监听容器。


@Bean public DefaultJmsListenerContainerFactory txQueueListenerContainerFactory( ConnectionFactory connectionFactory ) { DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); factory.setSessionTransacted(true); return factory; }

监听:


@JmsListener( destination = ActiveMqDestinations.ORDER_QUEUE, containerFactory = "txQueueListenerContainerFactory" ) public void handleWithTx(OrderCreatedMessage message) { System.out.println("事务消费消息:" + message); // 方法正常结束:提交 Session // 方法抛出异常:回滚 Session,消息等待重投递 }

事务消费适合:

  • 消息处理成功才确认
  • 失败后触发重投递
  • 和本地数据库事务配合

幂等处理

消息中间件通常更接近“至少一次”投递。

因此,消费者需要能处理重复消息。

常见做法:


消息带唯一 messageId 消费前检查处理记录 未处理则执行业务 处理成功后保存记录 重复消息直接跳过

示例:


@JmsListener(destination = ActiveMqDestinations.ORDER_QUEUE) public void handle(OrderCreatedMessage message) { String messageId = message.orderNo(); if (messageLogRepository.exists(messageId)) { return; } processOrder(message); messageLogRepository.save(messageId); }

可以用来做幂等的方式:

  • 数据库唯一索引
  • 消息消费日志表
  • Redis SETNX
  • 业务状态机

ActiveMQ 数据存储在哪里

ActiveMQ 数据存储在 Broker 节点上。

主要包括:

  • 队列和主题元数据
  • 持久化消息
  • 订阅关系
  • 事务和调度消息信息

ActiveMQ Classic 常见持久化存储是:


KahaDB

Artemis 常见持久化方式是:


Journal

Docker 部署时,需要挂载数据目录。

Classic 常见目录:


/opt/apache-activemq/data

不同镜像目录可能不同,需要以镜像说明为准。

示例:


docker run -d \ --name activemq-classic \ -p 61616:61616 \ -p 8161:8161 \ -v activemq-data:/opt/apache-activemq/data \ apache/activemq-classic:latest

如果没有挂载数据卷,容器删除后数据也会删除。

消息重启后是否保留,取决于:


消息是否持久化 目的地和 Broker 持久化配置 存储目录是否保留

管理后台常看指标

ActiveMQ 管理后台常见关注点:

指标 说明
Pending Messages 等待消费的消息
Consumers 消费者数量
Enqueued 入队消息总数
Dequeued 出队消息总数
Dispatch Queue 已分派但未确认消息
Expired 过期消息
DLQ 死信消息

排查思路:


Pending Messages 持续增加:消费能力不足或消费者异常 Consumers 为 0:消费者未启动或监听配置错误 DLQ 增加:业务处理失败、重投递耗尽或消息过期 Enqueued 高于 Dequeued:生产速度超过消费速度

常见使用建议

Queue 和 Topic 分清楚

Queue 是任务分发。


一条消息只给一个消费者

Topic 是广播事件。


一条消息给多个订阅者

如果业务是“发短信任务”,通常选 Queue。

如果业务是“订单已支付事件”,多个系统都要收到,通常选 Topic。

JSON 优先于 Java 原生序列化

跨系统消息更适合 JSON。

原因:

  • 可读性更好
  • 跨语言更容易
  • 版本演进更可控
  • 排查消息更方便

关键消息设置持久化

发送端可以设置:


jmsTemplate.setDeliveryPersistent(true);

原生 JMS 可以设置:


producer.setDeliveryMode(DeliveryMode.PERSISTENT);

还需要确保 Broker 持久化存储配置正常。

消费者需要幂等

消息可能重复投递。

消费者处理逻辑需要支持重复执行。

例如:


订单已处理 -> 直接跳过 订单未处理 -> 执行业务并记录处理状态

失败消息进入 DLQ

失败消息不适合无限重试。

更常见的做法:


有限次数重投递 超过次数进入 DLQ 后台补偿或人工处理

常用 API 汇总

API / 注解 作用
JmsTemplate.convertAndSend(...) 发送消息
@JmsListener 监听消息
ConnectionFactory 创建连接
Connection JMS 连接
Session JMS 会话
Queue 点对点目的地
Topic 发布订阅目的地
MessageProducer 消息生产者
MessageConsumer 消息消费者
TextMessage 文本消息
MappingJackson2MessageConverter JSON 消息转换
Session.CLIENT_ACKNOWLEDGE 客户端确认
session.commit() 提交事务会话
session.rollback() 回滚事务会话
RedeliveryPolicy 重投递策略

总结

ActiveMQ 是 Java 生态里经典的 JMS 消息中间件。

它的核心模型很清晰:


Queue:点对点,一条消息一个消费者 Topic:发布订阅,一条消息多个订阅者

日常 Spring Boot 项目里,常用组合是:


spring-boot-starter-activemq JmsTemplate @JmsListener MappingJackson2MessageConverter

真正落到工程实践,需要重点关注:

  • Queue 和 Topic 模型选择
  • JSON 消息格式
  • 消息持久化
  • 事务或确认机制
  • 重投递策略
  • DLQ 死信队列
  • 消费幂等
  • 管理后台监控

ActiveMQ 比 RabbitMQ 更贴近 JMS 规范。

维护传统 Java 企业系统、对接 JMS 老系统、使用 Queue / Topic 这种经典模型时,ActiveMQ 依然有明确价值。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐