Maven:一个JVM中的不同库版本

时间:2013-11-14 22:43:53

标签: java maven

我有一个项目,其依赖树很大,即它包含来自几个团队的模块。

现在有一些常用的依赖项在几个模块中很常见。

简化示例可以是:

TopModule.jar
  ChildModule.jar
    CommonModule-v1.jar
  CommonModule-v2.jar

当我构建我的项目时,我指定了最新版本的公共依赖项,但很难向其他团队提出相同的问题。

因此,经常使用不同版本的CommonModule(上例中的v1和v2)构建TopModule。

我的问题是:

如果最终的jar文件包含CommonModule-v1.jar和CommonModule-v2.jar,它如何影响运行时?

运行时是否会错误地加载需要v1的版本v2,反之亦然?

6 个答案:

答案 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继承它。

参考http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management

答案 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中。