![cbdfd113650edb213790a79fbc39447c.gif](https://i-blog.csdnimg.cn/blog_migrate/71d358b796880dfc27e7fb3737a5719f.gif)
点击上方蓝色字体,关注我们
前言
Maven 是众多 Java 开发者所青睐的构建工具之一。还记得未接触Maven之前,所有的依赖包都是从网站找的,找了某个jar包后,又要去搜索它的依赖,如此循环往复。耗费大量的时间和精力,很多初识Maven的开发者可能会存在很多疑惑,没有系统的摸清Maven的用法,所以本篇文章想要介绍在Maven领域的一切实践思路,让读者更好的领略 Maven 的精髓。maven的兼容性矩阵
高高兴兴的下载Idea 2019.2.2 和 Maven 3.6.2。
安装配置,一气呵成!
打包报错????
配置没问题,环境变量没问题,到底是哪里出了问题?
崩溃!换3.6.0版本的Maven
再次打包成功!
看来是Idea 和 maven的兼容性问题导致的。果然,每次下载最新版本,总能能遇到一些坑。后续通过 idea官网 也印证了这个兼容性的bug。认识 maven 的生命周期
相信一提到Maven,大家脑海里浮现出来它的第一个作用,就是用来打包,但是经常“用完即走”的我们真的到了需要认认真真梳理一下Maven的相关概念了。 Maven为我们提供了一套自动化的构建方案,从最基础的清理、编译代码、运行测试到打包和部署。这一系列过程称之为它的生命周期。深入理解 maven 的生命周期
maven使用一个名为 components.xml 的配置文件来描述其架构的组织结构,以我本地的maven 3.6.0版本为例。不同版本的maven, 配置文件的路径相似。apache-maven-${version}\lib\maven-core-${version}.jar
\META-INFO\plexus\conponents.xml
这里我们针对default生命周期来作详细的了解:
mvn { 例如: mvn package }
可以看到 当我们执行一个 简单的 mvn package 时,maven其实内部按照顺序流转了很多的phase (阶段)。
那如何来理解 Goal (目标)呢?
我们前面说过,一系列的 Goal (目标) 组成 了 phase (阶段)。
相信你用过maven的很多插件吧?这里我以 打 jar包的插件为例来介绍:
mvn [插件名称]:[goal的名称]
再举一个实际案例,在打包时,分离出三方的依赖包。我们会使用到一个叫maven-dependency-plugin的插件。
mvn clean dependency:copy-dependencies package
Maven 管理项目的依赖
Maven提供的依赖管理,是其中的一大核心功能。就像文章开始所说的,我们需要一个jar包,这个jar包又依赖于另外的jar包,这种依赖关系会不断的传递,直至最后一个没有任何其他依赖包。 Maven就是通过自动去发现和包含这些传递的依赖,避免了我们人工的去搜索下载。 这个传递依赖的层级是没有限制的,在使用过程中需要注意的一点是,循环依赖的问题。mvn dependency:help
mvn dependency:analyze
mvn dependency:tree
mvn dependency:tree -Dverbose
除了使用命令查看依赖树,常见的办法还有:
- 在项目启动时把所有的加载的 jar 包都打印出来,添加 VM 参数 -verbose:class 。通过打印的信息确认是否正确的 jar 包被依赖。
- 有的时候仅仅通过 mvn dependency:tree 可能无法快速的发现冲突,这个时候就可以尝试使用 Enforcer 插件,这个插件也可以自定义许多规则,我们可以使用 dependencyConvergence 规则。来保证所有的依赖都使用相同的版本。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-enforcer-pluginartifactId>
<version>1.3.1version>
<executions>
<execution>
<id>enforceid>
<configuration>
<rules><DependencyConvergence />rules>
configuration>
<goals>
<goal>enforcegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
Maven 管理的依赖范围
依赖范围主要是用来限制各个包的传递性。并且影响我们最终的构建结果。在引入依赖时,通过 标签来指定依赖的范围。- compile:缺省值,编译、测试都有效。
- provided:编译,测试都有效,但是在运行时并不会加入。例如Servlet API,因为Web容器本身有,如果加入就会出现冲突。
- runtime:测试、运行有效,表明这个依赖项不是编译所必须的,但是是执行时需要的。需要位于运行时的类路径中。
- test:仅测试时有效,这个范围不是可传递的。
- system:与本机相关,可移植性差。
- import:导入的依赖范围,仅适用在dependencyManager中,表示从其他pom导入dependency配置。
dependencyManagement 作用
上面介绍的依赖范围都比较好理解,最后一个import范围涉及到一个dependencyManagement,这里我们具体解释一下他和dependencies 的区别。 dependencyManagement 主要有两个作用:- 一是集中管理项目的依赖项
- 二是控制使用的依赖项的版本
Maven 的仓库分类
从大类来看,Maven仓库主要分为两大类,一是本地仓库,二是远程仓库。 本地仓库,主要是用来存储从远程仓库下载的插件和 jar 包,当项目需要使用 插件 或 jar 包时,会优先从本地仓库中查找。 远程仓库,是当无法在本地仓库中查找到包时,会默认去远程仓库下载。 远程仓库包括了,中央仓库、镜像仓库和私服。- 1) 在本地仓库中寻找,如果没有则进入下一步。
- 2) 在全局配置的私服仓库(settings.xml中配置的并有激活)中寻找,如果没有则进入下一步。
- 3) 在项目自身配置的私服仓库(pom.xml)中寻找,如果没有则进入下一步。
- 4) 在中央仓库中寻找,如果没有则终止寻找。
Maven 内置的变量
${basedir} 表示项目根目录(即pom.xml文件所在目录)${project.build.directory} 构建目录,缺省为target目录${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes${project.build.finalName} 产出物名称比如jar包,缺省为${project.artifactId}-${project.version}${project.packaging} 打包类型,缺省为jar${project.xxx} 当前pom文件的任意节点的内容${env.xxx} 获取系统环境变量。例如,"env.PATH"指代了$path环境变量(在Windows上是%PATH%)。${settings.xxx} 指代了settings.xml中对应元素的值。
Java System Properties: 所有可通过java.lang.System.getProperties()访问的属性都能在POM中使用
比较实用的,例如 ${JAVA_HOME}。
总结
本文主要以一个兼容性问题为引,介绍了maven的兼容性矩阵,及其三大默认的生命周期,了解了阶段(phase) 和 Goals(目标)的概念。对比了dependencyManagement和dependencies的区别。以及Maven仓库的分类、依赖管理的范围及内置实用变量的学习。希望能帮助到大家。![ae2215aa8c98517f136659c172c6e13d.gif](https://i-blog.csdnimg.cn/blog_migrate/75594962e79441fd6a3dbbd476ee4f09.gif)
![426b88fc34aa67f5692461997bfd81c9.png](https://i-blog.csdnimg.cn/blog_migrate/ee13866a1f927438072d9c29d2cc438d.jpeg)
![3f31b601461141872c84abeede0bf9e2.gif](https://i-blog.csdnimg.cn/blog_migrate/e02d79eed43546eee548a480c595cadf.gif)