Spring Boot3下通过JNDI访问嵌入式ActiveMQ Artemis连接失败求助
问题描述
生产环境基于Spring Boot 3.0.5对接无官方starter支持的商用JMS Broker,通过JNDI方式获取ConnectionFactory;测试环境计划替换为嵌入式内存ActiveMQ Artemis,但配置后访问抛出ActiveMQNotConnectedException,提示无法连接服务器。此前在Spring Boot 2 + ActiveMQ Classic环境下使用vm://localhost可正常工作,现在切换Artemis后同样报错。
现有配置代码
主类配置
@EnableJms @SpringBootApplication public class Main { @Bean public ConnectionFactory connectionFactory( @Value("${jms.jndi-context-factory}") String jndiContextFactory, @Value("${jms.broker-url}") String brokerUrl) throws NamingException { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, jndiContextFactory); props.put(Context.PROVIDER_URL, brokerUrl); InitialContext ctx = new InitialContext(props); return (ConnectionFactory) ctx.lookup("ConnectionFactory"); } public static void main(String[] args) { SpringApplication.run(Main.class, args); } }
Receiver组件
@Component public class Receiver { private final BlockingDeque<String> receivedMessages = new LinkedBlockingDeque<>(100); @JmsListener(destination = "testtopic") public void receive(Message<String> message) { receivedMessages.add(message.getPayload()); } public String getNextReceivedMessage() { try { return receivedMessages.poll(1_000L, MILLISECONDS); } catch (InterruptedException e) { throw new AssertionError(e); } } }
测试环境application.yml
jms: jndi-context-factory: 'org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory' broker-url: 'vm://0'
Maven测试依赖
<dependency> <groupId>org.apache.activemq</groupId> <artifactId>artemis-jakarta-server</artifactId> <scope>test</scope> </dependency>
异常信息
org.springframework.jms.UncategorizedJmsException: Uncategorized exception occurred during JMS processing; 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) ...(省略中间栈信息) Caused by: ActiveMQNotConnectedException[errorType=NOT_CONNECTED message=AMQ219007: Cannot connect to server(s). Tried with all available servers.] at org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:703) ... 77 more
解决方案
问题根源
- 嵌入式Broker未启动:ActiveMQ Artemis的VM连接模式要求Broker实例已显式启动,当前仅配置JNDI连接工厂,未初始化并启动嵌入式Artemis Broker。
- JNDI配置缺失:Artemis的JNDI初始上下文工厂需要额外配置映射关系,仅指定
provider-url无法让JNDI找到ConnectionFactory实例。
具体修复方案
方案1:保留JNDI逻辑,启动嵌入式Broker
步骤1:添加测试专用Broker配置Bean
创建测试配置类,手动启动嵌入式Artemis Broker:
@TestConfiguration public class EmbeddedArtemisConfig { @Bean(destroyMethod = "stop") public EmbeddedActiveMQ startEmbeddedBroker() throws Exception { EmbeddedActiveMQ embeddedBroker = new EmbeddedActiveMQ(); embeddedBroker.start(); return embeddedBroker; } }
在测试类中引入该配置:
@SpringBootTest @Import(EmbeddedArtemisConfig.class) public class ReceiverTest { // 原有测试代码不变 }
步骤2:补充JNDI配置属性
修改测试环境application.yml,添加JNDI连接工厂映射:
jms: jndi-context-factory: 'org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory' broker-url: 'vm://0' jndi-additional-props: connectionFactory.ConnectionFactory: vm://0
同时修改主类的connectionFactory Bean,加载额外JNDI属性:
@Bean public ConnectionFactory connectionFactory( @Value("${jms.jndi-context-factory}") String jndiContextFactory, @Value("${jms.broker-url}") String brokerUrl, @Value("#{${jms.jndi-additional-props:{}}}") Map<String, String> additionalJndiProps) throws NamingException { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, jndiContextFactory); props.put(Context.PROVIDER_URL, brokerUrl); props.putAll(additionalJndiProps); // 注入额外属性 InitialContext ctx = new InitialContext(props); return (ConnectionFactory) ctx.lookup("ConnectionFactory"); }
方案2:绕过JNDI,直接创建Artemis连接工厂
如果测试环境无需沿用JNDI逻辑,可直接替换ConnectionFactory Bean简化配置:
@TestConfiguration public class TestJmsConfig { @Bean public ConnectionFactory connectionFactory() { return new ActiveMQConnectionFactory("vm://0"); } }
在测试类中引入该配置,覆盖生产环境的JNDI连接工厂:
@SpringBootTest @Import(TestJmsConfig.class) public class ReceiverTest { // 原有测试代码不变 }
关键说明
- ActiveMQ Artemis与ActiveMQ Classic的VM连接逻辑不同:Classic会自动创建VM Broker,而Artemis必须显式启动嵌入式实例。
- 若坚持使用JNDI,必须确保Broker已启动,且JNDI属性包含
connectionFactory.ConnectionFactory映射,让Artemis JNDI工厂能识别对应的连接工厂。
内容的提问来源于stack exchange,提问作者Thomas Oellrich
相关产品推荐
相关产品推荐

