我需要从运行在 WebSphere AS 6.1 应用程序服务器上的Web应用程序连接到远程 z / OS 队列上的WebSphere MQ。在WebSphere AS上,我配置了QueueConnectionFactory和Queue(包含远程队列数据的一部分的对象),大多数设置都设置为默认值 - 我只需要设置队列名称,通道,主机,端口和传输类型是CLIENT。我使用JNDI查找在 Spring 3.2 配置中注入它们:
<jee:jndi-lookup id="destination" jndi-name="MyMQQueue" expected-type="javax.jms.Queue" />
<jee:jndi-lookup id="targetConnectionFactory" jndi-name="MyMQQCF" expected-type="javax.jms.QueueConnectionFactory" />
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="targetConnectionFactory"
p:defaultDestination-ref="destination" />
<bean id="simpleMessageListener" class="my.own.SimpleMessageListener"/>
<bean id="msgListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="targetConnectionFactory" />
<property name="destination" ref="destination" />
<property name="messageListener" ref="simpleMessageListener" />
<property name="taskExecutor" ref="managedThreadsTaskExecutor" />
<property name="receiveTimeout" value="5000" />
<property name="recoveryInterval" value="5000" />
</bean>
<bean id="managedThreadsTaskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
</bean>
JmsTemplate正确发送和接收(同步)消息。 DefaultMessageListenerContainer,一个异步消息接收器,在WebSphere AS启动期间从MQ队列中读取一些(先前发送的)消息,但很快就会发生阻塞,并开始反复抛出“连接已关闭”异常。在每次这样的场合,它通知我
DefaultMessag W org.springframework.jms.listener.DefaultMessageListenerContainer handleListenerSetupFailure Setup of JMS message listener invoker failed for destination 'queue://myqueue' - trying to recover. Cause: Connection closed
DefaultMessag I org.springframework.jms.listener.DefaultMessageListenerContainer refreshConnectionUntilSuccessful Successfully refreshed JMS Connection
但停止将消息从队列中删除。
挖掘一下Spring代码,我发现在DefaultMessageListenerContainer上设置
<property name="cacheLevel" value="0"/>
解决了这个问题,因为每次发送消息时都会从队列中读取消息。但是,查看到WebSphere MQ的TCP流量,我发现MQCLOSE / MQOPEN命令被重复发送到它,如下所示:
这可能意味着连接会持续关闭并重新打开。
任何人都可以建议可能导致缓存无法正常工作的原因,以及是否有一种相对简单的方法来修改Spring代码(例如,扩展DefaultMessageListenerContainer),或者可能在MQ队列连接工厂/队列上设置一些属性,让它工作?
修改
进一步搜索互联网,我找到了以下链接
似乎描述了Tomcat上发生的类似问题。解决方案是在DefaultMessageListenerContainer上设置某个exceptionListener。但是,尝试在WebSphere上执行此操作会抛出异常“javax.jms.IllegalStateException:Method setExceptionListener not allowed”。根本原因似乎是J2EE 1.4规范禁止在JMS连接上调用setExceptionListener。
https://www.ibm.com/developerworks/library/j-getmess/j-getmess-pdf.pdf
答案 0 :(得分:1)
似乎设置
<property name="cacheLevel" value="0"/>
DefaultMessageListenerContainer上的实际上是正确的解决方案。
我通过解释我在Wireshark捕获的TCP流量上看到的MQCLOSE / MQOPEN误导自己,作为重量级连接开放。
首先,管理控制台WebSphere AS 6.1上新创建的连接工厂默认具有JMS连接池(最大大小为10)。通过调试DefaultMessageListenerContainer的基类,AbstractPollingMessageListenerContainer,(特别是方法
protected boolean doReceiveAndExecute(
Object invoker, Session session, MessageConsumer consumer, TransactionStatus status)
)
我们发现无论是创建连接的调用,还是从连接创建会话的调用都没有生成TCP流量,只有通过创建消费者才能生成TCP流量(如果我理解正确,则认为是“轻量级操作”) ),尝试从队列接收消息,并关闭消费者。
所以似乎连接是从相应的池中获取的,并且会话也以某种方式“缓存”。
因此,不是通过Spring缓存,缓存似乎是由应用程序服务器在这里完成的。