JmsTemplate 无法使用 "AMQ219007: Cannot connect to server" 向 ActiveMQ Artemis 发送消息,但可以使用 JMS 类 发送消息
JmsTemplate fails to send message to ActiveMQ Artemis with "AMQ219007: Cannot connect to server" but can send message with JMS classes
我正在尝试使用 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}&password=$jmsArtemisSetup{password}&jms.prefetchPolicy.all=1&consumerWindowSize=0&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.access0(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.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
)。
这是我试过的目标解析器配置。我使用 <property name="destinationResolver" ref="artemisDestinationResolver" />
:
将它添加到 JmsTemplate
配置中
<bean id="artemisDestinationResolver"
class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="amqJndiTemplate" />
<property name="cache" value="true" />
</bean>
错误的根本原因是应用程序试图使用相同的客户端 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}&password=$jmsArtemisSetup{password}&consumerWindowSize=0&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 一起使用。
我正在尝试使用 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}&password=$jmsArtemisSetup{password}&jms.prefetchPolicy.all=1&consumerWindowSize=0&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.access0(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.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
)。
这是我试过的目标解析器配置。我使用 <property name="destinationResolver" ref="artemisDestinationResolver" />
:
JmsTemplate
配置中
<bean id="artemisDestinationResolver"
class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="amqJndiTemplate" />
<property name="cache" value="true" />
</bean>
错误的根本原因是应用程序试图使用相同的客户端 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}&password=$jmsArtemisSetup{password}&consumerWindowSize=0&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 一起使用。