【问题标题】:JmsTemplate fails to send message to ActiveMQ Artemis with "AMQ219007: Cannot connect to server" but can send message with JMS classesJmsTemplate 无法使用“AMQ219007:无法连接到服务器”向 ActiveMQ Artemis 发送消息,但可以使用 JMS 类发送消息
【发布时间】:2021-10-20 12:15:34
【问题描述】:

我正在尝试使用 Spring 的 JmsTemplate 发送 JMS 消息,但它失败了,这是堆栈跟踪中显示的根本原因:

AMQ219007: Cannot connect to server

但是,我可以使用传递给JmsTemplate 的相同连接工厂直接针对JMS 类发送消息编程。我确定我遗漏了一些明显的东西,但我只是不知道缺少什么配置才能使JmsTemplate 工作。我认为ActiveMQInitialContextFactory 的配置是正确的,因为我可以使用javax.jms.* 类发送消息。 FWIW,我尝试使用目标解析器配置 JmsTemplate,但这没有帮助。

这里是配置:

<bean id="artemisJndiTemplate"
        class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory</prop>
            <prop key="java.naming.provider.url">(tcp://artemisServer1:61616,tcp://artemisServer2:61616)?user=$jmsArtemisSetup{user}&amp;password=$jmsArtemisSetup{password}&amp;jms.prefetchPolicy.all=1&amp;consumerWindowSize=0&amp;clientID=${NODENBRTAG}</prop>
        </props>
    </property>
</bean>

<!-- look up the JMS ConnectionFactory in JNDI -->
<bean id="artemisConnectionFactory"
        class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate" ref="artemisJndiTemplate" />
    <property name="jndiName" value="ConnectionFactory" />
</bean>

<bean id="qFromSvcToESB"
        class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="artemisConnectionFactory" />
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" />
    <property name="sessionTransacted" value="true" />
    <property name="defaultDestination">
        <bean class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate" ref="artemisJndiTemplate" />
            <property name="jndiName" value="dynamicQueues/qFromSvcToESB" />
        </bean>
    </property>
</bean>

当我使用JmsTemplate 发送消息时,我得到以下堆栈跟踪:

2021-08-18 10:06:31,796 [ERROR] [com.example.emailassistant.msghdlr.EmailAssistantMsgHdlr]:171  - 1629306356191 - jmsTemplate.send(...) failed.
org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; nested exception is javax.jms.JMSException: Failed to create session factory; nested exception is ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ219007: Cannot connect to server(s). Tried with all available servers.]
        at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:311) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:185) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:507) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:576) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:567) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at com.example.emailassistant.msghdlr.EmailAssistantMsgHdlr.execute(EmailAssistantMsgHdlr.java:151) ~[com.example.emailassistant.msghdlr-0.0.1-SNAPSHOT.jar:?]
        at com.example.framework2.activemq.artemis.EpmServiceHandlerAdapter.dispatchToListener(EpmServiceHandlerAdapter.java:71) ~[com.example.framework2.activemq.artemis-5.1-SNAPSHOT.jar:?]
        at com.example.framework2.AbstractEpmMsgHdlrAdapter$EpmMessageListener.onMessage(AbstractEpmMsgHdlrAdapter.java:615) ~[com.example.framework2-5.1-SNAPSHOT.jar:?]
        at org.apache.activemq.artemis.jms.client.JMSMessageListenerWrapper.onMessage(JMSMessageListenerWrapper.java:110) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.core.client.impl.ClientConsumerImpl.callOnMessage(ClientConsumerImpl.java:1031) ~[artemis-core-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.core.client.impl.ClientConsumerImpl.access$400(ClientConsumerImpl.java:50) ~[artemis-core-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.core.client.impl.ClientConsumerImpl$Runner.run(ClientConsumerImpl.java:1154) ~[artemis-core-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.utils.actors.OrderedExecutor.doTask(OrderedExecutor.java:42) ~[artemis-commons-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.utils.actors.OrderedExecutor.doTask(OrderedExecutor.java:31) ~[artemis-commons-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.utils.actors.ProcessorBase.executePendingTasks(ProcessorBase.java:65) ~[artemis-commons-2.12.0.jar:2.12.0]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
        at org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118) [artemis-commons-2.12.0.jar:2.12.0]
Caused by: javax.jms.JMSException: Failed to create session factory
        at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:886) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:299) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:294) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:196) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:494) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        ... 15 more
Caused by: org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException: AMQ219007: Cannot connect to server(s). Tried with all available servers.
        at org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:690) ~[artemis-core-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:884) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:299) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:294) ~[artemis-jms-client-2.12.0.jar:2.12.0]
        at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:196) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:494) ~[spring-jms-5.2.12.RELEASE.jar:5.2.12.RELEASE]
        ... 15 more

此代码和配置以前使用 ActiveMQ“经典”连接工厂(即org.apache.activemq.jndi.ActiveMQInitialContextFactory)。

这是我尝试的目标解析器配置。我使用&lt;property name="destinationResolver" ref="artemisDestinationResolver" /&gt; 将它添加到JmsTemplate 配置中:

<bean id="artemisDestinationResolver"
        class="org.springframework.jms.support.destination.JndiDestinationResolver">
    <property name="jndiTemplate" ref="amqJndiTemplate" />
    <property name="cache" value="true" />
</bean>

【问题讨论】:

  • 服务器的about页面报告它是2.10.1版本。代码正在拉入 2.12.0 版的 artemis 库(jar 文件)。
  • 另外值得注意的是,ActiveMQ Artemis 支持 ActiveMQ“经典”使用的 OpenWire JMS 客户端,因此不必将您的客户端应用程序更改为 Artemis 附带的核心 JMS 客户端。
  • 确实如此,这就是我们去年运行 JMS 服务的方式。但是,我们在关闭预取时遇到了问题,因此我正在探索从 Artemis 切换到使用核心的 JMS 库。问题是我们动态启动节点来处理消息,第一个开始使用 failover:(tcp://artemisServer1:61616,tcp: //artemisServer2:61616)?jms.watchTopicAdvisories=false,jms.prefetchPolicy.all=1,consumerWindowSize=0,clientID=${AIS_NODENBRTAG}
  • 使用 2.18.0 库,我得到“javax.jms.InvalidClientIDException:clientID=Node1 已设置到另一个连接”。我已经有一个来自工厂的连接,它正在侦听 JMS 消息,因此注册了具有该 ID 的客户端,但我希望能够连接以发送消息....
  • 连接用于什么并不重要。两个连接不能同时使用相同的客户端 ID。这违反了 JMS 规范。

标签: java spring-jms activemq-artemis jmstemplate


【解决方案1】:

该错误的根本原因是应用程序尝试使用相同的客户端 ID 与 JMS 服务器建立两个 JMS 连接。 JMS 规范不允许这样做。

解决方案是使用连接池。通常,出于性能原因,应包括连接池。在这种特殊情况下,应用程序启动,侦听一条消息,发送一条回复消息,然后关闭,因此未启用池。但是,在使用 artemis-jms-client 库时,这意味着使用相同的客户端 ID 创建了两个不同的 JMS 连接,从而导致失败。

以下使用池的 XML 配置允许服务正常工作:

<bean id="artemisJndiTemplate"
        class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory</prop>
            <prop key="java.naming.provider.url">(tcp://artemisServer1:61616,tcp://artemisServer1:61616)?user=$jmsArtemisSetup{user}&amp;password=$jmsArtemisSetup{password}&amp;consumerWindowSize=0&amp;clientID=${NODENBRTAG}</prop>
        </props>
    </property>
</bean>

<!-- look up the JMS ConnectionFactory in JNDI -->
<bean id="artemisConnectionFactoryBase"
        class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate" ref="artemisJndiTemplate" />
    <property name="jndiName" value="ConnectionFactory" />
</bean>

<!-- A cached connection to wrap the ActiveMQ connection -->
<bean id="artemisConnectionFactory"
    class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory">
        <ref bean="artemisConnectionFactoryBase" />
    </property>
    <property name="sessionCacheSize">
        <value>100</value>
    </property>
</bean>

<bean id="replyJmsQueue"
        class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="artemisConnectionFactory" />
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" />
    <property name="sessionTransacted" value="true" />
    <property name="defaultDestination">
        <bean class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiTemplate" ref="artemisJndiTemplate" />
            <property name="jndiName" value="dynamicQueues/replyJmsQueue" />
        </bean>
    </property>
</bean>

原始 JMS 代码和 JmsTemplate 都使用连接池,因此最终使用相同的连接。

顺便说一句,将 artemis-jms-client 库从 2.10.1 升级到 2.18.0 在堆栈跟踪中提供了比原来更有用的消息。

javax.jms.InvalidClientIDException: clientID=Node1 was already set into another connection

通过连接池,JMS 代码可用于 artemis-jms-client 2.10.1 或 2.18.0。

【讨论】:

  • 如果这是正确答案,您应该将其标记为正确答案。谢谢!
猜你喜欢
  • 2015-02-19
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 2018-11-24
  • 2015-08-25
  • 1970-01-01
相关资源
最近更新 更多