一、快照版本SNAPSHOT和发布版本RELEASE区别
快照版本SNAPSHOT和发布版本RELEASE区别-CSDN博客
在使⽤maven过程中,我们在开发阶段经常性的会有很多公共库处于不稳定状态,随时需要修改并发布,可能⼀天就要发布⼀次,遇到bug时,甚⾄⼀天要发布N次。我们知道,maven的依赖管理是基于版本管理的,对于发布状态的artifact,如果版本号相同,即使我们内部的镜像服务器上的组件⽐本地新,maven也不会主动下载的。如果我们在开发阶段都是基于正式发布版本来做依赖管理,那么遇到这个问题,就需要升级组件的版本号,可这样就明显不符合要求和实际情况了。但是,如果是基于快照版本,那么问题就⾃热⽽然的解决了,⽽maven已经为我们准备好了这⼀切。
maven中的仓库分为两种,snapshot快照仓库和release发布仓库。snapshot快照仓库⽤于保存开发过程中的不稳定版本,release正式仓库则是⽤来保存稳定的发⾏版本。定义⼀个组件/模块为快照版本,只需要在pom⽂件中在该模块的版本号后加上-SNAPSHOT即可(注意这⾥必须是⼤写),如下:
<artifactId>bty-catering-platform-api</artifactId>
<version>1.1.2-SNAPSHOT</version>
<name>api</name>
<description>api</description>
如果是快照版本,那么在mvn deploy时会⾃动发布到快照版本库中,会覆盖⽼的快照版本。在使⽤快照版本的模块,在不更改版本号的情况下,直接编译打包时,maven会⾃动从镜像服务器上下载最新的快照版本。
如果是正式发布版本,那么在mvn deploy时会⾃动发布到正式版本库中,⽽使⽤正式版本的模块,在不更改版本号的情况下,编译打包时如果本地已经存在该版本的模块则不会主动去镜像服务器上下载.
所以,我们在开发阶段,可以将公⽤库的版本设置为快照版本,⽽被依赖组件则引⽤快照版本进⾏开发,在公⽤库的快照版本更新后,我们也不需要修改pom⽂件提示版本号来下载新的版本,直接mvn执⾏相关编译、打包命令即可重新下载最新的快照库了,从⽽也⽅便了我们进⾏开发。
⽬前在JAVA的世界中,maven已经成为事实上的构建标准,很多开源库的管理构建也是基于maven的,maven本身的学习曲线⽐较陡峭,遵循“约定优于配置”的理念,maven存在很多约定。
本次我先描述下,关于版本的定义的选择,SNAPSHOT or RELEASE?
版本之争
在maven的约定中,依赖的版本分为两类——SNAPSHOT和RELEASE。SNAPSHOT依赖泛指以SNAPSHOT为结尾的版本号,例如1.0.1-SNAPSHOT。除此之外,所有⾮-SNAPSHOT结尾的版本号则都被认定为RELEASE版本,即正式版,虽然会有beta、rc之类说法,但是这些只是软件⼯程⻆度的测试版,对于maven⽽⾔,这些都是RELEASE版本。既然Maven提供了这两类版本号,那么他们之前的优劣势是什么?分别在什么场景下使⽤?
解读SNAPSHOT
同⼀个SNAPSHOT版本的依赖可以多次发布(deploy)到仓库中,也就是说同⼀个SNAPSHOT版本的依赖可以在仓库中存在多份,每⼀份都是代码在某⼀个特定时间的快照,这也是SNAPSHOT的含义。SNAPSHOT不是⼀个特定的版本,⽽是⼀系列的版本的集合,其中HEAD总是指向最新的快照,对外界可⻅的⼀般也是最新版,这种给⼈的假象是新的覆盖了⽼的,从⽽使得使⽤SNAPSHOT依赖的客户端总是通过重新构建(有时候需要-U强制更新)就可以拿到最新的代码。例如:A-->B-1.3.8-SNAPSHOT(理解为A依赖了B的1.3.8-SNAPSHOT版本),那么B-1.3.8-SNAPSHOT更新之后重新deploy到仓库之后,A只需要重新构建就可以拿到最新的代码,并不需要改变依赖B的版本。由此可⻅,这样达到了变更传达的透明性,这对于开发过程中的团队协作的帮助不⾔⽽喻。
SNAPSHOT之殇
SNAPSHOT版本的依赖因为存在变更传达的透明性的优势⽽被赏识,甚⾄被“溺爱”,有很多团队索性直接使⽤SNAPSHOT到⽣产环境中,这样对于变更直接⽣效,很⽅便。但是作为技术⼈员的我们其实应该很严谨地看待变更传达的透明性,变更就意味着⻛险,透明性更是把⻛险彻底隐藏了起来,⽣产环境中存在这样的现象更是⼼惊胆战。例如:A-->B.1.0.3-SNAPSHOT,B对⼀个A使⽤的功能实现进⾏了调整,直接发布到仓库,A重新构建或许就会失败,更糟糕的是构建成功,运⾏时异常。这个时候A甚⾄完全没有代码变更就突然失败了,会带来更多的困惑这也是maven经常遭⼈诟病的⼀个因素,对于同⼀份代码,构建结果却不具备确定性,让很多⼈沮丧。当然这个不完全是因为依赖的问题,也有maven插件的问题,maven之前的版本寻找插件策略的⽅式也存在不确定性,maven在版本2的时候,会去寻找最新的插件版本(如果没配置的话)来执⾏构建,经常会找到SNAPSHOT版本的插件,所以依赖了⼀个不稳定的插件来执⾏构建,不确定性就⼤⼤增加。不过maven在3版本就改变了这个策略,会寻找最新稳定版的插件来执⾏构建,使得构建具备了确定性,稳定性也好多了。说明maven本身也在SNAPSHOT的问题上狠狠摔了⼀跤。
归根到底,这些问题的根源就是SNAPSHOT是变化的,是不稳定的,⽽应⽤(软件)依赖于变化并且不稳定的SNAPSHOT的依赖会导致⾃身也在变化和不稳定中,这是稳定性的⼀个⼤忌,依赖不稳定的服务或者依赖,上述的maven2的问题就是⼀个典型反例。
RELEASE简介
RELEASE版本和SNAPSHOT是相对的,⾮SANPSHOT版本即RELEASE版本,RELEASE版本是⼀个稳定的版本号,看清楚咯,是⼀个,不是⼀系列,可以认为RELEASE版本是不可变化的,⼀旦发布,即永远不会变化。
虽然RELEASE版本是稳定不变的,但是仓库还是有策略让这个原则变得可配置,有的仓库会配置成redeploy覆盖,这样RELEASE版本就变成SNAPSHOT了,伪装成RELEASE的SNAPSHOT,会让问题更费解和棘⼿,我⼀般称这类⼈为“挖坑专家”。
记住,RELEASE⼀旦发布,就不可改变。
如何选择
那么什么时候使⽤SNAPSHOT?什么时候使⽤RELEASE?这个可以从他们各⾃的特性上来看,SNAPSHOT版本的库是⼀直在变化的,或者说随时都会变化的,这样虽然可以获取到最新的特性,但是也存在不稳定因素,依赖⼀个不稳定的模块或者库会让模块⾃身也变得不稳定,尤其是⾃身对被依赖模块的变化超出掌控的情况。即使可以掌控被依赖模块的变化,也会带来不稳定的因素,因为每次变更都有引⼊bug的可能性。如果这么说,那么我们是不是要摒弃SANPSHOT了呢?答案肯定是否定的。
想象下,什么情况下,模块会⼀直变化或者变化⽐较剧烈?开发新特性的时候,所以对于团队之间协同开发的时候,模块之间出现依赖,变化会⾮常剧烈,如模块A依赖模块B,模块A必然需要最⽅便地获取模块B的特性,在开发期间,⽅便性⽐稳定性更重要。可以反证下,假设模块B使⽤RELEASE版本1.0.0,模块A依赖1.0.0,现在模块A出现了bug,需要修复下,那么A就要提供⼀个版本号1.0.1,这样所有依赖A模块都需要更新版本号,因为开发期间这种事情是如此多,所以会带来巨变。反观SNAPSHOT⽅案,如果模块B的版本是1.0.0-SNAPSHOT,模块A完全不需要修改版本号即可获取模块B的新特性。当开发进⼊预发布阶段,为了⽣产环境的稳定性,依赖应该是RELEASE版本,因为此时SNAPSHOT版本的模块⾃动获取新特性的特点恰恰会造成⽣产环境的不稳定性,⽣产环境上,稳定性重于⼀切。
现在已经很明确了,在开发期间,活跃模块的版本号使⽤SNAPSHOT,在⽣产期间,依赖RELEASE版本模块。貌似,我们找到了银弹,不过这个只是理想状态,即所有的模块的版本都在⾃⼰的掌控或者间接掌控下,只有这样你才能影响对应模块的版本号。往往是理想很丰满,现实却很⻣感,如果你依赖的⼀个模块只有SNAPSHOT版本,并且该模块也很活跃,最⽆助的是模块的维护⼈不理会你的请求,那么是否就没辙了,只能把应⽤构建在不稳定模块上呢?介绍⼀款maven插件——versions,这是⼀个⾮常强⼤的版本管理插件,其中有个对依赖版本加锁的特性——lock-snapshots,并且提供了参数可以控制锁定的依赖,就可以实现对特定的SNAPSHOT模块锁定版本,执⾏的命令如下:mvn versions:lock-snapshots -DincludesList="groupId:artifactId:type:classier:version",执⾏这个命令之后,对应的版本号会变化,⽐如1.0.0-SNAPSHOT会变成1.0.0.20090327.172306-4,即完成了锁定,此时这个SNAPSHOT就变成了固定⼩版本的稳定版本,不会在变化了,也相当于正式版的功能了。当然以后也可以解锁,详细请看对应⽂档。
二、Nexus的仓库与仓库组
Maven仓库管理器-Nexus_nexus - maven管理器介绍-CSDN博客
Nexus的仓库与仓库组_nexus group-CSDN博客
Nexus(也称Nexus私服)是Maven的仓库管理器,你可以使用Gradle或者Maven,从远程仓库或者本地仓库下载你所需要的构件
Nexus的 仓库类型 主要分为以下四种:
group: 仓库组(用来合并多个hosted/proxy仓库,当你的项目希望在多个repository使用资源
时就不需要多次引用了,只需要引用一个group即可)
hosted:宿主(通常我们会部署自己的构件到这一类型的仓库。比如公司的第二方库)
proxy:代理代理(它们被用来代理远程的公共仓库,如maven中央仓库。)
virtual:虚拟
依赖流程图
Nexus私服的优势
如果没有私服,我们所需的所有构件都需要通过maven的中央仓库和第三方的Maven仓库远程提供了,假如没网了或者出现其他情况,我们怎么办?
这也就是说我们对中央仓库的依赖性太高了。而搭建一个Nexus服务器相当于我们在我们本地局域网搭建了一个类似中央仓库的服务器,我们可以将中央仓库的一些资料下载到私服务器上,然后平时我们的gradle或maven项目就是直接访问局域网内的私服即可,既节省了网络带宽也会加速项目搭建的进程,这样对我们开发来说,对公司来说都是非常好的选择,而且可以方便对公司内部开发包的管理
宿主类型仓库
release库:发布内部模块中的releas模块的仓库,用来管理发布版本构建
snapshot库:发布内部模块中snapshot模块的仓库,用来管理快照版本的构建,snapshot意味快照,如果项目版本是snaphost,意味着项目在开发中,还不稳定