共计 12617 个字符,预计需要花费 32 分钟才能阅读完成。
原创文章,总结不易,禁止侵权转载。转载请先私信知乎「编程大 K」征求批准原创文章,总结不易,禁止侵权转载。转载请先私信知乎「编程大 K」征求批准原创文章,总结不易,禁止侵权转载。转载请先私信知乎「编程大 K」征求批准什么是 Mavne Maven 是一个项目管理工具,它蕴含了一个我的项目对象模型 (POM:Project Object Model),一组规范汇合。因为 Maven 应用规范目录布局和默认构建生命周期,开发团队简直能够立刻自动化我的项目的构建基础设施。在多个开发团队环境的状况下,Maven 能够在很短的工夫内依照规范设置工作形式。Maven 之前,更多的是应用 Ant 的我的项目构建工具,Ant 有一个特点,每次都得写,每次都写的差不多,配置也臃肿。所以,起初搞进去 Maven。Maven 就是最先进的版本构建工具吗?不是的,只不过,目前在 Java 畛域 Maven 应用比拟多。除了 Maven,还有 Gradle。它的次要性能有:提供了一套标准化的我的项目构造;提供了一套标准化的构建流程(编译,测试,打包,公布……);提供了一套依赖管理机制。为了实现下面的次要性能,Maven 提供了两大外围:依赖治理:对 jar 的对立治理 (Maven 提供了一个 Maven 的地方仓库,当咱们在我的项目中增加完会主动去地方仓库下载相干的依赖,并且解决依赖的依赖问题) 我的项目构建:对我的项目进行编译、测试、打包、部署、上传到私服等 Maven 模型上面来谈一谈 Maven 模型的整体构造,包含三个局部:我的项目对象模型 (Project Object Model)依赖治理模型 (Dependency) 插件(Plugin)
如上图所示,包含蓝、黄两个局部别离对应着依赖关系和我的项目构建两大外围性能。首当其冲的一个外围就是我的项目对象模型,也就是常常应用的 pom.xml 另外一个就是我的项目构建,Maven 的我的项目构建能够依照生命周期具备以下三个规范生命周期:clean:我的项目清理的解决 default(或 build):我的项目部署的解决 site:我的项目站点文档创立的解决我的项目对象模型(POM)POM 代表我的项目对象模型。它是 Maven 中的根本工作单元。它是一个 XML 文件,作为 pom.xml 驻留在我的项目的跟目录中。POM 不仅蕴含无关我的项目的信息以及 Maven 用于构建我的项目的各种配置详细信息,还蕴含指标和插件。在执行工作或指标时,Maven 在当前目录中查找 POM。它读取 POM,获取所需的配置信息,而后执行指标。在 POM 文件中常见的配置包含一下几点:我的项目依赖插件指标建设档案我的项目版本开发商邮件列表在创立 POM 之前,咱们应该首先确定项目组(groupId)、项目名称(artifactId) 和版本,因为这些属性有助于在存储库中惟一标识我的项目。<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.coderV</groupId> <artifactId>coderV</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>com.coderV</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> //… </plugin> </plugins> </build></project> 接下来认真拆解 POM 文件构造 1、我的项目标识符 Maven 应用一组标识符(也称为坐标)来惟一标识我的项目并指定应如何打包我的项目工件:groupId:创立我的项目的公司或组的惟一根本名称 artifactId:我的项目的惟一名称 version:我的项目的一个版本 packaging:一种打包办法(例如 WAR / JAR / ZIP)其中所有 POM 文件都须要我的项目元素和三个必填字段:groupId、artifactId、version。其中的前三个 (groupId:artifactId:version) 联合造成惟一标识符,并且是您指定我的项目将应用的内部库(例如 JAR)版本的机制。具体阐明一些根本的我的项目标识符 6 参数名称形容 Project root 这是我的项目 root 的标签。您须要指定根本架构设置,例如 apache 架构和 w3.org 标准。Model version 模型版本应为 4.0.0。groupId 这是项目组 / 公司的 ID。这在组织或我的项目中通常是惟一的。artifactId 这是我的项目的 ID。这通常是我的项目的名称 version 这是我的项目的版本 2、依赖治理 Maven 应用存储库的概念进行依赖治理,我的项目中应用的这些内部库称为依赖项。Maven 中的依赖项治理性能可确保从地方存储库主动下载这些库,因而您不用将它们存储在本地。这是 Maven 的一个要害个性,并提供以下益处:联合本地仓库大幅缩小从近程存储库下载的数量,缩小存储使用量治理我的项目依赖性变得更容易提供了一个无效的平台,用于在组织内外替换二进制组件,而无需每次都从源代码手动装置组件为了申明对外部库的依赖,您须要提供库的 groupId、artifactId、verison。让咱们看一个例子:<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.16</version></dependency> 当 Maven 解决依赖项时,它会将 Spring Core 库下载到本地 Maven 存储库中,并在我的项目中应用传递依赖
如下图所示,我的项目 A 依赖于我的项目 B,B 又依赖于我的项目 C,此时 B 是 A 的间接依赖,C 是 A 的间接依赖 Maven 的依赖传递机制是指:不论 Maven 我的项目存在多少间接依赖,POM 中都只须要定义其间接依赖,不用定义任何间接依赖,Maven 会动读取以后我的项目各个间接依赖的 POM,将那些必要的间接依赖以传递性依赖的模式引入到以后我的项目中。Maven 的依赖传递机制可能帮忙用户肯定水平上简化 POM 的配置。基于 A、B、C 三者的依赖关系,依据 Maven 的依赖传递机制,咱们只须要在我的项目 A 的 POM 中定义其间接依赖 B,在我的项目 B 的 POM 中定义其间接依赖 C,Maven 会解析 A 的间接依赖 B 的 POM,将间接依赖 C 以传递性依赖的模式引入到我的项目 A 中。通过这种依赖传递关系,能够使依赖关系树迅速增长到一个很大的量级,很有可能会呈现依赖反复,依赖抵触等状况,Maven 针对这些状况提供了如下性能进行解决。依赖范畴(Dependency scope)依赖调解(Dependency mediation)可选依赖(Optional dependencies)排除依赖(Excluded dependencies)依赖治理(Dependency management)Maven 具备以下 6 中常见的依赖范畴,如下表所示。依赖范畴形容 compile 编译依赖范畴,scope 元素的缺省值。应用此依赖范畴的 Maven 依赖,对于三种 classpath 均无效,即该 Maven 依赖在上述三种 classpath 均会被引入。例如,log4j 在编译、测试、运行过程都是必须的。test 测试依赖范畴。应用此依赖范畴的 Maven 依赖,只对测试 classpath 无效。例如,Junit 依赖只有在测试阶段才须要。provided 已提供依赖范畴。应用此依赖范畴的 Maven 依赖,只对编译 classpath 和测试 classpath 无效。例如,servlet-api 依赖对于编译、测试阶段而言是须要的,然而运行阶段,因为内部容器曾经提供,故不须要 Maven 反复引入该依赖。runtime 运行时依赖范畴。应用此依赖范畴的 Maven 依赖,只对测试 classpath、运行 classpath 无效。例如,JDBC 驱动实现依赖,其在编译时只需 JDK 提供的 JDBC 接口即可,只有测试、运行阶段才须要实现了 JDBC 接口的驱动。system 零碎依赖范畴,其成果与 provided 的依赖范畴统一。其用于增加非 Maven 仓库的本地依赖,通过依赖元素 dependency 中的 systemPath 元素指定本地依赖的门路。鉴于应用其会导致我的项目的可移植性升高,个别不举荐应用。import 导入依赖范畴,该依赖范畴只能与 dependencyManagement 元素配合应用,其性能是将指标 pom.xml 文件中 dependencyManagement 的配置导入合并到以后 pom.xml 的 dependencyManagement 中。依赖范畴与三种 classpath 的关系一览表,如下所示。依赖范畴编译 classpath 测试 classpath 运行 classpath 例子 compile√√√log4jtest-√-junitprovided√√-servlet-apiruntime–√JDBC-driversystem√√- 非 Maven 仓库的本地依赖依赖范畴对传递依赖的影响我的项目 A 依赖于我的项目 B,B 又依赖于我的项目 C,此时咱们能够将 A 对于 B 的依赖称之为第一间接依赖,B 对于 C 的依赖称之为第二间接依赖。B 是 A 的间接依赖,C 是 A 的间接依赖,依据 Maven 的依赖传递机制,间接依赖 C 会以传递性依赖的模式引入到 A 中,但这种引入并不是无条件的,它会受到依赖范畴的影响。传递性依赖的依赖范畴受第一间接依赖和第二间接依赖的范畴影响,如下表所示。compiletestprovidedruntimecompilecompile–runtimetesttest–testprovidedprovided-providedprovidedruntimeruntime–runtime 注:上表中,右边第一列示意第一间接依赖的依赖范畴,上边第一行示意第二间接依赖的依赖范畴。穿插局部的单元格的取值为传递性依赖的依赖范畴,若穿插单元格取值为“-”,则示意该传递性依赖不能被传递。通过上表,能够总结出以下法则(*):当第二间接依赖的范畴是 compile 时,传递性依赖的范畴与第一间接依赖的范畴统一;当第二间接依赖的范畴是 test 时,传递性依赖不会被传递;当第二间接依赖的范畴是 provided 时,只传递第一间接依赖的范畴也为 provided 的依赖,且传递性依赖的范畴也为 provided;当第二间接依赖的范畴是 runtime 时,传递性依赖的范畴与第一间接依赖的范畴统一,但 compile 例外,此时传递性依赖的范畴为 runtime。依赖调节 Maven 的依赖传递机制能够简化依赖的申明,用户只须要关怀我的项目的间接依赖,而不用关怀这些间接依赖会引入哪些间接依赖了。为了避免出现依赖反复的问题,Maven 通过依赖调节来确定间接依赖的引入门路。依赖调节遵循以下两条准则:引入门路短者优先先声明者优先引入门路短者优先引入门路短者优先,顾名思义,当一个间接依赖存在多条引入门路时,引入门路短的会被解析应用。例如,A 存在这样的依赖关系:
A->B->C->D(1.0)
A->X->D(2.0)D 是 A 的间接依赖,但两条引入门路上有两个不同的版本,很显然不能同时引入,否则造成反复依赖的问题。依据 Maven 依赖调节的第一个准则:引入门路短者优先,D(1.0)的门路长度为 3,D(2.0)的门路长度为 2,因而间接依赖 D(2.0)将从 A->X->D(2.0) 门路引入到 A 中。先声明者优先先声明者优先,顾名思义,在引入门路长度雷同的前提下,POM 文件中依赖申明的程序决定了间接依赖会不会被解析应用,程序靠前的优先应用。例如,A 存在以下依赖关系:
A->B->D(1.0)
A->X->D(2.0)D 是 A 的间接依赖,其两条引入门路的长度都是 2,此时 Maven 依赖调节的第一准则曾经无奈解决,须要应用第二准则:先声明者优先。Maven 排除依赖和可选依赖咱们晓得 Maven 依赖具备传递性,例如 A 依赖于 B,B 依赖于 C,在不思考依赖范畴等因素的状况下,Maven 会依据依赖传递机制,将间接依赖 C 引入到 A 中。但如果 A 出于某种原因,心愿将间接依赖 C 排除,那该怎么办呢?Maven 为用户提供了两种解决形式:排除依赖(Dependency Exclusions)和可选依赖(Optional Dependencies)。排除依赖假如存在这样的依赖关系,A 依赖于 B,B 依赖于 X,B 又依赖于 Y。B 实现了两个个性,其中一个个性依赖于 X,另一个个性依赖于 Y,且两个个性是互斥的关系,用户无奈同时应用两个个性,所以 A 须要排除 X,此时就能够在 A 中将间接依赖 X 排除。排除依赖是通过在 A 中应用 exclusions 元素实现的,该元素下能够蕴含若干个 exclusion 子元素,用于排除若干个间接依赖,示例代码如下:<dependencies> <dependency> <groupId>net.biancheng.www</groupId> <artifactId>B</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <!– 设置排除 –> <!– 排除依赖必须基于间接依赖中的间接依赖设置为能够依赖为 false –> <!– 设置以后依赖中是否应用间接依赖 –> <exclusion> <!– 设置具体排除 –> <groupId>net.biancheng.www</groupId> <artifactId>X</artifactId> </exclusion> </exclusions> </dependency> </dependencies> 对于 exclusions 元素及排除依赖阐明如下:排除依赖是管制以后我的项目是否应用其间接依赖传递下来的间接依赖;exclusions 元素下能够蕴含若干个 exclusion 子元素,用于排除若干个间接依赖;exclusion 元素用来设置具体排除的间接依赖,该元素蕴含两个子元素:groupId 和 artifactId,用来确定须要排除的间接依赖的坐标信息;exclusion 元素中只须要设置 groupId 和 artifactId 就能够确定须要排除的依赖,无需指定版本 version。可选依赖与上文的利用场景雷同,也是 A 心愿排除间接依赖 X,除了在 B 中设置可选依赖外,咱们还能够在 B 中将 X 设置为可选依赖。设置可选依赖在 B 的 POM 对于 X 的依赖申明中应用 optional 元素,将其设置成可选依赖,示例配置如下: <dependencies> <dependency> <groupId>net.biancheng.www</groupId> <artifactId>X</artifactId> <version>1.0-SNAPSHOT</version> <!– 设置可选依赖 –> <optional>true</optional> </dependency> </dependencies> 对于 optional 元素及可选依赖阐明如下:可选依赖用来管制以后依赖是否向下传递成为间接依赖;optional 默认值为 false,示意能够向下传递称为间接依赖;若 optional 元素取值为 true,则示意以后依赖不能向下传递成为间接依赖。排除依赖 VS 可选依赖 排除依赖和可选依赖都能在我的项目中将间接依赖排除在外,但两者实现机制却齐全不一样。排除依赖是管制以后我的项目是否应用其间接依赖传递下来的接间依赖;可选依赖是管制以后我的项目的依赖是否向下传递;可选依赖的优先级高于排除依赖;若对于同一个间接依赖同时应用排除依赖和可选依赖进行设置,那么可选依赖的取值必须为 false,否则排除依赖无奈失效。3、Maven 仓库
在 Maven 术语中,仓库是存储所有我的项目的 jar 包的中央,Maven 能够轻松应用它们。依据类别能够将 Maven 仓库分为三类:1)本地仓库
默认状况下,每个本地计算机的用户目录下都有一个路径名为.m2/repository/ 的仓库目录,这个就是本地的仓库也能够在 settings.xml 文件配置本地仓库的门路 2)近程仓库
近程仓库也称为私服,由公司或者项目组保护,是开发人员本人定义的近程仓库,其中蕴含我的项目所须要的库或其余的 jar 包,能够通过 <repositories> 标签来制订近程仓库地址 <repositories> <repository> <id>companyname.lib1</id> <url>http://download.companyname.o…</url> </repository> </repositories>3)地方仓库 Maven 地方仓库是 Maven 社区提供的仓库。它蕴含大量罕用的库。当 Maven 在本地存储库中找不到任何依赖项时,就会从地方仓库中搜寻其中地方仓库有以下几点须要留神:此存储库由 Maven 社区治理。不须要配置,但能够替换地方仓库的源为制订的镜像源它须要互联网拜访能力搜寻。Maven 依赖加载程序
当咱们执行 Maven 构建命令时,Maven 开始按以下程序查找依赖库:第 1 步 - 在本地存储库中搜寻依赖项,如果未找到,则转到第 2 步,否则执行进一步解决。第 2 步 - 如果没有提到近程存储库,则跳转到第 3 步。在一个或多个近程存储库中搜寻依赖项,如果找到则将其下载到本地存储库以供未来参考第 3 步 - 在地方存储库中搜寻依赖项,将其下载到本地存储库以供未来参考。如果未找到 Maven 只是进行解决并抛出谬误(无奈找到依赖项)4、属性 (properties) 自定义属性有助于 pom.xml 文件更易于浏览和保护。一个非常经典的应用场景就是,通过自定义属性来定义我的项目依赖项的版本。Maven 的 properties 是一个占位符,通过 properties 定义不同属性名的值例如上面的例子中,通过 <properties> 定义了一个 spring.version 的属性,其具体的值为 5.3.16;如果想要将 Spring 降级到更新的版本,就只需更改 <spring.version> 属性标签内的值,所有在其 <version> 标签中应用该属性的依赖项都将更新。<properties> <spring.version>5.3.16</spring.version></properties><dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency></dependencies> 另一个罕用的场景就是应用 <properties> 定义构建门路的变量,例如 <properties> <project.build.folder>${project.build.directory}/tmp/</project.build.folder></properties><plugin> //… <outputDirectory>${project.resources.build.folder}</outputDirectory> //…</plugin>5、Buildbuild 局部也是 Maven POM 中十分重要的局部。它提供无关默认 Maven 指标、已编译我的项目的目录和应用程序的最终名称的信息。默认 build 如下所示:<build> <!– 当我的项目没有规定指标(Maven2 叫做阶段(phase))时的默认值,–> <!– 必须跟命令行上的参数雷同例如 jar:jar,或者与某个阶段(phase)雷同例如 install、compile 等 –> <defaultGoal>install</defaultGoal> <!– 构建产生的所有文件寄存的目录, 默认为 ${basedir}/target,即我的项目根目录下的 target –> <directory>${basedir}/target</directory> <!– 产生的构件的文件名,默认值是 ${artifactId}-${version}–> <finalName>${artifactId}-${version}</finalName> <!– 当 filtering 开关关上时,应用到的过滤器属性文件列表。–> <!– 我的项目配置信息中诸如 ${spring.version}之类的占位符会被属性文件中的理论值替换掉 –> <filters> <filter>filters/filter1.properties</filter> </filters> //…</build> 编译工件的默认输入文件夹名为 target,打包工件的最终名称由artifactId 和version组成,但您能够随时更改。6、配置文件构建配置文件是一组配置值,可用于设置或笼罩 Maven 构建的默认值。应用构建配置文件,您能够为不同的环境(例如生产环境和开发环境)自定义构建。配置文件次要分为两种类型,一种是在定义在我的项目上 pom.xml 文件中,另一种是定义在 setting.xml 上 <profiles> <profile> <id>production</id> <build> <plugins> <plugin> //… </plugin> </plugins> </build> </profile> <profile> <id>development</id> <activation> <activeByDefault>true</activeByDefault> </activation> <build> <plugins> <plugin> //… </plugin> </plugins> </build> </profile> </profiles> 定义在 pom.xml 文件上的 profile 能够看做 pom.xml 的正本,领有与 pom.xml 雷同的子元素与配置办法。正如您在下面的示例中看到的,默认配置文件设置为 development。如果要运行生产配置文件,能够应用以下 Maven 的 -P 命令显示的激活一个 profile:mvn clean install -P productionMaven 构建生命周期每个 Maven 构建都遵循指定的生命周期。您能够执行多个构建生命周期指标,包含编译我的项目代码、创立包以及在本地 Maven 依赖项存储库中装置存档文件的指标。以下列表显示了最重要的 Maven 生命周期阶段:validate: 查看我的项目的正确性 compile: 将提供的源代码编译成二进制工件 test: 执行单元测试 package: 将编译后的代码打包 * 到归档文件中 integration-test: 执行额定的测试,这须要打包 verify——查看包是否无效 install – 将包文件装置到本地 Maven 存储库 deploy – 将包文件部署到近程服务器或存储库 1、Clean 生命周期当咱们执行 mvn post-clean 命令时,Maven 调用 clean 生命周期,它蕴含以下阶段:pre-clean:执行一些须要在 clean 之前实现的工作 clean:移除所有上一次构建生成的文件 post-clean:执行一些须要在 clean 之后立即实现的工作
在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,如果执行 mvn clean 将运行 pre-clean, clean 两个生命周期阶段;运行 mvn post-clean,则运行 pre-clean, clean, post-clean 三个生命周期阶段 2、Default (Build) 生命周期这是 Maven 的次要生命周期,被用于构建利用,包含上面的 23 个阶段:生命周期阶段形容 validate(校验)校验我的项目是否正确并且所有必要的信息能够实现我的项目的构建过程。initialize(初始化)初始化构建状态,比方设置属性值。generate-sources(生成源代码)生成蕴含在编译阶段中的任何源代码。process-sources(解决源代码)解决源代码,比如说,过滤任意值。generate-resources(生成资源文件)生成将会蕴含在我的项目包中的资源文件。process-resources(解决资源文件)复制和解决资源到目标目录,为打包阶段最好筹备。compile(编译)编译我的项目的源代码。process-classes(解决类文件)解决编译生成的文件,比如说对 Java class 文件做字节码改善优化。generate-test-sources(生成测试源代码)生成蕴含在编译阶段中的任何测试源代码。process-test-sources(解决测试源代码)解决测试源代码,比如说,过滤任意值。generate-test-resources(生成测试资源文件)为测试创立资源文件。process-test-resources(解决测试资源文件)复制和解决测试资源到目标目录。test-compile(编译测试源码)编译测试源代码到测试目标目录.process-test-classes(解决测试类文件)解决测试源码编译生成的文件。test(测试)应用适合的单元测试框架运行测试(Juint 是其中之一)。prepare-package(筹备打包)在理论打包之前,执行任何的必要的操作为打包做筹备。package(打包)将编译后的代码打包成可散发格局的文件,比方 JAR、WAR 或者 EAR 文件。pre-integration-test(集成测试前)在执行集成测试前进行必要的动作。比如说,搭建须要的环境。integration-test(集成测试)解决和部署我的项目到能够运行集成测试环境中。post-integration-test(集成测试后)在执行集成测试实现后进行必要的动作。比如说,清理集成测试环境。verify(验证)运行任意的查看来验证我的项目包无效且达到质量标准。install(装置)装置我的项目包到本地仓库,这样我的项目包能够用作其余本地我的项目的依赖。deploy(部署)将最终的我的项目包复制到近程仓库中与其余开发者和我的项目共享。Site 生命周期 Maven Site 插件个别用来创立新的报告文档、部署站点等。pre-site:执行一些须要在生成站点文档之前实现的工作 site:生成我的项目的站点文档 post-site:执行一些须要在生成站点文档之后实现的工作,并且为部署做筹备 site-deploy:将生成的站点文档部署到特定的服务器上插件(Plugin)插件治理与依赖治理原理一样、不同的是定义的元素标签不一样、插件治理标签是 build 标签的子标签 pluginManagement 中 pluginManagement 用来做插件治理的。它是示意插件申明,即你在我的项目中的 pluginManagement 下申明了插件,Maven 不会加载该插件,pluginManagement 申明能够被继承。如上面的例子 <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1</version> <configuration> <attach>true</attach> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> </plugins></pluginManagement><!– 子 POM–><plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> </plugin></plugins>原创文章,总结不易,禁止侵权转载。转载请先私信知乎「编程大 K」征求批准