Java Maven:一个JVM中的不同库版本
我有一个项目,它的依赖关系树很大,也就是说,它包含了来自多个团队的模块 现在有一些常用的依赖项,这些依赖项在多个模块中很常见 一个简化的例子可以是:Java Maven:一个JVM中的不同库版本,java,maven,Java,Maven,我有一个项目,它的依赖关系树很大,也就是说,它包含了来自多个团队的模块 现在有一些常用的依赖项,这些依赖项在多个模块中很常见 一个简化的例子可以是: TopModule.jar ChildModule.jar CommonModule-v1.jar CommonModule-v2.jar 当我构建我的项目时,我指定了最新版本的通用依赖项,但是很难要求其他团队也这样做 因此,TopModule通常使用CommonModule的不同版本(上例中的v1和v2)构建 我的问题是: 如果
TopModule.jar
ChildModule.jar
CommonModule-v1.jar
CommonModule-v2.jar
当我构建我的项目时,我指定了最新版本的通用依赖项,但是很难要求其他团队也这样做
因此,TopModule通常使用CommonModule的不同版本(上例中的v1和v2)构建
我的问题是:
如果最终的jar文件同时包含CommonModule-v1.jar和CommonModule-v2.jar,它将如何影响运行时
运行时是否会在需要v1的地方错误地加载v2版本,反之亦然?如果pom.xml只是已打包模块的聚合器,则这一点适用。如果情况并非如此,并且您的项目实际上将所有这些模块编译并打包为子模块,那么maven将选择一个。如果它自己编译每个项目,那么它将使用该依赖项进行打包。但是,如果它们最终都在同一个类加载器中,那么它将无法正常工作 在运行时,它可能会导致错误,比如
找不到方法
等等。您的字节码类已编译并与正确的依赖项链接,但由于类装入器找到了两个候选类,因此它只在运行时装入一个
您可以做的是设置一个定义
的父pom,然后要求所有团队将其用作父pom,不要声明
,而是从父pom.xml继承它
参考资料这取决于模块在maven中的命名方式。通常,maven尝试解决冲突的lib,并将最高版本放入树中。但是,如果这些库在artifactId方面是不同的工件,那么maven将看不到它们来自同一品种,因此无法解决歧义 通常通过公共parent.pom解决此问题,在该文件中定义整个项目中常用库的版本。如果您无法控制其他项目(不是构建的一部分,只是依赖项),那么您可能很幸运最终的项目运行良好。如果库在较新版本中破坏了兼容性,您将无法使用它
那么,您的最终项目是否包含库的两个版本,您检查了吗?依赖关系树可能会显示两个版本,但如果maven只使用层次结构中依赖关系的最新版本,那么maven最终只会使用每个工件的一个版本——它不会做任何奇特的类装入器隔离技巧。您可以看到它将与
mvn依赖项:resolve
一起使用哪个版本
如果需要在依赖项中使用特定版本,可以使用。它将执行重命名技巧,以便依赖项获得它们自己的库版本。Classloader将加载出现在类路径上的第一个JAR。更详细地说,它将搜索类路径上的第一个类,因此在每种情况下,所有这些搜索都将分为
CommonModule-v2.jar
。所以答案是肯定的-如果v1出现在类路径的前面,它可能会错误地加载v2版本。要在全局范围内解决此问题,请使用此选项
此规则要求依赖项版本号聚合。如果
项目有两个依赖项,A和B,它们都依赖于同一个项目
工件C,如果A依赖于不同的
C的版本然后B依赖C的版本
org.apache.maven.plugins
maven enforcer插件
1.3.1
执行
执行
在这之后,所有团队都使用一致版本的依赖项一起工作。在@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>
子模块组
儿童模块化激活
1
CommonModuleGroupId
公共模块化激活
您应该将其放在TopModule pom.xml中。您所说的“最终jar文件同时包含
CommonModule-v1.jar
和CommonModule-v2.jar
”是什么意思?你通常不会把罐子装在其他罐子里。你的问题对于Java应用程序的普遍部署方式没有多大意义。(其中包含类路径中某个位置的所有可传递依赖项的平面列表。)Maven将使用最新版本,您可以尝试dependency:analyze duplicate。@millimoose,欢迎使用maven@user2250246我很了解Maven,你所描述的并不是Maven的工作方式。对于一个mvn包
,它只会对给定模块的类文件进行JAR处理,在编译之后它不会处理依赖项。如果您正在进行WAR,那么它会将依赖项放入WEB-INF/lib/
,但在这种情况下,它会选择其中一个版本,而不是两个版本。(除非不同的版本有不同的groupId
+artifactId
,这并不是Maven能够自动处理的东西。)那么,与其说你很油嘴滑舌,不如说你描述了实际发生的事情;dr:Maven默认情况下不会将jar
s放入其他jar
s中。如果你有,发布相关的配置。Maven将在一个构建中发现两个JAR版本时自动只选择一个版本<代码>是决定哪个版本的方法。他说,将模块打包在一起。这些模块可能已经打包。但这只是一个猜测。
<dependency>
<groupId>ChildModuleGroupid</groupId>
<artifactId>ChildModuleArtifactid</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>CommonModuleGroupId</groupId>
<artifactId>CommonModuleArtifactId</artifactId>
</exclusion>
</exclusions>
</dependency>