在Maven的世界中,任何一个项目或者构件都必须有自己的版本。版本的值可能是1.0.0、1.3-alpha-4、2.0、2.1-SNAPSHOT或者2.1-20091214.221414-13。其中,1.0.0、1.3-alpha-4和2.0是稳定的发布版本,而2.1-SNAPSHOT和2.1-20091214.221414-13是不稳定的快照版本。
Maven为什么要区分发布版和快照版呢?简单的1.0.0、1.2、2.1等不就够了吗?为什么还要有2.1-SNAPSHOT,甚至是长长的2.1-20091214.221414-13?试想一下这样的情况,小张在开发模块A的2.1版本,该版本还未正式发布,与模块A一同开发的还有模块B,它由小张的同事季MM开发,B的功能依赖于A。在开发的过程中,小张需要经常将自己最新的构建输出,交给季MM,供她开发和集成调试,问题是,这个工作如何进行呢?
1.方案一
让季MM自己签出模块A的源码进行构建。这种方法能够确保季MM得到模块A的最新构件,不过她不得不去构建模块A。多了一些版本控制和Maven操作还不算,当构建A失败的时候,她会是一头雾水,最后不得不找小张解决。显然,这种方式是低效的。
2.方案二
重复部署模块A的2.1版本供季MM下载。虽然小张能够保证仓库中的构件是最新的,但对于Maven来说,同样的版本和同样的坐标就意味着同样的构件。因此,如果季MM在本机的本地仓库包含了模块A的2.1版本构件,Maven就不会再对照远程仓库进行更新。除非她每次执行Maven命令之前,清除本地仓库,但这种要求手工干预的做法显然也是不可取的。
3.方案三
不停更新版本2.1.1、2.1.2、2.1.3……。首先,小张和季MM两人都需要频繁地更改POM,如果有更多的模块依赖于模块A,就会涉及更多的POM更改;其次,大量的版本其实仅仅包含了微小的差异,有时候是对版本号的滥用。
Maven的快照版本机制就是为了解决上述问题。在该例中,小张只需要将模块A的版本设定为2.1-SNAPSHOT,然后发布到私服中,在发布的过程中,Maven会自动为构件打上时间戳。比如2.1-20091214.221414-13就表示2009年12月14日22点14分14秒的第13次快照。有了该时间戳,Maven就能随时找到仓库中该构件2.1-SNAPSHOT版本最新的文件。这时,季MM配置对于模块A的2.1-SNAPSHOT版本的依赖,当她构建模块B的时候,Maven会自动从仓库中检查模块A的2.1-SNAPSHOT的最新构件,当发现有更新时便进行下载。默认情况下,Maven每天检查一次更新(由仓库配置的updatePolicy控制,见第6.4节),用户也可以使用命令行-U参数强制让Maven检查更新,如mvn clean install-U。
基于快照版本机制,小张在构建成功之后才能将构件部署至仓库,而季MM可以完全不用考虑模块A的构建,并且她能确保随时得到模块A的最新可用的快照构件,而这一切都不需要额外的手工操作。
当项目经过完善的测试后需要发布的时候,就应该将快照版本更改为发布版本。例如,将2.1-SNAPSHOT更改为2.1,表示该版本已经稳定,且只对应了唯一的构件。相比之下,2.1-SNAPSHOT往往对应了大量的带有不同时间戳的构件,这也决定了其不稳定性。
快照版本只应该在组织内部的项目或模块间依赖使用,因为这时,组织对于这些快照版本的依赖具有完全的理解及控制权。项目不应该依赖于任何组织外部的快照版本依赖,由于快照版本的不稳定性,这样的依赖会造成潜在的危险。也就是说,即使项目构建今天是成功的,由于外部的快照版本依赖实际对应的构件随时可能变化,项目的构建就可能由于这些外部的不受控制的因素而失败。