maven基础
Maven概念
1.Maven以及其使用意义
Maven是Apache推出的一个软件项目管理和综合工具。基于项目对象模型(POM)的概念,Maven可以从一个中心资料片管理项目构建,报告和文件。Maven提供了开发人员构建一个完整的生命周期框架。开发团队可以自动完成项目的基础工具建设,Maven使用标准的目录结构和默认构建生命周期。在多个开发团队环境时,Maven可以设置按标准在非常短的时间里完成配置工作。由于大部分项目的设置都很简单,并且可重复使用,Maven让开发人员的工作更轻松,同事创建报表,检查,构建和测试自动化设置。
概括地说,Maven起到了简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝衔接。Maven增加可重用性并负责建立相关的任务。
2.Maven下载
Maven官方下载地址:
http://maven.apache.org/download.cgi
3.Maven目标
Maven主要目标是提供给开发人员:
1).项目是可重复使用,易维护,更容易理解的一个综合模型。
2).插件或交互的工具,这种声明性的模式。
Maven项目的结构和内容在一个XML文件中声明,pom.xml项目对象模型(POM),这是整个Maven系统的基本单元.Maven最强大的功能就是能够自动下载项目依赖库。
4.Maven POM
POM(Project Object Model,项目对象模型)是Maven工程的基本工作单元,是一个XML文件。它包含了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。执行任务或目标时,Maven会在当前目录中查找POM。它读取POM,获取所需的配置信息,然后执行目标。
所有POM文件都需要project元素和三个必需字段:groupId,artifactId,version。
节点 | 描述 |
---|---|
project | 工程的根标签 |
modelVersion | 模型版本需要设置为4.0 |
groupId | 这是工程组的标识。它在一个组织或者项目中通常是唯一的。通常是项目的域名反写 |
artfactId | 这是工程的标识,即工程的名称 |
version | 这是工程版本号。在artifact的仓库中,它用来区分不同的版本。 |
<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.woniuxy.build</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 打包类型 -->
<packaging>jar</packaging>
<!-- 项目名 -->
<name>demo</name>
<!-- 官方网站 -->
<url>http://maven.apache.org</url>
<!-- 项目属性 -->
<properties>
<!-- 项目构建时的字符编码集 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 依赖: druid gson -->
<dependencies>
<!-- 单元测试工具包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
5.Maven架构图解
Maven通过在核心配置文件–setting.xml中配置本地仓库、中央仓库以及私服。然后在项目中通过包的依赖关系优先从本地仓库中查找对应资源。如果本地仓库中不存在资源,则通过网络的形式在中央或者其他仓库中去下载对应的依赖资源。
本地仓库(local)->私服镜像(aliyun)->中央仓库central
Maven工作流程图
6.Maven目录结构
Maven中约定优于配置
maven目录结构
7.Maven生命周期
生命周期简介:
Maven的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。Maven的生命周期是抽象的,即生命周期不做任何实际工作,实际任务由插件完成。
1):运行Maven的每个步骤都由它来定义,这种预定义的默认行为使得我们使用Maven变得简单。
2):这个模型是一种标准,在不同的项目中,使用Maven的接口是一样的,这样就不用去仔细理解每个项目的构建了,一般情况下,mvn clean install 这样的命令是通用的。
Maven有三套互相独立的生命周期,分别是clean、defualt、site。每个生命周期包含一些阶段,阶段是有顺序的,后面的阶段依赖于前面的阶段。
-
clean生命周期:清理项目,包含三个phase:
1)pre-clean:执行清理前需要完成的工作
2)clean:清理上一次构建生成的文件
3)post-clean:执行清理后需要完成的工作 -
default生命周期:构建项目,重要的phase如下:
1)validate:验证工程是否正确,所有需要的资源是否可用。
2)compile:编译项目的源代码。
3)test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。4)Package:把已编译的代码打包成可发布的格式,比如jar。
5)integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。
6)verify:运行所有检查,验证包是否有效且达到质量标准。
7)install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。
8)Deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。 -
site生命周期:建立和发布项目站点,phase如下:
1)pre-site:生成项目站点之前需要完成的工作
2)site:生成项目站点文档
3)post-site:生成项目站点之后需要完成的工作
4)site-deploy:将项目站点发布到服务器
举例如下:
1、mvn clean
调用clean生命周期的clean阶段,实际执行pre-clean和clean阶段。
2、mvn test
调用default生命周期的test阶段,实际执行test以及之前所有阶段。
3、mvn clean install
调用clean生命周期的clean阶段和default的install阶段,实际执行pre-clean和clean,install以及之前所有阶段。
8.Maven坐标
Maven坐标为各种构件引入了秩序,任何一个构件都必须明确定义自己的坐标,而一组Maven坐标是通过一些元素定义的,他们是groupId、artifactId、version、packaging、classifier。
<!-- 坐标 -->
<groupId>com.woniuxy.build</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT**</version>
<!-- 打包类型 -->
<packaging>jar</packaging>
<classifier>jdk15</classifier>
- groupId
定义当前Maven项目隶属的实际项目。 - artifactId
该元素定义实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀。 - version
该元素定义Maven项目当前所处的版本,如上例中nexus-indexer的版本是2.0.0。需要注意的是,Maven定义了一套完成的版本规范,以及快照(SNAPSHOT)的概念。 - packaging
该元素定义Maven项目的打包方式。 - classifier
该元素用来帮助定义构建输出的一些附属构建。
9.Maven依赖
- 依赖范围:
• compile:编译时依赖在所有阶段都可获得,这是默认值。
• provided: 提供的依赖范围用来编译应用程序,但无需部署。若你用到jdk或者应用服务器提供的JAR,则使用此范围,servlet APIs就属于这个依赖范围。测试时,此依赖范围也加入到classpath。
• runtime:运行依赖范围在编译阶段是不需要的,只有在运行时需要,比如JDBC驱动程序。
• test:测试范围依赖,仅在编译和运行单元测试时需要(比如Junit)。
• system 本地依赖,不建议使用。(nexus) - 依赖传递:
所使用的大多数情况下,不会只有一成依赖关系,例如 a依赖b,我们用a->b表示,那么,a->b,b->c,则a对于b是第一依赖,b对于c是第二依赖,而a对于c是传递性依赖,传递性依赖的scope传递规则,与第一依赖和第二依赖有关,下表第一列表示第一依赖,第一行表示第二依赖
从上表我们可以轻松得到几点信息
- 第二依赖为complie不改变第一依赖
- 第二依赖test不传递依赖
- 第二依赖provided只传递provided
- 第二依赖runtime对compile第一依赖的传递依赖是runtime
依赖调节
常遇到的问题是,有不同版本的包,他们都存在传递性依赖,如下
a->b->c->x(1.0)
a->b->x(2.0)
那么此时,根据maven依赖调节第一原则最短路径的规则,使用的x包的版本是2.0,如果当2个不同版本的包的依赖相同怎么办?这个时候就启动了第二原则,也就是按pom中声明的顺序,谁先被声明,谁优先的策略去选择包。
可选依赖
假设有 a->b,b->x和 b->y的 optional值都是true,那么a对于x和y的依赖不会被传递,如果a想要使用x或y的包,那么需要在a中重新进行依赖。
- 依赖排除:
exclusions标签,即依赖排除,标记 一些排除的依赖,也就是在使用A时需要依赖B,但B又依赖C,exclusion标签就将C给排除了,与项目B的pom配置的依赖C中的optional作用一样,即阻止依赖传递C,两种方式的区别是明显的。
单依赖过滤: 同依赖过滤直接处理:可以过滤一个或者多个,如果过滤多个要写多个。
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
<version>0.94.17</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
多依赖过滤
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
<version>0.94.17</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
- 依赖归类:
<properties>
<spring.version>2.5</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
properties标签为属性配置,可以理解为变量,Maven 运行的时候会将 spring.version标签中的内容替换整个POM 中的所有 ${org.springframework.version} 。
5. 依赖冲突:
• A->B->C
简单传递依赖:A->C
• A->B-C(0.1)
• A->C(0.2)
最短路径优先原则: A->C(0.2)
• A->B->C(0.1)
• A->E->C(0.2)
第一声明优先原则:最终依赖C(0.1)
10.Maven常用命令
-
创建Maven的普通java项目:
mvn archetype:create
-DgroupId=packageName
-DartifactId=projectName -
创建Maven的Web项目:
mvn archetype:create
-DgroupId=packageName
-DartifactId=webappName
-DarchetypeArtifactId=maven-archetype-webapp -
编译源代码: mvn compile
-
编译测试代码:mvn test-compile
-
运行测试:mvn test
-
产生site:mvn site
-
打包:mvn package
-
在本地Repository中安装jar:mvn install
-
清除产生的项目:mvn clean
-
生成eclipse项目:mvn eclipse:eclipse
-
生成idea项目:mvn idea:idea
-
组合使用goal命令,如只打包不测试:mvn -Dtest package
-
编译测试的内容:mvn test-compile
-
只打jar包: mvn jar:jar
-
只测试而不编译,也不测试编译:mvn test -skipping compile -skipping test-compile
( -skipping 的灵活运用,当然也可以用于其他组合命令) -
清除eclipse的一些系统设置:mvn eclipse:clean
11.Maven继承和聚合
1.Maven 继承:
一个 maven 项目可以继承另一个 maven 的依赖, 称为子项目 父项目
多个子项目都需要某些依赖, 就可以把子项目共同的依赖抽取到父项目中, 子项目通过继承得到这些依赖, 这样也更好的来管理(比如升级, 删除等)。
1) 父项目的打包方式修改为 pom
<groupId>com.ictpaas</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
2) 父项目使用 dependencyManagement 标签来管理, 表示子项目默认不继承, 可以配置继承, optional 表示子 pom 无论如何都不能继承
<dependencyManagement>
<dependencies>
<!-- 子 pom 可以继承 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!-- 子 pom 不可以继承 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<optional>true</optional>
</dependency>
</dependencies>
</dependencyManagement
3) 子项目配置父项目
<parent>
<!-- 父项目坐标 -->
<artifactId>parent</artifactId>
<groupId>com.ictpaas</groupId>
<version>1.0-SNAPSHOT</version>
<!-- 父项目 pom 文件路径-->
<relativePath>../parent/pom.xml</relativePath>
</parent>
4) 子项目依赖配置
<dependencies>
<!-- 不需要版本, 会从父项目继承, 如果指定版本就是代表不是来自父 pom 而是子 pom 自己的. 父项目的 log4j 是不能继承的 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
5) 子项目不仅仅继承依赖, url, name, modeVersion等也能继承, 换句话说子 pom 文件内容很少, 看起来很简洁。
2.Maven聚合:
聚合类似于0OP中的组合。为了能够使用一条命令就能构建一个项目中的多个模块 ,可使用聚合技术。聚合模块仅仅是帮助聚合其他模块构建的工具,本身并无实质的内容。
聚合的目的以及优点:主要为了方便快速构建项目。可一次构建同-项目下的多个模块。
聚合两种表现形式:1.父子目录,2.平行结构
< packaging> pom< /packaging>
<name> Account Aggregator</name>
< modules>
< module> account-email</module>
<module> account-persist< /module>
< module> account-parent< /module>
</modules>