关于maven中版本控制问题
之前我们说过Maven的版本分为快照和稳定版本,快照版本使⽤在开发的过程中,⽅便于团队内部交流学习。⽽所说的稳定版本,理想状态下是项⽬到了某个⽐较稳定的状态,这个稳定包含了源代码和构建都要稳定。
maven中的仓库分为两种,snapshot快照仓库和release发布仓库。snapshot快照仓库⽤于保存开发过程中的不稳定版本,release正式仓库则是⽤来保存稳定的发⾏版本。定义⼀个组件/模块为快照版本,只需要在pom⽂件中在该模块的版本号后加上-SNAPSHOT即可(注意这⾥必须是⼤写)
maven2会根据模块的版本号(pom⽂件中的version)中是否带有-SNAPSHOT来判断是快照版本还是正式版本。
如果是快照版本,那么在mvn deploy时会⾃动发布到快照版本库中,会覆盖⽼的快照版本,⽽在使⽤快照版本的模块,在不更改版本号的情况下,
直接编译打包时,maven会⾃动从镜像服务器上下载最新的快照版本。如果是正式发布版本,那么在mvn deploy时会⾃动发布到正式版本库中,
⽽使⽤正式版本的模块,在不更改版本号的情况下,编译打包时如果本地已经存在该版本的模块则不会
主动去镜像服务器上下载。
使⽤SNAPSHOT具有透明性,变更会直接⽣效,但这样会被依赖者带来不稳定性和不确定性,所以不应该被滥⽤
补充:
maven打包本地jar包
对于服务,biz是没有版本这⼀说的,运⾏的永远都是最新的版本,但是对于API是有版本的。
API提供接⼝,biz提供服务,⼀般来说,版本往上升的话,API只增不减,⽽biz也随之增加实现,如果新版本删除了某个接⼝及实现,⽽调⽤者使⽤old version的依赖,尝试调⽤这个接⼝,就会调不到产⽣错误。
Maven中建⽴的依赖管理⽅式基本已成为Java语⾔依赖管理的事实标准,Maven的替代者Gradle也基本沿⽤了Maven的依赖管理机制。在Maven依赖管理中,唯⼀标识⼀个依赖项是由该依赖项的三个属性构成的,分别是groupId、artifactId以及version。这三个属性可以唯⼀确定⼀个组件(Jar包或者War包)。
其实在Nexus仓库中,⼀个仓库⼀般分为public(Release)仓和SNAPSHOT仓,前者存放正式版本,后者存放快照版本。如果在项⽬配置⽂件中(⽆论是adle还是l)指定的版本号带有’-SNA
PSHOT’后缀,⽐如版本号为’Junit-4.10-SNAPSHOT’,那么打出的包就是⼀个快照版本。
快照版本和正式版本的主要区别在于,本地获取这些依赖的机制有所不同。假设你依赖⼀个库的正式版本,构建的时候构建⼯具会先在本次仓库中查是否已经有了这个依赖库,如果没有的话才会去远程仓库中去拉取。所以假设你发布了Junit-4.10.jar到了远程仓库,有⼀个项⽬依赖了这个库,它第⼀次构建的时候会把该库从远程仓库中下载到本地仓库缓存,以后再次构建都不会去访问远程仓库了。所以如果你修改了代码,向远程仓库中发布了新的软件包,但仍然叫Junit-4.10.jar,那么依赖这个库的项⽬就⽆法得到最新更新。你只有在重新发布的时候升级版本,⽐如叫做Junit-4.11.jar,然后通知依赖该库的项⽬组也修改依赖版本为Junit-4.11,这样才能使⽤到你最新添加的功能。
这种⽅式在团队内部开发的时候会变的特别蛋痛。假设有两个⼩组负责维护两个组件,example-service和example-ui,其中example-ui项⽬依赖于example-service。⽽这两个项⽬每天都会构建多次,如果每次构建你都要升级example-service的版本,那么你会疯掉。这个时候SNAPSHOT版本就派上⽤场了。每天⽇常构建时你可以构建example-service的快照版本,⽐如example-service-1.0-SNAPSHOT.jar,⽽example-ui依赖该快照版本。每次example-ui构建时,会优先去远程仓库中查看是否有最新的example-service-1.0-SNAPSHOT.jar,如果有则下载下来使⽤。即使本地仓库中已经有了example-service-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就是那4种类型之⼀。如果配置间隔时间更新,可以写作interval:XX(XX是间隔分钟数)。daily配置是默认值。
⽽在Gradle,可以设置本地缓存的更新策略。
onfigurations.all {
// check for updates every build
resolutionStrategy.cacheChangingModulesFor  0,'seconds'
}
当然也可以按照分钟或者⼩时来设置.
configurations.all {
resolutionStrategy.cacheChangingModulesFor  10, ‘minutes'
}
configurations.all {
resolutionStrategy.cacheChangingModulesFor  4, ‘hours'
}
所以⼀般在开发模式下,我们可以频繁的发布SNAPSHOT版本,以便让其它项⽬能实时的使⽤到最新的功能做联调;当版本趋于稳定时,再发布⼀个正式版本,供正式使⽤。当然在做正式发布时,也要确保当前项⽬的依赖项中不包含对任何SNAPSHOT版本的依赖,保证正式版本的稳定性。
⼀、如何衡量项⽬的稳定状态呢?
1. 所有的⾃动化测试应当全部通过
2. 项⽬没有配置任何快照版本的依赖
3. 项⽬没有配置任何快照版本的插件
4. 项⽬所包含的代码都已经全部提交到了版本控制系统中
5.我们应当再⼀次执⾏Maven构建,以确保项⽬的状态是OK的
6. 我们将这⼀次变更提交到版本控制的主⼲中,并打上标签
只有满⾜了上述6个条件, 我们就可以将这⼀个快照版本更新⾄发布版本
⼆、在开发的过程中,版本号要如何进⾏变更呢?Maven是否有潜在的约定?
我们在开发的过程中,下载jar包的时候经常会发现某个jar类似这样:1.2.3-beat-4.jar
多么复杂的⼀个名称。。。下⾯来解释⼀下,这⾥每个数字的含义:
“ 1 ” :  表⽰该版本的第⼀个重⼤版本
“ 2 ” :  表⽰这是基于重⼤版本的第⼆个次要版本
“ 3 ” :  表⽰该次要版本的第三个增量
" beat-4" : 表⽰该增量的⼀个⾥程碑
⽤⼀个图来描述:
< 主版本 >  ------  < 次版本 > ------ < 增量版本 > ------ < ⾥程碑版本 >
主版本:表⽰了项⽬的重⼤架构变更  struts1 --  struts2
次版本:表⽰较⼤范围的功能增加和变化  Nexus1.5 ----  Nexus1.4
增量版本:⼀般表⽰重⼤Bug修复
⾥程碑版本:指某⼀个版本的⾥程碑  *.*-alpha-1  *.*-beat-1
看起来有点⿇烦啊,但是在⼀般来说,我们只会声明主版本和次版本,增量版本和⾥程碑版本就不⼀定了。
注:maven中约定的版本次序:
对于主版本、次版本、增量版本来说他们的⽐较是基于数字的,因此:1.5>1.4>1.3>1.2.11>1.2.8
对于⾥程碑版本来说,⽐较是基于字符串的,因此:1.5>1.4>1.3>1.2.3>1.2.11
三、主⼲、分⽀、标签
上⾯的笔记中提到了主⼲和标签,到底如何理解主⼲、分⽀、标签呢?
主⼲: 项⽬开发代码的主体,是从项⽬开始到当前都处于活动的状态,从这⾥可以获得项⽬最新的源代码和⼏乎所有的变更历史
分⽀: 从主⼲的某个点分离出来的代码拷贝,通常可以在不影响主⼲的前提下,在这⾥进⾏重⼤的bug修复或者实验性质的开发,如果达到了预期的⽬的,通常将这⾥的变更合并到主⼲中去。
标签: ⽤来标识主⼲或者分⽀的某个点的状态,以代表项⽬的某个稳定状态,也就是通常说的发布状态
这三个元素,可以清晰的描述出项⽬的版本管理,⽽且也已经成了⼀个默认的⾏业标准。
四、⾃动化版本发布
⽤久了⼿动版本发布之后,我们会想到能否进⾏⾃动化的发布版本,答案是肯定的,这将引⼊⼀个新的插件:Maven Release Plugin
通过⼀些必要的配置,就可以完成版本发布
Maven Release Plugin 插件简介:
该插件主要有三个⽬标:release: prepare,  release: rollback,  release: perform (什么是插件⽬标),在介绍分⽀⾃动化的时候还会引⼊branch ⽬标
①release:prepare  准备版本发布,依次执⾏下列操作
1. 检查项⽬是否有未提交的代码
2. 检查项⽬是否有快照版本依赖
3. 根据⽤户的输⼊将快照版本升级为发布版
4. 将POM中的SCM信息更新为标签地址
5. 基于修改后的POM执⾏maven构建
6. 提交POM变更
7. 基于⽤户输⼊为代码打标签
8. 将代码从发布版升级为新的快照版
9.提交POM变更
release: rollback
回退release: prepare所执⾏的操作。将POM回退⾄release:prepare之前的状态,并提交。
注:该步骤不会删除release:prepare⽣成的标签,需要⽤户⼿动删除
release: perform
执⾏版本发布
签出release:prepare⽣成的标签中的源代码,并在此基础上执⾏mvn deploy命令打包并部署构件⾄仓库
注:要为项⽬发布版本,⾸先需要为其添加正确的版本控制系统信息(这是因为Maven Release Plugin需要知道版本控制系统的主⼲、标签等地址后才能执⾏相关操作)
②分⽀的⾃动化创建
先看⼀下Maven Release Plugin 的branch⽬标能帮助我们做哪些事情
1. 检查本地有⽆未提交的代码
2. 将分⽀更改POM的版本,如:1.1.0-SNAPSHOT改成1.1.1-SNAPSHOT
3. 将POM中的SCM信息更新为分⽀地址
4. 提交以上更改
5. 将主⼲代码复制到分⽀中
6. 修改本地代码使其回退到分⽀前的版本(⽤户可以指定新的版本)
7. 提交本地更改
注:此时也必须正确的配置SCM信息
五、代码安全
代码安全是我们⽐较关⼼的⼀个问题,⽐如说,当我们从中央仓库下载第三⽅构件的时候,我们可能要去验证这些⽂件的合法性,或者当我们发布项⽬后,使⽤我们项⽬的⼈也要验证
引⼊⼀个新的插件:Maven GPG Plugin ⾃动的完成签名
在使⽤Maven GPG Plugin之前,⾸先需要确定GPG是可⽤的,然后再POM中配置插件即可
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
然后使⽤⼀般的Maven命令签名并发布项⽬构件
$mvn clean deploy -Dgpg.passphrase=****
注:
1. 如果不提供 -Dgpg.passphrase参数,运⾏时就会要求输⼊密码

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。