IBM WebSphere MQ (現 IBM MQ) 是企業級消息中間件標桿,提供可靠、異步、跨平台的消息傳遞能力。本文解析核心概念、通信機制,並給出生產級 Java 客戶端收發消息完整代碼。
| 概念 | 說明 | 類比 |
|---|---|---|
| Message (消息) | 數據載體,包含應用數據 + 描述符(Message Descriptor: ID、類型、優先級、過期時間) | 信封裡的信件 |
| Queue (隊列) | 消息緩存容器,FIFO 順序存儲,支援持久化 | 郵筒 |
| Queue Manager (隊列管理器) | MQ 運行時核心進程,管理隊列、通道、事務、持久化 | 郵局 |
| Channel (通道) | 隊列管理器間通信路徑,傳輸消息 | 郵路 |
| MQI (Message Queue Interface) | C/Java 等語言調用的標準 API | 郵政業務接口 |

異步特性:發送者無需等待接收者處理,消息持久化存儲於隊列,即使接收端離線也不丟失。

本文採用原生 MQI 演示底層控制力。
package com.example.mq;
import com.ibm.mq.*;
import com.ibm.mq.constants.MQConstants;
public class MqMessageSender {
private static final String HOST = "192.168.1.18";
private static final int PORT = 1414; // 默認監聽端口
private static final String CHANNEL = "CHANNEL1";
private static final String QM_NAME = "QM_SERVER";
private static final String QUEUE_NAME = "INITQ";
private static final int CCSID = 1381; // 簡體中文 GBK/GB18030
public void sendMessages(int count) {
MQQueueManager qMgr = null;
MQQueue queue = null;
try {
// 1. 設置連接環境
MQEnvironment.hostname = HOST;
MQEnvironment.port = PORT;
MQEnvironment.channel = CHANNEL;
MQEnvironment.CCSID = CCSID;
// MQEnvironment.userId = "mqm"; // 若需認證
// MQEnvironment.password = "password";
// 2. 連接隊列管理器
qMgr = new MQQueueManager(QM_NAME);
System.out.println("連接隊列管理器成功: " + QM_NAME);
// 3. 打開隊列 (輸出/查詢權限)
int openOptions = MQConstants.MQOO_OUTPUT | MQConstants.MQOO_INQUIRE;
queue = qMgr.accessQueue(QUEUE_NAME, openOptions);
System.out.println("打開隊列成功: " + QUEUE_NAME);
// 4. 構建消息
MQMessage message = new MQMessage();
message.format = MQConstants.MQFMT_STRING;
message.characterSet = CCSID;
message.writeString("這是測試消息 - " + System.currentTimeMillis());
message.expiry = MQConstants.MQEI_UNLIMITED; // 永不過期
// 5. 發送選項
MQPutMessageOptions pmo = new MQPutMessageOptions();
pmo.options = MQConstants.MQPMO_SYNCPOINT; // 事務性發送 (可選)
// 6. 批量發送
for (int i = 1; i <= count; i++) {
message.writeString("批次消息 #" + i + " @ " + new java.util.Date());
message.messageId = MQConstants.MQMI_NONE; // 讓 MQ 自動生成 MsgId
message.correlationId = MQConstants.MQCI_NONE;
queue.put(message, pmo);
System.out.println("發送第 " + i + " 條消息成功");
}
} catch (MQException mqe) {
System.err.println("MQ 錯誤: CC=" + mqe.completionCode + " RC=" + mqe.reasonCode);
mqe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 7. 資源釋放 (逆序關閉)
closeQuietly(queue);
disconnectQuietly(qMgr);
}
}
private void closeQuietly(MQQueue queue) {
if (queue != null && queue.isOpen()) {
try { queue.close(); } catch (MQException ignored) {}
}
}
private void disconnectQuietly(MQQueueManager qMgr) {
if (qMgr != null && qMgr.isConnected()) {
try { qMgr.disconnect(); } catch (MQException ignored) {}
}
}
public static void main(String[] args) {
new MqMessageSender().sendMessages(5);
}
}

public void receiveMessages() {
// ... 連接、打開隊列 (MQOO_INPUT_AS_Q_DEF | MQOO_INQUIRE)
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQConstants.MQGMO_WAIT | MQConstants.MQGMO_SYNCPOINT;
gmo.waitInterval = 5000; // 等待 5 秒
while (running) {
MQMessage msg = new MQMessage();
try {
queue.get(msg, gmo); // 阻塞等待消息
String text = msg.readStringOfByteLength(msg.getMessageLength());
System.out.println("收到消息: " + text);
// 業務處理...
qMgr.commit(); // 事務提交確認消費
} catch (MQException mqe) {
if (mqe.reasonCode == MQConstants.MQRC_NO_MSG_AVAILABLE) {
continue; // 超時無消息,繼續等待
}
// 其他錯誤處理
}
}
}
| 維度 | 建議 |
|---|---|
| 連接管理 | 使用連接池 (如 Spring MQQueueConnectionFactory + PooledConnectionFactory) |
| 事務控制 | 本地事務 MQPMO_SYNCPOINT/MQGMO_SYNCPOINT;分布式事務接入 JTA |
| 消息持久化 | 發送端 message.persistence = MQPER_PERSISTENT,隊列定義 DEFPERSIST(YES) |
| 編碼統一 | 全鏈路指定 CCSID (如 1381/5488/1200),避免跨平台亂碼 |
| 錯誤重試 | 指數退避重試 + 死信隊列 (DLQ) 配置 |
| 監控指標 | 隊列深度、消息延遲、連接數、錯誤率 |
掌握 MQ 核心模型與 Java 客戶端編程,即可構建高可靠的企業集成總線骨幹。