Maven快照
Maven 构建出来的 jar 包分为快照版本(Snapshot)和发布版本(Release),那么为什么有如此区分呢?
在实际开发中,我们经常遇到这样的场景,比如A服务依赖于B服务,A和B同时开发,B在开发中发现了BUG,修改后,将版本由1.0升级为2.0,那么A必须也跟着在 pom.xml 中进行版本升级。过了几天后,B又发现了问题,进行修改后升级版本发布,然后通知A进行升级...如此反复,A就有点抓狂,团队矛盾开始升级,可以说这是开发过程中的版本不稳定导致了这样的问题。
Maven 已经替我们想好了解决方案,就是使用 Snapshot 版本,在开发过程中B发布的版本标志为 Snapshot 版本,A进行依赖的时候选择 Snapshot 版本,那么每次B发布的话,会在私服仓库中,形成带有时间戳的 Snapshot 版本,而A构建的时候会自动下载B最新时间戳的 Snapshot 版本!
对于版本,如果 Maven 以前下载过指定的版本文件,比如说 data-service:1.0,Maven 将不会再从仓库下载新的可用的 1.0 文件。若要下载更新的代码,data-service 的版本需要升到1.1。 在快照的情况下,每次重新构建项目的时候,Maven 将自动获取最新的快照(data-service:1.0-SNAPSHOT)。
项目快照 vs 版本
在Maven依赖管理中,唯一标识依赖是三个属性,分别是 groupId、artifactId以及version。这三个属性可以唯一确定一个组件(Jar包或者War包)。
其实在 Maven 仓库中,一般情况下,一个仓库会分为 public(Release)仓和 SNAPSHOT 仓,前者存放正式版本,后者存放快照版本。如果在项目配置文件中 pom.xml 指定的版本号带有"-SNAPSHOT"后缀,比如版本号为"JUnit-4.10-SNAPSHOT",那么打出的包就是一个快照版本。
快照版本和正式版本的主要区别在于,本地获取这些依赖的机制有所不同。假设你依赖一个库的正式版本,构建的时候构建工具会先在本次仓库中查找是否已经有了这个依赖库,如果没有的话才会去远程仓库中去拉取。所以假设你发布了JUnit-4.10.jar到了远程仓库,有一个项目依赖了这个库,它第一次构建的时候会把该库从远程仓库中下载到本地仓库缓存,以后再次构建都不会去访问远程仓库了。所以如果你修改了代码,向远程仓库中发布了新的软件包,但仍然叫JUnit-4.10.jar,那么依赖这个库的项目就无法得到最新更新。你只有在重新发布的时候升级版本,比如叫做JUnit-4.11.jar,然后通知依赖该库的项目组也修改依赖版本为JUnit-4.11,这样才能使用到你最新添加的功能。
这种方式在团队内部开发的时候令人抓狂,痛不欲生。假设有两个小组负责维护两个组件,web-dao和web-service,其中 web-service 项目依赖于 web-dao。而这两个项目每天都会构建多次,如果每次构建你都要升级 web-dao 的版本,那么你会疯掉。这个时候 SNAPSHOT 版本就派上用场了。每天日常构建时你可以构建 web-dao 的快照版本,比如 web-dao-1.0-SNAPSHOT.jar,而 web-service 依赖该快照版本。每次 web-service 构建时,会优先去远程仓库中查看是否有最新的 web-dao-1.0-SNAPSHOT.jar,如果有则下载下来使用。即使本地仓库中已经有了web-dao-1.0-SNAPSHOT.jar,它也会尝试去远程仓库中查看同名的 jar 是否是最新的。有的人可能会问,这样不就不能充分利用本地仓库的缓存机制了吗?别着急,Maven 比我们想象中的要聪明。在配置 Maven 的 Repository 的时候中有个配置项,可以配置对于 SNAPSHOT 版本向远程仓库中查找的频率。频率共有四种,分别是 always、daily、interval、never。当本地仓库中存在需要的依赖项目时,always是每次都去远程仓库查看是否有更新,daily是只在第一次的时候查看是否有更新,当天的其它时候则不会查看;interval允许设置一个分钟为单位的间隔时间,在这个间隔时间内只会去远程仓库中查找一次,never是不会去远程仓库中查找(这种就和正式版本的行为一样了)。
Maven版本的配置方式为:
<repository>
<id>myRepository</id>
<url>...</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>XXX</updatePolicy>
</snapshots>
</repository>
其中,updatePolicy属性的值可以配置为上面所说的四种类型,默认值是daily。如果配置间隔时间更新,可以写作interval:XX(XX是间隔分钟数)。
所以,一般在开发模式下,我们可以频繁的发布SNAPSHOT版本,以便让其它项目能实时的使用到最新的功能做联调。当版本趋于稳定时,再发布一个正式版本,供正式使用。当然,在做正式发布时,也要确保当前项目的依赖项中不包含对任何SNAPSHOT版本的依赖,保证正式版本的稳定性。