目录
[1. 概念](#1. 概念)
[2. 依赖管理](#2. 依赖管理)
[3. 依赖范围](#3. 依赖范围)
[4. 依赖传递性](#4. 依赖传递性)
[5. 依赖排除](#5. 依赖排除)
[6. 依赖的原则](#6. 依赖的原则)
[7. 使用自定义标签统一版本](#7. 使用自定义标签统一版本)
[1. 概念](#1. 概念)
[2. Maven内置三套相互独立的生命周期](#2. Maven内置三套相互独立的生命周期)
[1. 概念](#1. 概念)
[2. Maven继承的语法](#2. Maven继承的语法)
[1. 概念](#1. 概念)
[2. 聚合的语法](#2. 聚合的语法)
[1. 自动部署配置](#1. 自动部署配置)
一、Maven常用命令
(1) mvn clean
删除target目录,清理构建文件。
(2) mvn compile
编译主代码,生成class文件到target/classes目录。
(3) mvn test-compile
编译测试代码,生成class文件。
(4) mvn test
执行单元测试,验证代码正确性。
(5) mvn package
打包项目为JAR/WAR文件,输出到target目录。
(6) mvn install
将包安装到本地仓库,供其他项目引用(放入的位置是通过gav决定)。
(7) mvn site
生成站点。
说明:
执行与构建过程相关的Maven命令时,必须进入pom.xml所在的目录,如:编译、测试、打包等。
第一次执行命令时,因为需要下载执行该命令的基础环境,所以会从中央仓库下载该环境到本地仓库。
二、Maven依赖
1. 概念
Maven解析依赖信息时会到本地仓库中查找被依赖的jar包。对于自己开发的Maven工程,使用install命令安装后就可以进入仓库。
2. 依赖管理
Maven通过<dependency>元素在pom.xml中管理项目依赖。它支持自动依赖解析和冲突解决,减少了手动管理依赖的复杂性。
A中的某些类需要使用B中的某些类,则称为A依赖于B。在maven项目中,如果要使用一个当时不存在的jar包或模块,则可以通过依赖实现(去仓库中寻找并下载)。
如果A.jar依赖B.jar,当通过pom.xml引入A.jar时,Maven会自动引入B.jar
3. 依赖范围
说明:
(1) 默认范围是:compile
(2) system依赖范围与provided一样,但必须显式提供本地JAR文件的路径。这
种依赖不会被包含在最终的部署包中。
4. 依赖传递性
依赖的传递性指的是一个项目A的依赖可以被另一个依赖于项目A的项目B间接使用。如果有项目C依赖于项目B,则项目C也可以间接使用项目A的依赖。
如果: 项目C-->项目B-->项目A-->spring-core.jar
**则:**项目C和项目B可以间接使用spring-core.jar(1) 依赖传递性的工作原理
**① 声明依赖:**在项目的pom.xml文件中,你可以通过<dependencies>标签声明
项目直接依赖的库。
**② 解析依赖:**Maven会解析这些直接依赖,并查找这些库的pom.xml文件,以确
定它们自己的依赖。这个过程是递归的,Maven会继续解析每个依赖的依赖,直到所
有必要的依赖都被解析出来。
**③ 冲突解决:**在解析过程中,如果两个或多个依赖引入了相同库的不同版本,
Maven会使用其策略(例如,最近者优先、最短路径优先等)来决定使用哪个版本。
**④ 传递性依赖的管理:**一旦所有依赖都被解析和解决,Maven会将所有必要的
库打包到项目中,使得可以在代码中直接使用这些库。
说明:
非compile范围的依赖不能传递。
5. 依赖排除
(1) 使用依赖排除的背景
如果A.jar依赖B.jar,当通过pom.xml引入A.jar时,Maven会自动引入B.jar\nA.jar
包含(x1.java、x2.java等),B.jar包含(y1.java、y2.java等),A.jar与B.jar之间有依
赖关系的实际是x2.java依赖y2.java。如果我们不需要使用A.jar包中的x2.java文件,则
可以通过依赖排除不引入B.jar。
(2) 使用<exclusions>标签
在pom.xml文件中,可以在<dependency>标签内使用<exclusions>标签来排除
特定的传递性依赖。
例:
<dependency> <groupId>org.example</groupId> <artifactId>example-artifact</artifactId> <version>1.0</version> <!-- 排除依赖 --> <exclusions> <exclusion> <groupId>com.excluded</groupId> <artifactId>excluded-artifact</artifactId> </exclusion> </exclusions> </dependency>(3) 使用<dependencyManagement>标签
如果想要在多个项目中重复使用相同的排除设置,可以在
<dependencyManagement>部分定义这些排除,然后在需要的地方引用。这样做的
好处是可以保持pom.xml的整洁,并避免在每个依赖中重复定义排除规则。
例:
<dependencyManagement> <dependencies> <dependency> <groupId>org.example</groupId> <artifactId>example-artifact</artifactId> <version>1.0</version> <exclusions> <exclusion> <groupId>com.excluded</groupId> <artifactId>excluded-artifact</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </dependencyManagement>(4) 使用mvn dependency:tree命令分析依赖树
有时候,排除一个依赖是因为它导致了版本冲突。在这种情况下,应该首先尝试
解决冲突而不是简单地排除它。可以通过查看mvn dependency:tree的输出结果来识别
和解决冲突。Maven的dependency:tree命令可以帮助理解项目的依赖树,这样就可以
看到哪些依赖被传递性地引入了。
例:下面这个命令会显示所有包含com.excluded:excluded-artifact的依赖路径
mvn dependency:tree -Dverbose -Dincludes=com.excluded:excluded-artifact6. 依赖的原则
(1) 最短路径优先原则
当存在多个依赖路径时,Maven 会优先选择路径最短的版本。
例如:
若项目同时依赖 A-B-C-X(1.0) 和 A-D-X(2.0),由于 X(2.0) 路径更短,Maven 将选择 X(2.0)。
(2) 声明顺序优先原则
当依赖路径长度相同时,Maven 根据 pom.xml 中声明的顺序选择依赖。
例如:
若同时声明 A-B-X(1.0) 和 A-C-X(2.0),若 B 在 C 之前声明,则选择 X(1.0)。
(3) 子项目优先原则
子项目(子 POM)中声明的依赖优先级高于父项目(父 POM)中的依赖。
例如:
若父 POM 依赖 A-B,子 POM 依赖 A-D,则最终使用 A-D。
7. 使用自定义标签统一版本
(1) 统一jar包的版本号
① 在properties标签内使用自定义标签统一声明版本号
<properties> <自定义标签.version>4.0.0</自定义标签.version> </properties>② 在需要统一版本的位置,使用${自定义标签名}引用声明的版本号
<version>${自定义标签.version}</version>(2) 说明
凡是需要统一声明后再引用的场合都可以使用自定义标签的方式,使用
${自定义标签名}进行引用。
<properties> <自定义标签1.version>4.0.0</自定义标签1.version> <自定义标签2.encoding>UTF-8</自定义标签2.encoding> </properties>(3) 设置JDK版本
① 全局配置:
修改Maven安装目录下的settings.xml文件(位于conf文件夹):
<profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile>② 项目级配置:
在项目pom.xml文件中添加:
<profiles> <profile> <id>jdk-1.8</id> <activation> <activeByDefault>true</activeByDefault> <jdk>1.8</jdk> </activation> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion> </properties> </profile> </profiles>
三、Maven生命周期
1. 概念
Maven生命周期是项目构建过程的抽象化定义,将复杂的构建步骤划分为有序的阶段,确保自动化执行。
2. Maven内置三套相互独立的生命周期
(1)清理生命周期(Clean Lifecycle):
用于清理构建过程中产生的文件,包含以下阶段:
pre-clean:执行一些准备工作,例如环境检查等。
clean:清理上一次构建生成的文件。
post-clean:清理之后的操作。
(2)默认生命周期(Default Lifecycle):
构建的核心流程,包含编译、测试、打包等任务:
validate:校验项目配置信息。
initialize:初始化构建状态
generate-sources:生成源代码
process-sources:处理源代码
generate-resources:生成资源文件
process-resources:处理资源文件
compile:编译项目的源代码process-classes:处理编译生成的类文件
generate-test-sources:生成测试源代码
process-test-sources:处理测试源代码
generate-test-resources:生成测试资源文件
process-test-resources:处理测试资源文件
test-compile:编译测试源代码。process-test-classes:处理编译生成的测试类文件
test:使用适当的单元测试框架(如JUnit)运行测试。prepare-package:应用打包前的准备工作
package:将编译后的代码打包,如jar、war等。pre-integration-test:集成测试的前置阶段
integration-test:集成测试
post-integration-test:运行集成测试后的清理工作或额外处理
verify:运行所有检查来验证包是有效的并且符合质量标准。
install:将包安装到本地仓库,以让其他项目依赖。
deploy:将最终的包复制到远程仓库。(3)站点生命周期(Site Lifecycle):
生成项目报告和站点信息,通常用于文档生成:
pre-site:执行一些准备工作,例如环境检查等。
site:生成项目的站点文档。
post-site:站点生成后的操作,并且为部署做准备。
site-deploy:将生成的站点部署到服务器上。
说明:
(1) 这些生命周期和阶段可以被组合使用,以满足不同的构建需求。例如,一个常见的构建顺序是先进行validate、compile、test、package,然后是install或deploy。Maven的生命周期管理使得构建过程更加标准化和可重复。
(2) Maven定义了一组标准构建生命周期(如clean, compile, test, package, install, deploy),并且提供了大量的插件来支持这些生命周期的各个阶段。开发者可以通过简单的配置使用这些插件,而不需要深入了解每个插件的内部机制。
(3) Maven核心程序为了更好的实现自动化构建,按照这一的特点执行生命周期中的各个阶段,不论现在要执行生命周期中的哪一个阶段,都是从这个生命周期最初的位置开始执行。
四、Maven继承
1. 概念
在Maven项目中,继承允许一个项目(称为父项目)定义一些共有的配置和依赖,这些配置和依赖可以被多个子项目(称为子模块)继承。这种方式有助于减少重复配置,提高项目的可维护性和一致性。
2. Maven继承的语法
(1) 创建一个父项目,这个项目将包含一些共有的配置和依赖。
例:
<!-- 父项目的坐标 --> <groupId>com.example</groupId> <artifactId>parent-project</artifactId> <version>1.0.0</version> <!-- 修改打包方式为pom --> <packaging>pom</packaging>说明:
父项目的打包方式配置为pom(Maven工程的默认打包方式为jar),因为父项目
不打包也不写代码。
(2) 父项目中使用<dependencyManagement>标签配置对依赖的管理。
例:
<!-- 管理依赖的版本 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.0.0.RELEASE</version> </dependency> </dependencies> </dependencyManagement>说明:
被管理的依赖并没有真正被引入到工程,这里只是声明依赖版本。
(3) 子项目中使用<parent>标签指定继承父项目的gav属性。
例:
<!-- 子项目坐标 --> <!-- <groupId>com.example</groupId> --> <artifactId>child-project</artifactId> <!-- <version>1.0.0</version> --> <!-- 指定父项目坐标 --> <parent> <groupId>com.example</groupId> <artifactId>parent-project</artifactId> <version>1.0.0</version> <!-- 以当前文件为基准的父项目pom.xm1文件的相对路径 --> <relativePath>../parent-project/pom.xml</relativePath> </parent>说明:
1)当子项目的 <groupId>、<version> 与父项目相同时,在子项目中就可以将子
项目的 <groupId>、<version> 省略。
2)<relativePath>标签用相对路径指定父项目pom.xml文件的位置,如果父项目
已经安装在本地或远程仓库中,那么 <relativePath> 可以省略。
3)<relativePath> 声明后,其寻找父项目的路径为 relativePath -> 本地仓库 -> 远
程仓库。
(4) 子项目引用父项目的依赖版本。
例:
<!-- 引入依赖,不需要指定version信息 --> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </dependency> </dependencies>说明:
1)子项目引用父项目中的依赖信息时,可以把版本号去掉。把版本号去掉就表示
子项目中这个依赖的版本由父项目的dependencyManagement来决定。如果在子项目
中写上版本号,则会覆盖父项目中的版本信息(不建议)。
2)子项目 <dependencies> 中的声明才是真正的把依赖引入进来,子项目如果不
主动引入依赖,那么父项目 <dependencyManagement> 节点下声明的依赖就不会被真
正的引入。
3)子项目配置继承后,执行安装命令时要先安装父项目。
五、Maven聚合
1. 概念
聚合就是将多个子模块作为一个项目进行构建。它可以帮助你管理和构建整个项目的不同部分。
2. 聚合的语法
创建一个父项目pom.xml文件。这个文件将包含所有子模块的配置,并定义聚合。
例:
<!-- 修改打包方式为pom --> <packaging>pom</packaging> <!-- 指定各个子模块的相对路径 --> <modules> <module>../module-test1</module> <module>../module-test2</module> <module>../module-test3</module> </modules>说明:
1)打包方式需要配置为pom。
2)<modules>标签列出了所有子模块的相对路径。
3)继承和聚合都需要单独写一个父项目,且pom.xml中打包方式都需要配置
为pom,实际开发中一般会将两种关系写到同一个pom.xml文件中。
六、Web工程的自动部署
1. 自动部署配置
<!--配置当前工程构建过程中的特殊设置--> <build> <finalName>TestWeb</finalName> <!-- 配置构建过程中需要使用的插件 --> <plugins> <plugin> <!-- cargo是一家专门从"启动Servlet容器"的组织--> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.2.3</version> <!--针对插件进行的配置--> <configuration> <!-- 配置当前系统中容器的位置--> <container> <containerId>tomcat6x</containerId> <home>D:\tomcat\apache-tomcat-6.0.43</home> </container> <configuration> <type>existing</type> <home>D;\tomcat\apache-tomcat-6.0.43</home> <!-- 如果Tomcat端口为默认值8080则不必设置该属性--> <!-- <properties> <cargo.servlet.port>8081</cargo.servlet.port> </properties> --> </configuration> </configuration> <!-- 配置播件在什么情况下执行--> <executions> <execution> <id>cargo-run</id> <!-- 生命周期的阶段--> <phase>install</phase> <goals> <!-- 插件的目标 --> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
