Spring集成JMS实践
2015-02-26
- 
    参照 《Spring攻略(第二版)》中的例子完成基本功能的实现
- 
    使用以上完成的例子,修改为在 Webphere MQ上测试通过
- 
    JMS事务,保持 数据一致性的测试和研究
JMS
IBM MQ(WebSphere MQ)
- JMS API 实现收发消息
    - 获取ConnectionFactory
- 创建连接cf.createConnection()
- 创建会话conn.createSession()
- 创建消息生产者session.createProducer(destination)
- 创建消息session.createMapMessage()
- 发送消息producer.send(message)
 
- JMS集成Spring实现收发消息参考
    - 使用JmsTemplate 处理收发(注入或继承JmsGatewaySupport获取)
- 使用MessageConverter进行消息转换
- 使用JmsListener 消息监听
- 使用@Transactional控制事务处理(需要配置过<tx:annotation-driven/>)
 
- JMS消息监听处理
    - 需要在applicationContext配置文件中配置 监听器容器
        - SimpleMessageListenerContainer 不支持事务
- DefaultMessageListenerContainer 支持事务
 
- 消息驱动POJO,编写接收方法,通过适配器进行监听,接收到数据通过反射调入POJO指定的方法;
        - MessageListenerAdapter 适配器
 
 <bean id="jmsMessageListener" class="foo.bar.spring.JmsMessageListener"/> <bean id="listenerContainer" class="org.springframework.jms.listener.SimpleMessageListenerContainer"> <property name="connectionFactory" ref="jmsConnectionFactory"/> <property name="messageListener" ref="jmsMessageListener"/> <property name="destinationName" value="${queue.name}"/> </bean>
- 需要在applicationContext配置文件中配置 监听器容器
        
- 
    Spring 消息转换器 默认实现 - SimpleMessageConverter 基本的map、text、byte等的转换器
- MarshallingMessageConverter 使用JAXB的xml转换器
- MappingJacksonMessageConverter 使用Jackson json库的json和对象相互转换器
 
- Spring集成jms事务控制同jdbc的事务控制
    - 如何处理jdbc和jms事务在一个方法中参考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
- 
    javax.jms.JMSException: MQJMS2005: 未能为 '192.168.1.104:FirstLocalQ' 创建 MQQueueManager错误提示;MQQueueConnectionFactory cf = new MQQueueConnectionFactory(); cf.setCCSID(1381);//必须要设置;一般都为1381,具体的值可以查看队列管理器属性中有指定
- 
    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
- 
    DetailedJMSSecurityException: JMSWMQ2013: 为队列管理器 'FirstLocalQ' 提供的安全性认证无效错误提示;MQQueueConnectionFactory cf = new MQQueueConnectionFactory(); QueueConnection conn = null; conn = cf.createQueueConnection("MUSR_MQADMIN", "");//"MUSR_MQADMIN"为用户名,该用户名应该是默认通道`SYSTEM.DEF.SVRCONN`的默认用户名
- 
    针对 上面一条(第4条)的问题,在spring中如何配置用户名和密码呢?MQQueueConnectionFactory中无法通过属性注入用户名和密码,需要通过适配器(UserCredentialsConnectionFactoryAdapter)以中转的方式注入用户名和密码;对此在 JMSTemplate和JmsTransactionManager中的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>
- 
    InvalidDestinationException的异常提示;该异常的发生原因是使用 com.ibm.disthub2.impl.jms.MapMessageImpl和setStringProperty方法造成的,该方法是配置消息头的额外属性,导致目标队列无效,而MQ服务器已经有数据,不过并没有响应的值,需要注意;