原文地址: pjmike的博客java
上周去实习入职,领完电脑装maven环境的时候被gank了,觉得本身装好了,settings.xml文件也导入了,镜像也换成了国内阿里云镜像了,结果搭建maven项目时发现,POM.xml文件导不进依赖项,提示错误,并且使用IDEA编写maven依赖项没有自动提示功能。mysql
通过一番折腾,发现是首先公司使用的IDEA社区版,功能并无专业版强大,用惯了专业版着实不习惯,第二个是个人settings.xml文件里的阿里云镜像写错了,由于是直接在网上找的,看上去都差很少,其实倒是本身踩到了坑。后来师兄给了我一个公司特定版本的setting.xml配置文件才搞好。linux
从这个小问题,我也意识到我本身对Maven的掌握仍是不够,因此才有这篇文章对Maven的一些知识点进行系统性的学习,并概括总结。git
"对你遇到每个知识点要有一个系统的认识",忘记在哪看到的了,感受挺受用的。github
Maven的仓库分为两类: 本地仓库和远程仓库,当maven根据坐标寻找构件的时候,它首先会查看本地仓库,若是本地仓库存在此构件,则直接使用,若是不存在,或者须要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现须要的构件以后,下载到本地仓库再使用。若是本地仓库和远程仓库都没有须要的构建,就会报错。spring
中央仓库是Maven核心自带的远程仓库,它包含了绝大部分开源的构建,在默认配置下,当本地仓库没有maven须要的的构件时,它就会尝试从中央仓库中下载。sql
私服是另外一种特殊的远程仓库,为了节省带宽和事件,应该在局域网内架设一个私有的仓库服务器,用其代理全部外部的远程仓库,内部的项目还能部署到私服上供其余项目使用。缓存
默认状况下,不论是在Windows仍是linux下,每一个用户在本身的用户目录下都有一个路径名为.m2/repository/的仓库目录。服务器
有时候,由于某些缘由(例如C盘空间不够),用户会想要自定义本地仓库目录地址,这时,能够编辑文件~/.m2/settings.xml,设置localRepository想要的仓库地址,例如:框架
<localRepository>d:maven/maven.m2/repository</localRepository>
复制代码
默认状况下,~/.m2/settings.xml文件是不存在的,用户须要从maven安装目录下/conf/settings.xml文件再进行编辑。
一个构件只有在本地仓库以后,才能由其余maven项目使用。
安装好maven以后,若是不执行任何maven命令,本地仓库目录是不存在的,当用户输入第一条maven命令以后,maven才会建立本地仓库,而后根据配置和须要,从远程仓库下载构件到本地仓库
大部分远程仓库都不须要认证,可是仍是有些仓库须要认证,认证配置以下:
<server>
<id>deploymentRepo</id>
<username>repouser</username>
<password>repopwd</password>
</server>
复制代码
本地原始的本地仓库是空的,maven必须知道至少一个可用的远程仓库,才能在执行maven命令的时候下载到须要的构件,中央仓库就是这样一个默认的远程仓库,maven的安装文件自带了中央仓库的配置。/MAVEN_HOME/lib/maven2.2x-uber.jar
私服是一种特殊的远程仓库,它是架设到局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的maven用户使用。当maven须要下载构件的时候,它从私服请求,若是私服不存在该条件,则从外部的远程仓库下载,缓存到私服上以后。
若是仓库X能够提供仓库Y存储的全部内容,那么就能够认为X是Y的一个镜像,换句话说,任何一个能够从仓库Y得到的构件,都可以从它的镜像中获取。
好比说,maven.net.cn/content/gro… 是中央仓库 repo1.maven.org/maven2/ 在中国的镜像,因为地理位置的因素,该镜像每每可以提供比中央仓库更快的服务。在国内咱们更多的是使用阿里云提供的镜像服务:
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
复制代码
在maven的世界中,任何一个项目都有本身的版本,版本的值多是1.0.0,1.3-alpha-4,2.0,2.1-SNAPSHOT等
那为何还区分稳定版和快照版呢?好比你接到一个需求,针对公司的二方库进行开发,新增某某接口等,可是你的需求不是很稳定,须要总是修改二方库里的内容,而公司某项目A又要依赖该二方库,若是没有快照版本,那么二方库每次修改好了,都会指定一个新的版本给项目A,项目A每次又要修改二方库的版本,这样就会显得很是麻烦。
而Maven的快照版本机制就是为了解决上述问题的,项目A只须要引入快照版本号,好比2.1-SNAPSHOT版本,由于是快照版本,针对二方库的每次修改而且发布后,在发布过程当中,maven会自动为构件打上时间戳,有了该时间戳,Maven就能够随时找到仓库中该构件2.1-SNAPSHOT版本最新的文件,也就是说项目A能够拉取到最新的版本内容。
默认状况下,Maven天天检查一次更新,固然用户也可使用命令行-U参数强制让maven检查更新,如 mvn clean install -U
maven的生命周期就是为了对全部的构建过程进行抽象和统一,这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎全部构建步骤,可是maven的生命周期是抽象的,这意味着生命周期自己不作任何实际的工做,在maven的设计中,实际的任务都交给插件来完成。
maven有三个内置的构建生命周期:default、clean和site,可是平时工做中咱们更多的关注的是maven更加细分的生命周期阶段:
阶段的执行是按顺序的,一个阶段执行完成以后才会执行下一个阶段,好比执行mvn install命令,实际上它会执行install阶段以前的全部阶段,而后才会执行install阶段自己。
前面就提到过在maven的设计中,实际的任务(好比编译源代码)是交给插件来完成的,下面展现几个经常使用的插件:
maven的一大功能就是管理项目依赖,为了能自动化解析任何一个Java构件,maven就必须将它们惟一标识,这就依赖管理的底层基础——坐标,也就是GAV,即groupId artifactId version,由这三个属性能够惟一肯定一个jar包
如下面这个依赖项为例
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.4.RELEASE</version>
<scope>test</scope>
</dependency>
复制代码
除了GAV,仍是一个scope配置,其实就是依赖的范围,依赖范围就是用来控制依赖与三种classpath(编译 classpath、测试classpath、运行classpath)的关系,Maven主要有如下几种依赖范围:
谈到依赖,就不得不提使用maven可能碰到的依赖冲突问题,当一个项目中不一样的Jar包依赖了相同的jar包时,此时就会发生依赖冲突的问题,为了不冲突的发生,maven使用如下几种策略来解决冲突:
那么上面只是两种策略,具体如何作呢?有两种作法,手动分析冲突并解决和使用maven helper插件
mvn dependency:tree -Dverbose -Dincludes=commons-logging:commons-loggging
,该命令将打印出全部依赖了groupId和artifactId都为commons-logging的jar包的依赖路径。以下所示为聚合:
<packaging>pom</packaging>
<modules>
<module>module-1</module>
<module>module-2</module>
<module>module-3</module>
</modules>
复制代码
父POM:
<groupId>com.pjmike</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
</dependencies>
</dependencyManagement>
复制代码
子POM,引入父POM
<!-- 指定parent,说明是从哪一个pom继承 -->
<parent>
<groupId>com.pjmike</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 指定相对路径 -->
<relativePath>../maven-parent</relativePath>
</parent>
<!-- 只须要指明groupId + artifactId,就能够到父pom找到了,无需指明版本 -->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
复制代码
使用dependencyManagement可对依赖进行管理,子类只要不引用这个里面写的依赖,则不会添加,这样防止了重复加包,若是不使用dependencyManagement,那么只要写了dependency,子pom中会所有添加到依赖中。
下面列举一些比较常见的maven命令
下面总结一个maven相关知识的思惟导图,以下图
上面总结的maven知识点并非特别全,更多关于maven的讲解能够参阅《maven实战》这本书。