无论如何,是否要排除从父POM继承的工件?


119

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

<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取决于同一库的另一个版本。由于执行环境上存在mail.jarfrom 的事实ALL-DEPS,尽管未导出,但与mail.jar父级上存在的from发生冲突,范围为compile

一种解决方案是从父POM摆脱mail.jar,但是大多数继承base的项目都需要它(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>
...

Answers:


49

一些想法:

  1. 在这种情况下,也许您根本无法从父项继承(并声明base排除项的依赖项)。如果您在父pom中有很多东西,则不方便。

  2. 要测试的另一件事是在父pom 下声明mail具有所需版本的工件以强制收敛(尽管我不确定这是否可以解决范围问题)。ALL-DEPSdependencyManagement

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. 或者mail,如果您不使用依赖于log4j的功能,则可以将其从log4j中排除(这就是我要做的):
<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版本(为什么它们不将上述依赖项标记为可选?!)。

感谢您的回复。这包含很多有用的信息。关于1)正如您已经注意到的那样,这不是最佳的,因为如果将base标记为依赖项,则父pom不仅包含可传递地解决的依赖项,而且还包含公共报告,源代码管理以及公司中每个项目之间重用的其他内容。关于2),我尝试了它,但是还指定了提供的工件范围,并且它起作用了:)。起初,我认为编译优先于所提供的功能,因此无法正常工作,但幸运的是我错了(子POM覆盖了父级的配置)
Miguel 2010年

29

您可以使用pomSonatypes Best Practices所述的打包方式将不同项目中的依赖项分组:

<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>

您的子项目像以前一样继承了此父pom。但是现在,可以在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>

4
为此,+ 1,尽管子pom应该使用<dependencies>部分而不是<dependencyManagement>,因为后者用于从父pom中管理依赖项的版本
Matthew Wise 2014年

1
这也称为BOM,也称为材料清单:-)
Pim Hazebroek '16

这仅适用于传递依赖吗?我的父pom包含log4j,这阻止了pom的logback正常工作。
Sridhar Sarnobat

10

不要使用父pom

这可能听起来有些极端,但以同样的方式“继承地狱”是一个原因,一些人转向面向对象编程仰睡(或更喜欢在继承组成),删除有问题的<parent>复制和粘贴任何<dependencies>你需要(如果你的团队给你这种自由)。

应该忽略将绒球分割成父母和孩子以“重用”和“避免冗余”的假设,并且应该首先满足您的即时需求(治疗比疾病更糟糕)。此外,冗余具有其优势-即外部变化的独立性(即稳定性)。

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

我想logback用作我的slf4j绑定,但是我的父pom包括log4j依赖项。我不想去,而不得不将其他孩子对log4j的依赖性下放到自己的pom.xml文件中,以使我的通畅无阻。


1
非常仔细地记录此操作(以及您执行的过程),因为将来的维护人员如果需要使用父pom的更新版本,则需要重做此操作。
托尔比约恩Ravn的安徒生

您确定要在父pom中不使用依赖项吗?父pom在管理依赖版本和常用插件方面仍然非常有用。仅使用它注入依赖项可能会适得其反-我们仅将其用于必需的依赖项(例如一组微服务父级的必不可少的Spring Boot启动程序)
Amit Goldstein,

不,我不是说要使用轻量级的父pom。团队中的其他人不允许您修剪父pom,因为其他应用程序依赖于您不需要的父pom中的垃圾。
Sridhar Sarnobat,

8

使用scope系统指向空jar 重新定义依赖项(在子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.txt

谢谢您的回答,在Windows 10,我不得不跑notepad empty.class,然后jar cvf empty.jar empty.class生成一个空罐子。
6

1
看起来像是不好的做法
PiotrŻak

6

您是否尝试过明确声明所需的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>

1
您的方法(因为Pascal的解决方法#2也是有效的),实际上,您还考虑到应该声明提供的邮件依赖项。谢谢。
米格尔(Miguel)2010年

提供的范围对我不起作用。我使用了范围测试,请检查我的答案。 stackoverflow.com/a/55970293/4587961
Yan Khonski,

3

最好的选择是使您不总是希望继承的依赖关系不传递。

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

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


1

当您调用一个程序包但不希望其具有某些依赖性时,您可以执行以下操作(在这种情况下,我不希望添加旧的log4j,因为我需要使用较新的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很陌生,所以它可能不是最佳选择。


欢迎使用Stack Overflow,不要让我一直不屑一顾的不礼貌的人阻止您发帖。
Sridhar Sarnobat

1

我真的需要做这件肮脏的事...这是

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

我们使用spring Boot插件来构建胖子。我们有定义通用库的通用模块common,例如Springfox swagger-2。我的超级服务需要具有父公共关系(它不想这样做,但是公司规则会强制执行!)

所以我的父母或下议院有pom。

<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>

还有我的超级服务 pom。

<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


0

我们可以将父pom添加为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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.