2017-02-28 65 views
1

我需要從一個的WebSphere運行AS 6.1應用服務器Web應用程序連接到遠程的WebSphere MQ z/OS上隊列。在WebSphere AS上,我配置了QueueConnectionFactory和Queue(一個包含部分遠程隊列數據的對象),並將大部分設置設置爲其默認值 - 我只需要設置隊列名稱,通道,主機,端口和傳輸類型是CLIENT。我注入它們在以下春3.2配置中使用JNDI查找:使用使用DefaultMessageListenerContainer連接到WebSphere MQ拋出「連接已關閉」反覆

<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"/> 

設置解決了這個問題,在這個意義上,這些消息現在正在讀出隊列每次我給他們時間。然而,看着TCP流量到WebSphere MQ我發現MQCLOSE/MQOPEN命令重複發送到它作爲:

Wireshark captured traffic

這可能意味着連接被不斷關閉並重新打開。

任何人都可以提出什麼可能導致緩存工作不正常,以及是否有相對簡單的方法來修改Spring代碼(例如,擴展DefaultMessageListenerContainer),或者可能在MQ隊列連接工廠/排隊,讓它工作?

編輯:

進一步搜索互聯網,我發現下面的鏈接

http://forum.spring.io/forum/spring-projects/integration/jms/89532-defaultmessagelistenercontainer-cachingconnectionfactory-tomcat-and-websphere-mq

這似乎說明在Tomcat上出現類似的問題。解決方法是在DefaultMessageListenerContainer上設置一個特定的exceptionListener。但是,試圖在WebSphere上執行此操作會引發異常「javax.jms.IllegalStateException:方法setExceptionListener不允許」。根本原因似乎是J2EE 1.4規範禁止在JMS連接上調用setExceptionListener。

https://www.ibm.com/developerworks/library/j-getmess/j-getmess-pdf.pdf

回答

1

似乎對使用DefaultMessageListenerContainer設置

<property name="cacheLevel" value="0"/> 

實際上是正確的解決方案。

我通過解釋我在Wireshark捕獲的TCP流量中看到的MQCLOSE/MQOPEN來誤導我自己,因爲這是重量級連接開放。

首先,管理控制檯WebSphere AS 6.1上新創建的Connection Factory默認具有JMS連接池(最大大小爲10)。通過調試基類使用DefaultMessageListenerContainer,AbstractPollingMessageListenerContainer的,(特別是該方法

protected boolean doReceiveAndExecute(
      Object invoker, Session session, MessageConsumer consumer, TransactionStatus status) 

人們看到,無論是呼叫建立的連接,無論是呼叫建立從連接產生TCP業務的會話,並且TCP流量僅通過創建一個消費者(如果我理解正確的話認爲是「輕量級操作」),試圖從隊列中接收消息並關閉消費者來生成。

因此,似乎連接取自各自的池,並且會話以某種方式「緩存」。

因此,不是由Spring進行緩存,而是由應用程序服務器在這裏完成緩存。