Maven学过java的都认识,但是大多数人只知道了他的依赖打包功能,对于其他核心功能理解并不深,下面我来讲讲maven的核心知识:
坐标与依赖、
仓库、
生命周期与插件、
模块聚合、
模块继承
等概念。并通过一个开发Maven插件的实例来深入了解Maven的核心机制. 而对于 如何配置Maven、Nexus私服、Jenkins持续集成、Maven测试、构建Web、资源过滤、自定义Archetype 等相对简单、讲解繁琐且网上有大量实践案例的内容没有涉及. 本文的目标是希望读者能够通过本文能对Maven核心原理有个相对深入的理解.
坐标与依赖
为了能够自动化的解析任何一个java构件,maven必须将他们唯一的标识,这就是依赖管理的底层基础,坐标————maven的坐标为java引入了秩序,任何一个构件都必须为自己定义一个坐标,如groupid,artifactId、version、packaging、classfier:
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
<packaging>jar</packaging>
groupId: 定义当前模块隶属的实际Maven项目, 表示方式与Java包类似 groupId不应直接对应项目隶属的公司/组织(一个公司/组织下可能会有很多的项目).
artifactId: 定义实际项目中的一个Maven模块 推荐使用项目名作为artifactId前缀, 如:commons-lang3以commons作为前缀(因为Maven打包默认以artifactId作为前缀)
version :定义当前项目所处版本(如1.0-SNAPSHOT、4.2.7.RELEASE、1.2.15、14.0.1-h-3 等) Maven版本号定义约定: <主版本>.<次版本>.<增量版本>-<里程碑版本>
packaging: 定义Maven项目打包方式, 通常打包方式与所生成构件扩展名对应 有jar(默认)、war、pom、maven-plugin等.
classifier: 用来帮助定义构建输出的一些附属构件(如javadoc、sources) 不能直接定义项目的classifier(因为附属构件不是由项目默认生成, 须有附加插件的帮助)
依赖:
maven最出名的就是maven的依赖管理,用了之后,我们不需再去开源网站一一下载组件,只需一个依赖声明即可:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.7.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
<optional>false</optional>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
依赖传递\
maven的依赖传递机制会自动帮助我们加载我们依赖包的依赖,如:我们的项目依赖了spring-core, 而spring-core又依赖了commons-logging:
有了依赖传递机制, 在项目中添加了spring-core依赖时就不用再去考虑它依赖了什么, 也不用担心引入多余的依赖. Maven会解析各个直接依赖的POM, 将必要的间接依赖以传递性依赖的形式引入到当前目录中(inherits from its parents, or from its dependencies, and so on).
(依赖调节原则: 1. 路径最近者优先; 2. 第一声明者优先.)
依赖管理
Maven提供了dependency插件可以对Maven项目依赖查看以及优化, 如
mvndependency:tree可以查看当前项目的依赖树,详见
mvn dependency:help.
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
Maven 仓库
Maven 中, 任何一个依赖、插件或项目构建的输出, 都可称为构件, 而Maven仓库就是集中存储这些构件的地方.
maven有两类仓库,本地仓库和远程仓库,当maven根据坐标去寻找构件的时候,maven会先找本地仓库,如果没有再去远程仓库去下载
本地仓库:默认地址是~/.m2/,一个构件只有在本地仓库存在后才能被maven项目所引用。
远程仓库也分为两类:中央仓库和私服。
中央仓库:当我们创建maven项目时,原始的本地仓库是空的,所以我们要有一个默认的远程的仓库提供我们去下载,中央仓库就是这样的仓库。
私服:
私服属于一种特殊的远程仓库,通过代理广域网的远程仓库,maven用户发送下载插件请求,私服收到后如果不存在该构件就去找中央仓库去下载,并缓存下来,再为用户提供下载服务,此外如果在外部中央仓库没有的构件,如公司内部的插件,maven也可以上传到私服,供公司其他maven下载使用。架设私服需对pom做如下配置:
<project >
...
<distributionManagement>
<repository>
<id>releases</id>
<url>http://mvn.server.com/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>http://mvn.server.com/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
repository表示发布版本构件的仓库, snapshotRepository代表快照版本的仓库.
id为该远程仓库唯一标识, url表示该仓库地址.
配置正确后, 执行$ mvn clean deploy则可以将项目构建输出的构件部署到对应配置的远程仓库.
注: 往远程仓库部署构件时, 往往需要认证: 需要在settings.xml中创建servers元素, 其id与仓库的id匹配, 详见: Password Encryption.
生命周期与插件
maven将所有项目的构建过程都统一抽象成生命周期:项目的清理,初始化,编译,测试,打包,集成测试,验证,部署,站点生成….
几乎所有的项目都能映射到这些生命周期上去,但是生命周期是抽象的,任务执行都是靠插件来完成,每个生命周期阶段都由一个或多个插件完成,maven为大多数步骤绑定了默认的插件,当然如果需要可以自定义插件。
Maven 拥有三套相互独立的生命周期: clean、default 和 site, 而每个生命周期包含一些phase阶段, 阶段是有顺序的, 并且后面的阶段依赖于前面的阶段. 而三套生命周期相互之间却并没有前后依赖关系, 即调用site周期内的某个phase阶段并不会对clean产生任何影响.
clean生命周期的目的是清理项目:
执行如$ mvn clean;
default生命周期定义了真正构建时所需要执行的所有步骤:
执行如$ mvn clean install;
site生命周期的目的是建立和发布项目站点: Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息
执行命令如$ mvn clean deploy site-deploy;
插件
生命周期的阶段phase与插件的目标goal相互绑定, 用以完成实际的构建任务. 而对于插件本身, 为了能够复用代码,它往往能够完成多个任务, 这些功能聚集在一个插件里,每个功能就是一个目标.
如:$ mvn compiler:compile: 冒号前是插件前缀, 后面是该插件目标(即: maven-compiler-plugin的compile目标).
而该目标绑定了default生命周期的compile阶段:
自定义绑定
除了内置绑定以外, 用户还能够自定义将某个插件目标绑定到生命周期的某个阶段上. 如创建项目的源码包, maven-source-plugin插件的jar-no-fork目标能够将项目的主代码打包成jar文件, 可以将其绑定到verify阶段上:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
executions下每个execution子元素可以用来配置执行一个任务.
在线
Maven 官方插件
https://maven.apache.org/plugins/index.html
CodeHaus 插件
http://www.mojohaus.org/plugins.html
maven-help-plugin
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin[:3.0.0] [-Ddetail] [-Dgoal=jar-no-fork]