Maven 排除/删除父 POM 中定义的测试依赖项

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

这类似于 排除从父 pom 继承的子 pom 中的依赖关系,不同之处在于它与

test
compile
作用域有关。

我有一个包含

org.slf4j:slf4j-api
依赖项的父 POM,以便所有后代项目都将使用 SLF4J 作为日志记录 API。然后,为了让所有项目都可以有一些用于单元测试的日志记录(无论它们在主要(即非测试)项目的一部分中使用哪种 SLF4J 实现),我包含 SLF4J Simple,但仅在
test
范围内:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <scope>test</scope>
</dependency>

我理解父 POM 不应声明依赖项而仅使用依赖项管理的观点。虽然我一般不反对,但配置测试是另一回事。我不希望每个子项目都必须声明 JUnit, Hamcrest、Hamcrest 可选、Mockito、简单日志记录等。我们所有项目的测试框架应该是统一的,不需要为了建立一个项目而进行大量的仪式。

这一切都很好,直到一个项目

Foo
想要使用 Logback 作为 SLF4J 实现。

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.4.1</version>
</dependency>

这对于

Foo
应用程序本身来说效果很好,但现在对于
Foo
测试,突然出现了两个相互竞争的 SLF4J 实现:Logback 和 SLF4J simple。这出现了绑定冲突:

SLF4J: Class path contains multiple SLF4J providers.
SLF4J: Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider@363ee3a2]
SLF4J: Found provider [org.slf4j.simple.SimpleServiceProvider@4690b489]
SLF4J: See https://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual provider is of type [ch.qos.logback.classic.spi.LogbackServiceProvider@363ee3a2]

我需要执行以下操作之一:

  • 在引入
    ch.qos.logback:logback-classic
    依赖项的 POM 中,我需要从父 POM 中排除
    org.slf4j:slf4j-simple
    。 (这是首选解决方案。)
  • 在引入
    ch.qos.logback:logback-classic
    依赖项的 POM 中,我需要指定
    ch.qos.logback:logback-classic
    适用于所有范围 除了
    test
    范围(以免与
    org.slf4j:slf4j-simple
    冲突)。

我不太明白如何做其中任何一个。有什么想法吗?

一个建议是用

org.slf4j:slf4j-simple
重新声明
<scope>provided</scope>
。因此,项目
pom.xml
Foo
看起来像这样:

…
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <scope>provided</scope>
</dependency>
…

不幸的是,这不起作用。 SLF4J 仍然在类路径上看到两个 SLF4J 提供程序,并且显示上面看到的消息。

provided
的范围只是防止依赖关系被传递到其他项目中;它似乎没有将其从当前项目的类路径中删除。

java maven logback slf4j
2个回答
0
投票

听起来你正在尝试使用错误的工具建造大教堂,但你得到的是异教寺庙而不是大教堂:)

  1. 从技术上讲,可以通过定义
    system
    范围来覆盖父pom强加的类路径/模块依赖,类似于
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.1</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/../dummy.jar</systemPath>
</dependency>

但是,我不建议这样做

  1. 另一个选择是利用surefire插件的classpathDependencyExcludes配置选项类似于
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <classpathDependencyExcludes>org.slf4j:slf4j-simple</classpathDependencyExcludes>
    </configuration>
</plugin>
  1. 如果特定的父母不适合孩子的需要,孩子可以收养另一位父母:)没有严格要求聚合器pom必须是父母pom
  2. 真正的问题与现代构建工具maven不区分
    test compile
    test runtime
    范围,但是可以模拟这种行为
<properties>
    <surefire.runtime>${project.build.directory}/surefire-runtime/slf4j-simple-2.0.1.jar</surefire.runtime>
</properties>

...

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-surefire-runtime</id>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <artifactItems>
                    <artifactItem>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-simple</artifactId>
                        <version>2.0.1</version>
                        <type>jar</type>
                        <overWrite>false</overWrite>
                        <outputDirectory>${project.build.directory}/surefire-runtime/</outputDirectory>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <additionalClasspathElements>${surefire.runtime}</additionalClasspathElements>
    </configuration>
</plugin>

是的,那里的字太多了,但在我看来,这只是

test runtime
依赖项的正确配置,m.b.值得向surefire项目提交相应的PR - 我相信需要编写大约10个LoC来避免
maven-dependency-plugin
配置并能够通过以下方式配置
test runtime

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <additionalClasspathElements>
            <additionalClasspathElement>org.slf4j:slf4j-api:2.0.1</additionalClasspathElement>
        </additionalClasspathElements>
    </configuration>
</plugin>

0
投票

在运行时,您会遇到问题,因为 Logback 是类路径上唯一的日志记录实现。没关系。

test
范围内,额外的
slf4j-simple
依赖项会导致绑定冲突。这里的解决方案只是让 Maven Surefire 插件(运行测试)设置一个特殊的系统属性来显式选择正确的日志记录实现:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <systemPropertyVariables>
                    <!-- Suppress warning "Class path contains multiple SLF4J providers" which is caused by additional slf4j-simple dependency in test scope  -->
                    <slf4j.provider>org.slf4j.simple.SimpleServiceProvider</slf4j.provider>
                </systemPropertyVariables>
            </configuration>
        </plugin>
© www.soinside.com 2019 - 2024. All rights reserved.