问题背景
hm-common模块里编写了RabbitMQHelper工具类:
1 | package com.hmall.common.utils; |
hm-common模块里有amqp和rabbit相关依赖但是scope是provided其他继承了
hm-common模块的模块调用RabbitMQHelper工具类来发送消息,报错:1
2Caused by: java.lang.NoClassDefFoundError: org/springframework/amqp/core/Message
Caused by: java.lang.ClassNotFoundException: org.springframework.amqp.core.Message将
RabbitMQHelper工具类做如下改动之后就不报错正常运行了去掉
@Component1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package com.hmall.common.utils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFutureCallback;
import java.util.UUID;
public class RabbitMQHelper {
private final RabbitTemplate rabbitTemplate;
// 防止篇幅太长,方法就简写示意一下了
public void sendMessage(String exchange, String routingKey, Object message) {
rabbitTemplate.convertAndSend(exchange, routingKey, message);
}
public void sendDelayMessage(String exchange, String routingKey, Object message, int delay)
public void sendMsgWithConfirm(String exchange, String routingKey, Object msg, int maxRetries) {
sendMsgWithConfirmInternal(exchange, routingKey, msg, maxRetries, 0);
}
private void sendMsgWithConfirmInternal(String exchange, String routingKey, Object msg, int maxRetries, int currentRetry) {
}在配置类中注册为
Bean1
2
3
4
public RabbitMQHelper rabbitMQHelper(RabbitTemplate rabbitTemplate) {
return new RabbitMQHelper(rabbitTemplate);
}
解读
@Component被标注了
@Component的类,Spring 在启动时就会扫描并创建 Bean,并且,Spring 会加载类及其构造器、字段类型。而RabbitMQHelper构造器有RabbitTemplate参数,而RabbitTemplate依赖org.springframework.amqp.core.Message等类。common模块里spring-rabbit依赖的 scope 被标记为provided,编译可以用,但运行时 JVM 找不到Message类。所以启动时报
NoClassDefFoundError。
@Bean:- 使用配置类注册 Bean 时,Spring 延迟创建 Bean,直到调用方法时才真正需要
RabbitTemplate。这时才会用到spring-rabbit依赖。而调用方法的模块是有spring-rabbit依赖的
- 使用配置类注册 Bean 时,Spring 延迟创建 Bean,直到调用方法时才真正需要
| 方式 | 特点 | 风险 |
|---|---|---|
@Component + @RequiredArgsConstructor |
Spring 扫描组件,自动注入 | 扫描时必须能加载类依赖,否则 NoClassDefFoundError |
配置类 @Bean 方法 |
手动创建 Bean,延迟注入 | 扫描时不解析类依赖,风险低 |
provided: (相关详解:Maven 核心知识体系)
- 作用域:编译(有) + 运行(无) + 打包(无)
⚠️ 如果 common 模块不直接依赖 AMQP,只在别的模块使用 RabbitMQHelper,那用provided + 配置类注册是最好的方式。