
rest-content-exchange (Topic 類型,持久化)rest-sms-queue、rest-jpush-queue、rest-sysmsg-queue(均持久化)<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:rabbit="https://www.springframework.org/schema/rabbit"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/rabbit
https://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<!-- 1. 連接工廠 -->
<rabbit:connection-factory id="connectionFactory"
host="${rabbitmq.host}" port="${rabbitmq.port}"
username="${rabbitmq.username}" password="${rabbitmq.password}"
virtual-host="${rabbitmq.vhost}" />
<!-- 2. 管理員(自動聲明 Exchange/Queue/Binding) -->
<rabbit:admin connection-factory="connectionFactory"/>
<!-- 3. 生產者端配置 -->
<rabbit:topic-exchange name="rest-content-exchange" durable="true" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="rest-sms-queue" pattern="rest.sms.#"/>
<rabbit:binding queue="rest-jpush-queue" pattern="rest.jpush.#"/>
<rabbit:binding queue="rest-sysmsg-queue" pattern="rest.sysmsg.#"/>
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"
exchange="rest-content-exchange"/>
<!-- 4. 消費者端配置 -->
<rabbit:queue name="rest-sms-queue" durable="true" auto-declare="true"/>
<rabbit:queue name="rest-jpush-queue" durable="true" auto-declare="true"/>
<rabbit:queue name="rest-sysmsg-queue" durable="true" auto-declare="true"/>
<bean id="smsHandler" class="com.dingli.components.mq.handler.SmsHandler"/>
<bean id="jpushHandler" class="com.dingli.components.mq.handler.JpushHandler"/>
<bean id="saveSysMsgHandler" class="com.dingli.components.mq.handler.SaveSysMsgHandler"/>
<!-- 關鍵:acknowledge="none" 避免異常重試無限循環 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="none">
<rabbit:listener ref="smsHandler" method="execute" queue-names="rest-sms-queue"/>
<rabbit:listener ref="jpushHandler" method="execute" queue-names="rest-jpush-queue"/>
<rabbit:listener ref="saveSysMsgHandler" method="saveMsgExecute" queue-names="rest-sysmsg-queue"/>
</rabbit:listener-container>
</beans>
auto(默認):自動確認,異常時消息丟失manual:手動確認,需在代碼中調用 channel.basicAck(),支持重試但需防無限循環none:無確認模式,消息發送即視為成功,適合業務允許極少量丟失、追求高吞吐的場景本項目選用 none,因為業務為異步通知(短信、推送、系統消息),允許極低概率丟失,優先保證性能。
@Component
public class SendMsgRestProducerImpl implements SendMsgRestProducer {
@Autowired private RabbitTemplate rabbitTemplate;
@Override public void sendSMS(String mqSMSMessageJson) {
rabbitTemplate.convertAndSend("rest.sms.send", mqSMSMessageJson);
}
@Override public void jpushContent(String mqJPushMessageJson) {
rabbitTemplate.convertAndSend("rest.jpush.send", mqJPushMessageJson);
}
@Override public void saveContent(String mqSysMessageJson) {
rabbitTemplate.convertAndSend("rest.sysmsg.send", mqSysMessageJson);
}
}
調用示例:sendMsgRestProducer.sendSMS(jsonStr),三業務完全異步解耦。
@Component
public class SmsHandler {
private static final Logger log = LoggerFactory.getLogger(SmsHandler.class);
public void execute(String messageJson) {
try {
// 解析 JSON -> 發送短信業務邏輯
SmsMessage msg = JSON.parseObject(messageJson, SmsMessage.class);
smsService.send(msg.getMobile(), msg.getContent());
log.info("短信發送成功: {}", msg.getMobile());
} catch (Exception e) {
log.error("短信發送失敗: {}", messageJson, e);
// acknowledge="none" 時,異常不會導致消息重回隊列
}
}
}
# rabbitmq.properties rabbitmq.host=192.168.1.188 rabbitmq.port=5672 rabbitmq.username=lee rabbitmq.password=lee rabbitmq.vhost=danger
| 決策點 | 選擇 | 理由 |
|---|---|---|
| Exchange 類型 | Topic | 支持通配符路由,擴展性強 |
| 持久化 | 全鏈路持久化 | 防止 Broker 重啟丟失數據 |
| 確認機制 | acknowledge="none" | 業務允許極少丟失,換取高吞吐 |
| 異步處理 | RabbitTemplate.convertAndSend | 非阻塞發送,主流程無感知 |
| 錯誤處理 | 日誌記錄 + 監控告警 | 不重試,避免死循環;人工介入補償 |
核心業務(訂單、支付、庫存)嚴禁使用無確認模式,需採用手動 ACK + 幂等性設計 + 死信隊列重試機制。
輔助業務(日誌、通知、統計、緩存刷新)可根據業務容忍度選擇none或manual。