可以通过在 <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>
...
一些想法:
在这种情况下,也许你不能简单地从父级继承(并声明对 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 版本(他们为什么不将上述依赖项标记为可选?!)。
如 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>
<dependencyManagement>
块中定义依赖项的上下文中被调用。这种方法是不同的,因为它依赖于传递性来传递依赖关系。这可以称为BOM吗?附带问题:有什么方法可以分发测试范围依赖项而不在父项中硬声明它以便将它们排除在外?谢谢!
import
的特殊 scope
将其导入项目 POM,然后项目需要进一步将它们声明为直接依赖项。上述方法可传递地引入所有必需的依赖项,并且将被视为反模式,不建议将其作为 BOM 的通用替代方案。
不要使用父 pom
这听起来可能很极端,但是“继承地狱”也是一些人背弃面向对象编程(或 prefer composition over inheritance)的原因,删除有问题的 <parent>
块和 copy and paste 您需要的任何 <dependencies>
(如果你的团队给你这个自由)。
应该忽略将 poms 拆分为父母和孩子以“重用”和“避免冗余”的假设,您应该首先满足您的即时需求(治疗比疾病更糟糕)。此外,冗余还有它的优点——即独立于外部变化(即稳定性)。
如果您生成有效的 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
notepad empty.class
,然后再运行 jar cvf empty.jar empty.class
才能生成一个空 jar。
您是否尝试过明确声明您想要的 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 中标记它们来做到这一点。
如果您仍希望父级管理这些 deps 的版本,您可以使用 <dependencyManagement>
标记来设置您想要的版本,而无需显式继承它们,或将该继承传递给子级。
我真的需要做这件肮脏的事情......这是怎么做的
我用范围 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
我们可以将父 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>
在子 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>
当您调用一个包但不想要它的某些依赖项时,您可以执行以下操作(在这种情况下,我不希望添加旧的 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 很陌生,所以它可能不是最佳的。
禁用从父级继承的子级工件
<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>
不定期副业成功案例分享