是否有排除继承自父 POM 的工件的方法?

通过在 <dependency>中声明一个 <exclusions>元素,可以排除来自依赖项的工件,但是在这种情况下,需要排除从父项目继承的工件。以下是正在讨论的项目组的摘录:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>


<dependencies>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>ALL-DEPS</artifactId>
<version>1.0</version>
<scope>provided</scope>
<type>pom</type>
</dependency>
</dependencies>
</project>

base构件,依赖于 javax.mail:mail-1.4.jar,而 ALL-DEPS依赖于同一库的另一个版本。由于来自 ALL-DEPSmail.jar存在于执行环境中,虽然没有导出,但是与存在于父级(范围为 compile)上的 mail.jar发生了冲突。

一个解决方案可能是从父 POM 中去除 mail.jar,但是大多数继承基础的项目都需要它(就像 log4j 的传递依赖一样)。因此,我想做的就是简单地使用 从子项目中排除父类库,如果 base是一个依赖项而不是父 pom,那么就可以这样做:

...
<dependency>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<type>pom<type>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
</exclusions>
</dependency>
...
201867 次浏览

一些想法:

  1. 在这种情况下,也许您可以简单地不从父继承(并在排除 base的情况下声明一个依赖项)。如果你在家长会上有很多东西就不方便了。

  2. 另一件需要测试的事情是声明 mail工件,其版本是 ALL-DEPS所需要的,在父 POM 中的 dependencyManagement下面,以强制收敛(尽管我不确定这将解决范围问题)。

<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>???</version><!-- put the "right" version here -->
</dependency>
</dependencies>
</dependencyManagement>
  1. 或者,如果不使用依赖于 log4j 的特性,可以从 log4j 中排除 mail依赖项(我会这么做) :
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
</dependency>
  1. 或者您可以恢复到 log4j 的1.2.14版本,而不是异端的1.2.15版本(为什么他们没有将上述依赖项标记为 可以选择? !).

是否尝试显式声明所需的 mail.jar 版本?Maven 的依赖项解析应该使用这个来解析所有其他版本的依赖项。

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>VERSION-#</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>ALL-DEPS</artifactId>
<version>1.0</version>
<scope>provided</scope>
<type>pom</type>
</dependency>
</dependencies>
</project>

最好的办法是使您并不总是希望继承的依赖项成为不传递的。

可以通过在父 pom 中使用提供的范围标记它们来实现这一点。

如果仍然希望父代管理这些 dep 的版本,则可以使用 <dependencyManagement>标记设置所需的版本,而无需显式继承它们,或将继承传递给子代。

您可以将您的依赖项分组到不同的项目中,使用 Sonatype 最佳实践所描述的打包 pom:

<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

并从你的父-pom 引用它们(注意依赖关系 <type>pom</type>) :

<project>
<modelVersion>4.0.0</modelVersion>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>

您的子项目像以前一样继承这个父项。但是现在,在 dependencyManagement块中的子项目中可以排除邮件依赖项:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>jruby</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>base</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
</parent>


<dependencyManagement>
<dependencies>
<dependency>
<artifactId>base-dependencies</artifactId>
<groupId>es.uniovi.innova</groupId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
</project>

当你调用一个包但是不想要它的一些依赖项时,你可以这样做(在这个例子中,我不想添加旧的 log4j,因为我需要使用新的) :

<dependency>
<groupId>package</groupId>
<artifactId>package-pk</artifactId>
<version>${package-pk.version}</version>


<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>


<!-- LOG4J -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>

这对我很有用... ... 但是我对 java/maven 还很陌生,所以它可能不是最佳选择。

不要用家长彩球

这听起来可能有些极端,但同样的道理,“继承地狱”是一些人背弃面向对象编程(或 比起继承,我更喜欢合成)的原因,删除有问题的 <parent>块和 复制粘贴无论 <dependencies>你需要(如果你的团队给你这个自由)。

应该忽略这样一个假设: 为了“重复使用”和“避免冗余”,把绒球分成父母和孩子两部分,你应该首先满足自己的迫切需要(治疗比疾病更糟糕)。此外,冗余还有其优点-即独立于外部变化(即稳定性)。

如果您生成有效的 pom,这比听起来要容易(eclipse 提供了它,但是您可以使用 mvn help:effective从命令行生成它)。

例子

我想使用 logback作为 slf4j 绑定,但是我的父 pom 包含 log4j依赖项。我不想去,不得不把其他孩子对 log4j 的依赖下降到他们自己的 pom.xml文件,以便我的是通畅的。

使用指向空 jar 的 scope系统重新定义依赖项(在子 pom 中) :

<dependency>
<groupId>dependency.coming</groupId>
<artifactId>from.parent</artifactId>
<version>0</version>
<scope>system</scope>
<systemPath>${project.basedir}/empty.jar</systemPath>
</dependency>

Jar 只能包含一个空文件:

touch empty.txt
jar cvf empty.jar empty.txt

我真的需要做这件肮脏的事情... 这就是方法

我用范围 test重新定义了这些依赖项。范围 provided对我不起作用。

我们使用弹簧启动插件建立脂肪罐。我们有定义公共库的模块 很普通,例如 Springfox swagger-2。我的 超级服务需要有父 很普通(它不想这样做,但公司规则强制!)

所以我的父母或者下院有。

<dependencyManagement>


<!- I do not need Springfox in one child but in others ->


<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<version>${swagger.version}</version>
</dependency>


<!- All services need them ->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${apache.poi.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

还有我的 超级服务彩球。

<name>super-service</name>
<parent>
<groupId>com.company</groupId>
<artifactId>common</artifactId>
<version>1</version>
</parent>


<dependencies>


<!- I don't need them ->


<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-bean-validators</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-core</artifactId>
<version>2.8.0</version>
<scope>test</scope>
</dependency>


<!- Required dependencies ->


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
</dependencies>

这是最终脂肪藏物的大小

82.3 MB (86,351,753 bytes) - redefined dependency with scope test
86.1 MB (90,335,466 bytes) - redefined dependency with scope provided
86.1 MB (90,335,489 bytes) - without exclusion

这个答案也值得一提-我想这样做,但我很懒..。 Https://stackoverflow.com/a/48103554/4587961

我们可以将父 pom 作为依赖项添加到 pom 类型中,并对其进行排除。因为无论如何,父母的彩球是下载的。这招对我很管用

<dependency>
<groupId>com.abc.boot</groupId>
<artifactId>abc-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>

在子 pom.xml 中重复父代的依赖项,并在其中插入排除项:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>

禁用从父级继承的子级工件

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

从父级移除特定的工件

    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>