java / maven如何在运行时解决依赖项冲突

时间:2017-06-18 07:44:03

标签: java maven

抱歉我的新手问题。

据说我有一个包A,它在其maven文件中声明B,C作为其依赖项。 B,C使用两个不同版本的log4j进行日志记录。我有几个问题:

  1. 如果我使用maven,并将B,C声明为A的依赖项。当maven从mavencentral repo中拉出B,C的神器(.jar)。 B,C jar文件包含log4j类文件或只包含自己编译的文件(B,C拥有源,而不是依赖)。
  2. 如果我理解正确,当构建发生时,最后,构建中只会有一个log4j类文件(即使B,C使用不同版本的log4j)。在这里选择要构建哪个版本的log4j?这是否意味着我还需要将log4j声明为A依赖(在A的maven构建文件中) - 并且该版本将被选择为要构建的版本。
  3. B,C可能使用完全不同的log4j版本。 API可能完全不同。它应该在运行时引起问题?但实际上,这是非常罕见的?为什么这样?
  4. 感谢。

4 个答案:

答案 0 :(得分:3)

  1. jar文件通常不包含其依赖项。有一种方法可以做到这个叫做胖罐子。 What is a fat JAR?但我们假设您正在使用常规jar依赖项。 jar只会在自己的pom.xml中声明它们的依赖项。因此,对于您的示例,B和C将仅包含自己编译的源代码。

  2. 这实际上取决于您如何打包文件。通常,如果您只生成一个简单的jar,它将不包含依赖项,并且运行器负责提供正确的依赖项。例如,在发生战争的情况下,maven会抛出所有依赖关系。前面提到的另一种方法是胖罐。一种更常见的方法是压缩所有依赖项并单独提供它们。

  3. 我不知道为什么你之前没有遇到过冲突,我有很多其他的库,我不记得log4j的情况。作为库维护者,处理这类冲突的一种方法是,当您进行非向后兼容的更改时,更改包名称,这样用户可以在类路径中安全地拥有多个版本(无论如何都应该避免)。

  4. Maven有办法避免这种冲突,它会优先考虑最接近的定义依赖版本。例如,如果您在A中声明了版本a,在B中声明了版本b,那么有效版本将是A.

    此外,还有一些其他机制,如依赖关系管理。你可以在这里查看:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

    这个主题非常严重,可能会导致很多难以发现的生产错误。希望这会有所帮助...

答案 1 :(得分:1)

  1. 他们应该只包含自己的类。不是它们的依赖类。您可以打开jar文件并自己查看。 Jar文件只是zip文件。
  2. Maven将通过选择最接近依赖关系树根的版本来解决冲突。如果两个版本在依赖关系树中处于相同深度,则拾取第一个版本(IIRC)。如果A本身依赖于log4j,或者您希望在运行时使用特定版本,则应将log4j指定为A的直接依赖项,并使用所需的版本。或者至少在构建的dependencyManagement部分中指定它。
  3. 因为像Log4J这样流行的库努力拥有一个非常稳定的API,因此不会破坏针对旧版本库编译的代码。

答案 2 :(得分:0)

  1. 人工制品通常不包含其依赖关系(但是有包装选项可以)。
  2. Maven将只使用一些规则确定一个版本(我不记得详细)。如果由于某种原因必须覆盖它,可以将依赖关系管理部分放入POM。
  3. 是的,这可能会导致问题。只有在更改公共API时要小心,才能避免使用它们。

答案 3 :(得分:0)

  1. 如果将log4j指定为B和C的依赖项,并且您不使用创建uber-jars / fat-jar的特殊插件,则B和C都不会包含log4j类文件。

    < / LI>
  2. 具有相同坐标的一个依赖项(groupId,artifactId)。正如这里已经提到的那样,版本通常是通过root的最短路径选择的。因此,如果您想使用特定的log4j版本,您只需在pom中指定它。

  3. 如果以标准方式使用log4j,即只指定配置文件,则两个版本(log4j和log4j2)通常可以共存,因为它们使用不同的包和不同的配置文件。只需检查log4j的迁移站点:Migration from log4j to log4j2