您好,有人曾经将Camel与IBM的MQ一起使用。我们正在研究可能同时使用这两种产品,但是没有两个产品一起工作的示例。

最佳答案

我所能得到的最好的记录在下面,以Spring XML应用程序上下文为例,该上下文本身承载CAMEL上下文和路由。此样本与IBM原生符合MQ JCA的资源适配器v7.5,CAMEL 2.16,Spring core 4.2一起使用。我已经将其部署在Glassfish,Weblogic和JBoss EAP7服务器中。

这种复杂性势必会处理其哲学与纯JMS答复消息的哲学相冲突的MQ报告流。有关详细说明,请参阅Implementing native websphere MQ with CoD over Camel JMS component

这个基于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">

奇怪:在Weblogic上,获取(例如)3个监听器的唯一方法是强制实现3个连接(顺序使用3个Camel:from语句),每个连接最多1个 session ,否则会出现MQ错误:MQJCA1018:每个连接仅一个 session 允许的。在JBoss上,您可以简单地调整parallelConsumers = ...
  <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>

这将结束MQ到jms路由;接下来是仍在相同CAMEL上下文中的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 header 来强制禁止JMS MQ消息 header 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>

我们还没有完成,我们仍然需要声明 native JMS提供程序和Websphere MQ的队列工厂(通过 native 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>

从JNDI获取工厂(和JCA适配器)的另一种方法是将JMS客户端声明为Spring Bean。在Weblogic和Glassfish中,通过部署 native IBM JCA资源适配器并创建随后在Spring Context中引用的JNDI资源(如上文所述,在JBoss中最适合如下所示的直接MQ客户端bean声明)会更好地激发您的灵感。
<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>

欢迎评论和改进。

关于带有IBM MQ的Apache Camel,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35085762/

10-12 20:05