Spring Boot 用JNDI访问嵌入式ActiveMQ Artemis

qvsjd97n  于 2023-05-06  发布在  Spring
关注(0)|答案(2)|浏览(257)

在生产中,我们使用Sping Boot 不直接支持的商业JMS代理(没有启动项目,也没有应用程序属性)。我们通过JNDI访问连接工厂。在测试范围内,我想用一个嵌入式内存中的ActiveMQ 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);
  }
}

这是接收器:

@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);
    }
  }
}

yml配置主题和JNDI属性:

spring:
  jms:
    pub-sub-domain: true

jms:
  jndi-context-factory: '<COMMERCIAL_BROKER_INITIAL_CONTEXT_FACTORY>'
  broker-url: '<COMMERCIAL_BROKER_URL>'

下面是一些测试代码:

@SpringBootTest
public class ReceiverTest {

  @Autowired
  private JmsTemplate jmsTemplate;

  @Autowired
  private Receiver receiver;

  @Test
  public void receive() {
    jmsTemplate.convertAndSend("testtopic", "Hello World!");

    String message = receiver.getNextReceivedMessage();

    assertThat(message).isEqualTo("Hello World!");
  }
}

在测试应用程序.yml(src/test/resources/config)中,我覆盖了JNDI信息:

jms:
  jndi-context-factory: 'org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory'
  broker-url: 'vm://0'

我们的Maven POM看起来像这样:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>        
    <dependency>
      <groupId>jakarta.jms</groupId>
      <artifactId>jakarta.jms-api</artifactId>
    </dependency>    
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jms</artifactId>
    </dependency>    
    <dependency>
      <groupId>commercial-broker-groupid</groupId>
      <artifactId>commercial-broker-artifactid</artifactId>
      <version>${commercial-broker-version}</version>
      <scope>runtime</scope>
    </dependency>    
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>artemis-jakarta-server</artifactId>
      <scope>test</scope>      
    </dependency>          
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>  
 </dependencies>

但没有用。我得到以下异常:

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)
    at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:184)
    at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:510)
    at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:587)
    at org.springframework.jms.core.JmsTemplate.convertAndSend(JmsTemplate.java:664)
    at test.ReceiverTest.receive(ReceiverTest.java:21)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
    at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
    at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: jakarta.jms.JMSException: Failed to create session factory
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:867)
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:284)
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnection(ActiveMQConnectionFactory.java:279)
    at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:196)
    at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:497)
    ... 73 more
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)
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:865)
    ... 77 more

Sping Boot 3.0.5和Java 17这曾经适用于Sping Boot 2和ActiveMQ Classic。对于ActiveMQ Classic,我曾经使用URL vm://localhost,我也尝试过,它生成了相同的异常。我错过了什么?是否不再能够通过JNDI访问嵌入式代理?

wj8zmpe1

wj8zmpe11#

在您的配置中,我没有看到任何实际启动ActiveMQ Artemis示例的内容。
我相信区别在于,在ActiveMQ“Classic”中,当使用vm://连接时,可以在后台自动启动示例。ActiveMQ Artemis目前没有实现这种行为,因此您需要start an instance of ActiveMQ Artemis yourself或使用Spring Boot documentation中提到的类似spring-boot-starter-artemis的东西。
事实上,如果有一个ActiveMQ Artemis示例正在运行,它可能没有配置acceptor,而vm://0配置了acceptor。在这种情况下,我建议在application.yml中使用它:

jms:
  jndi-context-factory: 'org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory'
  broker-url: 'tcp://localhost:61616'
bcs8qyzn

bcs8qyzn2#

我知道问题出在哪了。当您定义自己的ConnectionFactory时,嵌入式代理根本不会启动。这大概是因为ArtemisAutoConfiguration类上的@ConditionalOnMissingBean注解:

@AutoConfiguration(before = JmsAutoConfiguration.class, after = JndiConnectionFactoryAutoConfiguration.class)
@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })
@ConditionalOnMissingBean(ConnectionFactory.class)
@EnableConfigurationProperties({ ArtemisProperties.class, JmsProperties.class })
@Import({ ArtemisEmbeddedServerConfiguration.class, ArtemisXAConnectionFactoryConfiguration.class,
        ArtemisConnectionFactoryConfiguration.class })
public class ArtemisAutoConfiguration {

}

相关问题