现象
rocketmq-common-4.9.3
版本作为客户端消费数据时,从MessageExt.getMsgId()
获取消息ID时,会存在一个潜在的依赖冲突问题,最终导致方法执行失败,如下图:
从现象来看,Could not initialize class org.apache.rocketmq.common.message.MessageClientIDSetter
表示 MessageClientIDSetter
类为正确被加载,通过搜索类似的资料找到了以下文章:
从51cto的文章来看,基本可以分析出是MessageClientIDSetter
的静态代码块在执行时异常导致类加载器加载类失败。
static {
byte[] ip;
try {
// 执行异常,导致`MessageClientIDSetter`未成功被类加载器加载
ip = UtilAll.getIP();
} catch (Exception e) {
ip = createFakeIP();
}
LEN = ip.length + 2 + 4 + 4 + 2;
ByteBuffer tempBuffer = ByteBuffer.allocate(ip.length + 2 + 4);
tempBuffer.put(ip);
tempBuffer.putShort((short) UtilAll.getPid());
tempBuffer.putInt(MessageClientIDSetter.class.getClassLoader().hashCode());
FIX_STRING = UtilAll.bytes2string(tempBuffer.array()).toCharArray();
setStartTime(System.currentTimeMillis());
COUNTER = new AtomicInteger(0);
}
分析
从上面的博客中已经可以得到结论是依赖冲突造成的,但问题是部分服务会出现,大多数服务不会出现,通过往深层次分析得出结论:
rocketmq-acl
rocketmq-client
均依赖于 commons-validator-1.7
版本,而项目中如果有类似于 aliyun-log-appender
老版本的依赖,会传递依赖于旧版本的 commons-validator
,如下图所示:
Maven在遇到依赖冲突时,首先会采用就近原则,上图中第一个传递依赖有5个层级,而下一个传递依赖只有4个层级,所以就近取到了错误的1.4.0版本。
其它的服务更多是单模块项目,直接依赖于RocketMQ的client代码,而出现问题的服务是一个多模块依赖关系的服务,最终依赖传递了3层,导致依赖链路变长,最终优先依赖了链路更近的由 log-appender
引入进来的 1.4.0
版本。
相关文章: Maven依赖冲突避坑指北