DLancerC

Maven 学习笔记(三)

Maven 中, 任何一个依赖,插件或者项目构建的输出, 被称为构件. 利用坐标机制, Maven 会使用一个统一位置来存储所有Maven项目共享的构建, 就是 Maven 仓库. 对应一个构建在Maven仓库的路径一般为 groupId/artifactId/version/artifactId-version[-classifier].packaging

Maven 仓库的分类

  • 本地仓库
    本机用户目录下的.m2/repository
    可以通过修改配置文件(~/.m2/settings.xml)自定义本地仓库目录, 也可以修改全局配置文件($MAVEN_HOME/conf/settings.xml)

    1
    2
    3
    <settings>
    <localRepository>customer Path </localRepository>
    </settings>
  • 远程仓库
    包括中央仓库和私服, 可以修改配文件或者POM文件添加远程仓库地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    <settings>
    ...
    <profiles>
    <profile>
    <!-- profile配置的唯一标识符 -->
    <id></id>
    <activation>
    <!--profile默认是否激活的标识 -->
    <activeByDefault>false</activeByDefault>
    <!--检测jdk版本,与设置一样profile被激活。 -->
    <jdk>1.7</jdk>
    <!--匹配的操作系统属性被检测到,profile被激活 -->
    <os>
    <!--激活profile的操作系统的名字 -->
    <name>Windows XP</name>
    <!--激活profile的操作系统所属家族(如 'windows') -->
    <family>Windows</family>
    <!--激活profile的操作系统体系结构 -->
    <arch>x86</arch>
    <!--激活profile的操作系统版本 -->
    <version>5.1.2600</version>
    </os>
    <!--如果Maven检测到某一个属性(其值可以在POM中通过${名称}引用),其拥有对应的名称和值,Profile就会被激活。-->
    <!--如果值字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段 -->
    <property>
    <!--激活profile的属性的名称 -->
    <name>mavenVersion</name>
    <!--激活profile的属性的值 -->
    <value>2.0.3</value>
    </property>
    <!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。-->
    <file>
    <!--如果指定的文件存在,则激活profile。 -->
    <exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</exists>
    <!--如果指定的文件不存在,则激活profile。 -->
    <missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</missing>
    </file>
    </activation>
    <!--对应profile的扩展属性列表。Maven属性和Ant中的属性一样,可以用来存放一些值。这些值可以在POM中的任何地方使用标记${X}来使用,这里X是指属性的名称。-->
    <!--属性有五种不同的形式,并且都能在settings.xml文件中访问。 -->
    <!--1. env.X: 在一个变量前加上"env."的前缀,会返回一个shell环境变量。例如,"env.PATH"指代了$path环境变量(在Windows上是%PATH%)。 -->
    <!--2. project.x:指代了POM中对应的元素值。 -->
    <!--3. settings.x: 指代了settings.xml中对应元素的值。 -->
    <!--4. Java System Properties: 所有可通过java.lang.System.getProperties()访问的属性都能在POM中使用该形式访问, -->
    <!-- 如/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre。 -->
    <!--5. x: 在<properties/>元素中,或者外部文件中设置,以${someVar}的形式使用。 -->
    <properties>
    <!-- 这个profile被激活,则属性${user.install}就可以被访问了 -->
    <user.install></user.install>
    </properties>
    <!-- POM文件修改在 project 标签内添加 -->
    <repositories>
    <repository>
    <!-- 仓库ID, 唯一的, Maven自带的中央仓库使用的ID是central, 如果添加的其它仓库也使用了该ID, 会覆盖 -->
    <id></id>
    <name></name>
    <url></url>
    <!-- 是否支持发布版本下载 -->
    <releases>
    <enabled>true</enabled>
    <!--
    配置更新频率, 默认daily, 每天检查一次.
    never 从不检查更新
    always 每次构建时检查更新
    interval: X 每隔X分钟检查更新
    -->
    <updatePolicy></updatePolicy>
    <!--
    配置检查检验和文件策略, 构建时下载构件出现校验和验证的失败, 默认为warn, 会输出警告信息
    fail Maven遇到校验和验证的失败, 让构建失败
    ignore Maven完全忽略校验和验证的失败错误
    -->
    <checksumPolicy></checksumPolicy>
    </releases>
    <!-- 是否支持快照版本下载 -->
    <snapshots>
    <enabled>false</enabled>
    </snapshots>
    <layout>default</layout>
    </repository>
    <!-- 可以添加多个地址 -->
    <repository>
    ...
    </repository>
    </repositories>
    </profile>
    </profiles>
    <servers>
    <server>
    <!-- 对应Repository的ID -->
    <id><id>
    <username></username>
    <password></password>
    </server>
    </servers>
    ...
    </settings>

部署至远程仓库

私服可以部署第三方构件, 可以通过配置POM文件或者部署命令将项目生成的构件部署到仓库中.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<project>
...
<distributionManagement>
<repositroy>
<id>Release Repository ID</id>
<name>Release Repository Name</name>
<url>deploy URL</url>
</repositroy>
<snapshotRepository>
<id>Snapshot Repository ID</id>
<name>Snapshot Repository Name</name>
<url>deploy URL</url>
</snapshotRepository>
</distributionManagement>
...
</project>

配置完后, 命令运行mvn clean deploy即可.
如果不配置POM, 则使用:

1
2
3
4
mvn clean deploy -U -Dmaven.test.skip=true -DaltDeploymentRepository=id::layout::url
# id: 对 应 setting 中<servers>标签里配置的 Repository ID
# layout: Either default for the Maven2 layout or legacy for the Maven1 layout. Maven3 also uses the default layout.
# url: The location of the repository

部署或者是下载构件到远程仓库, 当需要认证时, 配置方式都是一致的.

快照版本

在快照发布到私服时, Maven 会自动为构件打上时间戳, 当构建最新项目时, Maven会从仓库中检查对应快照版本的默认的最新构件, 发现有更新时会下载. 默认情况下(未修改snapshots下的updatePolicy), Maven 会每天检查一次更新, 构建时可以使用 -U 强制检查更新.

1
mvn clean install -e -U -Dmaven.skip=true

从仓库解析依赖的机制

  1. 当依赖范围是 system 的时候, Maven 直接从本地文件系统解析构件.
  2. 根据依赖坐标计算仓库路径, 尝试直接从本地仓库寻找构件, 如果发现相应构件, 则解析成功.
  3. 在本地仓库不存在相应构件的情况下, 如果依赖的版本是显示的发布版本构件, 如 1.1, 2.3 等, 则遍历所有远程仓库, 发现后, 下载并解析使用.
  4. 如果依赖的版本是 RELEASE 或者 LATEST, 则基于更新策略读取所有远程仓库的元数据 groupId/artifactId/version/maven-metadata.xml, 将其与本地仓库的对应元数据合并后, 计算出 RELEASE 的真实值, 然后基于这个真实值检查本地和远程仓库
  5. 如果依赖的版本是 SNAPSHOT, 则基于更新策略读取所有远程仓库的与则基于更新策略读取所有远程仓库的元数据 groupId/artifactId/version/maven-metadata.xml, 将其与本地仓库的对应元数据合并后, 计算出快照的最新版本, 然后基于这个真实值检查本地和远程仓库.
  6. 如果最后解析得到的构件是时间格式的快照, 会将其复制为非时间戳的格式, 并会使用该构件.

△: 依赖和声明中不推荐使用 LATEST 和 RELEASE, 由于 Maven 构件的解析机制可能会不同时间的构件会解析到不同版本的构件.

镜像

如果仓库 A 可以提供 仓库 B 的所有的内容, 则 A 是 B 仓库的镜像. 则任何从 B 仓库获取的构件, A 也可获取. 可以通过修改setting.xml使用镜像.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<settings>
...
<mirrors>
<mirror>
<!-- 该镜像的唯一标识 -->
<id></id>
<name></name>
<url></url>
<!-- 值对应一般仓库的Id,*(所有) -->
<mirrorOf></mirrorOf>
<!-- 通配例子 -->
<!-- 匹配所有远程仓库 -->
<mirrorOf>*</mirrorOf>
<!-- 匹配所有不在本机上的远程仓库, 如localhost, file:// -->
<mirrorOf>external: *</mirrorOf>
<!-- 匹配仓库 repo1, repo2. 多个仓库用 , 分开 -->
<mirrorOf>repo1, repo2</mirrorOf>
<!-- 匹配所有仓库, 除了仓库 repo1 -->
<mirrorOf>*, !repo1</mirrorOf>
</mirror>
</mirrors>
...
</settings>