maven这个话题谈起来有点久远。下面是在open sharing上一些简单的分享。
maven 的属性包含以下几种:java系统环境变量、settings属性变量、用户变量等。可通过以下的方式获取:${user.home},${env.JAVA_HOME},${settings.localRepository}。
maven项目通过它的pom文件,将其相关依赖以及构建的步骤进行管理。我们不仅可以通过pom文件来知晓当前项目的基本信息,还可以知晓该项目在整体工程中的关系。pom文件中会定义该工程的类型(打成jar?war?ear?pom?等)、依赖、插件依赖等。可以定义项目依赖的资源文件,输出的目录路径等,当然如果需要给其他用户使用,还可以定义仓库、生命周期等。下面列举部分tag:
modelVersion:当前pom模型的版本。
groupId:属于哪个组。
artifactId:当前项目组中的唯一ID。
version:指定当前项目的版本。
packaging:指定当前项目的构建类型:jar,war,pom等。
name:对于用户的友好的项目名称。
xml:指定该xml文档的版本和编码方式。
project:是所有pom.xml的根元素。
Classifier:帮助定义构建输出的一些附属构件。
maven的依赖管理遵循两个基本原则:
1.路径最近优先。当A依赖B,B依赖C,还有一个是A直接依赖C,那么会直接建立A与C的依赖。
2.第一声明者优先。A依赖C,B也依赖C。此时D同时依赖A和B。那么可以看出两条路径的长度相等。maven是如何处理依赖的呢?看在D的pom文件中,A和B谁的申明在前,如果A的声明在前,那么就会取A中的依赖C。
传递依赖:A依赖B,B依赖C,那么A和C就建立起传递依赖。
排除依赖:主要排除版本的影响,比如引用了两个版本的jar。或者都是log的包,比如spring中spring-core会隐式引入commons-log,项目中同时又引入了quartz,它又隐式的引入了slf4j, 项目中会导致既有comon-log,又有lf4j, log4j.properties里配置的mybatis的sql显示配置没起作用。所以为了排除jar冲突,需要排除对slf4j的依赖。
可选依赖:是用于一个项目中采用了多个数据库,便于拓展项目。但是真正用的时候只会有一个生效。因此为了避免设计上以及打包上的重复,在pom中配置optional。在真正用到的地方显性的声明出来。
当然,我们可以通过以下命令:mvn dependency:list /mvn dependency:tree以及mvn help:effective-pom/mvn help:effective-settings来查看项目的依赖。
接下来介绍maven的另一个重要概念:repository。
本地仓库指的是 ${user_home}/.m2/repository/,Maven 默认会先从本地仓库内寻找所需 Jar 包。如果本地仓库不存在,Maven 才会向远程仓库请求下载,同时缓存到本地仓库。
远程仓库
私服
为了节省资源,一般是局域网内设置的私有服务器,当本地仓库内不存在 Maven 所需 Jar 包时,会先去私服上下载 Jar 包。
中央仓库
是 Maven 自带的远程仓库,不需要特殊配置。如果私服上也不存在 Maven 所需 Jar 包,那么就去中央仓库上下载 Jar 包,同时缓存在私服和本地仓库。
同步远程仓库和私服的频率可以设置:默认daily。
当你编好一个jar包需要分享给其他人用时,maven会自动会jar打上时间戳。
当你完成一个项目的编写,编译的时候,maven会先去本地仓库找相关的依赖包,并比较本地的依赖包和远程仓的包的时间戳,如果远程仓的时候戳晚于本地,则会去下载远程仓的包到本地,然后再关联到该项目中。如果本地仓没有找到,则会去私服上找,私服上再找不到,则会去中央仓库上找。
仓库的配置方面:我们可以定义仓库的具体用途以及权限控制,比如该仓库只能上传和下载snapshot包,或者只能上传和下载release包,或者上传和下载需要用户名和密码等。这些都可以通过在setting.xml或者pom中设置。当然当你下载maven安装时,会自带有个全局的setting.xml文件,但是不建议用户直接使用它,而是copy其到当前用户的目录中。因为全局的setting文件更改后不利于以后maven的无干扰更新。
说到maven构建,不得不说它的生命周期和插件。
分为三大阶段:clean、default和site。clean阶段是处理清理项目jar的过程,site是用来通过网页的形式发布该项目的信息,代码依赖,覆盖率等,我们用的比较多的是default阶段。如下:
maven的生命周期比较多,我们编译项目或者打包等都可以在上面图片中找出对应的阶段。而且它的处理过程是由上而下的。比如我install包,则会把这阶段之前的所有生命周期跑个遍。回去validate,compile,test,package等。这也方便了用户在打包项目时只需要一个阶段,其余阶段maven会自动帮助用户去实现。命令较为简单。Maven的生命周期是抽象的,实际需要插件来完成任务,这一过程是通过将插件的目标(goal)绑定到生命周期的具体阶段(phase)来完成的。如:将maven-compiler-plugin插件的compile目标绑定到default生命周期的compile阶段,完成项目的源代码编译。生命周期和插件的对应关系如下:
还有其他两大特性:聚合和继承,在顶层项目中我们可以声明其打包类型为:pom,然后在下层的项目中用<parent>来标记。