开发工具: Maven 01、Maven入门

本文详细介绍Maven在项目构建中的作用,包括依赖管理、版本控制、生命周期管理、插件配置、工程聚合与继承,以及版本管理策略。涵盖从依赖解析到项目部署的全过程。

1. maven的作用

1.1 项目的依赖管理

传统的WEB项目中,必须将工程所依赖的jar包导入到工程中,导致工程变得很大
01
如果使用maven来构建,会发现同样的项目其大小会少很多
02
这是因为用maven构建的工程是不直接将jar包导入到工程中,而是通过在pom.xml文件中添加所需jar包的坐标,从而避免将jar直接引入进来。在工程需要用到jar包的时候,只要查找项目中的pom.xml文件,再通过pom.xml文件中的坐标,到一个专门用于”存放jar包的仓库”(maven仓库)中根据坐标找到这些jar包,再把这些jar包拿来运行。
03

1.2 项目的一键构建

项目往往都要经历编译、测试、运行、打包、安装 ,部署等一系列过程。

项目构建指的是项目从编译、测试、运行、打包、安装 ,部署整个过程都交给maven进行管理。

通过使用maven的一些命令可以轻松完成整个工作。
04

2. 依赖管理

2.1 坐标机制

  • groupId:以公司或者组织的官网的域名倒序来开头 + 项目名。如:com.baidu.oa

  • artifactId:项目中的某个模块,或者某个服务(主流)。如oa-auth服务。

  • version:工程的版本号

  • packaging:工程的打包方式。一般是war和jar两种方式。

  • classifier:定义某个工程的附属项目。几乎不用。

    坐标的意义:通过五个维度的坐标可以唯一定位一个项目的发布包

2.2 版本管理

version:1.0.0-SNAPSHOT 版本

  • 第一位是大版本。通常在整体架构有特别的升级或者变化时才会累加第一位大版本。
  • 第二位是小版本,一般如果加入一些新的功能或者模块,或者做了一些重构,就会累加第二位小版本。
  • 第三位是最小版本,一般如果是修复一些 bug,或者作出轻微的改动,就会累加第三位小版本。
  • SNAPSHOT:就是当前这个版本下的快照版本,代表代码正在开发或者测试中,可以试用,但是没有经过完善测试,不会承诺非常稳定。如果没有 SNAPSHOT,那么就是说已经经过完善测试,是可以发布的稳定版本。

2.3 依赖范围

maven 有三套 classpath。classpath 就是项目中用到的各种依赖的类,jvm 在运行的时候需要去 classpath 下面加载对应的类。

maven 在编译源代码的时候有一套 classpath;在编译测试代码以及执行测试代码的时候有一套 classpath;运行项目的时候有一套 classpath;依赖范围就是用来控制依赖包与这三种 classpath 的关系的。

简单来说,不同的依赖范围,会导致那个依赖包可能在编译、测试或者打包运行的时候,有时候可以使用,有时候不能够使用

  • compile:编译依赖范围,在编译,测试,运行时都需要。
  • test: 测试依赖范围,测试时需要。编译和运行不需要。如 Junit
  • runtime: 运行时依赖范围,测试和运行时需要。编译不需要。如 JDBC 驱动包
  • provided:已提供依赖范围,编译和测试时需要。运行时不需要。如 servlet-api
  • system:系统依赖范围。本地依赖,不在 maven 中央仓库。

2.4 依赖传递

1级依赖 \二级依赖compiletestprovidedruntime
compilecompile--runtime
testtest--test
providedprovided-providedprovided
runtimeruntime--runtime

举例1:junit 的依赖范围是 test,junit 对 A 的依赖范围是 compile,那么项目对 A 的依赖是 test。

举例2:项目依赖于A,A是 compile;A依赖于B,B 是 test;则项目对 B 的依赖范围是空。

2.5 依赖冲突的调节

Maven 会自动依赖调解,即对已给项目不同的版本选择一个版本来使用。

Maven 对依赖冲突采取的调节方式是 最短路径原则第一声明原则

A->B->C->X(1.0)
A->D->X(2.0)
由于只能引入一个版本的包,此时 Maven 按照最短路径选择导入x(2.0)
A->B->X(1.0)
A->D->X(2.0)
路径长度一致,那么哪个依赖在 pom.xml 里先声明,Maven 就采用哪个。

2.6 可选依赖

<optional>true</optional>

此时依赖传递失效,不会向上传递。很少使用。

如果 A 依赖于 B,B 依赖于 C,B 对 C 的依赖是 optional,那么 A 就不会依赖于 C。
反之,如果没有 optional,根据传递性依赖机制,A 会依赖于 C。

2.7 排除依赖

场景再现

X -> A -> C-1.0
X -> B -> D -> C-2.0
根据两大依赖原则,此时项目会采用 1.0 版本的 C。如果 D 调用了2.0 版本 C 中新的方法,此时由于项目中依赖的是 1.0 版本的C,该版本还没有此方法,那么项目就会报错。

显然,根据软件的兼容性,通常是引入最新版的依赖。此时,需要手动控制 maven 的依赖传递。

使用 mvn dependency:tree 进行依赖分析,此时的依赖路径树如下。

A
  --C-1.0
B
  --D
    --C-2.0

使用 exclusion 将 A 中的 1.0 版本所依赖的 C 给排除掉,即可解决问题

<dependency>
<groupId>A</groupId>
<artifactId>A</artifactId>
<version>1.0</version>
<exclusions>
		<exclusion>
			<groupId>C</groupId>
			<artifactId>C</artifactId>
		</exclusion>
</exclusions>
</dependency>

此时的依赖树如下:

A
B
  --D
    --C-2.0

3. 多仓库架构

Maven多仓库架构

4. nexus(V3.12)

4.1 常见仓库介绍

常见仓库

  • hosted:宿主仓库。这个仓库是用来让你把你公司内部的发布包部署到这个仓库里来,然后公司内的其他人就可以从 这个宿主仓库里下载依赖去使用。
  • proxy:代理仓库。代理了公司外部的中央仓库,国内目前流行的是阿里云镜像仓库,由阿里云去连接中央仓库。
  • group:仓库组。其实就是将各种宿主仓库、代理仓库全部组成一个虚拟的仓库组,然后项目只要配置依赖于一个仓库组,该项目就可以自动连接仓库组对应的各种仓库。
  • maven-central:maven 中央仓库的代理仓库。
  • maven-releases:该仓库是个宿主仓库。用于部署公司内部的 release 版本的发布包(类似于1.0.0,release 的意思就是你的工程已经经过了完善的测试,如单元测试,集成测试,QA测试,上生产环境使用了)。到这个仓库里面,供其他同事在生产环境依赖和使用。
  • maven-snapshots:该仓库是个宿主仓库,用于部署公司内部的 snapshot 版本的发布包到这个仓库里(如果你的某个工程还在开发过程中,测试还没结束,但是,此时公司里其他同事也在开发一些工程,需要依赖你的包进行开发和测试、联调,此时你的工程的版本就是类似 1.0.0-SNAPSHOT 这样的版本),供其他同事在开发和测试的时候使用。
  • 3rd party:该仓库是个宿主仓库,主要用来部署没法从公共仓库获取的第三方依赖包。比如说,你的项目依赖于第三方支付厂商的一个依赖包,但是那个依赖包不是开源的,是商业的包。那么你是没有办法从 maven 中央仓库获取的。此时,可能会自己手动从支付厂商那里获取到一个jar 包,下载之后上传到私服里来,就放这个仓库里。该仓库需要手动创建。
  • maven-public:仓库组。上面所有 release 仓库都在这个仓库组内

4.2 nexus仓库架构

nexus仓库架构

4.3 nexus的使用

4.3.1 激活 profile

有了私服后就需要将公司中的项目配置为强制从公司内的私服来下载,不允许走外网。这样可以统一管理。毕竟 nexus 私服本身也是代理了各种中央仓库,直接用 nexus 私服就可以了。

通常会在 settings.xml 配置文件中,为当前机器统一配置使用的私服仓库地址,而且一般都是直接用私服中的仓库组,在 settings.xml 中用 profiles 即可。

<profiles>
	<profile>
		<id>nexus</id>
      	<repositories>
        		<repository>
          			<id>nexus</id>
          			<name>Nexus </name>
      	  		<url>http://localhost:8081/nexus/content/groups/public</url>
          			<releases><enabled>true</enabled></releases>
          			<snapshots><enabled>true</enabled></snapshots>
        		</repository>
      	</repositories>
      	<pluginRepositories>
        		<pluginRepository>
          			<id>nexus</id>
          			<name>Nexus Plugin Repository</name>
      			<url>http://localhost:8081/nexus/content/groups/public</url>
          			<releases><enabled>true</enabled></releases>
          			<snapshots><enabled>true</enabled></snapshots>
        		</pluginRepository>
      	</pluginRepositories>
	</profile>
</profiles>

<activeProfiles>
	<activeProfile>nexus</activeProfile>
</activeProfiles>

激活对应的 profile,在项目执行构建的时候,就会将 profile 中的仓库配置应用到每个项目中去。

4.3.2 配置mirror

用 mirror 镜像机制,来强制要求所有对远程仓库的请求,全部通过镜像走私服。

<mirrors>
	<mirror>
		<id>nexus</id>
		<mirrorOf>*</mirrorOf>
		<url>http://localhost:8081/nexus/content/groups/public</url>
	</mirror>
</mirros>

将所有 repository 的 id 修改为 central,直接覆盖 maven 超级 pom 中的 morning 中央仓库,相当于此时唯一的远程中央仓库变成了我们自己配置的两个仓库。

然后将 url 配置全部改为 http://central,其实是没意义的一个 url,因为此时在需要从远程仓库下载依赖或者插件的时候,会从两个自己配置的 central 仓库去走,然后看 release 或者 snapshot 是否支持,如果支持,那么就会找镜像配置,由于设置了镜像匹配所有请求,所以所有请求都会走镜像,而镜像配置的是私服地址,所以相当于所有的请求都会走私服了。

4.3.3 权限管理

nexus 私服默认就是可以读的,不需要认证,公司局域网内的人都可以去配置之后拉取依赖。但是如果要进行部署的话,需要有一个专用的部署账号,通过账号认证,才能部署发布包到 nexus 私服。

nexus的权限使用的是经典的 RBAC 模型,默认有三个用户:

  • admin:管理员账号。默认密码是 admin123
  • deployment:开发账号。可以进行搜索和部署构建。3版本后已经被消除掉了
  • anonymous:匿名账号。没有给认证信息的账号,只能查看依赖。

5. 部署项目到私服

5.1 发布仓库配置

在pox.xml中设置

<distributionManagement>
	<repository>
		<id> nexus-releases</id>
		<name> Nexus Release Repository</name>
		<url>http://localhost:8081/nexus/content/repositories/releases/</url>
	</repository>
	<snapshotRepository>
		<id> nexus-snapshots</id>
		<name> Nexus Snapshot Repository</name>
		<url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
	</snapshotRepository>
</distributionManagement>

5.2 部署专业账号的配置

由于匿名用户只能下载依赖,不能部署发布包,因此如果要能够部署发布包,还需要在 settings.xml 文件里通过 <server> 元素配置使用专用的部署用户,来通过认证,进行发布包的部署。

<servers>
	<server>
		<id>nexus-releases</id>
		<username>deployment</username>
		<password>deployment123</password>
	</server>
	<server>
		<id>nexus-snapshots</id>
		<username>deployment</username>
		<password>deployment123</password>
	</server>
</servers>

5.3 自动部署

mvn clean deploy

执行此命令后,maven 会自动编译源代码、运行单元测试、打成 jar包、将 jar包安装到本地仓库、将 jar包部署到配置的远程私服仓库里面去。(清理、编译、测试、打包、安装、部署)。

5.4 手动部署

有些第三方厂商的jar包,比如特殊数据库厂商的 jdbc 驱动,或者某个厂商的支付相关的 api jar包,是不提供公网下载的,只能从他们那里拿到一个 jar包 ,此时就需要手动将其上传到3rd party仓库里面去。

比如:fastdfs_client_v1.24.jar

手动部署:

mvn deploy:deploy-file -DgroupId=com.csource -DartifactId=fastdfs-client-java -Dversion=1.24 -Dpackaging=jar 
-Dfile=F:\DevelopmentKit\fastdfs_client_v1.24.jar 
-Durl=http://localhost:8081/repository/3rd-party/ 
-DrepositoryId=nexus-3rd-party 

6.常用命令

04
maven通过执行一些简单命令即可实现项目构建中的各各过程

  • clear:删除target目录及内容
  • compile:将src/main/java下的文件编译为class文件输出到target目录下。
  • test:执行src/test/java下的单元测试类
  • package:对于java工程执行package将打成jar包,对于web工程将打成war包。
  • install:将maven打成jar包或war包发布到本地仓库
  • deploy:部署项目

这些常用命令也是maven默认的生命周期,而且当后面的命令执行时,前面的操作过程也都会自动执行。

7. 生命周期

一个完整的项目构建过程通常包括清理、编译、测试、打包、集成测试、验证、部署等步骤,Maven 从中抽取了一套完善的、易扩展的生命周期。Maven 的生命周期是抽象的,其中的具体任务都交由插件来完成。Maven 为大多数构建任务编写并绑定了默认的插件,如针对编译的插件:maven-compiler-plugin。用户也可自行配置或编写插件。

7.1 三套生命周期

maven 有三套完全独立的生命周期,clean,default 和 site。每套生命周期都可以独立运行,每个生命周期的运行都会包含多个 phase,每个 phase 又是由各种插件的goal来完成的,一个插件的 goal 可以认为是一个功能。每次执行一个生命周期,都会依次执行这个生命周期内部的多个 phase,每个 phase 执行时都会执行某个插件的 goal 完成具体的功能。且后面的phase依赖于前面的 phase。执行某个 phase 时,其前面的 phase会依顺序执行,但不会触发另外两套生命周期中的任何 phase。
22maven生命周期

7.1.1 clean生命周期

phasegoal
pre-clean执行清理前的工作
clean清理上一次构建生成的所有文件
post-clean执行清理后的工作

7.1.2 default生命周期

default 生命周期是最核心的,它包含了构建项目时真正需要执行的所有步骤。
default生命周期

7.1.3 site生命周期

phasegoal
pre-site
site生成项目的站点文档
post-site
site-deploy发布生成的站点文档

注意,maven 会从上到下执行每个 pharse 的 plugin goal。如果该阶段没有绑定任务 plugin,该阶段将什么都不执行。

7.2 不执行生命周期

但是有些命令是不执行任何一个生命周期的任何一个 phase。而是直接执行指定的插件的一个 goal。如:

mvn dependency:tree —> 直接执行dependency这个插件的tree这个goal

mvn deploy:deploy-file —> 直接执行deploy这个插件的deploy-file这个goal

8. 插件

插件地址

由于 maven 在执行过程中会执行生命周期中的各种 phase,通过在 pom.xml 中配置想要的插件,将某个第三方插件绑定到某个阶段的 phase。此后插件就会执行其 goal,实现想要的功能。

8.1 插件和goal

插件
输出结果:
输出结果

8.2 自定义绑定

用户可以根据需要将任何插件目标绑定到任何生命周期的阶段,如:将 maven-source-plugin的 jar-no-fork 目标绑定到 default 生命周期的 package 阶段,这样,以后在执行 mvn package 命令打包项目时,在 package 阶段之后会执行源代码打包,生成如:ehcache-core-2.5.0-sources.jar 形式的源码包。

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-source-plugin</artifactId>
			<version>2.1.1</version>
			<executions>
				<execution>
					<id>attach-sources</id>
					<phase>verify</phase>	<!-- 要绑定到的生命周期的阶段 -->
					<goals>
						<goal>jar-no-fork</goal>	<!-- 要绑定的插件的目标 -->
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

8.3 配置插件

Maven 插件高度易扩展,可以方便的进行自定义配置。如:配置 maven-compiler-plugin 插件编译源代码的JDK 版本为1.8:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

也可以对插件的各个目标进行更具体的配置。Configuring Plug-ins

8.4 插件仓库

跟其他构件一样,插件也是根据坐标存储在 Maven 仓库中。超级 POM 中 Maven 配置的默认插件远程仓库如下:

<pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
</pluginRepositories>

9. 工程聚合

9.1 提出问题

假设有三个模块:组织机构,权限管理,流程审批,且这三个模块都是一个人在开发,那么势必会有一些场景,比如说是三个模块互相之间有一些依赖,然后呢,其中一个被依赖的基础模块修改了代码,这个时候,我们要干嘛?

(1)要运行一下基础模块的单元测试套件,确保所有单元测试都可以通过

(2)要将修改代码后的模块部署到本地仓库

(3)其他模块要依赖更新版本的snapshot包,

(4)需要运行其他所有依赖这个基础模块的模块的单元测试套件,确保依赖它的其他模块没有任何问题

那如果是20个工程呢?显然这样处理是不合理的。

9.2 解决方案

maven 的解决方案是提供聚合功能。通过设定一个父工程,在父工程里聚合这些子工程。只要对父模块运行一次构建命令,maven 就会自动对这个父模块下面的所有子模块都运行相应的构建命令,这样就可以保证一键自动化构建所有的模块,而无需一个一个依次去构建。

<groupId>com.xxx.oa</groupId>
<artifactId>oa-parent</artifactId> <!-- 通常父工程以parent结尾 -->
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>		   <!-- 注意是个pom项目 -->	
<name>oa parent project</name>

<modules>
	<module>oa-organ</module>     <!-- 聚合的子项目 -->
	<module>oa-auth</module>
	<module>oa-flow</module>
</modules>

一般来说会将模块统一放在父工程的目录下,然后对 oa-parent 运行 mvn clean install,此时就会对 oa-parent 中所有的工程都进行统一的构建。

10.继承

10.1 继承

通常对同一个系统,需要将各个模块的工程,其中的基础性的、相同的依赖,全部放入一个父工程中,集中式统一约束所有模块的依赖,避免每个模块负责的人胡乱使用依赖版本,比如有的人用 spring 3,有的人用 spring 4。

maven 里面提供了一个继承功能,即可以将一个项目中所有模块通用的一些配置,比如依赖和插件,全部放在一个父工程中,然后子工程可以选择从父工程中要继承的依赖和插件。此时子工程只要声明 groupId 和artifactId 即可,不需要声明version版本号,因为 version 全部放在父工程中统一声明,强制约束所有子工程的相同依赖的版本要一样。

10.2 实现方式

在父工程中,直接用 dependencies 和 plugins 来声明依赖和插件的话,会强制子工程全部继承。

在父工程中使用 <dependencyManagement> 元素和 <pluginManagement> 元素来声明所有的依赖和插件时,当子工程声明了某个依赖或者插件的 groupId+artifactId,但是不指定版本时,就会从父工程继承那个依赖和插件。

父工程oa-parent

<dependencyManagement>          
        <dependencies>  
            <dependency>  
                <groupId>org.eclipse.persistence</groupId>  
                <artifactId>org.eclipse.persistence.jpa</artifactId>  
                <version>${org.eclipse.persistence.jpa.version}</version>  
                <scope>provided</scope>  
            </dependency>                
            <dependency>  
                <groupId>javax</groupId>  
                <artifactId>javaee-api</artifactId>  
                <version>${javaee-api.version}</version>  
            </dependency>  
            <dependcy>
            	....
            </depency>
        </dependencies>  
    </dependencyManagement>

子模块

	<!--继承父类-->  
	<parent>  
        <artifactId>oa-parent</artifactId>  
        <groupId>com.xxx.oa</groupId>  
        <version>1.0.0-SNAPSHOT</version>  
    </parent>  
        
        <modelVersion>4.0.0</modelVersion>  
        <artifactId>oa-organ</artifactId>  
        <packaging>jar</packaging>  
          
        <!--依赖关系-->  
     <dependencies>                 
        <dependency>  
            <groupId>com.fasterxml.jackson.core</groupId>  
            <artifactId>jackson-annotations</artifactId>  
        </dependency>            
        <dependency>  
            <groupId>org.eclipse.persistence</groupId>  
            <artifactId>org.eclipse.persistence.jpa</artifactId>  
            <scope>provided</scope>  
        </dependency>  
    </dependencies>  
</project>

11.版本约束

通过 <properties> 元素用户可以自定义一个或多个 Maven 属性,然后在 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>com.xxx.oa</groupId>
  <artifactId>oa-parent</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <name>oa parent project</name>
  <url>http://maven.apache.org</url>
  
  <modules>
      <!-- 模块都写在此处 -->
      <module>oa-auth</module>
      <module>oa-persist</module>
      <module>oa-another</module>
  </modules>
  
  <properties>
      <!-- 定义 spring版本号 -->
    <spring.version>4.0.2.RELEASE</spring.version>
    <junit.version>4.7</junit.version>
  </properties>
  
  <!-- 配置共有依赖 -->
  <dependencyManagement>
      <dependencies> 
      <!-- spring 依赖 -->
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
      <!-- junit 依赖 -->
      <dependency>
      	<groupId>junit</groupId>
     	 <artifactId>junit</artifactId>
      	<version>${junit.version}</version>
     	 <scope>test</scope>
    </dependency>
  </dependencies>
  </dependencyManagement>
</project>

以后每次修改,比如升级 Spring 版本时,就直接修改父工程的 properties 元素就可以了,所有的子工程会保持一致

12.使用import强制约束依赖方的版本号

12.1 提出问题

比如你基于 activiti 开发了一个流程审批的封装组件,这是一个不属于任何一个项目的基础的一个组件。其他人如果要用你的这个组件,肯定会在 depedencies 里面去定义和声明。但是,假设依赖方依赖了你的组件,你的组件依赖了 activiti 1.3 版本,而依赖方自己又声明了一个对 activiti 1.2 的依赖,此时根据依赖调解的原则,肯定是用他自己的旧版本。这就会造成依赖冲突。

12.2 解决方案

所以说,对于公司里一些重量级的组件,一般来说会采取下面的这种方式:

  1. 首先自己开发一个工程,那个工程是对外提供服务的
  2. 接着再开发一个 pom 包,后缀名为 bom。这个 pom 包中用 <dependencyManagement> 元素声明好对你的组件的依赖的版本号,还有你的组件使用的重要的第三方开源框架的版本号
  3. 依赖方依赖于那个工程的 pom 类型的包,再在 dependency 里面去声明自己要的依赖,此时版本就被约束了

依赖方

<dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>com.zhss.commons</groupId>
               <artifactId>commons-flow-bom</artifactId>
               <version>1.2.9</version> 
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
</dependencyManagement>

此时,假设依赖方要自己依赖一个过旧的开源框架的版本,就会有提示报警,不让他自行定义过旧版本的框架。

13.版本管理与版本控制

13.1 两者的区别

版本管理:通常指的是 maven 中的 version,项目的版本管理,随着整个功能的开发,bug 的修复,或者大的架构升级,通常来说,都会增加版本号。

版本控制:代码版本控制,git 中的多次提交,每次往 git 代码仓库提交一次代码,这个代码的版本就变更了一次,而 git 会自动记录下来每次代码版本的变更。因为每次提交代码,相当就是代码的版本就变更了一次。

maven与git的关系

13.2 maven中的版本管理

13.2.1 版本的类别

版本分为两种,一种是快照(snapshot)版本,一种是发布(release)版本

快照版本就是版本号后面加上 SNAPSHOT,比如 1.0.0-SNAPSHOT

发布版本就是版本号上不加 SNAPSHOT 的,比如 1.0.0

13.2.2 常见的版本迭代规则

版本通常而言是三位的。比如 1.0.0

1.0.0 中的第一个1指的是一个重大版本,比如已经基本成型的一个系统架构。
也有不少项目一开始是 0.0.1 这样的版本,这个指的就是这个系统刚开始起步,甚至都没能形成一个完整的东西出来,只是少数核心功能也出来了。
比如,用 springboot 开发的电商系统,一开始 1.0.0 这个版本包含了商城首页、购物车、订单系统、物流系统,就这么几个模块。如果某天改造和升级到微服务架构,把核心的几个模块改造成了 spring cloud 的微服务化。那么版本就变为了 2.0.0。大版本的变更很少见,一般几年才一次。

1.0.0 中的第二个0指的是一个次要版本,比如 1.1.0,那么就是加了一些新的功能或者开发了一些新的模块,或者做了一些较大的代码重构,技术升级改造。
比如,新增一个用户评论功能,此时就会进入一个版本,叫做 1.1.0-SNAPSHOT,在内部先开发和测试。接着发布 1.1.0 版本,此时这个版本就新增了一个用户评论的模块。

次要版本的变更一般就是对应各种需求,比如一个持续几周,或者一个月或者了几个月的大需求,对应一个次要版本

1.0.0中的第三个0指的是日常迭代的一个增量版本,比如 1.1.1,一般对应着修复了一个 bug,或者对某些代码做了轻微的优化或者调整。
比如,突然发现购物车这块有个 bug,修复这个 bug 后版本号就是 1.1.1-SNAPSHOT,这个 bug 的修复在内部先开发和测试,让产品经理来验收。最后发布,此时版本变成了 1.1.1。此时代码就是包含了一个 bug 的修复。

增量版本一般就是一个大需求中的多个小需求,每个小需求可以给一个增量版本,或者是紧急 fix 了一个 bug,那么就增加一个增量版本。

13.2.3 其他常见的命名版本

1)beta版本

maven 的标准版本规范里,还包含了一个 1.0.0-beta-1。

这里的 beta 代表的是公开测试版,就是对外提供试用的。

最后一个1代表的是增量版本的一个里程碑,就是在进行某个 bug 修复,或者功能调整的时候,是分为多个步骤,也就是多个里程碑的,那么此时可能就会对应了 1.1.1-beta-1,1.1.1-beta-2,1.1.1-beta-3,这样好几个里程碑版本,每个里程碑版本代表完成了一个小阶段。

2)alpha版本

alpha 也可以理解为实验版本,也就是内部测试版本,就是给自己公司内部用的。

3)rc版本

预发布版本,基本就比较稳定了,但是还不是最终发布版,可以尝试下载使用了。

13.3 从SNAPSHOT到RELEASE

通常,在开发的时候,版本都是 SNAPSHOT 版本。

如果要将 snapshot 发布发布为 release 版本,至少需要满足几个条件:

(1)所有的单元测试全部通过

(2)pom.xml 中没有任何 snapshot 版本的依赖

(3)pom.xml 中没有任何 snapshot 版本的插件

(4)这个版本的代码已经全部提交到对应的 git 分支上了,同时一定从分支 merge 到了 master 主干分支上去,并且给 master 分支打上了一个 tag,这个 tag 就是对主干分支这一时刻代码的一个标签,这样任何时候都可以回退到主干分支的任何一个 tag 对应的版本的代码上去

此时一个 release 版本就完成了,然后就继续升级到下一个版本的 snapshot 版本上去,继续进行开发和测试。

13.4 版本与主干、分支以及标签

通常情况下一个版本对应一个分支,会在分支中进行各种开发+测试,搞定之后就会 merge 到主干。

然后就会给这个时候的主干打一个 tag 作为主干在这个版本的代码,以后任何时候都可以使用主干的某个 tag,也就是某个时刻的某个版本的代码。

参考书籍《Maven in Action》

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值