当前位置: 首页 > 知识库问答 >
问题:

使用DefaultMessageListenerContainer连接到WebSphere MQ会反复抛出“连接关闭”

申屠晟
2023-03-14

我需要从运行在WebSphereAS6.1应用服务器上的web应用程序连接到远程WebSphereMQ on z/OS队列。在WebSphere AS上,我配置了QueueConnectionFactory和Queue(一个包含部分远程队列数据的对象),并将大多数设置设置为它们的默认值——我只需要设置队列名称、通道、主机、端口和传输类型,即客户机。我使用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 start期间从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命令会重复发送到它,如中所示:

Wireshark捕获流量

这可能意味着连接会持续关闭和重新打开。

有人能建议缓存不能正常工作的原因吗,以及是否有一种相对简单的方法来修改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:Method setExceptionListener not Allowed”。根本原因似乎是J2EE 1.4规范禁止在JMS连接上调用setExceptionListener。

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

共有1个答案

庞乐池
2023-03-14

看来设置

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

在DefaultMessageListenerContainer上,实际上是正确的解决方案。

在本例中,我将Wireshark捕获的TCP流量中看到的MQCLOSE/MQOPEN解释为重量级连接打开,从而误导了自己。

首先,管理控制台WebSphere AS 6.1上新创建的连接html" target="_blank">工厂默认有一个JMS连接池(最大大小为10)。通过调试DefaultMessageListenerContainer的基类AbstractPollingMessageListenerContainer

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

我们可以看到,创建连接的调用和从连接创建会话的调用都不会生成TCP流量,而TCP流量只能通过创建使用者(如果我理解正确,则被视为“轻量级操作”),尝试从队列接收消息,并关闭使用者来生成。

因此,连接似乎是从各自的池中获取的,并且会话也以某种方式被“缓存”。

因此,这里的缓存似乎是由应用服务器完成的,而不是Spring缓存。

 类似资料:
  • 我尝试通过应用服务器Glassfish和JPA连接到mysql数据库。 我的persistence.xml如下所示: mysql中的“max_connections”设置为600。这样就够了。 有什么问题?

  • 我在unbundu机器中使用JMeter设置了一个分布式负载测试环境。 - - - - 系统上的防火墙已关闭 -所有计划的主和从都在同一个子网中 -JMeter 服务器可以访问目标。 -所有系统上的JMeter版本相同(版本2.3.4)。 1) 尝试通过ubundu终端从主设备ping到从设备,反之亦然。它正在发生。。 2) 在客户端(主)jmeter 属性中添加了以下内容: 3) 在服务器(从属

  • 另一个宽大处理--B: 这里要注意,实体A和B之间没有隐式关系,B表中的a_id是手工处理的,因此--关系类似于一对多(A-->B),但不是jpa-hibernate关系。而且,我的FullDto有A的所有属性和B的列表: 现在,我想从A的存储库接口中提取所有内容(A和B表一次完成),如下所示:

  • 我使用weblogic应用服务器和oracle数据库。我使用jdbc与oracle数据库通信。我从weblogic数据源获得连接,并向表中插入一条记录。问题是,当我想关闭连接(插入数据库后)时,我会遇到一个异常(连接已经关闭)。这是我的代码: 但是联系。close语句引发异常: 我试图避免连接。close语句(因为我教过连接是自动关闭的!!但过了一段时间,所有的连接都打开了,因此引发了一个异常)

  • 尝试使用Docker容器将Kibana连接到ES时出错: kibana-product-624|{"type":"log","@time戳":"2018-05-25T14:56:36Z","tags":["警告","elasticsearch","admin"],"pid": 1,"消息":"无法恢复连接:超文本传输协议://elasticsearch: 9200/"}kibana-product

  • 我有一个Java TLS客户端,它可以向服务器发送一系列请求,每个请求后面都有对服务器的响应。 但是,有许多不同的服务器。有些是“多消息”服务器,在第一个请求后保持连接打开,以便可以通过第一个连接发送后续请求。另一些是“单消息”服务器,在每条消息之后关闭连接,因此后续消息需要新的连接。客户端没有先验的方法来知道它正在与什么类型的服务器通信,也无法修复服务器。 非常希望单个消息服务能够在没有完全握手