文章目录
1. 为什么要学习Maven?
1.1 Maven 作为依赖管理工具
(1)jar 包的规模
①随着我们使用越来越多的框架,或者框架封装程度越来越高,项目中使用的jar包也越来越多。项目中,一个模块里面用到上百个jar包是非常正常的。
②比如下面的例子,我们只用到 SpringBoot、SpringCloud 框架中的三个功能:
- Nacos 服务注册发现
- Web 框架环境
- 图模板技术 Thymeleaf
最终却导入了 106 个 jar 包
③而如果使用 Maven 来引入这些 jar 包只需要配置三个『依赖』
<!-- Nacos 服务注册发现启动器 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- web启动器依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 视图模板技术 thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
(2)jar 包的来源
①这个jar包所属技术的官网。官网通常是英文界面,网站的结构又不尽相同,甚至找到下载链接还发现需要通过特殊的工具下载。
②而使用第三方网站提供下载。问题是不规范,在使用过程中会出现各种问题。
jar包的名称、jar包的版本、jar包内的具体细节;而使用 Maven 后,依赖对应的 jar 包能够自动下载,方便、快捷又规范。
(3)jar 包之间的依赖关系
①框架中使用的 jar 包,不仅数量庞大,而且彼此之间存在错综复杂的依赖关系。依赖关系的复杂程度,已经上升到了完全不能靠人力手动解决的程度。
②另外,jar 包之间有可能产生冲突。进一步增加了我们在 jar 包使用过程中的难度。
③而实际上 jar 包之间的依赖关系是普遍存在的,如果要由程序员手动梳理无疑会增加极高的学习成本,而这些工作又对实现业务功能毫无帮助。
④而使用 Maven 则几乎不需要管理这些关系,极个别的地方调整一下即可,极大的减轻了我们的工作量。
1.2 Maven 作为构建管理工具
(1)你可以不使用 Maven,但是构建必须要做。当我们使用 IDEA 进行开发时,构建是 IDEA 替我们做的。
(2)脱离 IDE 环境仍需构建
1.3 项目管理工具
(1)下面是 spring-boot-starter 的 POM 文件,可以看到:除了我们熟悉的坐标标签、dependencies 标签,还有 description、url、organization、licenses、developers、scm、issueManagement 等这些描述项目信息的标签。
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.6</version>
<name>spring-boot-starter</name>
<description>Core starter, including auto-configuration support, logging and YAML</description>
<url>https://spring.io/projects/spring-boot</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>https://spring.io</url>
</organization>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<developers>
<developer>
<name>Pivotal</name>
<email>info@pivotal.io</email>
<organization>Pivotal Software, Inc.</organization>
<organizationUrl>https://www.spring.io</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/spring-projects/spring-boot.git</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-boot.git</developerConnection>
<url>https://github.com/spring-projects/spring-boot</url>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/spring-projects/spring-boot/issues</url>
</issueManagement>
<dependencies>
<dependency>
……
</dependency>
</dependencies>
</project>
(2)所以从『项目管理』的角度来看,Maven 提供了如下这些功能:
- 项目对象模型(POM):将整个项目本身抽象、封装为应用程序中的一个对象,以便于管理和操作。
- 全局性构建逻辑重用:Maven 对整个构建过程进行封装之后,程序员只需要指定配置信息即可完成构建。让构建过程从 Ant 的『编程式』升级到了 Maven 的『声明式』。
- 构件的标准集合:在 Maven 提供的标准框架体系内,所有的构件都可以按照统一的规范生成和使用。
- 构件关系定义:Maven 定义了构件之间的三种基本关系,让大型应用系统可以使用 Maven 来进行管理
①继承关系:通过从上到下的继承关系,将各个子构件中的重复信息提取到父构件中统一管理
②聚合关系:将多个构件聚合为一个整体,便于统一操作
③依赖关系:Maven 定义了依赖的范围、依赖的传递、依赖的排除、版本仲裁机制等一系列规范和标准,让大型项目可以有序容纳数百甚至更多依赖 - 插件目标系统:Maven 核心程序定义抽象的生命周期,然后将插件的目标绑定到生命周期中的特定阶段,实现了标准和具体实现解耦合,让 Maven 程序极具扩展性
- 项目描述信息的维护:我们不仅可以在 POM 中声明项目描述信息,更可以将整个项目相关信息收集起来生成 HTML 页面组成的一个可以直接访问的站点。这些项目描述信息包括:
①公司或组织信息
②项目许可证
③开发成员信息
④issue 管理信息
⑤SCM 信息
2.什么是 Maven?
Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供构建和依赖管理支持的工具。
2.1 构建
(1)Java 项目开发过程中,构建指的是使用『原材料生产产品』的过程。
①原材料
-
Java 源代码
-
基于 HTML 的 Thymeleaf 文件
-
图片
-
配置文件
-
……
②产品:一个可以在服务器上运行的项目
(2)构建过程包含的主要的环节:
- 清理:删除上一次构建的结果,为下一次构建做好准备
- 编译:Java 源程序编译成 *.class 字节码文件
- 测试:运行提前准备好的测试程序
- 报告:针对刚才测试的结果生成一个全面的信息
- 打包
①Java工程:jar包
②Web工程:war包 - 安装:把一个 Maven 工程经过打包操作生成的 jar 包或 war 包存入本地 Maven 仓库
- 部署
①部署 jar 包:把一个 jar 包部署到 Nexus 私服服务器上
②部署 war 包:借助相关 Maven 插件(例如 cargo),将 war 包部署到 Tomcat 服务器上
2.2 依赖
(1)如果 A 工程里面用到了 B 工程的类、接口、配置文件等等这样的资源,那么我们就可以说 A 依赖 B。例如:
- junit-4.12 依赖 hamcrest-core-1.3
- thymeleaf-3.0.12.RELEASE 依赖 ognl-3.1.26
ognl-3.1.26 依赖 javassist-3.20.0-GA - thymeleaf-3.0.12.RELEASE 依赖 attoparser-2.0.5.RELEASE
- thymeleaf-3.0.12.RELEASE 依赖 unbescape-1.1.6.RELEASE
- thymeleaf-3.0.12.RELEASE 依赖 slf4j-api-1.7.26
(2)依赖管理中要解决的具体问题:
①jar 包的下载:使用 Maven 之后,jar 包会从规范的远程仓库下载到本地
②jar 包之间的依赖:通过依赖的传递性自动完成
③jar 包之间的冲突:通过对依赖的配置进行调整,让某些jar包不会被导入
2.3 Maven 的工作机制
3.Maven核心程序解压与配置
3.1 Maven 官网地址
(1)首页:https://maven.apache.org/
(2)下载页面:https://maven.apache.org/download.cgi
(3)下载链接
(4)解压Maven核心程序:
核心程序压缩包:apache-maven-3.8.4-bin.zip,解压到非中文、没有空格的目录
3.2 指定本地仓库
(1)本地仓库默认值:用户家目录/.m2/repository。由于本地仓库的默认位置是在用户的家目录下,而家目录往往是在 C 盘,也就是系统盘。将来 Maven 仓库中 jar 包越来越多,仓库体积越来越大,可能会拖慢 C 盘运行速度,影响系统性能。所以建议将 Maven 的本地仓库放在其他盘符下。在settings.xml配置如下:
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<localRepository>D:\maven-repository</localRepository>
(2)本地仓库这个目录,我们手动创建一个空的目录即可。
①记住:一定要把 localRepository 标签从注释中拿出来。
②注意:本地仓库本身也需要使用一个非中文、没有空格的目录。
3.3 配置阿里云提供的镜像仓库
(1)Maven 下载 jar 包默认访问境外的中央仓库,而国外网站速度很慢。改成阿里云提供的镜像仓库,访问国内网站,可以让 Maven 下载 jar 包的时候速度更快。配置的方式是:
①将原有的例子配置注释掉
<!-- <mirror>
<id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using HTTP.</name>
<url>http://0.0.0.0/</url>
<blocked>true</blocked>
</mirror> -->
②加入我们的配置
将下面 mirror 标签整体复制到 settings.xml 文件的 mirrors 标签的内部。
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
3.4 配置 Maven 工程的基础 JDK 版本
如果按照默认配置运行,Java 工程使用的默认 JDK 版本是 1.5,而我们熟悉和常用的是 JDK 1.8 版本。修改配置的方式是:将 profile 标签整个复制到 settings.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>
3.5 配置环境变量
(1)检查 JAVA_HOME 配置是否正确
Maven 是一个用 Java 语言开发的程序,它必须基于 JDK 来运行,需要通过 JAVA_HOME 来找到 JDK 的安装位置。
(2)配置 MAVEN_HOME
配置环境变量的规律:
①XXX_HOME 通常指向的是 bin 目录的上一级
②PATH 指向的是 bin 目录
(3)配置PATH
(4)验证
4.Maven 核心概念
4.1 坐标
(1)向量说明
使用三个『向量』在『Maven的仓库』中唯一的定位到一个『jar』包。
- groupId:公司或组织的 id
- artifactId:一个项目或者是项目中的一个模块的 id
- version:版本号
(2)三个向量的取值方式
- groupId:公司或组织域名的倒序,通常也会加上项目名称
例如:com.atguigu(就是com.atguigu的倒叙) - artifactId:模块的名称,将来作为 Maven 工程的工程名
- version:模块的版本号,根据自己的需要设定
例如:SNAPSHOT 表示快照版本,正在迭代过程中,不稳定的版本
例如:RELEASE 表示正式版本
(如:version:1.0-SNAPSHOT)
(3)坐标和仓库中 jar 包的存储路径之间的对应关系
①坐标:
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
②上面坐标对应的 jar 包在 Maven 本地仓库中的位置:
Maven本地仓库根目录\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
4.2 pom.xml文件解读
<!-- project标签:根标签,表示对当前工程进行配置、管理 -->
<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标签:从maven 2开始就固定是 4.0.0
代表当前 pom.xml 所采用的标签结构 -->
<modelVersion>4.0.0</modelVersion>
<!-- 当前Maven工程的坐标 -->
<groupId>com.atguigu.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前Maven工程的打包方式,可选值有下面三种: -->
<!-- jar:表示这个工程是一个Java工程 -->
<!-- war:表示这个工程是一个Web工程 -->
<!-- pom:表示这个工程是“管理其他工程”的工程 -->
<packaging>jar</packaging>
<!-- name:当前工程的名字 -->
<name>pro01-maven-java</name>
<!-- url:maven的官网地址 -->
<url>http://maven.apache.org</url>
<!-- properties标签:在maven中定义属性值 -->
<properties>
<!-- 工程构建过程中读取源码时使用的字符集 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 当前工程所依赖的jar包 -->
<dependencies>
<!-- 使用dependency配置一个具体的依赖 -->
<dependency>
<!-- 在dependency标签内使用具体的坐标依赖我们需要的一个jar包 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- scope标签配置依赖的范围 -->
<scope>test</scope>
</dependency>
</dependencies>
</project>
4.2.1 POM 的四个层次
(1)超级 POM
①Maven 在构建过程中有很多默认的设定。例如:源文件存放的目录、测试源文件存放的目录、构建输出的目录……等等。但是其实这些要素也都是被 Maven 定义过的。定义的位置就是:超级 POM。
②关于超级 POM,Maven 官网是这样介绍的:
The Super POM is Maven’s default POM. All POMs extend the Super POM unless explicitly set, meaning the configuration specified in the Super POM is inherited by the POMs you created for your projects.
译文:Super POM 是 Maven 的默认 POM。除非明确设置,否则所有 POM 都扩展 Super POM,这意味着 Super POM 中指定的配置由您为项目创建的 POM 继承。
③所以我们自己的 POM 即使没有明确指定一个父工程(父 POM),其实也默认继承了超级 POM。就好比一个 Java 类默认继承了 Object 类。
(2)父 POM
和 Java 类一样,POM 之间其实也是单继承的。如果我们给一个 POM 指定了父 POM,那么继承关系如下图所示:
(3)有效 POM
①概念
有效 POM 英文翻译为 effective POM,它的概念是这样的——在 POM 的继承关系中,子 POM 可以覆盖父 POM 中的配置;如果子 POM 没有覆盖,那么父 POM 中的配置将会被继承。按照这个规则,继承关系中的所有 POM 叠加到一起,就得到了一个最终生效的 POM。显然 Maven 实际运行过程中,执行构建操作就是按照这个最终生效的 POM 来运行的。这个最终生效的 POM 就是有效 POM,英文叫effective POM。
②查看有效 POM
mvn help:effective-pom
(4)综上所述,平时我们使用和配置的 POM 其实大致是由四个层次组成的:
①超级 POM:所有 POM 默认继承,只是有直接和间接之分。
②父 POM:这一层可能没有,可能有一层,也可能有很多层。
③当前 pom.xml 配置的 POM:我们最多关注和最多使用的一层。
④有效 POM:隐含的一层,但是实际上真正生效的一层。
4.3 约定的目录结构
(1)各个目录的作用
(2)约定目录结构的意义
Maven 为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。例如:Maven 执行编译操作,必须先去 Java 源程序目录读取 Java 源代码,然后执行编译,最后把编译结果存放在 target 目录。
(3)约定大于配置
①Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约定。这样会让我们在开发过程中非常方便。如果每次创建 Maven 工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。
②目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
4.4 生命周期
(1)作用
为了让构建过程自动化完成,Maven 设定了三个生命周期,生命周期中的每一个环节对应构建过程中的一个操作。
(2)三个生命周期
(3)特点
①前面三个生命周期彼此是独立的。
②在任何一个生命周期内部,执行任何一个具体环节的操作,都是从本周期最初的位置开始执行,直到指定的地方。
Maven 之所以这么设计其实就是为了提高构建过程的自动化程度:让使用者只关心最终要干的即可,过程中的各个环节是自动执行的。
4.2 插件和目标
(1)插件
Maven 的核心程序仅仅负责宏观调度,不做具体工作。具体工作都是由 Maven 插件完成的。例如:编译就是由 maven-compiler-plugin-3.1.jar 插件来执行的。
(2)目标
①一个插件可以对应多个目标,而每一个目标都和生命周期中的某一个环节对应。
②Default 生命周期中有 compile 和 test-compile 两个和编译相关的环节,这两个环节对应 compile 和 test-compile 两个目标,而这两个目标都是由 maven-compiler-plugin-3.1.jar 插件来执行的。
4.3 仓库
(1)本地仓库:在当前电脑上,为电脑上所有 Maven 工程服务
(2)远程仓库:需要联网
- 局域网:我们自己搭建的 Maven 私服,例如使用 Nexus 技术。(maven私服没有的jar包会从中央仓库中下载,其他用户再从私服中进行下载,私服相当于是个中转站)
- Internet
①中央仓库
②镜像仓库:内容和中央仓库保持一致,但是能够分担中央仓库的负载,同时让用户能够就近访问提高下载速度,例如:Nexus aliyun。
建议:不要中央仓库和阿里云镜像混用,否则 jar 包来源不纯,彼此冲突。
5.Maven 的构建命令
(1)运行 Maven 中和构建操作相关的命令时,必须进入到 pom.xml 所在的目录。如果没有在 pom.xml 所在的目录运行 Maven 的构建命令,那么会看到下面的错误信息:
The goal you specified requires a project to execute but there is no POM in this directory
(2)mvn -v 命令和构建操作无关,只要正确配置了 PATH,在任何目录下执行都可以。而构建相关的命令要在 pom.xml 所在目录下运行——操作哪个工程,就进入这个工程的 pom.xml 目录。
5.1 清理操作
(1)mvn clean
(2)效果:删除 target 目录
5.2 编译操作
(1)主程序编译:mvn compile
(2)测试程序编译:mvn test-compile
(3)主体程序编译结果存放的目录:target/classes
(4)测试程序编译结果存放的目录:target/test-classes
5.3 测试操作
(1)mvn test
(2)测试的报告存放的目录:target/surefire-reports
5.4 打包操作
(1)mvn package
(2)打包的结果——jar 包,存放的目录:target
5.5 安装操作
(1)mvn install
(2)安装的效果是将本地构建过程中生成的 jar 包存入 Maven 本地仓库。这个 jar 包在 Maven 仓库中的路径是根据它的坐标生成的。
(3)另外,安装操作还会将 pom.xml 文件转换为 XXX.pom 文件一起存入本地仓库。所以我们在 Maven 的本地仓库中想看一个 jar 包原始的 pom.xml 文件时,查看对应 XXX.pom 文件即可,它们是名字发生了改变,本质上是同一个文件。
9.继承
9.1 概念
(1)Maven工程之间,A 工程继承 B 工程
①B工程:父工程
②A工程:子工程
(2)本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。
9.2 作用
(1)在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
(2)它的背景是:
①对一个比较大型的项目进行了模块拆分。
②一个 project 下面,创建了很多个 module。
③每一个 module 都需要配置自己的依赖信息。
(3)它背后的需求是:
①在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
②使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
③使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索
(4)使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来
9.3 操作
9.3.1 创建父工程
(1)创建的过程和普通工程一样,但工程创建好之后,要修改它的打包方式:
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
(2)只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。打包方式为 pom 的 Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。
9.3.2 创建模块工程
(1)模块工程类似于 IDEA 中的 module,所以需要进入 pro03-maven-parent 工程的根目录,然后运行 mvn archetype:generate 命令来创建模块工程。假设,我们创建三个模块工程:
(2)查看被添加新内容的父工程 pom.xml,
下面 modules 和 module 标签是聚合功能的配置
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
(3)解读子工程的pom.xml
<!-- 使用parent标签指定当前工程的父工程 -->
<parent>
<!-- 父工程的坐标 -->
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的坐标 -->
<!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
<!-- <groupId>com.atguigu.maven</groupId> -->
<artifactId>pro04-maven-module</artifactId>
<!-- <version>1.0-SNAPSHOT</version> -->
9.3.3 在父工程中配置依赖的统一管理
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
9.3.4 子工程中引用那些被父工程管理的依赖
<!-- 子工程引用父工程中的依赖信息时,可以把版本号去掉。 -->
<!-- 把版本号去掉就表示子工程中这个依赖的版本由父工程决定。具体来说是由父工程的dependencyManagement来决定。也可以在子工程中自定义版本-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
</dependencies>
9.3.5在父工程中声明自定义属性
(1)创建我们自定义的属性标签
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 自定义标签,维护Spring版本数据 -->
<atguigu.spring.version>4.3.6.RELEASE</atguigu.spring.version>
</properties>
(2)在需要的地方使用${}的形式来引用自定义的属性名:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${atguigu.spring.version}</version>
</dependency>
(3)真正实现“一处修改,处处生效”
9.3.6 实际意义
(1)编写一套符合要求、开发各种功能都能正常工作的依赖组合并不容易。如果公司里已经有人总结了成熟的组合方案,那么再开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。
(2)如上图所示,公司级的父工程中管理的就是成熟的依赖组合方案,各个新项目、子系统各取所需即可。
10.聚合
10.1 Maven 中的聚合
(1)使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目。
①项目:整体
②模块:部分
(2)概念的对应关系:
①从继承关系角度来看:
●父工程
●子工程
②从聚合关系角度来看:
●总工程
●模块工程
(3)好处
①一键执行 Maven 命令:很多构建命令都可以在“总工程”中一键执行。
以 mvn install 命令为例:Maven 要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程。我们自己考虑这些规则会很麻烦。但是工程聚合之后,在总工程执行 mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
②配置聚合之后,各个模块工程会在总工程中展示一个列表,让项目中的各个模块一目了然。
(4)聚合的配置
在总工程中配置 modules 即可
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
(5)依赖循环问题
①如果 A 工程依赖 B 工程,B 工程依赖 C 工程,C 工程又反过来依赖 A 工程,那么在执行构建操作时会报下面的错误:
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
②这个错误的含义是:循环引用。
11.属性的声明与引用
11.1 help 插件的各个目标
官网说明地址:https://maven.apache.org/plugins/maven-help-plugin
(1)使用 help:evaluate 查看属性值
①定义属性
<properties>
<com.atguigu.hello>good morning maven</com.atguigu.hello>
</properties>
②运行命令
③运行结果
(2)通过 Maven 访问系统属性(使用 help:evaluate)
①Java 系统属性一览
Properties properties = System.getProperties();
Set<Object> propNameSet = properties.keySet();
for (Object propName : propNameSet) {
String propValue = properties.getProperty((String) propName);
System.out.println(propName + " = " + propValue);
}
②运行结果
java.runtime.name = Java™ SE Runtime Environment
sun.boot.library.path = D:\software\Java\jre\bin
java.vm.version = 25.141-b15
java.vm.vendor = Oracle Corporation
java.vendor.url = http://java.oracle.com/
path.separator = ;
java.vm.name = Java HotSpot™ 64-Bit Server VM
file.encoding.pkg = sun.io
user.country = CN
user.script =
sun.java.launcher = SUN_STANDARD
sun.os.patch.level =
java.vm.specification.name = Java Virtual Machine Specification
user.dir = D:\idea2019workspace\atguigu-maven-test-prepare
java.runtime.version = 1.8.0_141-b15
java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs = D:\software\Java\jre\lib\endorsed
os.arch = amd64
java.io.tmpdir = C:\Users\ADMINI~1\AppData\Local\Temp
line.separator =
java.vm.specification.vendor = Oracle Corporation
user.variant =
os.name = Windows 10
sun.jnu.encoding = GBK
java.library.path = D:\software\Java\bin;C:\WINDOWS\Sun\Java\bin;C:\WIN……
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 10.0
user.home = C:\Users\Administrator
user.timezone =
java.awt.printerjob = sun.awt.windows.WPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
java.class.path = D:\software\Java\jre\lib\charsets.jar;D:\softw……
user.name = Administrator
java.vm.specification.version = 1.8
sun.java.command = com.atguigu.maven.MyTest
java.home = D:\software\Java\jre
sun.arch.data.model = 64
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_141
java.ext.dirs = D:\software\Java\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
sun.boot.class.path = D:\software\Java\jre\lib\resources.jar;D:\sof……
java.vendor = Oracle Corporation
file.separator =
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
③使用 Maven 访问系统属性
(3)访问系统环境变量
${env.系统环境变量名}
(4)访问 project 属性
①含义
使用表达式 ${project.xxx}
可以访问当前 POM 中的元素值。
②访问一级标签
${project.标签名}
③访问子标签
${project.标签名.子标签名}
④访问列表标签
${project.标签名[下标]}
(5)访问 settings 全局配置
${settings.标签名}
可以访问 settings.xml 中配置的元素值。
(6)用途
①在当前 pom.xml 文件中引用属性
②资源过滤功能:在非 Maven 配置文件中引用属性,由 Maven 在处理资源时将引用属性的表达式替换为属性值
12.build 标签详解
在实际使用 Maven 的过程中,我们会发现 build 标签有时候有,有时候没,这是怎么回事呢?其实通过有效 POM 我们能够看到,build 标签的相关配置其实一直都在,只是在我们需要定制构建过程的时候才会通过配置 build 标签覆盖默认值或补充配置。这一点我们可以通过打印有效 POM 来看到。所以本质上来说:我们配置的 build 标签都是对超级 POM 配置的叠加。那我们又为什么要在默认配置的基础上叠加呢?很简单,在默认配置无法满足需求的时候定制构建过程。
12.1 build 标签组成
(1)定义约定的目录结构
参考示例中的如下部分:
<sourceDirectory>D:\idea2019workspace\atguigu-maven-test-prepare\src\main\java</sourceDirectory>
<scriptSourceDirectory>D:\idea2019workspace\atguigu-maven-test-prepare\src\main\scripts</scriptSourceDirectory>
<testSourceDirectory>D:\idea2019workspace\atguigu-maven-test-prepare\src\test\java</testSourceDirectory>
<outputDirectory>D:\idea2019workspace\atguigu-maven-test-prepare\target\classes</outputDirectory>
<testOutputDirectory>D:\idea2019workspace\atguigu-maven-test-prepare\target\test-classes</testOutputDirectory>
<resources>
<resource>
<directory>D:\idea2019workspace\atguigu-maven-test-prepare\src\main\resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>D:\idea2019workspace\atguigu-maven-test-prepare\src\test\resources</directory>
</testResource>
</testResources>
<directory>D:\idea2019workspace\atguigu-maven-test-prepare\target</directory>
(2)我们能看到各个目录的作用如下:
12.2 备用插件管理
(1)pluginManagement 标签存放着几个极少用到的插件:
maven-antrun-plugin
maven-assembly-plugin
maven-dependency-plugin
maven-release-plugin
(2)通过 pluginManagement 标签管理起来的插件就像 dependencyManagement 一样,子工程使用时可以省略版本号,起到在父工程中统一管理版本的效果。情看下面例子:
①被 spring-boot-dependencies 管理的插件信息:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.2</version>
</plugin>
②子工程使用的插件信息:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
12.3 生命周期插件
plugins 标签存放的是默认生命周期中实际会用到的插件,这些插件想必大家都不陌生,所以抛开插件本身不谈,我们来看看 plugin 标签的结构:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
(1)坐标部分
artifactId 和 version 标签定义了插件的坐标,作为 Maven 的自带插件这里省略了 groupId。
(2)执行部分
executions 标签内可以配置多个 execution 标签,execution 标签内:
id:指定唯一标识
phase:关联的生命周期阶段
goals/goal:关联指定生命周期的目标
goals 标签中可以配置多个 goal 标签,表示一个生命周期环节可以对应当前插件的多个目标。
另外,插件目标的执行过程可以进行配置,例如 maven-site-plugin 插件的 site 目标:
<execution>
<id>default-site</id>
<phase>site</phase>
<goals>
<goal>site</goal>
</goals>
<configuration>
<outputDirectory>D:\idea2019workspace\atguigu-maven-test-prepare\target\site</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</execution>