让我们假设我们的构建是关于构建从A到z的模块。这些项目的pom文件中的所有版本元素都设置为-SNAPSHOT。
当我们构建pom文件时,maven从项目A开始,然后转到B,然后最后到达项目Z。如果Z依赖于A, maven是否检查远程仓库中最新的A- snapshot .jar并可能替换刚刚在/target/和/或本地maven仓库创建的A- snapshot .jar作为同一构建的一部分?
我认为-o
可以避免上述情况,但我只是想了解。
是否可以将-o
设置为特定的groupId以避免在上述场景中可能发生的模糊错误?
是否有可能以这样的方式配置构建,以下载本地repo中不可用的任何工件,但不替换现有的工件。
不,反应器中的项目总是优先于其他依赖项。
即使在下列情况下也成立:
- 设置
-U
标志运行Maven,这意味着强制进行更新检查。 - 在
settings.xml
或POM中设置<updatePolicy>
为always
。 - 配置
install
插件到<installAtEnd>true</installAtEnd>
Maven将找出哪些工件是您的反应器的一部分,并从更新检查中排除它们。
这很容易证明。如果您尝试使用上述任何一种配置运行Maven,您将看到Maven不会下载工件A
(例如),因为每次下载都在控制台中记录。
例如,假设您有这样一个根POM:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>root</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>root</name>
<modules>
<module>A</module>
<module>B</module>
...
<module>Z</module>
</modules>
</project>
每个模块看起来像这样:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>root</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<name>...</name>
<artifactId>...</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
</project>
但是最后一个看起来是这样的:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>root</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>Z</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Z</name>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
那么不,模块A将永远不会被存储库中的工件的另一个版本所替换。
确认Daniel的回答,实现代码在Maven 2和3之间改变了很多,但基本原理是这样的:
- 当一个项目(模块)被构建时,它的工件被附加到"构建反应器"并标记为"已解决",
- 当项目需要工件时,它在反应器中查找已解决的工件,
- 如果没有找到附加的已解析工件,那么它将请求查看本地和远程存储库的解析。
因为只有在没有找到已解析的工件并且模块构建将其工件附加到反应器(标记为已解析)时才进行解析,那么答案是:不,Maven不会下载新的SNAPSHOT jar来替换在同一构建中刚刚创建的jar。
你可以看看以下代码:MavenProject, DefaultArtifactResolver, DefaultArtifactResolver。
对另一个问题的回答有一部分可以解决你的问题:
当您构建应用程序时,Maven将在本地存储库中搜索依赖项。如果没有找到稳定版本,它将搜索远程存储库(在settings.xml或pom.xml中定义)以检索此依赖项。然后,它会将其复制到本地存储库中,以便在下次构建时可用。
例如,foo-1.0.jar库被认为是一个稳定版本,如果Maven在本地存储库中找到它,它将在当前构建中使用这个库。
现在,如果您需要foo-1.0-SNAPSHOT.jar库,Maven将知道这个版本不稳定并且可能会发生更改。这就是为什么Maven将尝试在远程存储库中查找较新版本,即使在本地存储库中找到了该库的一个版本。但是,这张支票每天只开具一次。这意味着如果你在本地存储库中有一个foo-1.0-20110506.110000-1.jar(即这个库是在2011年5月6日11:00:00生成的),并且如果你在同一天再次运行Maven构建,Maven将不会检查存储库中是否有新版本。
注意,这种每日检查是默认行为。这个行为可以通过在snapshot
元素中定义的updatePolicy
元素来定制。
来自文档:
updatePolicy
下载更新的频率-可以"always","daily"(默认),"间隔:XXX"(以分钟为单位)或"从不";(只有在本地不存在的情况下)。
感谢Julien Carsique的这种精度
据我所知,如果可用,优先使用本地存储库中的快照构建。为了证明这一点,
- 将本地maven存储库移动到另一个位置,将
.m2/repository
目录保留为空。(不要删除它,因为您以后可能找不到一些工件。远程存储库确实关闭了:)) - 更改A中Z使用的API
- 运行构建。如果我的思路是正确的,它应该在构建Z时失败。您没有更改远程工件,并且存储库没有任何内容(因为您在上面步骤中移动了它)。
- 如果需要,请恢复原始存储库文件夹
- 回滚a中的API更改。