boqodo +

Spring集成JMS实践

  1. 参照《Spring攻略(第二版)》中的例子完成基本功能的实现

  2. 使用以上完成的例子,修改为在Webphere MQ上测试通过

  3. JMS事务,保持数据一致性的测试和研究


JMS

IBM MQ(WebSphere MQ)

问题记录

  1. com.ibm.mq.MQMsg2.getMessageData(Z)[B错误提示;

    mq的jar同当前MQ服务器的版本不一致,复制websphere MQ安装目录java下的jar文件替换; 需要jar包: + com.ibm.mq.jar + com.ibm.mq.jmqi.jar + com.ibm.mqjms.jar + dhbcore.jar

  2. javax.jms.JMSException: MQJMS2005: 未能为 '192.168.1.104:FirstLocalQ' 创建 MQQueueManager错误提示;

     MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
     cf.setCCSID(1381);//必须要设置;一般都为1381,具体的值可以查看队列管理器属性中有指定
    
  3. java.lang.UnsatisfiedLinkError: no mqjbnd05 in java.library.path错误提示;

     MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
     cf.setTransportType(WMQConstants.WMQ_CLIENT_NONJMS_MQ);//需要设置为`WMQConstants.WMQ_CLIENT_NONJMS_MQ`相当于1
    
  4. DetailedJMSSecurityException: JMSWMQ2013: 为队列管理器 'FirstLocalQ' 提供的安全性认证无效错误提示;

     MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
     QueueConnection conn = null;
     conn = cf.createQueueConnection("MUSR_MQADMIN", "");//"MUSR_MQADMIN"为用户名,该用户名应该是默认通道`SYSTEM.DEF.SVRCONN`的默认用户名
    
  5. 针对上面一条(第4条)的问题,在spring中如何配置用户名和密码呢?

    MQQueueConnectionFactory中无法通过属性注入用户名和密码,需要通过适配器(UserCredentialsConnectionFactoryAdapter)以中转的方式注入用户名和密码;

    对此在JMSTemplateJmsTransactionManager中的connectionFactory引用需要是适配器bean;

      <!--WebSphere MQ Connection Factory 用户名和密码注入适配器-->
     <bean id="jmsConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
         <property name="targetConnectionFactory" ref="mqConnectionFactory"/>
         <property name="username" value="${app.mq.username}"/>
         <property name="password" value="${app.mq.password}"/>
     </bean>
    
     <!-- JMS Queue Connection Factory -->
     <bean id="transactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
         <property name="connectionFactory" ref="jmsConnectionFactory"></property>
     </bean>
    
     <!-- Spring JmsTemplate -->
     <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
         <property name="connectionFactory" ref="jmsConnectionFactory"/>
         <property name="receiveTimeout" value="${queue.receive.timeout}"/>
         <property name="defaultDestinationName" value="${queue.name}"/>
         <property name="messageConverter" ref="mapMessageConverter"/>
         <!--<property name="defaultDestination" ref="fqueue"/>-->
     </bean>
     <bean id="mapMessageConverter" class="foo.bar.spring.MapMessageConverter"></bean>
     <!-- JmsGatewaySupport -->
     <bean id="jmsSpring" class="foo.bar.spring.JmsSpring">
         <property name="connectionFactory" ref="jmsConnectionFactory"/>
         <property name="jmsTemplate" ref="jmsTemplate"/>
     </bean>
     <bean id="jmsMessageListener" class="foo.bar.spring.JmsMessageListener"/>
     <!-- 监听消息适配器 -->
     <bean id="jmsListenerAapdter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
         <property name="delegate" ref="jmsReceiver"/>
         <!-- 可设置消息转换器-->
     </bean>
     <!-- 监听消息容器-->
     <bean id="listenerContainer" class="org.springframework.jms.listener.SimpleMessageListenerContainer">
         <property name="connectionFactory" ref="jmsConnectionFactory"/>
         <property name="messageListener" ref="jmsListenerAapdter"/>
         <property name="destinationName" value="${queue.name}"/>
     </bean>
    
  6. InvalidDestinationException的异常提示;

    该异常的发生原因是使用com.ibm.disthub2.impl.jms.MapMessageImplsetStringProperty方法造成的,该方法是配置消息头的额外属性,导致目标队列无效,而MQ服务器已经有数据,不过并没有响应的值,需要注意;

Demo

SpringJMSDemo

参考资料

Blog

Opinion

Project