You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.2.0 JMS单元测试:Embedded ActiveMQ连接及消息属性问题

问题分析与解决方案

错误原因

Spring Boot 3.x 基于 Jakarta EE 9+,所有原Java EE API的包路径从javax.*迁移到了jakarta.*。你遇到的NoClassDefFoundError: javax/jms/JMSException,是因为类路径中缺少适配Jakarta环境的JMS API,同时测试代码混合了JUnit 4和JUnit 5的注解,进一步加剧了依赖冲突问题。


分步解决方案

1. 修正依赖配置

移除直接引入的ActiveMQ独立包,改用Spring Boot官方的ActiveMQ Starter,它会自动适配Spring Boot 3的Jakarta环境并管理依赖版本:

// 移除原有activemq-broker、activemq-all,替换为starter
implementation 'org.springframework.boot:spring-boot-starter-activemq'

// 保留activemq-junit,让Spring Boot管理版本
testImplementation 'org.apache.activemq.tooling:activemq-junit'

// 其他测试依赖保持不变
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
testImplementation 'org.mockito:mockito-junit-jupiter:4.8.1'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.cloud:spring-cloud-starter-contract-stub-runner:4.1.0'
testImplementation 'org.mockito:mockito-core:5.8.0'
testImplementation 'org.testcontainers:testcontainers:1.19.3'
testImplementation 'org.testcontainers:junit-jupiter:1.16.3'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'

2. 修复测试类的JUnit版本冲突

你当前混合使用了JUnit 4的@RunWith、@ClassRule和JUnit 5的注解,需要统一为JUnit 5的写法:

import org.apache.activemq.junit.EmbeddedActiveMQBroker;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class JmsMessageListeningAndSendingTest extends IntegrationTestBase {
    // 替换JUnit 4的@ClassRule为JUnit 5的@RegisterExtension
    @RegisterExtension
    public static final EmbeddedActiveMQBroker embeddedBroker = new EmbeddedActiveMQBroker();

    @Autowired
    private JmsMessageSender jmsMessageSender;

    @MockBean
    private JmsMessageListener jmsMessageListener;

    @Test
    void testSendAndReceiveWithProperty() throws InterruptedException {
        // 测试逻辑见下文示例
    }
}

3. 修正配置文件前缀

你的application.yml中缺少spring.前缀,导致ActiveMQ配置无法生效:

spring:
  activemq:
    broker-url: tcp://localhost:61616
    close-timeout: 15
    packages:
      trusted: com.broker.activemq.entities,java.lang
    password: admin
    user: admin
    in-memory: true
    pool:
      enabled: false

消息收发与属性处理示例

消息发送者(带属性设置)

import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.Session;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;

@Component
public class JmsMessageSender {

    private final JmsTemplate jmsTemplate;

    public JmsMessageSender(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendMessageWithProperty(String destination, String content, String propKey, String propValue) {
        jmsTemplate.send(destination, session -> {
            Message message = session.createTextMessage(content);
            message.setStringProperty(propKey, propValue);
            return message;
        });
    }
}

消息监听器(提取属性)

import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.TextMessage;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class JmsMessageListener {

    @JmsListener(destination = "test-queue")
    public void handleMessage(Message message) throws JMSException {
        if (message instanceof TextMessage textMessage) {
            String content = textMessage.getText();
            String customProp = message.getStringProperty("custom-tag");
            
            // 业务处理逻辑
            System.out.println("收到消息内容:" + content);
            System.out.println("自定义属性值:" + customProp);
        }
    }
}

测试方法示例

@Test
void testSendAndReceiveWithProperty() throws InterruptedException {
    String destination = "test-queue";
    String content = "测试消息内容";
    String propKey = "custom-tag";
    String propValue = "activemq-test";

    // 发送带属性的消息
    jmsMessageSender.sendMessageWithProperty(destination, content, propKey, propValue);

    // 等待消息被处理(根据实际情况调整等待时长)
    Thread.sleep(1000);

    // 用Mockito验证监听器是否收到消息(可选)
    // verify(jmsMessageListener).handleMessage(any(Message.class));
}

内容的提问来源于stack exchange,提问作者user23114985

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:07:16