ChatGPT解决这个技术问题 Extra ChatGPT

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

可以通过在 <dependency> 中声明 <exclusions> 元素来排除依赖项中的工件,但在这种情况下,需要排除从父项目继承的工件。正在讨论的 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 依赖于同一库的另一个版本。由于 ALL-DEPS 中的 mail.jar 存在于执行环境中,尽管未导出,但与父级中存在的 mail.jar 发生冲突,其范围为 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>
...

A
Ahmed Ashour

一些想法:

在这种情况下,也许你不能简单地从父级继承(并声明对 base 的依赖项)。如果您在父 pom 中有很多东西,那就不方便了。要测试的另一件事是在父 pom 中的 dependencyManagement 下使用 ALL-DEPS 所需的版本声明邮件工件以强制收敛(尽管我不确定这是否会解决范围问题)。

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>

或者,如果您不使用依赖它的功能,您可以从 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>

或者您可以恢复到 log4j 的 1.2.14 版本,而不是异端的 1.2.15 版本(他们为什么不将上述依赖项标记为可选?!)。


感谢您的回复。这包含很多有用的信息。关于 1) 正如您所注意到的那样,这不是最优的,因为父 pom 不仅包含在将 base 标记为依赖项时将传递解决的依赖项,而且还包含通用报告、源管理和公司每个项目之间重用的其他内容。关于2)我试过了,但也指定了提供的工件范围,它工作了:)。一开始,我以为编译优先于提供,它不会起作用,但幸运的是我错了(子POM覆盖父的配置)
A
Ahmed Ashour

如 Sonatypes Best Practices 所述,您可以使用打包 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>

并从您的 parent-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>

为此 +1,尽管子 pom 应该使用 部分而不是 因为后者用于从父 pom 中管理依赖项的版本。
这也称为 BOM,又名物料清单 :-)
这仅适用于传递依赖项吗?我的父 pom 包含 log4j,它阻止了我的 pom 的 logback 正常工作。
嗨,这真的被称为 BOM 吗?我已经看到 BOM 仅在 <dependencyManagement> 块中定义依赖项的上下文中被调用。这种方法是不同的,因为它依赖于传递性来传递依赖关系。这可以称为BOM吗?附带问题:有什么方法可以分发测试范围依赖项而不在父项中硬声明它以便将它们排除在外?谢谢!
正如@GerardBosch 提到的,这与 BOM 方法相同。在 BOM 方法中,BOM POM 声明托管依赖项,然后使用称为 import 的特殊 scope 将其导入项目 POM,然后项目需要进一步将它们声明为直接依赖项。上述方法可传递地引入所有必需的依赖项,并且将被视为反模式,不建议将其作为 BOM 的通用替代方案。
S
Sridhar Sarnobat

不要使用父 pom

这听起来可能很极端,但是“继承地狱”也是一些人背弃面向对象编程(或 prefer composition over inheritance)的原因,删除有问题的 <parent> 块和 copy and paste 您需要的任何 <dependencies> (如果你的团队给你这个自由)。

应该忽略将 poms 拆分为父母和孩子以“重用”和“避免冗余”的假设,您应该首先满足您的即时需求(治疗比疾病更糟糕)。此外,冗余还有它的优点——即独立于外部变化(即稳定性)。

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

例子

我想使用 logback 作为我的 slf4j 绑定,但我的父 pom 包含 log4j 依赖项。我不想去,不得不将其他孩子对 log4j 的依赖推到他们自己的 pom.xml 文件中,这样我的就畅通无阻。


非常仔细地记录这个(和你遵循的过程),因为如果需要使用父 pom 的更新版本,未来的维护者需要重做这个。
当然,您的意思是不要在父 pom 中使用依赖项?父 pom 对于管理依赖版本和常用插件仍然非常有用。仅仅使用它来注入依赖可能会适得其反——我们只将它用于必须具有的依赖项(例如一组用于微服务父级的基本 Spring Boot 启动器)
不,我不是说使用轻量级的父 pom。您团队中的其他人不允许您修剪父 pom,因为其他应用程序依赖于您不想要的父 pom 中的垃圾。
S
Scott Kurz

使用指向空 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

感谢您的回答,在 Windows 10 上,我必须先运行 notepad empty.class,然后再运行 jar cvf empty.jar empty.class 才能生成一个空 jar。
看起来不好的做法
A
Ahmed Ashour

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

您的方法,因为 Pascal 的解决方法 #2 也是有效的,实际上,您还考虑到应该将邮件依赖项声明为已提供。谢谢你。
提供的范围对我不起作用。我使用了范围测试,请检查我的答案。 stackoverflow.com/a/55970293/4587961
A
Ajax

最好的办法是让你不总是想要继承的依赖关系不传递。

您可以通过在提供范围的父 pom 中标记它们来做到这一点。

如果您仍希望父级管理这些 deps 的版本,您可以使用 <dependencyManagement> 标记来设置您想要的版本,而无需显式继承它们,或将该继承传递给子级。


Y
Yan Khonski

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

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

我们使用 spring Boot 插件来构建 fat jar。我们有定义通用库的模块 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


V
Viki Jain

我们可以将父 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>

f
fritzthecat

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

A
Ahmed Ashour

当您调用一个包但不想要它的某些依赖项时,您可以执行以下操作(在这种情况下,我不希望添加旧的 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,不要让粗鲁的人经常忽略我的问题而阻止你发帖。
A
Amir Shaikh

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

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