尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

JMS异步消息通信:从核心模型到ActiveMQ实战指南

JMS异步消息通信:从核心模型到ActiveMQ实战指南 1. 项目概述为什么JMS依然是现代分布式系统的基石如果你在开发一个电商系统用户下单后你需要同时做几件事扣减库存、生成订单、发送短信通知、更新用户积分。如果把这些操作都塞在一个庞大的事务里任何一个环节比如短信服务商暂时不可用的失败都可能导致整个下单流程回滚用户体验极差。这就是典型的紧耦合、同步阻塞的架构痛点。而JMS即Java消息服务就是为解决这类问题而生的异步通信标准。它不是一个具体的消息产品而是一套API规范就像JDBC定义了访问数据库的接口一样JMS定义了Java程序访问消息中间件的通用方式。你可以把它想象成一个“邮政系统”的通用操作手册它规定了如何写信创建消息、如何投递到邮筒发送到队列/主题、以及如何从邮箱取信接收消息但具体是哪个邮局ActiveMQ、RabbitMQ、Kafka等来负责运输和分发它并不关心。尽管如今有Kafka、RabbitMQ等后起之秀它们各自有更擅长的领域和协议但JMS的价值在于其“标准性”和“抽象性”。对于需要跨不同消息中间件进行移植或者希望业务代码与底层消息实现解耦的企业级应用来说掌握JMS依然是Java工程师的必修课。它能让你以统一的编程模型应对从传统的企业集成到现代微服务间异步通信的各种场景。2. JMS核心模型与概念深度解析理解JMS首先要吃透它的两大消息传递模型Domain和几个核心对象。这就像学开车你得先分清手动挡和自动挡的区别再熟悉方向盘、油门、刹车各自是干什么的。2.1 两大消息传递模型点对点 vs. 发布/订阅JMS主要定义了两种消息消费方式它们决定了消息的生产者Producer和消费者Consumer之间的关系。点对点Point-to-Point, P2P模型这个模型基于“队列Queue”的概念。你可以把它想象成一个任务派发中心。核心角色一个队列Queue。消息流生产者将消息发送到特定的队列。队列会保存这些消息直到有消费者来取走。一条消息只会被一个消费者成功消费一旦被某个消费者取走并确认其他消费者就看不到了。典型场景订单处理、任务调度。比如你有10个订单消息进入“订单处理队列”后台有3个消费者实例在监听这个队列那么这10个订单会被这3个消费者竞争消费平均分配确保每个订单只被处理一次。特点消息具有“竞争消费”特性强调消息的可靠传输和一次性处理。发布/订阅Publish/Subscribe, Pub/Sub模型这个模型基于“主题Topic”的概念。它更像是一个广播电台或微信公众号。核心角色一个主题Topic。消息流生产者将消息发布到某个主题。所有订阅了该主题的消费者都会收到这条消息的一份副本。如果发布消息时没有活跃的订阅者那么这条消息就会丢失除非使用持久化订阅后文会讲。典型场景事件通知、实时数据广播。比如一个“用户注册成功”的事件被发布到“用户事件”主题那么“发送欢迎邮件”服务、“初始化用户画像”服务、“同步到CRM系统”服务等所有订阅者都会同时收到这个事件并各自执行自己的逻辑。特点消息具有“广播”特性一条消息可被多个消费者同时处理强调事件的广泛通知。注意在实际选择时关键判断点是“这条消息是需要被一个消费者处理还是需要被多个消费者知晓”。这是设计系统时最根本的决策之一。2.2 JMS核心对象及其生命周期无论使用哪种模型编程时都会与以下几个核心接口打交道理解它们的职责和生命周期至关重要。ConnectionFactory连接工厂这是入口。由消息中间件提供商如ActiveMQ实现用于创建到消息服务器的连接Connection。通常通过JNDI查找或在Spring中配置Bean来获取。它的创建成本较高应用通常只维护一个或几个实例。Connection连接代表了应用程序与JMS提供者消息服务器之间的一个活动TCP连接。它是重量级对象封装了通信链路。一个连接可以创建多个会话Session。Session会话是生产和消费消息的单线程上下文。它用于创建消息、生产者、消费者。事务性操作发送、确认都在会话的边界内进行。重要经验Session不是线程安全的通常不建议跨线程共享。为每个处理线程创建独立的Session是常见做法。Destination目的地即消息发送或接收的“地址”。在P2P模型中它是Queue在Pub/Sub模型中它是Topic。Destination对象同样由Connection创建。MessageProducer消息生产者/MessageConsumer消息消费者由Session创建用于向特定Destination发送消息或从其中接收消息。可以为生产者设置发送模式如持久化、优先级、为消费者设置消息选择器Selector等。Message消息被传输的数据载体。JMS定义了多种消息类型最常用的是TextMessage文本、ObjectMessage可序列化对象有安全风险慎用、BytesMessage字节流、MapMessage键值对。一个典型的生命周期流程是应用启动 - 获取ConnectionFactory - 创建Connection并启动connection.start() - 为每个处理线程创建Session - 用Session创建Destination、Producer/Consumer - 进行消息收发 - 关闭Consumer、Producer、Session、Connection。实操心得务必在finally块或使用try-with-resources实现AutoCloseable接口确保Connection和Session被正确关闭否则会导致资源泄漏。连接未启动start()是新手常犯的错误会导致消费者无法接收到消息。3. 消息的可靠性、事务与确认机制详解消息中间件核心价值之一是保证消息不丢。JMS通过持久化、事务和确认模式来提供不同级别的可靠性保证。这部分是JMS的精华也是面试高频点。3.1 消息传递的持久化Persistence这是针对消息本身的生存期保证。持久化消息PERSISTENT默认模式。消息发送者会告诉JMS提供者“务必保存这条消息即使服务器重启也要在恢复后把它送出去。” 提供者会将消息写入磁盘等持久化存储。这保证了消息的可靠性但性能有损耗。非持久化消息NON_PERSISTENT消息发送者说“尽力而为就行。” 提供者通常只把消息放在内存中。服务器宕机消息就丢失了。适用于对性能要求极高、允许少量丢失的场景如实时股票价格推送丢一两个报价影响不大。设置方式通常在生产者端// 创建生产者时设置传递模式 MessageProducer producer session.createProducer(destination); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); // 默认为 PERSISTENT // 或者发送单条消息时指定 producer.send(message, DeliveryMode.NON_PERSISTENT, priority, timeToLive);3.2 事务Transaction会话这是针对一组操作的原子性保证。在事务性会话session.createSession(true, Session.SESSION_TRANSACTED)中一组消息的发送和确认可以作为一个原子单元。事务内发送在调用session.commit()之前所有在该会话中发送的消息都不会真正进入队列/主题对其他消费者不可见。如果调用session.rollback()则这些发送操作全部撤销。事务内接收在事务会话中消费消息即使你调用了message.acknowledge()确认操作也会延迟到session.commit()时才真正发生。如果事务回滚消息会重新被递送取决于重投策略。应用场景需要将数据库操作和消息操作绑定在一起的场景。例如用户支付成功后需要在同一个事务中“更新订单状态为已支付”和“向积分队列发送增加积分的消息”。如果数据库更新失败事务回滚积分消息也不会发出避免了数据不一致。3.3 确认Acknowledgment模式这是针对单条消息的消费确认。当会话为非事务性createSession(false, ...)时确认模式生效它告诉服务器“这条消息我处理完了你可以把它删掉了。” 常见的模式有AUTO_ACKNOWLEDGE自动确认默认当消费者成功从receive方法返回或消息监听器MessageListener成功返回时会话会自动确认消息。坑点如果监听器方法内部抛出异常消息可能会被自动确认并丢失取决于提供者实现或者进入死信队列。这不是绝对安全的。CLIENT_ACKNOWLEDGE客户端确认消费者必须显式调用message.acknowledge()方法来确认消息。可以一次性确认之前所有未被确认的消息。这给了应用更大的控制权可以在业务逻辑完全成功后再确认。DUPS_OK_ACKNOWLEDGE允许重复确认一种“懒确认”模式。它暗示JMS提供者可以偶尔、延迟地确认消息即使消费者没有显式确认。这能提升性能但可能导致消息被重复传递“至少一次”语义。适用于可以容忍重复消费的场景。INDIVIDUAL_ACKNOWLEDGE单个确认这是JMS 2.0引入的更细粒度控制允许对单条消息进行确认而不影响会话中的其他消息。如何选择追求简单和性能且消费逻辑幂等可选AUTO_ACKNOWLEDGE或DUPS_OK_ACKNOWLEDGE。需要确保业务逻辑成功后才删除消息用CLIENT_ACKNOWLEDGE。需要将消息消费与数据库操作等绑定用事务性会话。重要经验在CLIENT_ACKNOWLEDGE模式下千万不要在catch块中调用acknowledge()除非你确定异常后消息也应该被确认即业务逻辑已成功。更安全的做法是在finally块中根据业务状态决定是否确认或者直接使用事务会话。4. 从零开始基于ActiveMQ的JMS实战理论讲得再多不如动手跑一遍。我们以最经典的JMS实现——Apache ActiveMQ “Classic”版本即5.x为例演示一个完整的P2P和Pub/Sub流程。4.1 环境准备与ActiveMQ启动首先去Apache ActiveMQ官网下载最新的稳定版如5.18.x。解压后其目录结构清晰bin/启动脚本。activemq start后台运行或activemq console前台控制台运行。conf/配置文件如activemq.xml、jetty.xml控制台配置。data/默认的KahaDB持久化数据存储目录。webapps/内置的管理控制台。启动ActiveMQ后默认会监听两个端口61616: 这是JMS服务默认的TCP协议端口我们的Java客户端将连接这里。8161: 这是内置的Web管理控制台端口。访问http://localhost:8161/admin(默认账号/密码: admin/admin)可以直观地查看队列、主题、连接、消息数量等信息是调试和监控的利器。在项目中我们需要引入客户端依赖。如果使用Maven添加dependency groupIdorg.apache.activemq/groupId artifactIdactivemq-client/artifactId version5.18.3/version !-- 请使用与服务器匹配的版本 -- /dependency4.2 点对点Queue生产者与消费者编码实现生产者代码示例import org.apache.activemq.ActiveMQConnectionFactory; import javax.jms.*; public class QueueProducer { private static final String BROKER_URL tcp://localhost:61616; private static final String QUEUE_NAME ORDER.QUEUE; public static void main(String[] args) throws JMSException { // 1. 创建连接工厂指定消息服务器地址 ConnectionFactory connectionFactory new ActiveMQConnectionFactory(BROKER_URL); // 2. 创建连接 Connection connection connectionFactory.createConnection(); connection.start(); // 记得启动连接 // 3. 创建会话 (非事务自动确认) Session session connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 4. 创建目的地 (队列) Destination destination session.createQueue(QUEUE_NAME); // 5. 创建生产者 MessageProducer producer session.createProducer(destination); // 设置消息持久化默认就是持久化这里显式设置以示强调 producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 6. 创建并发送一条文本消息 TextMessage message session.createTextMessage(这是一笔新的订单订单号: ORD20240527001); // 可以设置消息属性用于消息选择器 message.setStringProperty(orderType, NORMAL); message.setIntProperty(amount, 1000); producer.send(message); System.out.println(消息发送成功: message.getText()); // 7. 有序关闭资源 producer.close(); session.close(); connection.close(); } }消费者代码示例同步接收public class QueueConsumerSync { public static void main(String[] args) throws JMSException { ConnectionFactory factory new ActiveMQConnectionFactory(tcp://localhost:61616); Connection connection factory.createConnection(); connection.start(); Session session connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); // 使用客户端确认 Queue queue session.createQueue(ORDER.QUEUE); MessageConsumer consumer session.createConsumer(queue); // 同步接收消息等待3秒 Message message consumer.receive(3000); if (message instanceof TextMessage) { TextMessage textMessage (TextMessage) message; System.out.println(收到消息: textMessage.getText()); System.out.println(订单类型: textMessage.getStringProperty(orderType)); // 模拟业务处理 try { processOrder(textMessage.getText()); // 业务处理成功确认消息 message.acknowledge(); System.out.println(消息已确认。); } catch (Exception e) { System.err.println(处理订单失败消息未确认将被重投或进入死信队列。); // 不调用 acknowledge()会话关闭或重连后消息会重新被递送 // 更复杂的场景可以调用 session.recover() 让当前会话的消息重新投递 } } else { System.out.println(等待超时未收到消息。); } consumer.close(); session.close(); connection.close(); } private static void processOrder(String orderInfo) { // 模拟业务处理逻辑 System.out.println(正在处理订单: orderInfo); } }消费者代码示例异步监听 - 推荐在实际应用中我们更常用异步消息监听器它不会阻塞线程。public class QueueConsumerAsync { public static void main(String[] args) throws Exception { ConnectionFactory factory new ActiveMQConnectionFactory(tcp://localhost:61616); Connection connection factory.createConnection(); connection.start(); Session session connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue session.createQueue(ORDER.QUEUE); MessageConsumer consumer session.createConsumer(queue); // 设置消息监听器 consumer.setMessageListener(new MessageListener() { Override public void onMessage(Message message) { try { if (message instanceof TextMessage) { String text ((TextMessage) message).getText(); System.out.println(监听器收到消息: text); // 这里处理业务逻辑 // 如果使用 AUTO_ACKNOWLEDGE方法正常返回即自动确认。 // 如果抛出异常消息可能会被重投取决于提供者。 } } catch (JMSException e) { e.printStackTrace(); } } }); System.out.println(消费者已启动等待消息...); // 保持主线程不退出模拟服务常驻 Thread.sleep(60 * 1000); consumer.close(); session.close(); connection.close(); } }4.3 发布/订阅Topic与持久化订阅对于Topic默认是“即时消费”模式。如果消费者在消息发布之后才订阅是收不到历史消息的。但JMS提供了“持久化订阅Durable Subscription”来解决这个问题。非持久化订阅的Topic消费者public class TopicConsumerNonDurable { public static void main(String[] args) throws Exception { ConnectionFactory factory new ActiveMQConnectionFactory(tcp://localhost:61616); Connection connection factory.createConnection(); connection.start(); Session session connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic session.createTopic(STOCK.PRICE.TOPIC); // 创建非持久化订阅者 MessageConsumer consumer session.createConsumer(topic); consumer.setMessageListener(message - { // ... 处理消息 }); // 如果在这个消费者启动前有消息发布它收不到。 } }持久化订阅的Topic消费者持久化订阅要求为订阅者指定一个唯一的客户端IDClientID和订阅者名称SubscriptionName。服务器会为这个订阅者保存离线期间发布的消息待其上线后补发。public class TopicConsumerDurable { public static void main(String[] args) throws Exception { ActiveMQConnectionFactory factory new ActiveMQConnectionFactory(tcp://localhost:61616); Connection connection factory.createConnection(); // !!! 必须为连接设置一个唯一的客户端ID !!! connection.setClientID(CLIENT-001); connection.start(); Session session connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic session.createTopic(STOCK.PRICE.TOPIC); // 创建持久化订阅者需要提供订阅者名称 MessageConsumer consumer session.createDurableSubscriber(topic, SUBSCRIBER-001); consumer.setMessageListener(message - { try { System.out.println(持久化订阅者收到消息: ((TextMessage) message).getText()); } catch (JMSException e) { e.printStackTrace(); } }); System.out.println(持久化订阅者已启动。即使之前离线也能收到错过的消息。); Thread.sleep(120 * 1000); // 关闭前可以取消持久化订阅非必须但建议在应用卸载时清理 // session.unsubscribe(SUBSCRIBER-001); consumer.close(); session.close(); connection.close(); } }在管理控制台的“Subscribers”页面你可以看到活跃的持久化订阅者及其积压的消息数。5. 高级特性与生产环境实践掌握了基础我们来看看那些能让你的JMS应用更健壮、更高效的高级特性和实践。5.1 消息选择器Message Selector想象一下订单队列里有各种类型的订单普通订单、VIP订单、团购订单。消费者可能只关心处理金额大于1000的VIP订单。消息选择器允许消费者基于消息的属性Header和Property进行过滤只接收符合条件的消息。它使用类似于SQL WHERE子句的语法。生产者设置消息属性Message message session.createTextMessage(订单内容...); message.setStringProperty(orderType, VIP); message.setIntProperty(amount, 1500); message.setBooleanProperty(urgent, true); producer.send(message);消费者使用选择器// 只接收 orderTypeVIP 且 amount 1000 的消息 String selector orderType VIP AND amount 1000; MessageConsumer consumer session.createConsumer(queue, selector);注意选择器只能基于消息属性JMSX和自定义属性进行过滤不能基于消息体Body内容过滤。过滤工作是在服务端进行的这可以减少不必要的网络传输但复杂的筛选条件可能会增加服务器负担。5.2 消息的存活时间Time To Live, TTL与过期处理你可以为消息设置一个存活时间。如果消息在队列或主题中等待的时间超过了TTL它就会过期。过期的消息通常会被移送到一个特殊的队列——死信队列Dead Letter Queue, DLQ默认名称通常是ActiveMQ.DLQ。// 发送消息时设置TTL为5分钟300000毫秒 producer.send(message, DeliveryMode.PERSISTENT, Message.DEFAULT_PRIORITY, 300000);合理设置TTL可以防止因消费者长时间离线或处理失败导致“僵尸消息”无限期堆积占用系统资源。你需要有监控或处理DLQ中消息的机制。5.3 优先级PriorityJMS支持0-9共10个消息优先级9为最高4为默认。优先级高的消息会被优先投递给消费者。但请注意这只是一个建议并非严格保证。具体的投递顺序还取决于消息中间件的实现和当前队列状态。producer.send(message, DeliveryMode.PERSISTENT, 9, Message.DEFAULT_TIME_TO_LIVE); // 发送一个最高优先级的消息5.4 连接池与Spring集成实战在实际生产环境中直接使用原生API创建和关闭Connection、Session是低效的。我们通常使用连接池并借助Spring这样的框架来简化管理。使用Spring Boot集成ActiveMQ添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-activemq/artifactId /dependency !-- 如果需要连接池 -- dependency groupIdorg.messaginghub/groupId artifactIdpooled-jms/artifactId /dependency配置文件application.ymlspring: activemq: broker-url: tcp://localhost:61616 user: admin # 可选 password: admin # 可选 packages: trust-all: true # 信任所有包生产环境应指定具体包名 pool: enabled: true # 启用连接池 max-connections: 10 # 最大连接数配置JMS模板和监听容器Configuration EnableJms // 启用JMS注解支持 public class JmsConfig { Bean public JmsListenerContainerFactory? myFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) { DefaultJmsListenerContainerFactory factory new DefaultJmsListenerContainerFactory(); // 配置事务、确认模式等 factory.setSessionTransacted(true); // 开启事务会话 // factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE); // 客户端确认 configurer.configure(factory, connectionFactory); return factory; } }发送消息使用JmsTemplateService public class OrderService { Autowired private JmsTemplate jmsTemplate; public void sendOrder(Order order) { jmsTemplate.convertAndSend(ORDER.QUEUE, order, message - { // 可以在这里设置消息属性 message.setStringProperty(orderType, order.getType()); return message; }); } }接收消息使用JmsListener注解Component public class OrderProcessor { JmsListener(destination ORDER.QUEUE, containerFactory myFactory) public void processOrder(Order order, Session session, Message message) throws JMSException { try { // 处理订单业务... System.out.println(处理订单: order.getId()); // 如果使用事务会话成功则自动commit异常则自动rollback。 // 如果使用CLIENT_ACKNOWLEDGE可以在这里手动确认message.acknowledge(); } catch (Exception e) { // 记录日志事务会自动回滚消息会重投 throw new RuntimeException(订单处理失败, e); } } }Spring极大地简化了JMS的使用通过声明式事务和监听器让开发者能更专注于业务逻辑。6. 常见问题排查与性能调优指南即使框架再完善在实际开发和运维中你依然会遇到各种问题。这里记录一些典型的“坑”和解决思路。6.1 常见问题速查表问题现象可能原因排查步骤与解决方案消费者收不到消息1. 连接未启动 (connection.start())。2. 消费者创建时机晚于消息发送对于非持久化Topic。3. 消息选择器Selector条件不匹配。4. 消费者确认模式导致消息被“卡住”。1. 检查代码确保在创建消费者后调用了connection.start()。2. 检查消息模型。对于Topic考虑使用持久化订阅。3. 打印或检查消息属性核对选择器语法。4. 检查是否使用了CLIENT_ACKNOWLEDGE但未调用acknowledge()导致消息未被确认服务器认为消息还在处理中不会投递给其他消费者P2P下。消息重复消费1. 确认模式使用不当如AUTO_ACKNOWLEDGE下监听器异常后消息可能重投。2. 网络问题导致确认信息未送达服务器重发。3. 消费者处理时间过长会话超时。1. 确保消费逻辑的幂等性Idempotence。这是应对消息重复的最根本手段。2. 根据业务容忍度选择合适的确认模式。对可靠性要求高可使用事务会话。3. 优化消费者处理逻辑避免长时间阻塞。消息堆积消费者处理慢1. 生产者速率远大于消费者。2. 消费者业务逻辑复杂或存在外部依赖阻塞。3. 队列容量配置过小。1.增加消费者实例水平扩展。这是最直接有效的方法。2.优化消费者代码采用异步、批处理等方式。3.监控队列深度设置预警。在ActiveMQ控制台可以清晰看到。4. 检查服务器性能CPU、内存、磁盘IO。ObjectMessage反序列化报错1. 生产者和消费者使用的Java类版本或类路径不同。2. 没有配置可信任的包名。1.强烈建议避免使用ObjectMessage改用TextMessageJSON/XML或BytesMessageProtobuf等。2. 如果必须用确保序列化版本serialVersionUID一致并在连接工厂设置信任的包((ActiveMQConnectionFactory)factory).setTrustedPackages(Arrays.asList(com.yourcompany.model))。连接数过多服务器压力大未使用连接池每次收发消息都创建新连接。务必使用连接池。无论是原生的PooledConnectionFactory还是Spring Boot的自动配置。连接是重量级对象创建和销毁开销大。6.2 性能调优要点会话Session模式选择非事务 AUTO_ACKNOWLEDGE性能最高但可靠性最低可能丢消息或重复。事务会话可靠性最高但性能损耗最大因为涉及事务日志的同步写入。非事务 CLIENT_ACKNOWLEDGE性能和可靠性的折中。可以批量确认提升性能。建议对性能要求极高的非关键通知用DUPS_OK_ACKNOWLEDGE。对可靠性要求高的业务用事务会话。一般场景用CLIENT_ACKNOWLEDGE并实现幂等消费。消息持久化非持久化消息NON_PERSISTENT的性能远高于持久化消息。根据业务重要性权衡。预取限制Prefetch Limit消费者会预先从服务器拉取一批消息到本地缓冲区。如果预取值过大可能导致消息在单个消费者处堆积而其他消费者空闲过小则增加网络往返。在ActiveMQ中可以为连接设置预取值如?jms.prefetchPolicy.queuePrefetch50。对于处理慢的消费者可以调小此值甚至设为1以实现更公平的消息分发。使用异步发送ActiveMQ默认是异步发送消息除非指定了持久化消息且未使用事务。确保useAsyncSend参数为true可以显著提升生产者吞吐量。优化消息体尽量减小单条消息的体积。避免在消息中携带不必要的大对象或冗余信息。对于复杂对象使用高效的序列化方式如JSON、Protobuf、Avro替代Java原生序列化。6.3 监控与运维建议善用管理控制台ActiveMQ Web Console是你的第一道监控防线。定期查看队列深度、消费者数量、内存使用情况、磁盘存储情况。启用日志调整ActiveMQ和客户端日志级别如log4j.properties在出现问题时能获取更详细的线索。设置警报对关键队列的积压消息数Pending Message Count设置监控警报。例如当积压超过10000条时触发告警。规划死信队列处理设计一个后台进程或脚本定期检查并处理死信队列中的消息。可以尝试重投、记录日志后丢弃或人工干预。版本与客户端匹配确保客户端JAR版本与服务器版本兼容避免因协议不匹配导致奇怪的问题。JMS作为一项成熟的技术其核心思想——异步、解耦、可靠传递——在现代分布式架构中历久弥新。虽然直接使用原生API的场景在减少但理解其原理能让你在使用Spring JMS、Spring Cloud Stream等高级抽象时更加得心应手也能在遇到深层次问题时有足够的知识储备进行排查。从点对点的任务队列到发布订阅的事件驱动JMS提供的这套标准模型依然是构建稳健后端服务的重要工具之一。
返回列表