2009-09-08 148 views
14

假设我在下面的项目中定义了两个Maven依赖项。Maven依赖于不同范围内的依赖关系

<dependency> 
     <groupId>com.thoughtworks.xstream</groupId> 
     <artifactId>xstream</artifactId> 
     <version>1.3.1</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>mycompany.library</groupId> 
     <artifactId>mylibrary</artifactId> 
     <version>1.0.1</version> 
     <scope>compile</scope> 
    </dependency> 

然后,在mylibrary中,我也有一个依赖定义如下。

<dependency> 
     <groupId>com.thoughtworks.xstream</groupId> 
     <artifactId>xstream</artifactId> 
     <version>1.3.1</version> 
     <scope>compile</scope> 
    </dependency> 

当我打包我的项目时,我没有看到xstream打包在其中。我认为项目的xstream依赖范围'test'正在覆盖mylibrary的xstream依赖范围'compile'。

在这种情况下,在整个项目中包含xstream的最佳方式是什么,以便在打包到项目中时子模块可以访问它?

我已阅读Apache Maven网站对Transitive依赖关系的解释,但我正在努力理解它的含义,并且找出了这种情况下的最佳实践。

回答

11

这对我来说真的很奇怪,如果它是“功能”,我认为它是一个非常危险的。 无论如何,这不是Maven的bug,它在maven文档here中。

关于这个问题的最佳实践,我还没有听说过任何,但最安全的方法应该是从你的pom中完全移除xstream,依赖于传递依赖。如果删除对库文件的依赖关系,则会导致构建失败。这将作为通知给您,您需要修复某些内容。你不会默默地释放所需的依赖关系,并且你不会默默地拥有你不再需要的依赖关系。

在附注上,可以使用mvn依赖关系:analyze来检查包含但未使用的依赖关系。

0

如果你想要它打包,你为什么要声明范围?如果在编译和执行时需要,不应该将范围留空吗?如果你这样做,那么你只需要

<dependency> 
    <groupId>mycompany.modules</groupId> 
    <artifactId>submodule</artifactId> 
    <version>1.0.1</version> 
</dependency> 

在你的pom。除非在编译过程中有理由对其进行解析,但在包装过程中不能解析它?

+0

来自Apache Maven网站: - 编译 这是默认范围,如果没有指定,则使用。编译依赖关系在项目的所有类路径中都可用。而且,这些依赖关系会传播到依赖项目。 –

+0

也许我原来的问题导致了混乱,因为我使用了“子模块”。请参阅我上面编辑的问题。 –

+0

是的,我更关心测试范围。 – aperkins

4

通过声明您自己对xstream的依赖关系,并设置要测试的作用域,您将重写由mylibrary声明的依赖关系。

这实际上是一个Maven特性 - 它允许您在自己的项目中执行诸如依赖于传递依赖项的更高版本的事情,而不是最终打包相同工件的两个不同版本。例如,您可能依赖于log4j的版本1.2.15,但是因为您也使用libraryX,这取决于log4j-1.2.14 - 您不希望log4j-1.2.15log4j-1.2.14与您的项目打包在一起。

如果您确实希望将xstream打包到您的项目中,则不应声明范围为test。事实上,如果你删除你在xstream上列出的依赖关系,事情会按照你喜欢的方式工作,因为mylibrary对它有编译依赖性..

+1

在这种情况下,如果将来有一段时间,我不需要使用mylibrary,或者该库将xstream上的依赖项更改为其他内容,那么我的项目将无法通过测试。然后,我需要再次指定xstream作为项目的测试范围。这是Maven的特性/限制吗?我愿意接受Maven的限制,只是想看看最佳实践是什么。 –

+0

我不确定这是否正确。有一个更直观的机制来排除不需要的传递依赖,这就是块。 – Buhb

+0

“如果将来有一段时间,我不需要使用mylibrary或者该库将xstream上的依赖项更改为其他内容,那么我的项目将无法通过测试。”那么在这一点上简单地添加依赖关系。只要您继续依赖相同版本的mylibrary,就不会发生意外的更改。您的项目的新版本可能有不同的需求 - 这是完全正常的。 –

5

正如mattb的回答所言,声明依赖为test的作用域会覆盖传递式编译范围的依赖声明,因此依赖关系不会包含在打包的war中。

如果您只需要测试中的依赖项,因为'mylibrary'需要它执行,您不应该在项目的pom中声明依赖项的所有。让传递依赖关系解决过程处理它。

如果您的项目直接使用xstream jar,仍然可以依赖传递依赖项,因为您需要项目的兼容版本和'mylibrary'来针对xstream jar运行。你应该有单元测试来演示这个功能,如果mylibrary将xstream的版本更改为不兼容的版本,那么你的版本应该会失败,并且你可以在那个时候解决这个问题。

一般来说,我会说你应该尽量避免直接在多模块项目中声明依赖版本。我声明父POM的dependencyManagement部分中的版本,以便孩子只需声明groupId/artifactId。或者,从Maven 2.0.9开始,还有一个额外的依赖范围import

此范围仅用于该节中类型为pom的依赖项。它表明指定的POM应该替换为该POM部分中的依赖关系。由于它们被替换,因此具有导入范围的依赖关系实际上并不参与限制依赖关系的传递性。

因此,使用进口的范围,你可以定义你的共同依赖的版本在一个单一的POM,导入POM的依赖到你的dependencyManagement部分,只是在声明你的其他的POM依赖的的groupId/artifactId的。