当前位置: 首页 > 知识库问答 >
问题:

系统的方法与Maven处理依赖地狱

南宫阳焱
2023-03-14

我一直在挣扎如何接近地狱。我有一个Maven IntelliJ Scala项目,它使用了一些aws sdk。最近添加了kinesis sdk,引入了不兼容的Jackson版本。

我的问题是:我如何系统地处理Jar地狱的问题?

我了解类加载器以及maven如何在重复的JAR之间进行选择,但我仍然不知道解决这个问题的实际步骤。

我目前的尝试是基于尝试和错误,我在这里用杰克逊的例子来概述:

  • 首先,我看到了Jackson data bindings ObjectMapper类的实际异常是什么,在本例中是NoSuchMethodError。然后我查看Jackson文档,查看该方法是何时添加或删除的。这通常非常乏味,因为我手动检查每个版本的api文档(问题1:有更好的方法吗?)

最后,在比较了树输出之后,我尝试在POM中显式添加Jackson的最新工作版本,以触发maven依赖解析链中的优先级。如果最新版本不起作用,我将添加下一个最新版本,以此类推。

整个过程极其乏味。除了我问的具体问题,我还对其他人对这个问题的系统性方法感到好奇。有人有他们使用的资源吗?

共有3个答案

麻宾白
2023-03-14

根据我的经验,我没有发现任何完全自动化的方法,但我发现以下方法非常系统化,对我自己很有用:

首先,我试图有一个清晰的项目结构图,项目之间的关系,我通常使用Eclipse图形依赖视图,它告诉我,例如,如果一个依赖项与另一个冲突而被省略。此外,它告诉你项目已解决的依赖项。我真诚地不使用IntelliJ IDEA,但我相信它有类似的功能

通常我会尝试将非常常见的依赖关系放在结构中更高的位置,并利用

在这篇Maven-Manage Dependencies博客文章中,你可以找到一个关于依赖关系管理的好教程。

当向我的项目中添加新的依赖项时,就像您的情况一样,我会注意它在我的项目结构中添加的位置,并做出相应的更改,但在大多数情况下,依赖项管理机制能够处理这个问题。

在这篇Maven Best Practices博客文章中,你可以找到:

Maven的dependencyManagement部分允许使用父pom。xml来定义可能在子项目中重用的依赖项。这避免了重复;如果没有dependencyManagement部分,每个子项目都必须定义自己的依赖项,并复制依赖项的版本、范围和类型。

显然,如果您需要项目依赖项的特定版本,您总是可以在层次结构的深层本地指定所需的版本。

我同意你的观点,这可能会很乏味,但依赖关系管理可以给你一个很好的帮助。

邢和光
2023-03-14

使用Maven助手插件通过排除旧版本的依赖项轻松解决所有冲突。

郏实
2023-03-14

然后我查看Jackson文档,查看该方法是何时添加或删除的。这通常非常乏味,因为我手动检查每个版本的api文档(问题1:有更好的方法吗?)

为了检查API(中断)兼容性,有几个工具可以自动分析jars并为您提供正确的信息。从这篇Stack Overflow帖子中,有一些很好的提示,可以找到一些方便的工具。
JAPICC看起来相当不错。

然后,我使用mvn dependency:tree来确定我实际使用的是哪个版本的Jackson(问题2:有没有一种自动的方法来询问maven使用的是哪个版本的jar,而不是梳理树输出?)

maven依赖关系树无疑是一条可行之路,但您可以从一开始就筛选出范围,并使用其includes选项,仅获取您真正想要的内容,如下所示:

mvn dependency:tree -Dincludes=<groupId>

注意:您还可以以group Id: artifactId: type: version的形式向包括选项提供更多信息,或者使用通配符,如*: artifactId

这似乎是一个小提示,但是在有许多依赖项的大型项目中,缩小其输出是非常有帮助的。通常,只要group Id就足以作为过滤器,但是如果您正在寻找特定的依赖项,*: artifactId可能是最快的。

如果您对按字母顺序排列的依赖项列表(而不是树)感兴趣(在许多情况下非常方便),那么以下内容也可能会有所帮助:

mvn dependency:list -Dsort=true -DincludeGroupIds=groupId

问题3:当依赖解析发生时,maven如何使用阴影罐中的库?和其他任何一样?

阴影罐子的意思可能是:

  • 胖罐子,这也会将其他罐子带入类路径。在本例中,它们被视为一个依赖项,Maven依赖项中介的一个单元,其内容将成为项目类路径的一部分。一般来说,您不应该将胖罐子作为依赖项的一部分,因为您无法控制它带来的打包库
  • 带有阴影(重命名)包的罐子。在这种情况下——同样——就Maven依赖中介而言,没有控制:它是一个单元,一个jar,基于GAVC(GroupId、ArtifactId、Version、Classifier),这使得它是唯一的。然后将其内容添加到项目类路径(根据依赖范围,但由于其包已重命名,您可能会遇到难以处理的冲突。同样,您不应该将包重命名为项目依赖项的一部分(但通常您不知道这一点)

有人有他们使用的资源吗?

总的来说,你应该很好地理解Maven如何处理依赖关系和使用它提供的资源(它的工具和机制)。下面是一些要点:

  • dependencyManagement无疑是本主题的切入点:在这里,您可以处理Maven依赖项中介,影响其对可传递依赖项、其版本和范围的决策。重要的一点是:添加到依赖项管理中的内容不会自动添加为依赖项dependencyManagement只在项目的某个依赖项(如pom.xml文件或通过可传递依赖项声明的)与其中一个条目匹配时才被考虑,否则它将被忽略。它是pom的重要组成部分。xml因为它有助于管理依赖项及其可传递图,这就是为什么在父POM中经常使用xml的原因:您只想以集中的方式处理一个版本,例如,log4j您想在所有Maven项目中使用哪个版本,您可以在公共/共享父pom及其依赖项管理中声明它,并确保它将被如此使用。集中化意味着更好的治理和更好的维护

下面的示例将确保没有人(你、你的团队成员、你未来的自己)能够在编译范围内添加一个众所周知的测试库:构建将失败。它确保jUnit永远不会到达PROD(与你的war打包,例如)

<plugin>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.4.1<.version>
    <executions>
        <execution>
            <id>enforce-test-scope</id>
            <phase>validate</phase>
            <goals>
                <goal>enforce</goal>
            </goals>
            <configuration>
                <rules>
                    <bannedDependencies>
                        <excludes>
                            <exclude>junit:junit:*:*:compile</exclude>
                            <exclude>org.mockito:mockito-*:*:*:compile</exclude>
                            <exclude>org.easymock:easymock*:*:*:compile</exclude>
                            <exclude>org.powermock:powermock-*:*:*:compile</exclude>
                            <exclude>org.seleniumhq.selenium:selenium-*:*:*:compile</exclude>
                            <exclude>org.springframework:spring-test:*:*:compile</exclude>
                            <exclude>org.hamcrest:hamcrest-all:*:*:compile</exclude>
                        </excludes>
                        <message>Test dependencies should be in test scope!</message>
                    </bannedDependencies>
                </rules>
                <fail>true</fail>
            </configuration>
        </execution>
    </executions>
</plugin>

看看这个插件提供的其他标准规则:在错误的情况下,许多规则可能有助于中断构建:

  • 你可以禁止依赖关系(即使是传递性的),在很多情况下非常方便

同样,一个公共的父pom可以包括这些机制中的一个以上(dependencyManagement、enforcer插件、dependency族的属性),并确保遵守某些规则。你可能没有涵盖所有可能的场景,但它肯定会降低你感知和体验地狱的程度。

 类似资料:
  • 使用 我修改了以包含导入语句。因此,maven无法找到我试图使用并将其与项目链接的jar。 我向pom.xml文件添加了一个依赖项,如下所示:

  • 如何将这个插件添加为依赖项和插件?我如何将此用作依赖项? 谢谢

  • 我使用的是与Android Studio捆绑的Gradle构建系统。到目前为止,我能够使用存储在项目结构中的依赖关系构建多项目设置。我现在想使用maven依赖,但没有用。我写了一个非常简单的构建。总是失败的gradle文件: 显示以下消息: 到目前为止,我尝试过的任何产品都会发生这种情况。你知道怎么了吗? 谢谢

  • 问题内容: 我正在运行一个依赖groovy 1.7-beta-1的项目。gmaven插件使用groovy 1.6版作为依赖项。在pom中,我在依赖性管理部分中将grooyv-all版本指定为: 但是,当我在调试模式下运行maven时,我看到groovy 1.6被用于对gmaven插件的依赖。我以为我的依赖项管理部分会重写此设置,因此它们都使用1.7-beta-1,但是由于常规版本不同,我遇到了错误

  • maven允许您在pom文件中定义: (A) - (B) /- 如果我把错误/未知的工件放在A类-maven肯定会失败。 如果我将错误/未知工件放在类别B上-maven只会在它影响类别A时失败(例如,A在上定义dep,B在

  • 问题内容: 我有一个依赖关系如下: 当我部署一切正常时,这将拉下另一个引发ClassDefNotFound的依赖项。 我添加了两个依赖项,如下所示: 并且仍然面临着同样的问题,即:MVN带来下来不 我该如何解决? 编辑: 添加; 问题答案: 您可能有一个传递依赖项,另一个依赖项取决于您不需要的版本。 要获得所有直接和传递依赖关系的概述,请尝试: mvn依赖项:树 如果您发现同一依赖项的不同版本之间