Maven入门到精通
一、Maven入门
1.什么是Maven?
它是一个一键式的自动化的构建工具,
首先,Maven可以自动的帮助我们下载jar包.其次可以进行多个项目同时的编译运行.还有在开发的过程中需要进行测试运行,Mav©n提供了自动化的测试插件帮助我们进行项目测试功能的运行.最后项目是需要进行资源文件,配置文件的整合,来进行打包和部署,Maven可以轻松搞定.
2.项目构建过程
1)清理:将上次编译的结果删除,为下一次编译做准备.
2)编译:将.java的文件编译生成.class的文件.
3)测试:针对项目中的关键点进行测试,确保项目在迭代开发的过程中关键点的正确性.
4)报告:在每一次测试后以标签的格式记录和展示测试结果.
5)打包:将项目生成jar包或war包.
6)安装:将jar包安装到本地仓库.
7)部署:将jar包部署到私服上
3.两大核心功能
1.项目构建
对项目进行编译,测试,打包,部署等构建。
2.依赖管理
对jar包的统一管理,Maven提供中央仓库,私服,本地仓库解决jar包的依赖和相关依赖的下载。
如下图所示:包括蓝、黄两个部分分别对应着依赖关系和项目构建两大核心功能。
二、Maven核心概念
1.什么是POM
POM(Project Object Model))项目对象模型,它是Maven的核心组件。它是Maven中的基本工作单元。它是一个xml文件,以pom.xml驻留在项目的根目录中。POM不仅包含有关项目的信息及Maven用于构建项目的各种配置的详细信息,还包含目标和插件。
2.什么是约定的目录结构
所有Maven项目必须要遵循的目录规范.将java源码和测试代码拆分.便于项目的管理和扩展.
如图,可以打开项目结构,通过选中文件夹点击红框中的内容给文件夹赋予对应属性

3.什么是坐标GAV
也称为gv定位。使用三个标签来唯一定位jar资源。项目的唯一的名称,创建项目时定义gav名称,引用项目时使用gav名称。相当于项目的身份证号。
1.groupld:组织名称,一般是公司域名的倒写 com.bjpowernode
2.artifactld:项目名称 springmvc_006_ssm
3.version:版本编号 1.0-SNAPSHOT(开发时的临时版本号) 5.2.5.RELEASE(发布版本)
4.什么是仓库
存放jar包的位置。Maven中所有的jar包都在仓库中。仓库分为本地仓库和远程仓库。
1.本地仓库
2.远程仓库
5.什么是依赖
6.什么是生命周期
7.什么是插件
四、Maven的依赖管理
1.什么是依赖范围?
Maven的依赖构件包含一个依赖范围的属性,这个属性描述的是三套classpath的控制,即编译、测试、运行。这说白了就是添加的jar包起作用的范围。maven提供了以下几种依赖范围:compile, test,provided, runtime, system。
1. compile
编译依赖范围,如果没有指定,默认使用该依赖范围,对于编译、测式、运行3种classpath都有效。
2. test
测试依赖范围,使用此依赖范围的maven依赖,只对编译测试、运行测试的classpath有效,在编译主代码、运行项目时无法使用此类依赖。比如junit,它只有在编译测试代码及运行测试的时候才需要。
3. provided
已提供依赖范围。表示项目的运行环境中已经提供了所需要的构件,对于于此依赖范围的maven依赖,对于编译源码、编译测试、运行测试中classpath有效,但在运行时无效。比如上面说到的servlet-api,这个在编译和测试的时候需要用到,但是在运行的时候,web容器已经提供了,就不需要maven帮忙引入了。
4. runtime
运行时依赖范围,使用此依赖范围的maven依赖,对于测试和运行项目的的classpath有效,但在编译时无效,比如jdbc驱动实现,项目代码编译的时候只需要提供JDK提供的JDBC接口,运行的时候才需要具体的jdbc驱动动实现。
5.system
系统依赖范围,该依赖与3中classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显示第指定依赖文件的路径。这种依赖直接依赖于本地路径中的构件,可能每个开发者机器中构件的路径不一致,所以如果使用这种写法,你的机器中可能没有问题,别人的机器中就会有问题,所以建议谨慎使用。
2.什么是依赖传递?
依赖具有传递性。Maven的依赖传递机制是指:不管 Maven 项目存在多少间接依赖,POM中都只需要定义其直接依赖,不必定义任何间接依赖,这在一定程序上简化了POM的配置。
假项目A依赖项目B,项目B依赖项目C,则A------->直接依赖B,B----->直接依赖C,A------->间接依赖C。
直接依赖和间接依赖是一个相对的概念。直接在项目中配置的依赖称为直接依赖,通过添加依赖关联进来的依赖称为间接依赖。1是项目的直接依赖,2是1的直接依赖,2是项目的间接依赖,以此类推。如图
1.依赖范围对依赖传递的影响
B是A的直接依赖,C是A的间接依赖,根据Maven的依赖传递机制,间接依赖C会以传递性依赖的形式引入到A中,但这种引入并不是无条件的,它会受到依赖范围的影响。
图示依赖传递关系:
交叉部分的单元格的取值为传递性依赖的依赖范围,若交叉单元格取值为"-",则表示该传递性依赖不能被传递
通过上表,可以总结出以下规律:
1.当间接依赖的范围是compile时,与直接依赖的范围一致;
2.当间接依赖的范围是test或provided时,传递性依赖不会被传递
3.当间接依赖的范围是runtime时,传递性依赖的范围与直接依赖的范围一致,但compile例外,此时传递性依赖的范围为runtime。
3.什么是依赖冲突?
在Maven项目中,依赖通常被定义在项目的pom.xml文件中。当多个依赖项引入了不同版本的相同库时,就会发生依赖冲突。这可能是因为项目的直接依赖和间接依赖导致了同一库的多个版本存在于类路径中。每个显式声明的类包都会依赖于一些其它的隐式类包,这些隐式的类包会被maven间接引入进来,从而造成类包冲突。
1.依赖冲突的解决方案
1.版本锁定
在父工程中使用dependencyManagement进行版本锁定,dependencyManagement可以统一管理整个项目的版本号,确保应用的各个项目的依赖和版本一致。dependencyManagement只是声明依赖,并不自动实现引入,因此子项目需要显示的声明需要用的依赖,便可以忽略版本号。如果排斥父工程中定义的版本号,可以显示的进行版本号声明3。
父子工程:
父工程版本锁定特点:
1.父工程在dependencyManagement声明版本号后,子工程引入依赖可以不加版本号,和父工程一致。
2.子工程如果想和父工程依赖版本号不同,可以自己添加版本号。
3.父工程没有使用dependencyManagement,子工程会继承父工程的依赖。
2.短路径优先
引入路径短者优先,顾名思义,当一个间接依赖存在多条引入路径时,引入路径短的会被解析使用。如图
3.声明优先
如果存在短路径,则优先选择短路径,如果路径相同的情况下,先声明者优先,POM文件中依赖声明的顺序决定了间接依赖会不会被解析使用,顺序靠前的优先使用。如图。
4.特殊优先(后来居上)
同一个pom.xml文件中进行了多次依赖jar包不同版本的配置,后面的覆盖前面的配置。这种情况比较少见。
5.可选依赖
maven_03项目可选择是否传递间接依赖junit_4.13,主动权在当前项目maven03中。如果当前项目被依赖到其它项目中,当前项目可以拒绝交出间接依赖项。例如maven_02添加了maven_03的依赖,maven_03可以自主设置其依赖项junit_4.13是否被间接传递。<optional>true</optional>为不传递间接依赖,那么在maven_02项目中就没有junit_4.13的依赖。默认是false,是传递间接依赖。
6.排除依赖
是当前项目是否主动断开其依赖项目的间接依赖。也就是控制当前项目是否使用其直接依赖传递下来的接间依赖。在maven_02项目中添加maven_03项目的依赖,但不要maven_03项目中的junit_4.13的依赖,可以选择排除依赖。这样可以保证当前项目依赖的纯净性。
排除依赖使用exclusions元素排除依赖,说明如下:
1.exclusions元素下可以包含若干个exclusion子元素,用于排除若干个间接依赖,该元素包含两个子元素:groupld和artifactld,用来确定宝需要排除的间接依赖的坐标信息
2.exclusion元素中只需要设置groupld和artifactld就可以确定需要排除的依赖,无需指定版本version
如图
可选依赖和排除依赖的区别
排除依赖和可选依赖都能在项目中将间接依赖排除在外,但两者者实现机制却完全不一样
1.可选依赖是自己决定是否向外提供间接依赖(maven_03设置拒绝提供间接依赖junit)
2.排除依赖是主动拒绝添加直接依赖关联的间接依赖(maven_02项目设置排除maven_03的junit依赖)
3.可选依赖的优先级高于排除依赖
4.若对于同一个间接依赖同时使用排除依赖和可选依赖进行设置,那么可选依赖的取值必须为false,否则排除依赖无法生效。
4.刷新依赖的8种方式
在idea中有时候会出现刷新延时的情况,那么需要进行手工刷新衣赖。
1.点击M刷新按钮。
2.点Maven窗口的Reload All Maven Projects。
3.Build--->ReBuild Project重新构建项目的同时刷新所有依赖。
4.点击本项目的pom.xml文件--->右键--->Maven--->Reload Projedt刷新本项目的依赖。
5.打开pom.xml文件,全选,拷贝,删除、关闭、打开,粘贴.物理刷新pom.xml文件。
6.Invalidate Caches--->全选--->Invalidate and Restart清空idea的缓存并重启idea刷新依赖。
7.打开本地仓库,搜索last,全选删除,点Maven的刷新全部依赖的按钮。
8.在7的步骤后执行File--->settings--->Build,Execution,Deploymernt--->Build Tools--->Maven--->Repositories--->选中本地仓库-->update--->ok。
5.资源文件的指定
src/main/java和src/test/java 这两个目录中的所有*java文件会分分别在comile和test-comiple阶段被编译,编译结果分别放到了arget/classes和targe/test-classes目录中,但是这两个目录中的其他文件(后缀是.properties或.xml等文件)都会被忽略掉(编译后丢失),如果需要要把src目录下的除.java之外的文件包放到target/classes目录,作为输出的jar一部分。需要指定资源文件位置。以下内容放到<buildd>标签中。简单来说就是在resources目录下的*.properties文件和*.xml文件编译时不丢失,但resources目录外的*.properties文件和*.xml文件会丢失,所以要指定位置,保证编译后文件都在
五、Maven的继承和聚合
1.什么是继承?
Maven的依赖传递机制可以一定程度上简化POM的配置,但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同jar包的相同版本,且这些模块之间不存在依赖关系,这就导致同一个依赖需要在多个模块中重复声明,这显然是不可取的,大量的前人经验告诉我们,重复往往意味着更多的劳动和更高的潜在风险。
在Java面向对象中,我们可以建立一种类的父子结构,然后在父类中声明一些字段和方法供子类继承,这样就可以一定程度上消除重复,做到"一处声明,多处使用"。在Maven的世界中,也有类似的机制,它就是POM继承。
Maven在设计时,借鉴了Java面向对象中的继承思想,提出了POM继承思想。当一个项目包含多个模块时,可以在该项目中再创建一个父模块,并在其POM中声明依赖,其他模块的POM可通过继承父模块的POM来获得对相关依赖的声明。
对于父模块而言,其目的是为了消除子模块POM中的重复配置,其中不包含有任何实际代码,因此父模块POM的打包类型(packaging)必须是pom。
子工程可以继承的父工程的元素:
总结:一句话,通过继承可以实现子工程沿用父工程的配置。大大减少重复设置。
2.什么是聚合?
使用Maven聚合功能对项目进行构建时,需要在该项目中额外创建一个的聚合模块,然后通过这个模块构建整个项目的所有模块。聚合模块仅仅是帮助聚合其他模块的工具,其本身并无任何实质内容,因此聚合模块中只有一个POM文件,不包含src等目录。
与父模块相似,聚合模块的打包方式(packaging)也是pom,用户可以在其POM中通过modules下的module子元素来添加需要聚合的模块的目录灵路径。父模块的pom.xml文件的<modules>把子模块聚集起来。