我有一个项目,其依赖树很大,即它包含来自几个团队的模块。
现在有一些常用的依赖项在几个模块中很常见。
简化示例可以是:
TopModule.jar
ChildModule.jar
CommonModule-v1.jar
CommonModule-v2.jar
当我构建我的项目时,我指定了最新版本的公共依赖项,但很难向其他团队提出相同的问题。
因此,经常使用不同版本的CommonModule(上例中的v1和v2)构建TopModule。
我的问题是:
如果最终的jar文件包含CommonModule-v1.jar和CommonModule-v2.jar,它如何影响运行时?
运行时是否会错误地加载需要v1的版本v2,反之亦然?
答案 0 :(得分:4)
Maven最终只会使用每个工件的一个版本 - 它不会做任何花哨的类加载器隔离技巧。您可以查看它将与mvn dependency:resolve
一起使用的版本。
如果您需要在依赖项中使用特定版本,则可以使用shade plugin。它会重命名技巧,以便依赖项获得自己的库版本。
答案 1 :(得分:1)
要解决此问题,请使用此DependencyConvergence Rule
此规则要求依赖关系版本号收敛。如果一个 project有两个依赖项,A和B,两者都依赖于它们 artifact,C,如果A依赖于另一个,则此规则将失败 C的版本然后B的版本取决于B.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
<DependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>
在此之后,所有团队都会使用一致版本的依赖项。
答案 2 :(得分:0)
如果您的pom.xml只是已打包模块的聚合器,那么这适用。如果不是这样,并且您的项目实际编译并将所有这些模块打包为子模块,那么maven将选择一个。如果它自己编译每个项目,那么它将使用该依赖项进行打包。但如果所有这些都在同一个类加载器中结束,那么它将无法正常工作。
在运行时它可能会导致错误,想到method not found
等。您的字节代码类已经编译并与正确的依赖项链接,但由于类加载器找到两个候选项,它只是在运行时加载一个。
您可以做的是设置定义<dependencyManagement>
的父pom,然后要求所有团队将其用作父项,并且不要声明<version>
,而是从父pom.xml继承它。
答案 3 :(得分:0)
这取决于模块在maven中的命名方式。通常,maven尝试解析冲突的lib并将最高版本带入树中。但是如果库在artifactId方面是不同的工件,那么maven将不会看到它们来自同一品种,因此不会解决模糊性。
通常您可以通过公共parent.pom解决此问题,您可以在整个项目中定义常用库的版本。如果你无法控制其他项目(不是你的构建的一部分,只是依赖项),你可能很幸运,你的最终项目工作正常。如果库在新版本中破坏了兼容性,您将无法使用它。
那么,你的最终项目是否包含两个版本的库,你检查过吗?依赖关系树可以显示两个版本,但是如果maven将仅使用层次结构中的最新版本的依赖关系。
答案 4 :(得分:0)
Classloader将加载出现在类路径中的第一个JAR。更详细的说明 - 它将在您的课程路径中搜索第一堂课,因此在每种情况下,所有这些搜索都属于CommonModule-v2.jar
。所以答案是肯定的 - 它可能会错误地加载版本v2,如果它出现在类路径的前面,则会加载v1。
答案 5 :(得分:0)
除了@yshavit所说的,理想情况下你会排除早期版本的CommonModule
,以便只有v2在类路径中。仅当CommonModule
v2 api向后兼容CommonModule
v1时,才可以执行此操作。
以下是您如何排除的示例:
<dependency>
<groupId>ChildModuleGroupid</groupId>
<artifactId>ChildModuleArtifactid</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>CommonModuleGroupId</groupId>
<artifactId>CommonModuleArtifactId</artifactId>
</exclusion>
</exclusions>
</dependency>
你将它放在TopModule pom.xml中。