【问题标题】:Is my project using older versions of dependencies than what I need?我的项目是否使用了比我需要的旧版本的依赖项?
【发布时间】:2014-05-01 17:50:53
【问题描述】:

我工作的地方使用 Maven,我们有很多内部库。我们尝试以向后兼容的方式进行更改,但有时我们的一个库需要另一个库的更新版本。如果最终产品没有引入更新的库版本,这可能会导致问题。

对于每个最终产品,我们都有一个dependencyManagement 部分,用于声明项目应使用哪些版本的传递依赖项。我们这样做而不是让 Maven 找出要使用的版本,因为我们想要控制正在使用的库的版本。

即使我们让 maven 弄清楚应该使用哪个版本的库,也有可能使用的是旧的库,这可能会导致 ClassNotFoundExceptions 等...

当项目的依赖项之一需要较新版本时,是否有 Maven 插件或方法来确定我的项目是否使用旧版本的依赖项?

mvn dependency:tree,但我们有很多个依赖项,我不想手动查看庞大的列表。

谢谢!

编辑

由于我们有很多库,如果最终产品使用库 A、B 和 C,并且 A 和 B 都使用不同版本的 C,则并不总是使用最新版本的 C。来自Introduction to the Dependency Mechanism

依赖中介 - 这决定了依赖的版本 当遇到工件的多个版本时将使用。 目前,Maven 2.0 仅支持使用“最近定义” 这意味着它将使用最接近的依赖版本 你的项目在依赖树中。您始终可以保证 通过在项目的 POM 中明确声明版本。请注意,如果 两个依赖版本在依赖树中的深度相同, 直到 Maven 2.0.8 还没有定义哪一个会赢,但是因为 Maven 2.0.9 重要的是声明中的顺序:第一个 声明获胜

【问题讨论】:

  • 猜我很困惑。你有一个 pom.xml,所以你可以控制你自己的依赖。 Maven 3 有传递依赖,所以如果你使用的东西需要更新的依赖,它会代表你获取它。
  • Maven 3.x 已经发布了很长一段时间(5 年?)...您应该使用它。
  • 是的,我正在使用 Maven 3
  • 你需要定义你的依赖,而不仅仅是你的依赖管理部分。您要采用的方法听起来是错误的,因为如果您定义了一个库 (A) 版本,它会自动暗示许多传递依赖项(例如 Lib B、Lib C)。 Lib B 和 Lib C 使用 Lib D。因此,如果您更改 D,则必须更改 Lib B 和 Lib C 的 pom 文件中的版本,当然还有 Lib A 的 pom 中的版本。此外,如果您有这样的依赖关系,它可能值得考虑多模块构建而不是单个项目。

标签: maven maven-3


【解决方案1】:

由于我们几乎总是以向后兼容的方式进行更改,看起来对我们来说最好的解决方案是确保使用最新版本的依赖项。具有“要求上限依赖”功能的 Maven Enforcer 插件可以完成此操作。

来自http://maven.apache.org/enforcer/enforcer-rules/requireUpperBoundDeps.html

此规则要求每个依赖项的版本都已解析 在构建期间,等于或高于所有传递依赖 声明。在构建期间解决的每个依赖项的版本 通常是 POM 中指定的版本或带有 最小传递步骤(“最近”定义)。更多 有关 Maven 依赖解析的信息,请参阅 Maven 站点。

这是一个具体的例子。这将导致构建失败:

  <dependencies>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>0.9.9</version>
      <!-- Depends on org.slf4j:slf4j-api:1.5.0 -->
    </dependency>
  </dependencies>

因为项目将使用 slf4j-api 运行 logback-classic 0.9.9 1.4.0 和 slf4j-api 1.4.0 可能与 slf4j-api 1.5.0 不向前兼容。

这是日志消息:

Failed while enforcing RequireUpperBoundDeps. The error(s) are [
RequireUpperBoundDeps error for org.slf4j:slf4j-api:1.4.0 paths to dependency are:
+-test:TestParent:1.0-SNAPSHOT
  +-org.slf4j:slf4j-api:1.4.0
and
+-test:TestParent:1.0-SNAPSHOT
  +-ch.qos.logback:logback-classic:0.9.9
    +-org.slf4j:slf4j-api:1.5.0
]

我们可能会在可以打开或关闭的配置文件中设置此插件。

【讨论】:

  • 啊不知道这个规则。很好的发现。
【解决方案2】:

我不确定是否有插件可以按照您的要求进行操作。一般来说,您会选择较新的版本,但这并不总是硬性规定 - 有时您会收到较新的版本,但实际上您需要的是较旧的版本。

根据我的经验,您必须单独处理每个依赖问题。

我们处理此问题的方式是按照您的建议将&lt;dependencyManagement/&gt; 部分与Maven Enforcer 插件与&lt;DependencyConvergence/&gt; 规则结合使用。

The dependencyConvergence rule:

...要求依赖版本号收敛。如果一个项目有 两个依赖项 A 和 B,都依赖于同一个工件 C, 如果 A 依赖于不同版本的 C,则此规则将导致构建失败 那么C的版本依赖于B。

基本上,如果您的 dependency tree 中有同一个库的 2 个不同版本,那么 validate phase 会失败。

所以:

我这样做的方式是 - 我们通常有多个模块 Maven 项目,我尝试在父级别的 &lt;dependencyManagement/&gt; 部分中定义常见的依赖版本 - 例如 SpringJersey 等。然后在子模块级别,根据需要定义专家&lt;dependencyManagement/&gt; 部分。

在我们所有的 pom 中,我们定义了配置有 &lt;dependencyConvergence/&gt; 规则的 Maven Enforcer 插件,如下所示:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.3.1</version>
    <executions>
    <execution>
        <id>enforce-versions</id>
        <goals>
        <goal>enforce</goal>
        </goals>
    </execution>
    </executions>
    <configuration>
    <rules>
        <DependencyConvergence/>
    </rules>
    <fail>true</fail>
    </configuration>
</plugin>

然后在每个Maven 构建中,如果有人添加了一个与另一个冲突的新依赖项(或有一个新的传递依赖项),您的构建将失败,并且您将获得一个(稍微重复的)依赖问题日志交给你处理。

作为一个终点,我没有看到 Maven Enforcer 插件被大量使用,但它有 really useful rules 的负载以及生成 custom rules 的能力。

如果它真的是你一直想要的dependency 中的newest version,我相信你可以编写一个简单的规则来做到这一点。

希望对你有帮助,

【讨论】:

    猜你喜欢
    • 2020-02-12
    • 2014-07-07
    • 2018-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 2021-12-30
    相关资源
    最近更新 更多