前言
当我们使用 Maven 来构建我们的程序时,我们可以用几句配置来代替大量的 Jar 包,同时因为这种配置在我们交流代码时可以不用自己引入 Jar 包(避免了版本不一致而出错),只要更新 Maven,它就会在后台帮我们解决这一切。但是在我们享受这种方便的同时,我们也在为这种方便付出代价。通常都是版本不一致出现的依赖冲突。
依赖冲突-例
1 | <dependency> |
其依赖树如下:
我们可以清楚地看到 hibernate-core 所依赖的 jboss-logging 被省略了 (灰色的那一个依赖),因为 Maven ( 或者说是 Java 的 ClassLoader ) 先加载了 hibernate-validator 所依赖的 jboss-logging,就会忽略其他同名依赖。 一般情况来说, 这是不会出现问题的, 因为在你使用 Maven 时, 你已经不知不觉地通过这种方式多次使你的代码正确执行了, 但是一旦出现了错误, 你多半会被坑的死去活来 ~. ~
比如我举的这个例子, 当你初始化 SessionFactory 时, 你将会见到如下错误提醒:
java.lang.NoSuchMethodError: org.hibernate.internal.CoreMessageLogger.debugf(Ljava/lang/String;II)V
首先检查类或方法是否存在,如果找到类,却没有在该类及其父类中找到该方法,那么百分百就是版本错误。
最终确定是 jboss-logging 版本错误。
冲突解决
- 将重要的依赖放在前面
因为 maven 会优先加载第一个遇到的版本,所以我们只需要将 hibernate-core 移到 hibernate-validator 的前面,这样 Maven 就会加载到 3.3.0 这个版本。
1 | <dependency> |
- 使用 exclusions 标记排除依赖
将干扰的依赖排除后就没有后顾之忧了,如下:
1 | <dependency> |
- 使用 mvn dependency:tree 命令查看依赖树
mvn dependency:tree 选项
verbose 显示全部,不使用此选项则显示部分。当然了,这不是让你一次性显示所有依赖出来,因为太多了,显示出来的话阅读难度指数上升,有兴趣可亲身一试 ~. ~
includes 筛选出想要的的依赖,使用时只显示被加载的 jar 包,如果和 verbose 一起使用则可以查看被忽略的 jar 包,如下
excludes 这个就没什么好说的,includes 相反的作用
mvn dependency:tree -Dverbose -Dincludes=org.jboss.logging:jboss-logging