简体   繁体   English

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

[英]Is there anyway to exclude artifacts inherited from a parent POM?

Artifacts from dependencies can be excluded by declaring an <exclusions> element inside a <dependency> But in this case it's needed to exclude an artifact inherited from a parent project.可以通过在<dependency>中声明<exclusions>元素来排除依赖项中的工件,但在这种情况下,需要排除从父项目继承的工件。 An excerpt of the POM under discussion follows:正在讨论的 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 artifact, depends on javax.mail:mail-1.4.jar , and ALL-DEPS depends on another version of the same library. base工件,依赖于javax.mail:mail-1.4.jar ,而ALL-DEPS依赖于同一库的另一个版本。 Due to the fact that mail.jar from ALL-DEPS exist on the execution environment, although not exported, collides with the mail.jar that exists on the parent, which is scoped as compile .由于ALL-DEPS中的mail.jar存在于执行环境中,尽管未导出,但它与父级上存在的mail.jar发生冲突,其范围为compile

A solution could be to rid off mail.jar from the parent POM, but most of the projects that inherit base, need it (as is a transtive dependency for log4j).一个解决方案可能是从父 POM 中删除 mail.jar,但是大多数继承 base 的项目都需要它(就像 log4j 的传递依赖项一样)。 So What I would like to do is to simply exclude parent's library from the child project , as it could be done if base was a dependency and not the parent pom:所以我想做的是简单地从子项目中排除父库,因为如果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>
...

Some ideas:一些想法:

  1. Maybe you could simply not inherit from the parent in that case (and declare a dependency on base with the exclusion).在这种情况下,也许你不能简单地从父级继承(并声明对base的依赖项)。 Not handy if you have lot of stuff in the parent pom.如果您在父 pom 中有很多东西,那就不方便了。

  2. Another thing to test would be to declare the mail artifact with the version required by ALL-DEPS under the dependencyManagement in the parent pom to force the convergence (although I'm not sure this will solve the scoping problem).要测试的另一件事是在父 pom 中的dependencyManagement下使用ALL-DEPS所需的版本声明mail工件以强制收敛(尽管我不确定这是否会解决范围问题)。

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. Or you could exclude the mail dependency from log4j if you're not using the features relying on it (and this is what I would do):或者,如果您不使用依赖它的功能,您可以从 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. Or you could revert to the version 1.2.14 of log4j instead of the heretic 1.2.15 version (why didn't they mark the above dependencies as optional ?!).或者您可以恢复到 log4j 的 1.2.14 版本,而不是异端的 1.2.15 版本(他们为什么不将上述依赖项标记为可选?!)。

You can group your dependencies within a different project with packaging pom as described by Sonatypes Best Practices :您可以按照 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>

and reference them from your parent-pom (watch the dependency <type>pom</type> ):并从您的 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>

Your child-project inherits this parent-pom as before.您的子项目像以前一样继承了这个父 pom。 But now, the mail dependency can be excluded in the child-project within the dependencyManagement block:但是现在,可以在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>

Don't use a parent pom不要使用父 pom

This might sound extreme, but the same way "inheritance hell" is a reason some people turn their backs on Object Oriented Programming (or prefer composition over inheritance ), remove the problematic <parent> block and copy and paste whatever <dependencies> you need (if your team gives you this liberty).这听起来可能很极端,但是“继承地狱”也是一些人背弃面向对象编程(或者更喜欢组合而不是继承)的原因,删除有问题的<parent>块并复制和粘贴您需要的任何<dependencies> (如果你的团队给你这个自由)。

The assumption that splitting of poms into a parent and child for "reuse" and "avoidance of redunancy" should be ignored and you should serve your immediate needs first (the cure is worst than the disease).应该忽略将 poms 拆分为父母和孩子以“重用”和“避免冗余”的假设,您应该首先满足您的即时需求(治疗比疾病更糟糕)。 Besides, redundancy has its advantages - namely independence of external changes (ie stability).此外,冗余还有它的优点——即独立于外部变化(即稳定性)。

This is easier than it sounds if you generate the effective pom (eclipse provides it but you can generate it from the command line with mvn help:effective ).如果您生成有效的 pom,这比听起来要容易(eclipse 提供了它,但您可以使用mvn help:effective从命令行生成它)。

Example例子

I want to use logback as my slf4j binding, but my parent pom includes the log4j dependency.我想使用logback作为我的 slf4j 绑定,但我的父 pom 包含log4j依赖项。 I don't want to go and have to push the other children's dependence on log4j down into their own pom.xml files so that mine is unobstructed.我不想去,不得不将其他孩子对 log4j 的依赖推到他们自己的pom.xml文件中,这样我的就畅通无阻了。

Redefine the dependency (in the child pom) with scope system pointing to an empty jar :使用指向空 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>

The jar can contain just a single empty file : jar 可以只包含一个空文件:

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

Have you tried explicitly declaring the version of mail.jar you want?您是否尝试过明确声明您想要的 mail.jar 版本? Maven's dependency resolution should use this for dependency resolution over all other versions. 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>

Best bet is to make the dependencies you don't always want to inherit intransitive.最好的办法是让你不总是想要继承的依赖关系不传递。

You can do this by marking them in the parent pom with scope provided.您可以通过在提供范围的父 pom 中标记它们来做到这一点。

If you still want the parent to manage versions of these deps, you can use the <dependencyManagement> tag to setup the versions you want without explicitly inheriting them, or passing that inheritance along to children.如果您仍然希望父级管理这些 dep 的版本,您可以使用<dependencyManagement>标记来设置您想要的版本,而无需显式继承它们,或将该继承传递给子级。

I really needed to do this dirty thing... Here is how我真的需要做这件肮脏的事情......这是怎么做的

I redefined those dependencies with scope test .我使用范围test重新定义了这些依赖项。 Scope provided did not work for me. provided的范围对我不起作用。

We use spring Boot plugin to build fat jar.我们使用 spring Boot 插件来构建 fat jar。 We have module common which defines common libraries, for example Springfox swagger-2.我们有定义通用库的模块common ,例如 Springfox swagger-2。 My super-service needs to have parent common (it does not want to do so, but company rules force!)我的超级服务需要有父公共(它不想这样做,但公司规则强制!)

So my parent or commons has pom.所以我的父母或公地有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>

And my super-service pom.还有我的超级服务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>

This is size of the final fat artifact这是最终脂肪伪影的大小

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

Also this answer is worth mentioning - I wanted to do so, but I am lazy... https://stackoverflow.com/a/48103554/4587961这个答案也值得一提 - 我想这样做,但我很懒...... https://stackoverflow.com/a/48103554/4587961

We can add the parent pom as a dependency with type pom and make exclusion on that.我们可以将父 pom 添加为 pom 类型的依赖项并对其进行排除。 Because anyhow parent pom is downloaded.因为无论如何都会下载父pom。 This worked for me这对我有用

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

Repeat the parent's dependency in child pom.xml and insert the exclusion there:在子 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>

When you call a package but do not want some of its dependencies you can do a thing like this (in this case I did not want the old log4j to be added because I needed to use the newer one):当您调用一个包但不想要它的某些依赖项时,您可以执行以下操作(在这种情况下,我不希望添加旧的 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>

This works for me... but I am pretty new to java/maven so it is maybe not optimum.这对我有用......但我对 java/maven 很陌生,所以它可能不是最佳的。

Disable Child Artifact inherited from Parent禁用从父级继承的子级工件

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

Remove Specific Artifact from Parent从父级移除特定工件

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM