前言:此文章是根据尚硅谷Maven课程学习整理而来,仅供参考和复习。
Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供构建和依赖管理支持的工具。
构建过程包含的主要的环节:
如果 A 工程里面用到了 B 工程的类、接口、配置文件等等这样的资源,那么我们就可以说 A 依赖 B。
依赖管理中要解决的具体问题:
首页:
Maven – Welcome to Apache Maven(opens new window)
下载页面:
Maven – Download Apache Maven
核心程序压缩包:apache-maven-3.8.4-bin.zip,解压到非中文、没有空格的目录。
在解压目录中,我们需要着重关注 Maven 的核心配置文件:conf/settings.xml
本地仓库默认值:用户家目录/.m2/repository。由于本地仓库的默认位置是在用户的家目录下,而家目录往往是在 C 盘,也就是系统盘。将来 Maven 仓库中 jar 包越来越多,仓库体积越来越大,可能会拖慢 C 盘运行速度,影响系统性能。所以建议将 Maven 的本地仓库放在其他盘符下。配置方式如下:
<localRepository>D:\maven-repositorylocalRepository>
记住:一定要把 localRepository 标签从注释中拿出来。
注意:本地仓库本身也需要使用一个非中文、没有空格的目录。
Maven 下载 jar 包默认访问境外的中央仓库,而国外网站速度很慢。
改成阿里云提供的镜像仓库,访问国内网站,可以让 Maven 下载 jar 包的时候速度更快。配置的方式是:
mirrors里面包含很多标签 每一个标签都代表着一个镜像配置。
将下面 mirror 标签整体复制到 settings.xml 文件的 mirrors 标签的内部。
<mirror>
<id>nexus-aliyunid>
<mirrorOf>centralmirrorOf>
<name>Nexus aliyunname>
<url>http://maven.aliyun.com/nexus/content/groups/publicurl>
mirror>
按照默认配置运行,Java 工程使用的默认 JDK 版本是 1.5,而我们熟悉和常用的是 JDK 1.8 版本。
修改配置的方式是:将 profile 标签整个复制到 settings.xml 文件的 profiles 标签内。
maven中的标签
用户可以通过配置指定不同操作系统的信息,实现不同操作系统做不同的构建。
<profile>
<id>jdk-1.8id>
<activation>
<activeByDefault>trueactiveByDefault>
<jdk>1.8jdk>
activation>
<properties>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<maven.compiler.compilerVersion>1.8maven.compiler.compilerVersion>
properties>
profile>
使用 x、y、z 三个**『向量』作为空间的坐标系,可以在『空间』中唯一的定位到一个『点』**。
使用三个**『向量』在『Maven的仓库』中唯一的定位到一个『jar』**包。
举例:
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
上面坐标对应的 jar 包在 Maven 本地仓库中的位置:
Maven本地仓库根目录\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
Maven 默认生成的工程,对 **junit 依赖的是较低的 3.8.1 版本,**我们可以改成较适合的 4.12 版本。
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
POM:Project Object Model,项目对象模型。和 POM 类似的是:
DOM(Document Object Model),文档对象模型。它们都是模型化思想的具体体现。
POM 表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据。
POM 理念集中体现在 Maven 工程根目录下 pom.xml 这个配置文件中。所以这个 pom.xml 配置文件就是 Maven 工程的核心配置文件。其实学习 Maven 就是学这个文件怎么配置,各个配置有什么用
<groupId>com.atguigu.mavengroupId>
<artifactId>pro01-maven-javaartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>jarpackaging>
<name>pro01-maven-javaname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
另外还有一个 target 目录专门存放构建操作输出的结果。
Maven 为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。
例如:Maven 执行编译操作,必须先去 Java 源程序目录读取 Java 源代码,然后执行编译,最后把编译结果存放在 target 目录。
Maven 对于目录结构这个问题,没有采用配置的方式,而是基于约定。这样会让我们在开发过程中非常方便。如果每次创建 Maven 工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。
目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
运行 Maven 中和构建操作相关的命令时,必须进入到 pom.xml 所在的目录。
如果没有在 pom.xml 所在的目录运行 Maven 的构建命令,那么会看到下面的错误信息:
The goal you specified requires a project to execute but there is no POM in this directory
标签的位置:dependencies/dependency/scope
标签的可选值:compile/test/provided/system/runtime/import
compile:通常使用的第三方框架的 jar 包这样在项目实际运行时真正要用到的 jar 包都是以 compile 范围进行依赖的。比如 SSM 框架所需jar包。
**test:**测试过程中使用的 jar 包,以 test 范围依赖进来。比如 junit。通过test范围依赖的jar包不会放入war包。
provided:服务器已经存在,不需要再部署打包。
在开发过程中需要用到的服务器上的 jar 包通常以 provided 范围依赖进来。比如 servlet-api、jsp-api。而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类 jar 包产生冲突,同时减轻服务器的负担。
在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。
当 A 依赖 B,B 依赖 C 而且 C 可以传递到 A 的时候,A 不想要 C,需要在 A 里面把 C 排除掉,阻止某些 jar 包的传递。为了避免 jar 包之间的冲突。
使用excludes标签配置依赖的排除;
<dependency>
<groupId>com.atguigu.mavengroupId>
<artifactId>pro01-maven-javaartifactId>
<version>1.0-SNAPSHOTversion>
<scope>compilescope>
<exclusions>
<exclusion>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
exclusion>
exclusions>
dependency>
Maven工程之间,A 工程继承 B 工程
本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。
在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
它的背景是:
它背后的需求是:
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。
打包方式为 pom 的 Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。
<groupId>com.atguigu.mavengroupId>
<artifactId>pro03-maven-parentartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>pompackaging>
modules 和 module 标签是聚合功能的配置
<modules>
<module>pro04-maven-modulemodule>
<module>pro05-maven-modulemodule>
<module>pro06-maven-modulemodule>
modules>
使用parent标签指定当前工程的父工程
子工程坐标中的groupId和version与父工程一致,那么可以省略
<parent>
<groupId>com.atguigu.mavengroupId>
<artifactId>pro03-maven-parentartifactId>
<version>1.0-SNAPSHOTversion>
parent>
<artifactId>pro04-maven-moduleartifactId>
一处修改,处处生效
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<atguigu.spring.version>4.3.6.RELEASEatguigu.spring.version>
properties>
在需要的地方使用${}的形式来引用自定义的属性名:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${atguigu.spring.version}version>
dependency>
使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目。
从继承关系角度来看:
从聚合关系角度来看:
为了让构建过程自动化完成,Maven 设定了三个生命周期,生命周期中的每一个环节对应构建过程中的一个操作。
Maven 之所以这么设计其实就是为了**提高构建过程的自动化程度:**让使用者只关心最终要干的即可,过程中的各个环节是自动执行的
Maven 的核心程序仅仅负责宏观调度,不做具体工作。具体工作都是由 Maven 插件完成的。例如:编译就是由 maven-compiler-plugin-3.1.jar 插件来执行的。
一个插件可以对应多个目标,而每一个目标都和生命周期中的某一个环节对应。
Default 生命周期中有 compile 和 test-compile 两个和编译相关的环节,这两个环节对应 compile 和 test-compile 两个目标,而这两个目标都是由 maven-compiler-plugin-3.1.jar 插件来执行的。
建议:不要中央仓库和阿里云镜像混用,否则 jar 包来源不纯,彼此冲突。
专门搜索 Maven 依赖信息的网站:https://mvnrepository.com/
Maven 在构建过程中有很多默认的设定。例如:源文件存放的目录、测试源文件存放的目录、构建输出的目录……等等。但是其实这些要素也都是被 **Maven 定义过的。**定义的位置就是:超级 POM。
所以我们自己的 POM 即使没有明确指定一个父工程(父 POM),其实也默认继承了超级 POM。就好比一个 Java 类默认继承了 Object 类。
和 Java 类一样,POM 之间其实也是单继承的。
有效 POM 英文翻译为 effective POM,它的概念是这样的——在 POM 的继承关系中,子 POM 可以覆盖父 POM 中的配置;如果子 POM 没有覆盖,那么父 POM 中的配置将会被继承。按照这个规则,继承关系中的所有 POM 叠加到一起,就得到了一个最终生效的 POM。
显然 Maven 实际运行过程中,执行构建操作就是按照这个最终生效的 POM 来运行的。这个最终生效的 POM 就是有效 POM,英文叫effective POM。
综上所述,平时我们使用和配置的 POM 其实大致是由四个层次组成的: