| 值 | 含義 | 適用場景 |
0 (默認) | 目標為 JMS 客戶端,保留 RFH2 | 雙端均為 IBM MQ JMS Client |
1 | 目標為非 JMS 客戶端,剝離 RFH2 | 對接主機、C/C++、.NET、第三方 MQ 客戶端 |
三、Queue 場景配置代碼
// 方式一:創建 Queue 時指定(推薦)
String queueName = "DEV.QUEUE.1";
String targetClient = "1"; // 剝離 RFH2
Queue queue = session.createQueue("queue:///" + queueName + "?targetClient=" + targetClient);
// 方式二:使用 JNDI 查找預配置 Queue(運維預先在 MQ 控制台設置 TARGCLNT(1))
// @Resource(mappedName = "jms/MyQueue") Queue queue;
// 發送消息
MessageProducer producer = session.createProducer(queue);
TextMessage msg = session.createTextMessage("{\"orderId\":1001}");
producer.send(msg); // 到達隊列時無 RFH2 頭
四、Topic 發布/訂閱場景配置
String topicName = "PRICE.UPDATES";
String targetClient = "1";
Topic topic = session.createTopic("topic:///" + topicName + "?targetClient=" + targetClient);
MessageProducer publisher = session.createProducer(topic);
MapMessage msg = session.createMapMessage();
msg.setString("symbol", "AAPL");
msg.setDouble("price", 150.25);
publisher.send(msg); // 訂閱端收到純 MapMessage 體
五、Spring JMS 整合配置(生產推薦)
<!-- 連接工廠配置 targetClient -->
<bean id="mqConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="${mq.host}"/>
<property name="port" value="${mq.port}"/>
<property name="queueManager" value="${mq.qmgr}"/>
<property name="channel" value="${mq.channel}"/>
<property name="transportType" value="1"/> <!-- CLIENT 模式 -->
<property name="targetClient" value="1"/> <!-- 關鍵:全局剝離 RFH2 -->
</bean>
<!-- 或針對單個 Destination 覆蓋 -->
<bean id="orderQueue" class="com.ibm.mq.jms.MQQueue">
<property name="baseQueueName" value="DEV.ORDER.QUEUE"/>
<property name="targetClient" value="1"/>
</bean>
六、驗證 RFH2 是否剝離
- MQ Explorer / runmqsc:
DISPLAY QUEUE(DEV.QUEUE.1) TARGCLNT 確認 TARGCLNT(1);
- 消費端抓包:使用
amqsbcg (MQ 示例消費程序) 瀏覽消息,查看 Message Descriptor 中 Format 字段:
MQFMT_RF_HEADER_2 (RFH2) → 未剝離;
MQFMT_STRING / MQFMT_NONE → 已剝離。
- JMS 代碼檢查:
Message received = consumer.receive(5000);
if (received instanceof TextMessage) {
System.out.println("Body: " + ((TextMessage) received).getText());
// 檢查是否殘留 JMS_IBM_ 等 RFH2 專有屬性
Enumeration<String> props = received.getPropertyNames();
while (props.hasMoreElements()) {
String k = props.nextElement();
if (k.startsWith("JMS_IBM_")) System.out.println("⚠️ RFH2 屬性殘留: " + k);
}
}
七、常見誤區與避坑
| 誤區 | 真相 |
以為 targetClient 只能在 URL 字符串設置 | 可在 MQQueue/MQTopic 對象、ConnectionFactory、JNDI 綁定、MQ 服務端隊列定義 多層面設置,就近優先 |
| 設置了但消費端仍收到 RFH2 | 檢查是否使用 MQQueueConnectionFactory.createQueue() 而非 session.createQueue(),前者不解析 URL 參數 |
| 雙向通信一方 JMS 一方非 JMS | 發送端設置 targetClient=1,接收端(非 JMS)無需配置;若反向發送,非 JMS 端需自行構造無 RFH2 消息 |
| 以為剝離 RFH2 會丟失 JMS 屬性 | 標準 JMS 屬性(MessageID、CorrelationID、Timestamp 等)映射到 MQMD(Message Descriptor)中,不丟失;僅丟失 RFH2 專有擴展屬性(JMS_IBM_*) |
八、最佳實踐總結
- 全局默認剝離:連接工廠設置
targetClient=1,除非明確雙端均為 JMS;
- 隊列級別覆蓋:特定業務需保留 RFH2 時,在該 Queue/Topic Bean 覆蓋
targetClient=0;
- 文檔化約定:接口文檔明確註明「消息體格式:純 JSON/Protobuf,無 RFH2」,避免雙端理解不一致;
- 自動化測試:CI 流程中包含「發送→消費→斷言無 JMS_IBM_* 屬性」的集成測試。
「RFH2 是 IBM MQ 生態內的『身份證』,出了生態就是『亂碼』。一句 targetClient=1,讓消息輕裝上陣,暢行無阻。」
- 上一篇文章: Servlet 3.0+ @WebServlet 註解完整指南:替代 web.xml 的零配置映射
- 下一篇文章: Swing JScrollPane 實戰:打造 QQ 風格好友聊天視窗(含完整原始碼)
Copyright ©
程式碼之家 All Rights Reserved