Maven使用总结
依赖范围
-
maven创建的工程的目录中包含
main
和test
文件夹,分别表示主程序的文件夹和测试程序的文件夹 -
maven使用
scop
设置依赖范围,常用的依赖范围如下:-
compile :编译依赖范围,在测试和运行都有效,这个是默认的依赖范围
- 对主程序是否有效:有效
- 对测试程序是否 有效: 有效
- 是否参与打包:参与``
- 是否参与部署:参与
-
test:测试依赖的范围
- 对主程序是否有效:无效
- 对测试程序是否 有效: 有效
- 是否参与打包:不参与
- 典型的例子:
junit
-
provided
- 对主程序是否有效: 有效
- 对测试程序是否有效:有效
- 是否参与打包:不参与
- 是否参与部署:不参与
- 典型的例子:
servlet-api
- 主要解决在开发中需要用到的,但是在部署的时候不需要的依赖,比如
servlet-api
,在开发中没有Tomcat运行环境,因此需要这个servlet-api
,但是一旦部署在Tomcat中,Tomcat中会提供这个servlet-api
,如果此时在添加的话会产生依赖冲突
- 主要解决在开发中需要用到的,但是在部署的时候不需要的依赖,比如
-
Runtime
:测试和运行时需要。编译不需要。如JDBC驱动包- 对测试程序是否有效:有效
- 对主程序是否有效:有效
- 是否参与部署: 参与
- 是否参与打包:参与
-
system
:系统依赖范围。本地依赖,不在maven*仓库- 这个必须和
systemPath
结合使用,用来指定本地依赖的位置
<!-- 添加服务提供者的jar接口 --> <dependency> <groupId>cn.tedu.dubbo</groupId> <artifactId>dubbo-provider</artifactId> <version>0.0.1</version> <scope>system</scope> <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/dubbo-provider-helloService-0.0.1.jar</systemPath> </dependency>
- 这个必须和
-
依赖传递
- 在开发项目的时候,我们通常需要建立多个项目,如果一个项目中需要用到另外一个项目的类或者数据,那么需要引入这个项目快照
- 如果
HelloFriend
项目依赖Hello
这个项目,此时的HelloFriend
的pom.xml
文件如下:
<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>cn.tedu</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- 添加Hello这个项目的依赖快照 -->
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
- 此时项目
HelloFriend
中存在依赖只有Hello
项目这个jar
,但是如果我们在Hello
项目的pom.xml
文件中添加一个junit
的依赖,这个依赖范围为设置为compile
,如下:
<dependencies>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
- 做了上面的操作,我们可以查看项目
HelloFriend
和Hello
中都自动的导入了Junit
依赖,这个就是依赖传递。
注意
- 依赖传递只有是依赖范围为
compile
的情况下才有作用,如果我们需要一个servlet-api
的依赖,因为servlet-api
这个jar在部署的时候会和Tomcat冲突,因此只能设置为provided
,但是此时就不能依赖传递了,只能在每个项目中的pom.xml
文件中都添加了
依赖排除
HelloFriend
项目依赖Hello
项目,其中compile
范围的依赖都会导入HelloFriend
中- 使用
dubbo
默认会添加给我们添加spring-framework
的版本为2.5.6
,默认添加的依赖只能排除,不能在项目中再添加一个其他的版本,只有排除之后才能添加,否则会导致jar包冲突 -
Hello
项目中的依赖为:
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<!-- 添加dubbo依赖的jar,会自动添加spring 2.5版本的依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
</dependency>
-
此时
HelloFriend
的项目需要使用4.3.13
版本的spring,那么我们有如下解决办法:- 在
Hello
项目中改变依赖,排除spring2.5版本的:- 一般在公司中项目的版本都是定制好的,我们不可能随意改动父项目中定义好的版本,因此这个方法明显是不行的
<!-- 使用spring4.3.13 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.13.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> <!--排除spring2.5版本--> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> </exclusions> </dependency>
- 在
- 我们可以在项目
HelloFriend
排除这个spring的依赖,那么我们就可以不需要改变Hello
项目中的依赖了,如下:- 这个才是正确的排除依赖的方式
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<!-- 添加Hello这个项目的依赖快照 -->
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--排除项目中的spring2.5的依赖,这个不会影响Hello项目中的版本-->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
</exclusions>
</dependency>
依赖原则
依赖路径最短优先原则
- 假设项目
MakeFriend
依赖HelloFriend
,并且HelloFriend
依赖Hello
项目。此时Hello项目中
使用的log4j 1.2.14
版本的,但是在HelloFriend
版本中使用的是log4j1.2.17
版本的,那么此时的MakeFriend
应该选择什么版本呢? - image
-
Hello
的依赖如下:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
-
HelloFriend
依赖如下:
<!-- 添加Hello这个项目的依赖快照 -->
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--添加1.2.17版本的log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
-
MakeFriend
的依赖如下:
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
- 我们根据图形可以看到
MakeFriend
到HelloFriend
的log4j1.2.17
的路径是2
,但是到Hello
中的log4j1.2.14
的路径为3
,因此Maven会选择HelloFriend
中的log4j1.2.17
版本作为MakeFriend的依赖
pom文件中申明顺序优先
-
在
路径
都是一样的情况下,那么就要看在pom.xml
文件中申明的顺序了,先申明的就使用哪个项目中的依赖版本 -
假设现在的依赖改变了,
MakeFriend
现在是直接依赖Hello
和HelloFriend
,如下图 - image
-
我们可以看出此时到两个版本的依赖都是一样的路径为
2
,那么我们应该选择哪个版本呢,此时就需要看看在MakeFriend
中的pom.xml
文件的申明顺序- 可以看出先申明的是
HelloFriend
,因此MakeFriend
使用的是log4j1.2.17
- 可以看出先申明的是
<!-- 先申明HelloFriend,那么就要使用log4j.1.2.17版本 -->
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
覆写优先
生命周期
- maven的生命周期有三个部分组成,分别为
clean生命周期
,site生命周期
,default生命周期
生命周期调用的特点
- 三大生命周期中也会包含各个阶段,并且各个阶段是有序进行的,maven为了实现构建的自动化,如果我们使用了命令调用生命周期后面的处理阶段,那么会从最前面的阶段开始执行,不用每一个阶段都执行一遍。
clean生命周期
-
在进行真正的构建之前进行一些清理工作
-
clean生命周期包括:
-
per-clean
:执行了一些需要在clean之前完成的工作 -
clean
:移除所有上一次构建生成的文件 -
post-clean
:执行一些需要在clean之后立刻完成的工作
-
-
当我们执行
mvn:clean
命令的时候只会执行per-clean
和clean
这两个阶段的任务,不会执行post-clean
的工作
default生命周期
- 构建的核心部分,编译、测试、打包、部署
- 包括如下的23个生命周期阶段:
生命周期阶段 | 描述 |
---|---|
validate | 检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。 |
initialize | 初始化构建状态,例如设置属性。 |
generate-sources | 生成编译阶段需要包含的任何源码文件。 |
process-sources | 处理源代码,例如,过滤任何值(filter any value)。 |
generate-resources | 生成工程包中需要包含的资源文件。 |
process-resources | 拷贝和处理资源文件到目的目录中,为打包阶段做准备。 |
compile | 编译工程源码。 |
process-classes | 处理编译生成的文件,例如 Java Class 字节码的加强和优化。 |
generate-test-sources | 生成编译阶段需要包含的任何测试源代码。 |
process-test-sources | 处理测试源代码,例如,过滤任何值(filter any values)。 |
test-compile | 编译测试源代码到测试目的目录。 |
process-test-classes | 处理测试代码文件编译后生成的文件。 |
test | 使用适当的单元测试框架(例如JUnit)运行测试。 |
prepare-package | 在真正打包之前,为准备打包执行任何必要的操作。 |
package | 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。 |
pre-integration-test | 在集成测试执行之前,执行所需的操作。例如,设置所需的环境变量。 |
integration-test | 处理和部署必须的工程包到集成测试能够运行的环境中。 |
post-integration-test | 在集成测试被执行后执行必要的操作。例如,清理环境。 |
verify | 运行检查操作来验证工程包是有效的,并满足质量要求。 |
install | 安装工程包到本地仓库中,该仓库可以作为本地其他工程的依赖。 |
deploy | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。 |
- 当一个阶段通过 Maven 命令调用时,例如
mvn compile
,只有该阶段之前以及包括该阶段在内的所有阶段会被执行。 - [图片上传失败...(image-7b5809-1538922827484)]
Site生命周期
- Maven Site 插件一般用来创建新的报告文档、部署站点等。
- 包含以下阶段
-
pre-site
:执行一些需要在生成站点文档之前完成的工作 -
site
:生成项目的站点文档 -
post-site
:执行一些需要生成站点文档之后完成的工作 -
site-deploy
:将生成站点文档部署到特定的服务器上
-
Maven统一管理依赖的版本号
- 假设如下的依赖:
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<!-- Spring-JDBC,要和spring-webmvc的版本一致 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
- 那么当我们需要改变spring的依赖版本号为
4.3.12.RELEASE
,那么我们只有逐个改变version
中的值,现在是两个依赖比较好改变的,如果要有很多个的话,那么难免会改错,因此我们需要使用一种方式统一管理依赖的版本号。我们可以使用<properties>
标签来管理,新的配置文件如下:-
properties
中的标签体可以任意指定,如果需要引用定义的标签体中的内容,那么直接使用${标签体}
即可 - 此时我们要是改变版本,那么只需要改变
<properties>
中的版本即可
-
<!-- 使用properties管理版本号 -->
<properties>
<!-- 这里的标签体可以任意指定,后续只要使用${}引用标签体即可使用其中定义的内容 -->
<spring-version>4.3.13.RELEASE</spring-version>
</properties>
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<!-- version使用${} -->
<version>${spring-version}</version>
</dependency>
<!-- Spring-JDBC,要和spring-webmvc的版本一致 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
</dependencies>
继承
- 我们知道只有
compile
范围内的依赖才可以传递,但是对于test
和provided
中的依赖却是不可以传递的,那么必须在每个项目中都要添加依赖,此时肯定会出现每个项目中依赖版本不一致的情况,这样对于每个人的开发来说是比较困难的,因为不同版本的依赖使用的方式也不同,此时我们就需要统一管理这个版本了。 - 下面我们以
junit
的版本控制为例
步骤
- 创建一个父工程
Hello-Parent
,打包的方式为pom
- 在
Hello-Parent
中的pom.xml
文件中使用dependencyManagement
管理版本,控制junit
的版本依赖
<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>cn.tedu</groupId>
<artifactId>Hello-Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 使用properties控制版本号 -->
<properties>
<junit-version>4.12</junit-version>
</properties>
<!-- 使用dependencyManagement管理版本 -->
<dependencyManagement>
<dependencies>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit-version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
- 在子工程中使用
parent
标签指定声明对父工程的引用
<parent>
<groupId>cn.tedu</groupId>
<artifactId>Hello-Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 使用relativePath指定父工程的相对位置 -->
<relativePath>../Hello-Parent</relativePath>
</parent>
- 将子工程坐标和父工程坐标重复的地方删除,不删除也没关系
- 在子工程中删除
junit
的version
标签,表明是继承自父工程的版本,不需要指定
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--此时不需要指定version了,因为父工程中已经指定了-->
</dependency>
- 子工程全部的配置
<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和父工程中的重复了,因此可以删除
<groupId>cn.tedu</groupId>-->
<artifactId>Hello</artifactId>
<!-- 这里的version版本也和父工程的重复了,因此可以删除
<version>0.0.1-SNAPSHOT</version> -->
<parent>
<groupId>cn.tedu</groupId>
<artifactId>Hello-Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 使用relativePath指定父工程的相对位置 -->
<relativePath>../Hello-Parent</relativePath>
</parent>
<dependencies>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--不需要指定version-->
</dependency>
</dependencies>
</project>
聚合
- 我们在开发项目的时候都是分模块开发的,此时如果想要使用maven安装这个项目的话,那么需要一个一个的安装,但是我们可以使用聚合的方式,可以实现一次性安装。并且安装还是有先后顺序的,一定要先安装父工程,否则将会找不到依赖信息,我们使用聚合的方式就没有先后安装的障碍了,maven会为我们自动的解决
步骤
- 创建一个maven工程,打包方式为
pom
,当然也是可以直接使用父工程 - 在pom.xml配置文件中配置
module
- 详细的pom.xml如下:
<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>cn.tedu</groupId>
<artifactId>Hello-Manager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 继承父工程 -->
<parent>
<groupId>cn.tedu</groupId>
<artifactId>Hello-Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 使用relativePath指定父工程的相对位置 -->
<relativePath>../Hello-Parent</relativePath>
</parent>
<!-- 使用聚合的方式 -->
<modules>
<module>../Hello-Parent</module>
<module>../Hello</module>
<module>../HelloFriend</module>
<module>../MakeFriend</module>
</modules>
</project>
原文:https://www.jianshu.com/p/b7d08690d242