文章目录
概览
产生原因
-
标准化
在maven中,约定优于配置。规定好的标准,可以促进项目团队的标准化,减少写作冲突,在项目切换时免去了学习成本。这些标准具体包括:- 对于
项目目录结构
、测试用例命名方式等内容都有既定规则
。 - 引入了仓库的概念,
规范了jar包的获取方式
(maven方式),从而使得获取的jar包内容也更加规范。之前,jar包的获取方式五花八门,使得获取的jar包的内容也有差异。并且,统一集中式管理jar包的方式,使得jar包共享,实现了jar包和项目分离
,减轻了项目体积。 标准化工程构建过程
。提供了一个可复用、易维护的工程模型,从而让项目中各个工程可以更加方便地整合和交互,让团队更加方便协作
- 对于
-
自动化、智能化
- 最大化地消除构建的重复,抽象了构建生命周期。不需要在定义构建过程,且不需要手动实现这些步骤。其中就包括常见的,将java编译成bin,自动执行所有单元测试等功能,
无需依赖IDE工具
即可实现) - 传统web工程jar包直接放在项目中,Maven提供免费而非常丰富的中央仓库,帮助我们自动下载构建,解决依赖问题。我们需要做的只是在每个项目的 pom 中定义好直接的依赖关系。
- 管理原本分散在项目中各个角落的项目信息,包括项目描述、开发者列表、版本控制系统地址、许可证、缺陷管理系统地址等,节省了寻找信息的时间
- 自动生成站点,从而使得轻松地获得项目文档、测试报告、静态分析报告、原码版本日志报告等非常具有价值的项目信息。
- 将父工程和各个子工程或者模块打包成pom或者jar包到仓库中,为其他子工程或者模块提供相关依赖,更方便地将一个臃肿的大工程拆分成多个子工程或者模块,以便于团队协作开发。
- 最大化地消除构建的重复,抽象了构建生命周期。不需要在定义构建过程,且不需要手动实现这些步骤。其中就包括常见的,将java编译成bin,自动执行所有单元测试等功能,
定义
maven本质上是一个项目管理工具,提供了模板
和工具
来帮助开发人员快速了解项目并加速开发:
- 使用maven项目开发
模板
(包括项目架构
和构建过程
等),开发人员可以在了解一个项目的架构后,迅速了解和操作多个实际的项目。- 使用maven提供的项目管理
工具
,开发人员可以加速项目开发和管理。
maven是Apache开发的一款开源的服务于Java
平台的自动化构建
工具,完成重复性工作。2004年就产生了。
具体步骤包括(不限于):
- 工程目录的创建:标准化工程目录
- 包的导入:同一个项目所有工程使用同一个自动导入包和包的依赖(快照)
- 工程构建:本项目以及相关项目的自动化构建(清理、编译、测试、生成报告、打包、部署)
- 创建工程文档
工作原理相关知识
安装目录
-
maven安装目录
假设Maven_HOME为Maven的安装目录,该安装目录的内部目录包含:
bin boot conf lib LICENSE.txt NOTICE.txt README.txt
- bin: maven的运行脚本。执行任何一条mvn命令,实际上都是在调用这些脚本。
- boot: maven的类加载器
- conf: maven的配置文件,其中
settrings.xml
用于配置maven的全局行为。 - lib: maven本身对应的.class文件,即maven本身
-
maven本地仓库目录
maven默认的本地仓库目录为
C:\Users\用户名\.m2目录
生命周期
-
定义
maven对
项目构建过程
的抽象和统一,从理论上
定义了maven的工作内容和工作过程。通过插件
实现。 -
内容
maven定义了三套
生命周期
:clean
、default
、site
,各生命周期相互独立
。每个生命周期都包含了一些阶段(
phase
)【3套生命周期中phase详解】,每个生命周期中各phase执行时,必须从该生命周期第一个
phase开始,按照既定顺序
执行到要执行的phase。-
clean:清理项目
-
default:部署项目(即通过“原材料”得到一个可运行项目的过程)
主要(不是全部)包括:
- validate:验证项目是否正确,提供必要的信息
- compile:编译项目源代码
- test:测试
- package:打包
- verify:检查集成测试结果
- install:安装打包的项目到本地仓库,异构其他项目使用
- deploy:部署,拷贝最终的工程包到远程仓库
-
site:生成项目站点(为工程相关信息生成一个HTML)
-
插件
-
定义
java程序(jar包),通过maven命令调用运行。
-
作用
为实现maven定义的抽象的声明周期而生。每个插件包含多个插件目标(
goal
),goal和phase绑定
,在使用maven命令
实现某个phase时,实际上调用的是插件的goal。 -
执行语法
mvn [plugin-name]:[goal-name]
例子:
mvn compiler:comile //编译
-
实现方法
maven中每个插件可以实现多个功能(
goal
),通过将插件中的goal
和phase
进行绑定
,来实现maven的生命周期。maven对一些生命周期的phase绑定了默认插件目标,用户也可以在pom.xml中自定义绑定,实现自己定制的声明周期的实现。 -
位置
在maven仓库中
-
补充说明
用户可以根据需求,创建自己的maven插件。
依赖
依赖的释义
依赖,作为名词,指的是工程代码中直接用到的别人已经写好的工程代码(.class文件)。作为动词,指一个工程代码对另外一个工程的代码的引用。
依赖的配置
<!-- 依赖的坐标(必选,其他可根据需要配置 -->
<groupId>com.didispace</groupId>
<artifactId>chapter1-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 依赖的类型(默认为jar) -->
<type>jar</type>
<!-- 依赖的范围(默认为compile) -->
<scope>compile</scope>
<!-- 标记依赖是否可选 -->
<optional></optional>
<!-- 排除传递性依赖 -->
<exclusions></exclusions>
<!-- 依赖的统一配置 -->
<!-- 引用依赖属性值时,使用${属性名} -->
<properties>
<属性名>属性值</属性名>
</properties>
依赖范围
依赖范围即依赖产生作用的时期,maven有三个classpath文件,分别在编译
、测试
和运行
时用到。各依赖对应的.class文件,通过依赖被引入到对应classpath中,依赖范围对应依赖被引入到哪个classpath。除了表中的依赖范围之外,还有一个import依赖范围,其只在dependencyManagement元素中使用,用于导入其他dependencyManagement的配置。
依赖范围 | 含义 | 编译 | 测试 | 运行 | 例子 |
---|---|---|---|---|---|
compile | 编译时用到的依赖,依赖的默认值 | Y | Y | Y | spring-core |
test | 仅测试时用到的依赖 | Y | JUnit | ||
provided | 容器已提供的依赖 | Y | Y | servlet-api | |
runtime | 运行时用到了依赖 | Y | Y | JDBC驱动实现 | |
system | 操作系统提供的依赖 | Y | Y | 本地的,maven仓库外的类库文件 |
依赖的传递性
maven通过pom文件中,在标签工程的直接依赖,如果也使用pom文件来声明自己的直接依赖,直接依赖的直接依赖也是同样,那么如此循环下去,工程的直接依赖以及所有间接依赖就都可以通过传递性获知。因此,每个工程只需要在自己的pom文件中声明好自己直接依赖即可
。
依赖的传递性和依赖的作用范围有关
。下表中,最左边一列表示工程的第一直接依赖范围,第一行表示工程的第二直接依赖范围(即工程直接依赖的直接依赖),中间的交叉单元格表示传递性依赖范围(为空表示依赖不会传递,即不存在依赖关系)。
1 2 | compile | test | provided | runtime |
---|---|---|---|---|
compile | compile | runtime | ||
test | test | test | ||
provided | provided | provided | provided | |
runtime | runtime | runtime |
父子继承关系
的项目的依赖,不论什么范围(compile、test、provided、runtime)都
可以由父项目传递(继承)
下给子项目。因此可以利用父工程pom文件,实现所有子工程依赖“一改全改”。
依赖冲突的解决原则
-
路径近者优先
A–>B–>C–>D–>X(1.6) A–>E–>D–>X(2.0)
X(2.0)距离项目A更近,项目A使用X(2.0)
-
先声明者优先
A–>B–> X(1.6) A–>C–> X(2.0)
路径相同时,B先于C声明,则项目A使用X(1.6)
可选依赖&排除依赖
可选依赖和排除依赖都是阻断依赖传递
的方法。可选依赖阻断的是依赖本项目的项目对本项目的依赖之间的依赖关系,排除依赖阻断的是本项目和间接依赖之间的依赖关系。
- 可选依赖
项目B的某些依赖不推荐被依赖B的项目所使用
时,需要将这些依赖声明成可选依赖。可选依赖不会被传递
,即X和Y不会被A依赖。如果项目A想使用X作为依赖,则需要在自己的pom文件中重新声明。
-
排除依赖
项目A
不想使用他的某些间接依赖
时使用。如项目A所的依赖没有正确的设置它们的依赖集。被排除的依赖不会被传递
,即依赖项目A的项目,不会依赖被A排除的依赖。
依赖的统一配置
pom文件中,某些重复出现的常量值可能需要同步变动
,如需要统一的版本号。此时,为实现pom文件一改全改
的需求,就需要使用\ </properties>标签,声明常量名和常量值,并在常量出现的地方,使用${常量名}的方式引用常量。如:
<properties>
<springframework.version>属性值</springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework,version}</version>
</dependency>
</dependencies>
POM
-
定义
Project Object Model:项目对象模型。是
Maven 项目
的核心
和基本工作单元
。放在工程
根
目录下,文件命名为pom.xml
,包含了关于maven项目
的项目构建
和配置
信息,主要包括项目自身的信息,项目的依赖,项目运行所需环境信息(如:jdk,tomcat)。maven是根据 pom.xml 来识别maven工程的
pom.xml在打包以后就会变成.pom文件
在maven中执行maven命令:在 pom.xml 上右键
Super POM
所有的 POM 都继承自一个父 POM,用于继承默认设置,帮助开发者在 pom.xml 中做尽可能少的配置,当然这些配置可以被重写。
pom文件没有显示声明继承关系时,Maven有一个默认POM作为 Super POM
。
Maven 使用 effective pom
(Super pom + 工程自己的 pom)来执行相关的目标。
父 POM 通过<parent></parent>标签指定
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
使用时需知知识
标准目录结构
maven的标准项目结构如下,当然也可以通过更改pom.xml来配置适合自己的项目结构。
project (项目根目录)
- src (源码)
- main (主程序)
- java (java源码)
- resources (应用资源)
- filters (资源过滤器文件)
- webapp (web应用资源)
- test (测试程序)
- java
- resources
- filters
- it (集成测试(主要针对插件))
- assembly (装配描述符)
- site (站点)
- main (主程序)
- target (编译结果,存放java项目编译后生成的.class文件)
- LICENSE.txt
- NOTICE.txt (项目所依赖的库所需的通知和属性)
- README.txt
- pom.xml:maven的核心配置文件,与构建过程相关的一切设置都在这个文件中进行配置
坐标-完全限定名
构件(项目的依赖
,插件
,以及该项目的构建输出
)的完全限定名,用于在maven的各种仓库中,唯一地定位
一个构件。
构件在maven仓库中对应的目录
为groupId/artifactId/version
。如下面例子对应的构件的文件夹为:com/didispace/charpter1-1/0.0.1-SNAPSHOT。
构件名字为artifactId-version[-classifier].packaging
。如下面例子对应的文件的名字
为 charpter1-1-0.0.1-SNAPSHOT.jar。
<!-- Maven的坐标包含,但不仅限于以下子标签: -->
<!-- 工程组名 (必须) -->
<groupId>com.didispace</groupId>
<!-- 工程名(jar包名字前半部分) (必须) -->
<artifactId>chapter1-1</artifactId>
<!-- 工程版本(jar包名字后半部分)(必须) -->
<version>0.0.1-SNAPSHOT</version>
<!-- 工程打包方式 (可选,默认为jar) -->
<packaging>jar</packaging>
除了groupId,artifactId,version,packaging外,还有一个元素classifier:
该元素用来帮助定义项目构建输出的一些附属构件。附属构件和主构件对应,包括项目的Java文档和源代码等。附属构件不是项目直接默认生成的,需要单独用一些插件来生成,因此不能像 groupId等元素一样直接定义。
仓库
-
分类
-
项目仓库
:项目内文件夹中的依赖包
需要在pom.xml中配置proper<--! 格式 --> <repositories> <repository> <id>仓库唯一标识符</id> <name>仓库的描述</name> <url>仓库的路径</url> </repository> </repositories> <--! 例子 --> <repositories> <repository> <id>in-project</id> <name>In Project Repo</name> <url>file:///${project.basedir}\libs</url> </repository> </repositories>
其中,
${project.basedir}
是pom.xml在系统中的路径。file:///
的含义当然,
本地仓库和远程仓库也可以通过上述标签配置
,只需将仓库的项目的URL改成项目地址。 -
本地仓库
:当前电脑上部署的仓库目录,为当前电脑上所有maven工程服务。默认的仓库位置为:
[系统当前用户home目录]/.m2/repository
修改本地库位置:在
MAVEN_HOME/conf/setting.xml
文件中修改 -
远程仓库
:-
私服
:搭建在局域网环境
中,为局域网范围内所有maven工程服务,主流使用Nexus。有本地主机需要的jar包时,为本地主机提供jar包;没有本地主机需要的jar包时,代替本地主机从中央仓库下载需要的jar包。
-
中央仓库
:Maven社区提供的,为全世界所有maven工程服务。maven的默认远程仓库,安装时自带配置,需要联网访问。 -
其他公共库
:需要在POM中手动配置。
-
-
外部依赖
由于一些原因,存在于某个不是本地仓库和远程仓库下的依赖。例子
<dependencies> <!-- 在这里添加你的依赖 --> <dependency> <groupId>ldapjdk</groupId> <!-- 库名称,也可以自定义 --> <artifactId>ldapjdk</artifactId> <!--库名称,也可以自定义--> <version>1.0</version> <!--版本号--> <scope>system</scope> <!--作用域--> <systemPath>${basedir}\src\lib\ldapjdk.jar</systemPath> <!--项目根目录下的lib文件夹下--> </dependency> </dependencies>
-
-
内容
maven仓库中所有内容都按照统一方式管理和查找。仓库中的内容(即
构件
)包括:- maven
插件
- 第三方的框架或工具的jar包等
依赖
- 我们
自己开发的项目的模块
:需要执行 mvn install 命令,才能将包打入到仓库
- maven
-
使用顺序
本地仓库–>私服–>中央仓库–>其他远程仓库
上一个没有,去下一个查找,连接私服和中央仓库均需要联网
快照
需要依赖处于不断更新状态
的的版本的依赖(快照)时,Maven 会在每次构建时检查快照最新版本。快照版本通过在版本号后面加SNAPSHOT
或者日期
和常规版本进行区分。
<dependencies>
<dependency>
<groupId>data-service</groupId>
<artifactId>data-service</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 或者 <version>1.0-20190212.221414-13</version> -->
<!-- 上面的表示2019年2月12日,22点14分14秒,第13个版本 -->
<scope>test</scope>
</dependency>
</dependencies>
继承
-
定义:
多个模块的pom存在很多相同配置
时,为减少重复代码,统一配置信息,maven通过将相同配置信息写到一个父pom文件中,这些模块的pom文件作为子pom文件,继承父POM文件中的配置(即,可以不用显示声明父pom中已经存在的相关配置信息)。 -
使用:
-
声明一个父模块,父模块的
打包方式为pom
(通过在父pom文件中,设置<packaging>pom</packaging>实现),父模块一般只需要定义好pom.xml中的依赖
即可,无需编写其他代码。在父模块中的pom文件中,写入所有子模块的统一配置信息,在所有子模块的<parent>标签中配置父模块信息,包括<groupId>、<artifactId>、<version>以及<relativePath>。其中,<relativePath>的默认值为 …/pom.xml,即maven默认父POM在上一层目录。 -
如果子模块中需要使用和父模块中不一样的配置,则子模块应该显式声明。子模块会继承所有父模块相关的依赖配置(包括compile、test、provided、runtime)。
-
可继承的pom元素
-
groupId
-
version
-
description:项目的描述信息
-
organization:项目的组织信息
-
inceptionYear:项目的创始年份
-
url:项目的URL地址
-
developers:项目的开发者信息
-
contributions:项目的贡献者信息
-
distributionManagement:项目的部署配置
-
issueManagement:项目的缺陷跟踪系统信息
-
ciManagement:项目的持续集成系统信息
-
scm:项目的版本控制系统信息
-
mailingLists:项目的邮件列表信息
-
properties:自定义的Maven属性
-
dependencies:项目的依赖配置
-
dependencyManagement:项目的依赖管理配置
<!--dependencyManagement标签下的依赖,不会在父项目中引入依赖,也不会给他的子模块引入依赖,只有子类显示声明(如只包含groupId和artifactId)该标签下的依赖时,才会继承依赖的配置--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>com.juvenxu.mvnbook.account</groupId> <artifactId>account-parent</artifactId> <version>1.0-SHAPSHOP</version> <type>pom</type> <!--将依赖范围设为import,导入其他dependencyManagement的配置--> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
-
repositories:项目的仓库配置
-
build:项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
-
reporting:项目的报告输出目录配置、报告插件配置等
-
-
聚合
-
定义:
通过一个
打包方式为pom
的maven项目中,声明任意数量的module元素
来实现一次性构建多个模块
。当被构建的各个模块存在依赖关系时,maven会自动识别各个模块间的依赖关系,先构建被依赖的模块。 -
使用:
-
为了方便用户构建项目,通常将聚合模块放在项目目录最顶层,其他模块最为聚合模块的子模块。
-
module元素的值对应被构建模块和当前POM的相对目录。
-
项目模板 Archetype
为了帮助程序员快速创建一个项目结构,maven提供了archetype(原型/项目模板)插件。
命令
执行mvn命令时,需要调用bin目录下的脚本,大多数maven命令都需要依赖插件
才能执行。
maven的命令跨平台
(因为是java脚本),在Windows、Linux、Mac都是一样的命令。
执行和声明周期过程有关的maven命令,必须在pom.xml所在目录
。
- [1] 清理:mvn clean
- [2] 编译:mvn compile
- [3] 编译测试:mvn test-compile
- [4] 执行测试:mvn test
- [5] 打包:mvn package
- [6] 安装:mvn install
- [7] 部署:mvn site
常见问题
生命周期和插件的关系?
每套生命周期
对应一个接口/抽象类
,生命周期中的每个阶段(phase
)对应一个方法声明
。生命周期定义了phase的顺序,但是没有实现方法。插件目标goal
可以看做是生命周期各个phase对应方法的实现
,为复用代码,多个相似功能的goal组合成一个插件。使用maven命令
执行到生命周期某个phase时,是通过将该phase和对应插件goal绑定
实现的。maven的插件高度易扩展,可以自定义配置,插件和phase间的绑定关系也可以自定义。
不推荐使用IDE内嵌的Maven的原因
- IDE内嵌的maven通常比较新,不一定稳定
- IDE内嵌的maven和系统安装的maven的命令如果是不同版本,会造成构建行为不一致
什么是构建?
构建(build
)对应的就是maven的三个生命周期,其中核心是default
什么是构件?
构件包括构建项目时使用的依赖、插件,以及该项目的构建完成后的输出。
构件通过坐标定位,根据坐标在仓库中取得。
命令和插件的关系
maven命令的执行,使用的是maven安装目录下的bin目录中的脚本。
大部分maven命令的执行,需要依赖插件,即bin目录中的脚本会调用相关插件实现特定功能。
maven的配置文件有哪些?
maven的配置文件包括:
-
pom.xml
某个项目范围内有效
-
%USER_HOME%/.m2/settings.xml
某个用户范围内有效
-
${maven.home}/conf/settings.xml
全局范围有效
其他:
- maven可以通过settings.xml文件设置默认jdk,且不同maven可以识别的jdk版本会不同
artifact是什么?
artifact是maven中的一个概念,对应的是被打包文件的名字,也就对应一个被打包的文件。在IntelliJ IDEA中,module是编译、运行、测试和调试的单位,也是打包的单位。因此IDEA中使用maven时,一个module对应一个artifact包。
参考文献
https://blog.csdn.net/wangdong5678999/article/details/72848044 maven生命周期
https://www.cnblogs.com/luotaoyeah/p/3819001.html maven的生命周期和插件
https://www.runoob.com/maven/maven-tutorial.html maven 菜鸟教程
https://www.cnblogs.com/tooy/p/7364303.html 可选依赖和排除依赖
https://blog.csdn.net/weixin_42112635/article/details/87465997 外部依赖
https://www.runoob.com/maven/maven-snapshots.html 快照
https://blog.csdn.net/xiaoniaox/article/details/79029130 artifact 《Maven实战》
https://blog.csdn.net/zlgydx/article/details/51130627 maven 仓库配置 pom中repositories属性 - CSDN
https://blog.csdn.net/zhangbeizhen18/article/details/91353832 使用IntelliJ IDEA创建基于maven的父工程与子工程