簡體   English   中英

使用CoD over Camel JMS組件實現本機Websphere MQ

[英]Implementing native websphere MQ with CoD over Camel JMS component

我很難用Apache CAMEL來實現Websphere MQ(WMQ)連接器,該連接器可以無例外地處理MQ交付確認(CoD)報告,並且不會產生不需要的響應數據報形式的副作用。 最后,如果您習慣於編寫本機MQ客戶端,則可以按照我想要的方式進行操作,這是一種標准且通用的方法。 我在同一主題的帖子中記錄了該方法,但是我發現該解決方案充滿了復雜性,非常感謝任何建議或示例以使實現更簡潔,更優雅。

我了解到,該問題的根源是MQ設計請求-應答消息交換模式(MEP)的方式,JMS規范的方式以及其JMS組件中請求-應答MEP的CAMEL實現。 三種不同的哲學!

  1. WMQ具有一個MessageType標頭(請參閱MQMD字段常量 ),其值1代表請求,2代表回復,8代表數據報(單向MEP)。 此外,值4用於標記報告消息,其形式為CoD(交付確認),PAN(正向確認)和NAN(負向確認),就消息流而言,它們還會做出附加的答復信息。 可以使用另一個名為“報告”的標頭字段為請求消息,答復或數據報請求CoD,PAN和NAN確認,其中可以合並所有報告變量的標志。 附加標頭字段“ ReplyToQ”和“ ReplyToQMgr”指定原始發件人希望在其上進行報告和答復的隊列和隊列管理器,並且固定的24字節 “ CorrelId”字段(可選)可幫助將報告和答復與原始數據報相關聯。或請求消息。 為了使其更復雜,實際上可以使用相同的原始消息ID而不返回CorrelID來發送回覆和報告,或者在CorrelId中提供原始消息ID,或者在原始Request或Datagram中已經指定時返回CorrelId值。 IBM 在WMQ上提供了JMS API ,從而允許通過WMQ進行純JMS交換的傳輸(在額外的消息頭名稱MQRFH2的幫助下 ),或者將本機MQ消息映射到JMS消息上 ,反之亦然。
  2. 另一方面,JMS規范提供了可選的“ JMSReplyTo”頭字段和“ JMSCorrelationID”,但確實將確切的MEP語義留給了客戶端應用程序。 即在規格中說明:“ 響應可能是可選的;由客戶決定。
  3. CAMEL具有XML或Java DSL中的“路由”功能,以及一個內部Exchange對象模型,旨在支持EIP模式 ,其中包括請求-應答模式。 然后,CAMEL在其JMS組件中假設,如果設置了JMSReplyTo字段,則它必然是一個要求答復的請求,從而導致將Exchange的Out部分(如果Out為空,則修改為In部分)返回到JMSReplyTo中定義的隊列。 。

我願意通過遠程Websphere隊列管理器通過傳遞確認(CoD)報告來支持本機MQ消息交換,因此,除了事務和持久性(即無丟失,無重復)之外,還可以跟蹤何時消耗一條消息並在出現延遲時發出警報。

入站問題:

默認情況下,Websphere隊列管理器在隊列中的消息使用完成時會生成CoD報告。 因此,在沒有任何特定設置的情況下 ,當CAMEL端點使用該消息時,遠程MQ客戶端發送帶有CoD標志的數據報(然后是強制性的ReplyToQ)將作為第一個MQ報告從隊列管理器返回到隊列管理器,然后是第二個。由CAMEL明確返回的(意外)回復消息,其中包含CAMEL路由末尾在Exchange對象中留下的內容,因為鑒於存在JMSReplyTo字段,CAMEL假定了請求-應答EIP(由MQ ReplyToQ和ReplyToQMgr映射,兩者需要以支持CoD回流)。

出站問題:

沒有特定設置,CAMEL默認情況下也會在出站連接上假設一個請求-答復EIP / MEP。 然后,CAMEL JMS / MQ端點將等待1個響應。 當OUTbound消息是基於MQ的JMS時(因此帶有MQRFH2標頭),則工作正常。 當強制使用普通的原始MQ時,即按如下所示刪除MQRFH2標頭時,我無法使端點偵聽器與相關的傳入MQ報告相匹配,盡管跟蹤的值似乎都正確(強制使用24個字符的相關性ID,以便較長的CorrelId值被截斷或填充為空) MQ不能對關聯過濾器進行地理解析)。 有誰能夠解決這個問題?

詳細信息:盡管IBM JMS API接受傳遞特定的JMS屬性值WMQ_MESSAGE_BODY = {1 | 0} / WMQ_TARGET_CLIENT = {1 | 0}來控制生成的消息中JMS頭MQRFH2的存在,但是這些選項通過CAMEL無效。 必須使用CamelJmsDestinationName標頭( 如CAMEL JMS doc中所述 )為具有選項“ targetClient = 1”的目標提供IBM隊列URL,以便擺脫MQRFH2標頭。 但是,如果沒有此標頭,則CoD報告或MQ答復上的CAMEL關聯確實會失敗。

解決上述問題的方法確實是關於構建特定的CAMEL路由來處理由遠程方返回的CoD報告(以及相關的MQ答復)。 因此,CAMEL出站郵件必須強制為“ InOnlyExchangePattern ,因此不要等待任何答復。 但這將導致CAMEL抑制所有的ReplyTo字段。 然后,如果在出站MQ數據報上請求MQ CoD,則會發生CAMEL異常,其原因是MQException JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2027' ('MQRC_MISSING_REPLY_TO_Q')

CAMEL記錄了一個URI選項“ disableReplyTo = true”,以禁用交換模式上的回復偵聽,但保留ReplyTo字段-顯然在入站和出站交換上。 但是,此選項在出站JMS交換上不起作用(據觀察,我可能是錯的),並且必須使用不太直觀的“ preserveMessageQos”選項。

歡迎為這些問題提供優雅的解決方案。

我所能得到的最好的記錄在下面,以Spring XML應用程序上下文為例,該上下文本身承載CAMEL上下文和路由。 它與IBM原生MQ JCA兼容資源適配器v7.5,CAMEL 2.15,Spring core 4.2一起使用。 我可以將其部署到Glassfish和Weblogic服務器上。

當然,在給定眾多變量的情況下,實際實現中會使用Java DSL。 這個基於CAMEL XML DSL的示例是獨立的,易於測試。

我們從Spring和Camel聲明開始:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

CAMEL上下文遵循2條路由:從MQ到JMS和從JMS到MQ,在這里鏈接起來形成了簡化測試的橋梁。

<camel:camelContext id="mqBridgeCtxt">

  <camel:route id="mq2jms" autoStartup="true">

怪異的:使用本地MQ資源適配器時,獲取(例如)3個偵聽器的唯一方法是強制執行3個連接(依次使用3個Camel:from語句),每個連接最多具有1個會話,否則會出現MQ錯誤: MQJCA1018: Only one session per connection is allowed 但是,如果改為使用MQ客戶端jar,則CAMEL JMS中的concurentConsumers選項可以正常工作。

    <camel:from uri="wmq:queue:TEST.Q1?concurrentConsumers=1&amp;disableReplyTo=true&amp;
            acknowledgementModeName=SESSION_TRANSACTED"/> 
    <camel:from uri="wmq:queue:TEST.Q1?concurrentConsumers=1&amp;disableReplyTo=true&amp;
            acknowledgementModeName=SESSION_TRANSACTED"/> 
    <camel:from uri="wmq:queue:TEST.Q1?concurrentConsumers=1&amp;disableReplyTo=true&amp;
            acknowledgementModeName=SESSION_TRANSACTED"/> 

上面的disable disableReplyTo選項可確保CAMEL在我們測試MQ消息類型為1 = Request(-reply)或8 = datagram(單向!)之前不會產生回復。 該測試和答復的構造未在此處說明。

然后,在下一次發布到純JMS時,我們將EIP強制為InOnly,以與入站MQ模式保持一致。

    <camel:setExchangePattern pattern="InOnly"/>
    <!-- camel:process ref="reference to your MQ message processing bean fits here" / -->
    <camel:to uri="ref:innerQueue" />
  </camel:route>

接下來是jms到MQ路由:

  <camel:route id="jms2mq"  autoStartup="true">
    <camel:from uri="ref:innerQueue" />
    <!-- remove inner message headers and properties to test without inbound side effects! -->
    <camel:removeHeaders pattern="*"/> 
    <camel:removeProperties pattern="*" />
    <!-- camel:process ref="reference to your MQ message preparation bean fits here" / -->

現在出現了由遠程目標返回的MQ CoD報告的請求標志。 我們還將MQ消息強制為數據報類型(值8)。

    <camel:setHeader headerName="JMS_IBM_Report_COD"><camel:simple resultType="java.lang.Integer">2048</camel:simple></camel:setHeader>
    <camel:setHeader headerName="JMS_IBM_Report_Pass_Correl_ID"><camel:simple resultType="java.lang.Integer">64</camel:simple></camel:setHeader>
    <camel:setHeader headerName="JMS_IBM_MsgType"><camel:simple resultType="java.lang.Integer">8</camel:simple></camel:setHeader>

可以通過ReplyTo uri選項指定ReplyTo隊列,也可以如下指定標題。

接下來,我們確實使用CamelJmsDestinationName標頭來強制禁止JMS MQ消息標頭MQRFH2 (使用targetClient MQ URL選項值1)。 換句話說,我們要發送普通的原始MQ二進制消息(即,僅MQMD消息描述符,后跟有效負載)。

    <camel:setHeader headerName="JMSReplyTo"><camel:constant>TEST.REPLYTOQ</camel:constant></camel:setHeader>
    <camel:setHeader headerName="CamelJmsDestinationName"><camel:constant>queue://MYQMGR/TEST.Q2?targetClient=1</camel:constant></camel:setHeader>

可以通過保留的JMS屬性控制更多MQMD字段,如下所示。 請參閱IBM文檔中的限制

    <camel:setHeader headerName="JMS_IBM_Format"><camel:constant>MQSTR   </camel:constant></camel:setHeader>
    <camel:setHeader headerName="JMSCorrelationID"><camel:constant>_PLACEHOLDER_24_CHARS_ID_</camel:constant></camel:setHeader>

URI中的目標隊列被上面的CamelJmsDestinationName覆蓋,因此URI中的隊列名稱成為占位符。

URI選項preserveMessageQos是一種-如所觀察到的那樣-允許發送設置了ReplyTo數據的消息(以獲取MQ CoD報告),但是通過強制InOnly MEP阻止CAMEL實例化Reply消息偵聽器。

    <camel:to uri="wmq:queue:PLACEHOLDER.Q.NAME?concurrentConsumers=1&amp;
                exchangePattern=InOnly&amp;preserveMessageQos=true&amp;
                includeSentJMSMessageID=true" />
  </camel:route>
</camel:camelContext>

必須根據您的情況調整以下內容。 它為本地JMS提供程序和Websphere MQ(通過本地IBM WMQ JCA資源適配器)提供了隊列工廠。 我們在這里在管理對象上使用JNDI查找。

<camel:endpoint id="innerQueue" uri="jmsloc:queue:transitQueue">
</camel:endpoint>

<jee:jndi-lookup id="mqQCFBean" jndi-name="jms/MYQMGR_QCF"/>
<jee:jndi-lookup id="jmsraQCFBean" jndi-name="jms/jmsra_QCF"/>

<bean id="jmsloc" class="org.apache.camel.component.jms.JmsComponent">
  <property name="connectionFactory" ref="jmsraQCFBean" />
</bean>

<bean id="wmq" class="org.apache.camel.component.jms.JmsComponent">
  <property name="connectionFactory" ref="mqQCFBean" />
</bean>

</beans>

或者,如果您使用MQ客戶端jar而不是資源適配器,則將聲明連接工廠bean,例如(代替上面的JNDI查找):

<bean id="mqCFBean" class="com.ibm.mq.jms.MQXAConnectionFactory">
    <property name="hostName" value="${mqHost}"/>
    <property name="port" value="${mqPort}"/>
    <property name="queueManager" value="${mqQueueManager}"/>
    <property name="channel" value="${mqChannel}"/>
    <property name="transportType" value="1"/> <!-- This parameter is fixed and compulsory to work with pure MQI java libraries -->
    <property name="appName" value="${connectionName}"/>
</bean>

<bean id="wmq" class="org.apache.camel.component.jms.JmsComponent">
    <property name="connectionFactory" ref="mqCFBean"/>
    <property name="transacted" value="true"/>
    <property name="acknowledgementModeName" value="AUTO_ACKNOWLEDGE"/>
</bean>

歡迎評論和改進。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM