Maven坐标,依赖,仓库

1.  坐标和依赖

maven的一大功能就是管理项目依赖,为了能够自动化地解析任何一个java构件,maven就必须将它们一一标识,这就是依赖管理的基础——坐标。

 

1.1       坐标

重复地搜索、浏览网页和下载类似的jar文件,可以交由计算机来做。而计算机工作必须基于预定义的规则,maven中定义了这样一种规则:任何一个构件都可以使用maven坐标进行唯一标识,maven坐标的元素包括groupId, artifactId, version, packaging, classfier

 

maven中坐标各个元素的解释如下:

 

groupId:定义当前maven项目隶属的实际项目。maven项目和实际项目可能不是一对一的关系。

 

artifactId:该元素定义实际项目的一个maven项目(模块),推荐的做法是使用实际项目的名称作为artifactId前缀。

 

version:定义maven项目当前所处的版本。maven定义了一整套完成的版本规范,以及快照的概念。

 

packaging:定义maven项目的打包方式。打包方式通常与所生成构件的文件扩展名对应,比如jarwar;打包方式会影响构建的生命周期。

 

classfier:帮助定义构建输出的一些附属构件。附属构件与主构件对应,比如通常jar包会存在javadoc, sources等附属jar包,这些附属组件也有着唯一的坐标。

 

在上述5个元素中,groupId, artifactId, version是必选的,packaging是可选的,classfier是不能直接定义的。

 

1.2        依赖

pom中定义project下的dependencies元素可以包含一个或者多个dependency元素来声明一个或者多个项目依赖。

 

每个依赖可以包含的元素主要有:

元素

含义

groupId, artifactId, version

依赖的基本坐标

type

依赖的类型,对应于坐标的packaging,默认jar

scope

依赖的范围

optional

标记依赖是否可选

exclusions

用来排除传递性依赖

 

1.3  依赖范围

maven在编译项目主代码时需要使用一套classpath,编译项目主代码时需要用到的jar包会以依赖的方式被引入到classpath中。

 

maven在编译和执行测试这两个阶段会使用不同的classpath

 

依赖范围就是用来控制与这三种classpath(编译classpath,测试classpath,运行classpath)的关系。maven中有以下几种依赖范围:

依赖范围

含义

compile

编译依赖范围,默认范围。对于编译,测试,运行三种classpath都有效。

test

测试依赖范围。只对于测试classpath有效,在编译主代码和运行主程序中不会被用到。例如junit

provided

已提供依赖范围。对于编译和测试classpath有效,但在运行时无效。例如servlet-api

runtime

运行时编译依赖,对于测试和运行classpath有效,但在编译主代码时无效。例如数据库驱动。

system

系统依赖范围,和provided依赖范围完全一致,但必须通过systemPath显示指定依赖范围的路径,往往与本机系统绑定,谨慎使用

import

导入依赖范围。不会对三种classpath有影响。

 

2.   仓库

maven中任何一个依赖,插件或者项目构建的输出,都可以称为构件。在不是用maven的项目中,我们往往发现每个项目中都包含类似/lib的目录用来存储依赖的jar包,而且各个项目的lib包往往包含重复的内容。

 

maven项目使用任何一个构件的方式都是完全相同的,maven可以在某个位置统一存储所有maven共享的构件,这个统一的位置便是仓库。

 

2.1    仓库的布局

任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径,这就是maven的仓库布局方式。

 

在对应maven的用户.m2文件夹下,存在一个repository文件夹,其中存放着所有本地存储的jar包,maven的仓库时基于简单文件系统存储的。

 

基于构件的groupId用来准备路径,其中的.分隔符转换成路径分隔符。

基于构件的artifactId准备路径,前面的基础上加上artifactId路径分隔符。

使用的依赖版本信息。

如果构件中包含classifier,就加上构件分隔符和classifier

检查构件的extension,若存在则加上句点分隔符和extension

 

2.2  仓库的分类

对于maven来说,仓库只分为两类:本地仓库和远程仓库。当maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在,直接使用;如果本地仓库不存在,需要查看是否有更新的构件版本,maven就会去远程仓库寻找,发现需要的构件之后,下载到本地仓库再使用。如果都没有找到,maven会报错。

 

中央仓库是maven核心自带的远程仓库,包含了绝大多数开源的构件。默认配置下,本地仓库没有maven需要的构件,它会尝试从中央仓库中寻找。

 

私服是另一种特殊的远程仓库,为了节省网络带宽和下载时间,应该在局域网中架设一个私有的仓库服务器,用来代理所有外部的远程仓库。

 

 

2.2.1 本地仓库

一般在 maven 项目中不存在类似 /lib 这样用来存放依赖文件的目录。当使用 maven 执行编译或者测试时,如果需要使用依赖文件,总是基于坐标使用本地仓库的依赖文件。

 

本地仓库的默认目录是:用户名/.m2/repository,如果用户需要自定义的仓库目录,编辑~/.m2/settings.xml,设置localRepository即可。

 

默认情况下~/.m2/settings.xml是不存在的,用户需要从maven安装目录复制$M2_HOME/conf/settings.xml文件再进行编辑。

 

一个构件只有在本地仓库中之后,才能由其他maven项目使用。

 

2.2.2 远程仓库

安装完成maven之后,如果没有执行任何maven命令,本地仓库目录是不存在的。当maven无法从本地仓库中找到需要的构件的时候,就会从远程仓库下载构件至本地仓库。对于maven来说,每个用户只有一个本地仓库,但是可以配置多个远程仓库。

 

中央仓库就是一个默认的远程仓库,maven的安装文件自带了中央仓库的配置。

2.2.3 私服

私服是一种特殊的远程仓库,架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的maven用户使用。当maven需要下载构件的时候,从私服请求,如果私服上不存在此构件,则从外部的远程仓库中下载,缓存在私服之后,再为maven下载请求提供服务。此外,一些无法从外部仓库中下载到的构件也能从本地上传到私服供大家使用。

 

 

 

使用私服能够带来如下好处:

  • 节省网络(外网)带宽;
  • 加速maven构建;
  • 部署第三方构建:特指一些构件不能从远程仓库中获得;
  • 提供稳定性,增强控制;
  • 降低中央仓库的负荷;

 

2.3       远程仓库的配置

repositories元素下,使用repository子元素声明一个或多个远程仓库。任何一个仓库的id必须是唯一的,尤其需要注意的是,maven自带的中央仓库idcentral,其他仓库如果使用该id会覆盖该中央仓库;url指定了仓库的地址,一般都是基于http协议。

 

私服的一大作用是部署第三方组件,包括组织内部生成的构件以及一些无法从外部仓库直接获得的构件。maven除了能够对项目进行编译、测试、打包之外,还能将生成的构件部署至仓库中,编辑项目的pom.xml文件设置distributionManagement元素。

 

maven中的快照版本就是为了解决需要在开发过程中频繁升级的小版本问题,在发布的过程中,maven会自动为snapshot打上时间戳,maven根据时间戳就能随时找到仓库中该构件的版本最新文件。快照版本应该只在组织内部的项目或模块间依赖使用。

 

2.4        从仓库解析依赖的机制

maven根据怎样的规则从仓库解析并使用依赖构件,背后的依赖解析机制概括如下:

  1. 当依赖的范围是systemmaven直接从本地文件系统解析构件;
  2. 根据依赖坐标计算仓库路径后,尝试直接从本地仓库寻找构件,发现则解析成功;
  3. 本地仓库不存在相应构件,依赖的版本是显示所有的远程仓库,发现后下载并解析使用;
  4. 如果依赖的版本是releaselatest,基于更新策略读取所有的远程仓库元数据,与本地仓库进行合并计算出latest的真实值,基于真实值检查本地和远程仓库;
  5. 如果依赖的是snapshot,基于更新策略读取所有远程仓库的元数据,与本地仓库合并后,得到最新快照版本的值,基于该值检查本地仓库或从远程仓库下载;
  6. 如果最后解析的构件版本是时间戳格式的快照,复制其时间戳格式的文件至非时间戳格式并使用。

猜你喜欢

转载自brandnewuser.iteye.com/blog/2049208