You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring DefaultMessageListenerContainer无法故障切换至备用URL问题

Spring JMS对接Tibco EMS实现故障自动切换方案

问题场景

我们有一个Spring应用,使用spring-jms-5.2.24.RELEASE.jar提供的JMS工具对接Tibco EMS主题消费者,配置了双地址URL用于故障切换,配置如下:

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
   <property name="environment">
      <props>
         <prop key="java.naming.provider.url">tcp://usitdjms-vd3:7222,tcp://usitdjms-vd4:7222</prop>
         <prop key="java.naming.factory.initial">com.tibco.tibjms.naming.TibjmsInitialContextFactory</prop>
         <prop key="java.naming.security.principal">${USERNAME}</prop>
         <prop key="java.naming.security.credentials">${PASSWORD}</prop>
      </props>
   </property>
</bean>

但当vd3服务器宕机时,代码并未自动切换至vd4,而是持续打印错误,仅重启应用才能恢复,错误日志如下:

08/15/2023-14:20:19:453 [jmsContainer-1] - ERROR - DefaultMessageListenerContainer.java:962 - Could not refresh JMS Connection for destination 'Topic[in_order_perf]' - retrying using FixedBackOff{interval=5000, currentAttempts=54, maxAttempts=unlimited}. Cause: Failed to connect to the server at tcp://usitdjms-vd4.ny.cantor.com:7222; nested exception is java.net.ConnectException: Connection refused (Connection refused)

解决方案

1. 补充Tibco EMS故障转移属性

Tibco EMS的多地址故障切换需要通过专属配置属性开启重试与重连机制,在JndiTemplate的environment中添加以下属性:

  • com.tibco.tibjms.connect.attemptCount:设为-1表示无限次尝试连接
  • com.tibco.tibjms.connect.retryInterval:重试间隔(单位毫秒,示例设为3000)
  • com.tibco.tibjms.reconnect.attemptCount:重连尝试次数(-1表示无限)
  • com.tibco.tibjms.reconnect.retryInterval:重连间隔(示例设为5000)
  • com.tibco.tibjms.connect.attemptDelay:首次重试延迟(示例设为1000)

修改后的配置示例:

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
   <property name="environment">
      <props>
         <prop key="java.naming.provider.url">tcp://usitdjms-vd3:7222,tcp://usitdjms-vd4:7222</prop>
         <prop key="java.naming.factory.initial">com.tibco.tibjms.naming.TibjmsInitialContextFactory</prop>
         <prop key="java.naming.security.principal">${USERNAME}</prop>
         <prop key="java.naming.security.credentials">${PASSWORD}</prop>
         <!-- 开启Tibco EMS故障转移机制 -->
         <prop key="com.tibco.tibjms.connect.attemptCount">-1</prop>
         <prop key="com.tibco.tibjms.connect.retryInterval">3000</prop>
         <prop key="com.tibco.tibjms.reconnect.attemptCount">-1</prop>
         <prop key="com.tibco.tibjms.reconnect.retryInterval">5000</prop>
         <prop key="com.tibco.tibjms.connect.attemptDelay">1000</prop>
      </props>
   </property>
</bean>

2. 调整Spring JMS容器的连接配置

确保DefaultMessageListenerContainer的配置支持自动恢复并避免连接缓存:

  • 设置recoveryInterval:连接恢复间隔(示例设为5000毫秒)
  • 把cacheLevelName设为CACHE_NONE或CACHE_CONSUMER:避免缓存旧连接导致无法切换
  • 可选配置退避策略:用ExponentialBackOff实现指数递增的重试间隔

示例配置:

<bean id="jmsListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
   <property name="connectionFactory" ref="jmsConnectionFactory"/>
   <property name="destination" ref="topicDestination"/>
   <property name="messageListener" ref="topicMessageListener"/>
   <property name="recoveryInterval" value="5000"/>
   <property name="cacheLevelName" value="CACHE_NONE"/>
   <!-- 可选:指数退避重试配置 -->
   <property name="backOff">
      <bean class="org.springframework.util.backoff.ExponentialBackOff">
         <property name="initialInterval" value="3000"/>
         <property name="multiplier" value="1.5"/>
         <property name="maxInterval" value="30000"/>
      </bean>
   </property>
</bean>

3. 排查客户端版本兼容性

确认使用的Tibco EMS客户端jar版本与服务器版本匹配,客户端jar必须包含com.tibco.tibjms.naming.TibjmsInitialContextFactory类,且支持多地址故障转移功能。旧版本客户端可能无法正确解析多地址URL并触发轮询。

原理说明

Tibco EMS的JNDI初始上下文工厂原生支持多地址轮询,但需要通过连接属性开启重试、重连机制。Spring JMS的DefaultMessageListenerContainer在连接失败时,会根据配置的恢复策略重新从JNDI获取连接,此时Tibco客户端会依次尝试配置的所有URL,直到成功建立连接。

内容的提问来源于stack exchange,提问作者Michael Starkie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:23:09