在Maven中将可传递依赖项限制在运行时范围内

wqlqzqxt  于 2022-11-02  发布在  Maven
关注(0)|答案(8)|浏览(161)

我有两个使用Maven的项目。第一个是一个包含实用程序类和方法的库。第二个项目是一个实际的应用程序,它将该库作为依赖项。我的库在内部使用第三方库。
因此,这些是依赖关系:

  • 我的库:依赖第三方库
  • 我的申请:取决于我的库

然而,在一些情况下,我不希望第三方库类在编译时在我的应用程序中可用。这是因为应用程序是由一个大型团队支持的,我希望防止人们在应用程序中意外使用第三方库中的方法,因为两者之间的一些类名和一些方法名是相似的。当然,第三个-必须在运行时在应用程序中提供party库。
如果我的所有依赖项的作用域都是compile,那么它就不能实现我的目标。

nhaq1z21

nhaq1z211#

很好的问题,不幸的是你不能使用Maven 3,2,或者任何其他版本来实现这个,因为它的基本设计。你所问的实际上是一个期望的和理想的行为,因为事实上任何工件的compile依赖关系在runtime范围内都应该是可传递的。但是,这样的设计会导致一些问题。正如您在Maven的依赖机制介绍中所读到的关于compile作用域的内容:
它的目的是[编译依赖的传递依赖应该被考虑]运行时作用域,因此所有的编译依赖必须被显式地列出--然而,有这样的情况,你所依赖的库从另一个库扩展了一个类,迫使你在编译时使用。因此,编译时依赖关系即使是可传递的也仍然作为编译范围保留。
所以,正如你所看到的,你所需要的实际上是对这种行为的适当设计,不幸的是,这种行为是不可能实现的。

yqlxgs2m

yqlxgs2m2#

在过去的三年里,一切都没有改变,所以Michal的答案仍然是正确的:在Maven中无法限制传递可见性。
但是,您应该考虑重新设计您的库,将其拆分为一个api工件和一个实现工件,前者作为编译时依赖项是必需的,并且本身不依赖于第三方库,后者仅作为运行时依赖项是必需的,并且依赖于第三方库。

xj3cbfub

xj3cbfub3#

在应用程序中,您可以使用“运行时”作用域声明对第三方库的显式依赖项。
这可以防止在编译时看到第三方库,因此没有直接的使用可以潜入。但是,它在运行时仍然存在(因为您的库需要它)。
这是可行的,但是很笨拙,需要在pom中给出一个解释性的XML注解。

4nkexdtk

4nkexdtk4#

其他的答案都是正确的。除了通过拆分一个人工的仅支持API的模块来解决maven中缺少的关键特性之外,您还有以下选择:

  • 排除可传递依赖项,然后直接依赖它们(您必须自己管理版本号)
  • 使用checkstyle导入控制和CI。这样,团队成员可以使用传递性,但maven verify将失败
  • 使用gradle。这是对Maven的许多限制的解决方案
iq0todco

iq0todco5#

在pom中使用<dependencyManagement>部分似乎是可行的。您需要检查是否有任何副作用,因为它适用于整个项目。并且您必须具体指定每个库。
下面的代码示例允许我强制guava(它在google guice的项目中被smurfed为编译时传递依赖项)成为运行时依赖项。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
aor9mmx1

aor9mmx16#

您可以使用下列工具分析相依性:mvn dependency:analyze或将依赖关系作为验证生命周期阶段的一部分进行分析:https://maven.apache.org/plugins/maven-dependency-plugin/examples/failing-the-build-on-dependency-analysis-warnings.html

ymzxtsji

ymzxtsji7#

你可以这样试试:


# My application pom.xml

 <dependencies>
        <dependency>
            <groupId>My groupId</groupId>
            <artifactId>My library</artifactId>
            <version>${version}</version>
            <exclusions>
                <exclusion>
                    <groupId>third-party library</groupId>
                    <artifactId> third-party library</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>third-party library</groupId>
            <artifactId> third-party library</artifactId>
            <version>${version}</version>
            <scope>runtime</scope>
        </dependency>
</dependencies>
bweufnob

bweufnob8#

如果您可以从Maven迁移到Gradle,您就可以解决这个问题,正如@tkruse所指出的。我将解释原因:
借助Gradle,库作者可以使用2种不同的“编译”级别范围:apiimplementation中的一个或多个。
api作用域的行为与Maven的compile作用域类似,用于库的依赖项,这些依赖项将成为其API的一部分,因此也需要是库的使用者的“编译”依赖项。
implementation作用域的目的是解决您所提出的问题。它的作用域是针对您的库的依赖项,这些依赖项不是其API的一部分,因此只需要是您的库的消费者的“运行时”依赖项。

  • 这是一个非常聪明的方法:implementation依赖关系通常在编译阶段使用,但当Gradle生成要发布的库的pom.xml元数据(或任何其他类型的元数据)时,它会将此依赖关系设置为“运行时”依赖关系。*

来源:https://gradle.org/maven-vs-gradle

相关问题