如何实现ActiveMQ Classic向ActiveMQ Artemis转发消息?
问题
尝试让ActiveMQ Classic代理将消息转发至部署了相同队列的ActiveMQ Artemis代理,Classic侧配置如下:
<networkConnectors> <networkConnector uri="static:(tcp://172.18.0.3:61616)" name="artemis" userName="artemis" password="artemis"/> </networkConnectors>
Classic启动无报错,但Artemis日志出现以下错误:
2025-04-14 11:37:39,763 WARN [org.apache.activemq.artemis.core.server] AMQ222216: Security problem while authenticating: AMQ229031: Unable to validate user from 172.18.0.2:57000. Username: null; SSL certificate subject DN: unavailable 2025-04-14 11:37:39,763 WARN [org.apache.activemq.artemis.core.protocol.openwire.OpenWireConnection] Errors occurred during the buffering operation javax.jms.IllegalStateException: Cannot add a producer to a connection that had not been registered: localhost->ce2321bbff98-40547-1744630417600-30:2 at org.apache.activemq.artemis.core.protocol.openwire.OpenWireConnection$CommandProcessor.processAddProducer(OpenWireConnection.java:1230) ~[artemis-openwire-protocol-2.39.0.jar:2.39.0] at org.apache.activemq.command.ProducerInfo.visit(ProducerInfo.java:108) ~[activemq-client-5.18.6.jar:5.18.6] at org.apache.activemq.artemis.core.protocol.openwire.OpenWireConnection.act(OpenWireConnection.java:356) [artemis-openwire-protocol-2.39.0.jar:2.39.0] at org.apache.activemq.artemis.core.protocol.openwire.OpenWireConnection.bufferReceived(OpenWireConnection.java:299) [artemis-openwire-protocol-2.39.0.jar:2.39.0] at org.apache.activemq.artemis.core.remoting.server.impl.RemotingServiceImpl$DelegatingBufferHandler.bufferReceived(RemotingServiceImpl.java:723) [artemis-server-2.39.0.jar:2.39.0] at org.apache.activemq.artemis.core.remoting.impl.netty.ActiveMQChannelHandler.channelRead(ActiveMQChannelHandler.java:73) [artemis-core-client-2.39.0.jar:2.39.0] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) [netty-codec-4.1.115.Final.jar:4.1.115.Final] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:333) [netty-codec-4.1.115.Final.jar:4.1.115.Final] at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:455) [netty-codec-4.1.115.Final.jar:4.1.115.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) [netty-codec-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1357) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:868) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) [netty-transport-4.1.115.Final.jar:4.1.115.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) [netty-common-4.1.115.Final.jar:4.1.115.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.115.Final.jar:4.1.115.Final] at org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118) [artemis-commons-2.39.0.jar:2.39.0]
解决方案
修复当前networkConnector问题
日志核心问题为认证时用户名为null,进而导致未注册连接就添加生产者,可通过以下步骤修复:
- 修正Classic的networkConnector配置:
将认证信息直接嵌入URI,确保连接Artemis时正确传递用户名密码:
或补充<networkConnectors> <networkConnector uri="static:(tcp://artemis:artemis@172.18.0.3:61616)" name="artemis"/> </networkConnectors>bridgeUserName和bridgePassword参数,明确转发消息时的认证信息:<networkConnectors> <networkConnector uri="static:(tcp://172.18.0.3:61616)" name="artemis" userName="artemis" password="artemis" bridgeUserName="artemis" bridgePassword="artemis"/> </networkConnectors> - 检查Artemis的OpenWire acceptor配置:
确保Artemis的broker.xml中开启OpenWire协议 acceptor:
同时确认<acceptors> <acceptor name="openwire-acceptor">tcp://0.0.0.0:61616?protocols=OPENWIRE</acceptor> </acceptors>artemis用户具备连接、发送消息的权限:- 在
artemis-users.properties中确保用户存在:artemis=artemis - 在
artemis-roles.properties中配置角色权限:artemis=amq
- 在
替代方案(若上述方法无效)
如果networkConnector方式无法满足需求,可尝试以下方案:
- 使用ActiveMQ Classic消息桥(Bridge):
相比networkConnector,Bridge更适合点对点精准转发,示例配置:<bridges> <bridge name="classic-to-artemis-bridge"> <queueName>YOUR_QUEUE_NAME</queueName> <bridgeUri>tcp://172.18.0.3:61616</bridgeUri> <userName>artemis</userName> <password>artemis</password> <clientId>bridge-client</clientId> <dispatchAsync>true</dispatchAsync> </bridge> </bridges> - 使用Apache Camel路由消息:
通过Camel编写路由规则,支持复杂消息转换和逻辑,核心示例:from("activemq:queue:YOUR_QUEUE_NAME") .to("activemq:queue:YOUR_QUEUE_NAME?brokerURL=tcp://172.18.0.3:61616&username=artemis&password=artemis"); - 自定义JMS转发程序:
编写Java客户端程序,从Classic消费消息后发送到Artemis,完全控制转发逻辑和认证流程。
内容的提问来源于stack exchange,提问作者user30267968
相关产品推荐
相关产品推荐

