maven范围编译和提供JAR打包的区别

问题描述 投票:0回答:7

当工件构建为 JAR 时,maven 范围

compile
provided
之间有什么区别?如果是 WAR,我会理解 - 该工件将包含或不包含在 WEB-INF/lib 中。但对于 JAR 来说这并不重要——不包含依赖项。当它们的作用域为
compile
provided
时,它们必须位于类路径上。我知道
provided
依赖关系不可传递 - 但这只是一个区别吗?

maven jar
7个回答
356
投票

编译意味着您需要JAR来编译和运行应用程序。对于Web应用程序,例如,JAR放置在WEB-INF/lib目录中。

提供意味着您需要 JAR 来编译,但在运行时环境已经提供了 JAR,因此您不需要将其与应用程序一起打包。 对于 Web 应用程序,这意味着 JAR 文件 不会放入WEB-INF/lib目录下。

对于 Web 应用程序,如果应用程序服务器已经提供了 JAR(或其功能),则使用“provided”,否则使用“compile”。

这是参考。


348
投票

来自 Maven 文档

  • 编译

    这是默认范围,如果未指定则使用。编译 依赖项在项目的所有类路径中都可用。 此外,这些依赖项会传播到依赖项目。

  • 提供

    这很像编译,但表明您期望 JDK 或 容器在运行时提供依赖关系。例如,当 为 Java 企业版构建 Web 应用程序,您将 将 Servlet API 和相关 Java EE API 的依赖关系设置为 提供范围是因为 Web 容器提供了这些类。这 范围仅在编译和测试类路径上可用,并且是 不具有传递性。

回顾:

  • 依赖关系不具有传递性(正如您提到的)
  • provided 作用域仅在编译和测试类路径上可用,而编译作用域在所有类路径中可用。
  • 提供的依赖没有打包

30
投票

如果您计划生成一个包含其所有依赖项的 JAR 文件(典型的 xxxx-all.jar),那么提供的范围很重要,因为此范围内的类不会打包在生成的 JAR 中。

请参阅 maven-assemble-plugin 了解更多信息


14
投票
  • 编译

使可用到类路径中,如果是普通jar,则不要将此依赖项添加到最终jar中;但是如果最终的jar是单个jar(例如可执行jar),则将此jar添加到jar中

  • 提供

依赖将在运行时环境中可用,因此无论如何都不要添加此依赖;即使不在单个 jar 中(即可执行 jar 等)


4
投票

对于 jar 文件,如果在 maven-jar-plugin 配置中将 addClassPath 设置为 true,则差异在于 jar 中包含的 MANIFEST.MF 文件中列出的类路径。 “编译”依赖项将出现在清单中,“提供”依赖项则不会。

我最讨厌的事情之一是这两个词应该具有相同的时态。要么编译提供,要么编译提供。


1
投票

如果 jar 文件类似于可执行的 spring boot jar 文件,那么所有依赖项的范围必须是

compile
以包含所有 jar 文件。

但是如果 jar 文件在其他包或应用程序中使用,则不需要在 jar 文件中包含所有依赖项,因为这些包或应用程序本身可以提供其他依赖项。


0
投票

如果 JAR A 在编译时具有依赖项 B,则 B 将是 A 的传递依赖项。这意味着:

  • 您将能够在依赖于 A 的 jar X 中使用 B(但如果 B 按提供的方式定义则不能)。但是,如果您在 X 代码中显式使用 B,那么良好的实践要求您在 X 中包含 B,即使您不需要(或者因此建议 mvn dependency:analyze)。
  • 如果包含 A,则 B 将隐式包含在战争或耳朵中(但如果 B 被定义为所提供的,则不会)。因此,如果您按提供的方式定义 B,则可以编译它,但如果容器不提供 B,则会出现运行时类未找到错误。
  • B 将包含在 uber-jars 中,如此处其他答案所述(但如果提供了 B,则不会)。
© www.soinside.com 2019 - 2024. All rights reserved.