【问题标题】:What scope can be used to make a dependency non-transitive by default?默认情况下,可以使用什么范围使依赖项不可传递?
【发布时间】:2018-08-29 15:32:18
【问题描述】:

如果我希望项目 A 编译并测试以运行,但是当我将其作为依赖项放入项目 B 时,项目 A 的依赖项不应该可用于项目 B

例如:

  1. org.example.foo作为依赖项添加到项目A(不是B

  2. 添加项目A作为项目B中的依赖项

  3. 在项目B的类中添加此语句:import org.example.foo.*

  4. 你应该在这一行得到一个编译错误:import org.example.foo.*

【问题讨论】:

  • 我不确定,但我觉得经典的Java类路径机制是有限的,所以你的要求不能轻易实现。您可能需要使用 Java 9 中提供的模块路径机制来执行此操作。例如,您可以使用关键字 requires A 在模块 B 中声明 A 的模块依赖关系。
  • @MincongHuang:有趣,我可能会更多地探索拼图项目。如果运气不好,我想知道切换到 gradle 是否会打开更多的大门?
  • 嗨,你能更清楚为什么@khmarbaise 的回答对你不起作用吗?
  • @sujit:我不想明确定义任何exclusions,因为我希望默认排除所有内容
  • 我认为接受的答案是不正确的

标签: java maven gradle maven-2 maven-3


【解决方案1】:

您可以通过以下排除来排除特定的传递依赖项:

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>  <!-- declare the exclusion here -->
          <groupId>sample.ProjectB</groupId>
          <artifactId>Project-B</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>
</project>

或者您可以像这样排除所有传递依赖项(需要Maven 3.2.1+):

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>*</groupId>
          <artifactId>*</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>
</project>

除此之外,如果您可能需要更改项目 A 以使用不同的依赖项等,我真的会考虑您的项目结构。

【讨论】:

  • 我需要将它从正在交付的项目中排除,所以在这种情况下项目A 以便项目B 默认无法访问项目A 的依赖项,无需添加exclusions 在项目中 B
  • 如果是这样,您必须更改您的项目 A 并删除那些听起来仅在特殊情况下使用的依赖项...您能否详细说明我们正在谈论的依赖项类型?
  • 因此,当项目 B 添加项目 A 作为依赖项时,它不应该指定任何排除项。它应该只是获得import sample.projectA.* 类。如果项目A 使用StringUtils - 它不应该假设项目B 也需要StringUtils。项目B 只想要A 提供的任何项目作为StringUtils 的包装,并且不想详细排除如何到达那里。
【解决方案2】:

您应该使用&lt;scope&gt;provided&lt;/scope&gt; 指定项目“A”中的依赖项。这样,各个依赖项将用于编译和测试,但不会在项目“B”中传递。

在这里您可以找到 maven 依赖项的不同作用域:https://maven.apache.org/pom.html#Dependencies

【讨论】:

  • "provided - 这很像 compile,但表示您希望 JDK 或容器在运行时提供它":那么什么会为 A 提供 foo 包?好的,它不会是传递依赖,因此它解决了操作的问题,但在我看来它会产生另一个问题。
  • A 会有一个 rutime 问题,它不会运行良好,因为 foo 不会被打包。
  • @ToYonos:你能详细解释一下吗?
  • 此处示例:maven.apache.org/guides/introduction/… 在为 Java 企业版构建 Web 应用程序时,您可以将 Servlet API 和相关 Java EE API 的依赖设置为范围 provided,因为 Web容器提供这些类。此范围仅在编译和测试类路径上可用,并且不可传递。 基本上,在您的 ide 中开发和测试期间,没有问题,但是当您的应用程序在生产中运行时,A 将期望 foo由另一个模块/容器/任何东西提供
  • 很遗憾,对 OP 的其他可能正确的答案丢失了。
【解决方案3】:

对于 Gradle,你可以使用 gradle-dependency-analyze 插件,它会添加 analyzeClassesDependencies 任务:

此任务依赖classes任务并分析依赖关系 主源集的输出目录。这确保了所有 类的依赖关系在compile 中声明, compileOnlyprovided 配置。它还确保了 相反,使用这些配置的所有依赖项 按类别

所以它不会触发编译问题,但如果B 尝试导入org.example.foo.*,在B 的构建期间,您将收到此消息:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':B:analyzeClassesDependencies'.
> Dependency analysis found issues: usedUndeclaredArtifacts: 
   - org.example.foo:foo-core:1.0.0

B 需要它自己的 foo-coredependency(它不能使用 A 的)或者它是不允许的并且A 的依赖仍然不可用(无法构建)

【讨论】:

    【解决方案4】:

    answer 中提到的gradle-dependency-analyze 插件的自述文件在这里提到:

    这个插件试图复制 maven 的功能 依赖插件的分析目标,如果依赖项会导致构建失败 已声明但未使用或已使用但未声明。

    带头,当我检查 maven 依赖插件的dependency:analyze 目标时,我找到了failOnWarning 选项,这可能就是你想要的。

    因此,您可以将其插入到您的项目B 的 maven 调用中,如下所示:

    mvn -DfailOnWarning=true 依赖:分析

    并且,如果有任何 Used undeclared dependenciesUnused declared dependencies 的实例,前者是您的用例,构建将失败。

    唯一的缺点是,我没有找到任何命令行方式要求插件忽略Unused declared dependencies

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-21
      • 1970-01-01
      • 2014-07-14
      • 1970-01-01
      • 2015-06-08
      • 2017-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多