一, 前言
jar 包冲突分多种, 简单理解来说, 就是同 package 且同名的类在多个 jar 包内出现, 如果两个 jar 包在同一个 classloader 下, 那么最终的结果是, 只会加载其中的一个.
有时, 这个错误一般在运行时出现, 报的错可能是, 找不到某方法, 或者呢, 更隐蔽的, 不会报错, 但是逻辑不对.
针对运行中的应用, 可以考虑使用阿里出品的 arthas 来处理.
我今天呢, 只是简单的找不到方法的情况, 所以不需要用到那个. 我这里的场景是, 在学习 rocketMq 的过程中, 其依赖的 jar 包如下:
- <dependency>
- <groupId>org.apache.rocketmq</groupId>
- <artifactId>rocketmq-client</artifactId>
- <version>4.3.0</version>
- </dependency>
该 jar 包间接依赖如下:
上图是截的 idea 插件, maven helper. 但是一开始并没想起来去看这里.
为什么会冲突呢, 因为我把测试类写在了一个使用了 netty 5 版本的工程里.(为了偷懒..)
二, 解决冲突的方式一
我这里报错如下:
- Exception in thread "main" java.lang.NoSuchMethodError: io.netty.Bootstrap.Bootstrap.channel(Ljava/lang/Class;)Lio/netty/Bootstrap/AbstractBootstrap;
- at org.apache.rocketmq.remoting.netty.NettyRemotingClient.start(NettyRemotingClient.java:165)
- at org.apache.rocketmq.client.impl.MQClientAPIImpl.start(MQClientAPIImpl.java:225)
- at org.apache.rocketmq.client.impl.factory.MQClientInstance.start(MQClientInstance.java:234)
- at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.start(DefaultMQProducerImpl.java:171)
- at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.start(DefaultMQProducerImpl.java:144)
- at org.apache.rocketmq.client.producer.DefaultMQProducer.start(DefaultMQProducer.java:172)
- at rocketmq.TestRocketMq$SyncProducer.main(TestRocketMq.java:21)
上面意思就是, io/netty/Bootstrap/AbstractBootstrap 不存在 channel(Ljava/lang/Class;) 这个方法.
我在 ide 里, 打开了 netty 5 jar 包里的这个类, 确实没找到这个方法, 估计就是这个原因了.
怎么验证程序加载了这个类呢? 直接在启动参数里, 加入 -verbose:class , 然后重新启动, 过程中会打印出加载的 class:
上图可以看到, 果然是从 5.0 版本的 netty 里加载的.
三, 解决 jar 包冲突的方式 2
idea 里安装 maven helper 插件, 然后选择 pom, 下图即可看出冲突的 jar 包:
但是, 说实话, 这个一般事先并不会去看, 很有可能都是事后出问题才去这里看.
四, 总结
今天这个场景很简单, 文章开头那个链接里的案例要复杂一点 (Windows 上可以, Linux 不行). 大家也可以看下.
jar 包为什么冲突? 这里再理解下, 因为在 jvm 里, 一个类是唯一的, 说明类加载器相同 + 类的全路径名相同.
如果同一个类加载器下出现了两个全路径相同的类, 自然就冲突了.
来源: https://www.cnblogs.com/grey-wolf/p/11403444.html