Maven基础
第1章 maven概述
maven是一个自动化构建的项目管理工具
1、背景
(1)jar包的导入需要手动
(2)jar包的依赖需要清楚
(3)jar包重复导入(jar包版本问题)
(4)项目划分只能使用package
(5)项目打包文件大小小,节省磁盘空间
(与传统web项目不同,maven会将所有jar包放在镜像仓库,部署上线的项目会自动到仓库下载jar包)
2、解决
(1)自动导入jar包及其依赖jar包
(2)可以使用mudule划分大型项目
第2章 仓库类型
1、maven仓库分为3种
(1)本地仓库、远程仓库【企业搭建的私服、中央仓库】
2、maven下载jar包流程
(1)本地仓库 -> 远程仓库 -> 中央仓库->镜像仓库
本地仓库
一般来说,在Maven项目目录下,没有诸如lib/这样用来存放依赖文件的目录。当Maven在执行编译或测试时,如果需要使用依赖文件,它总是基于坐标使用本地仓库的依赖文件。
默认情况下,不管在Window还是Linux下,每个用户在自己用户目录下都有一个路径名为.m2/repository/的仓库目录。 如果你想自定义本地仓库目录地址。你可以编辑文件~/.m2/settings.xml,设置localRepository元素的值为想要的仓库地址,例如:
1
2
3
4<settings>
<localRepository>D:\java\repository\</localRepository>
</settings>这样,该用户的本地仓库地址就被设置成了 D:\java\repository\。 需要注意的是,默认情况下,~/.m2/settings.xml文件不存在,用户需要从Maven安装目录复制$M2_HOME/conf/settings.xml文件再进行编辑。
远程仓库-中央仓库
由于最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件。中央仓库就是这样一个默认的远程仓库,Maven的安装文件自带了中央仓库的配置。
中央仓库包含了这个世界上绝大多数流行的开源Java构件,以及源码、作者信息、SCM,信息、许可证信息等,每个月这里都会接受全世界Java程序员大概1亿次的访问,它对全世界Java开发者的贡献由此可见一斑。
远程仓库-私服
私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,它从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。因此,一些无法从外部仓库下载到的构件也能从本地上传到私服上供大家使用。 私服的好处:
- 节省自己的外网速度
- 加速Maven构建
- 部署第三方构建
- 提高稳定性,增强控制
- 降低中央仓库的负荷
远程仓库的配置
在平时的开发中,我们往往不会使用默认的中央仓库,默认的中央仓库访问的速度比较慢,访问的人或许很多,有时候也无法满足我们项目的需求,可能项目需要的某些构件中央仓库中是没有的,而在其他远程仓库中有,如JBoss Maven仓库。这时,可以在pom.xml中配置该仓库,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<!-- 配置远程仓库 -->
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
- **repository:**在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库。
- id:仓库声明的唯一id,尤其需要注意的是,Maven自带的中央仓库使用的id为central,如果其他仓库声明也使用该id,就会覆盖中央仓库的配置。
- name:仓库的名称,让我们直观方便的知道仓库是哪个,暂时没发现其他太大的含义。
- url:指向了仓库的地址,一般来说,该地址都基于http协议,Maven用户都可以在浏览器中打开仓库地址浏览构件。
- releases和snapshots:用来控制Maven对于发布版构件和快照版构件的下载权限。需要注意的是enabled子元素,该例中releases的enabled值为true,表示开启JBoss仓库的发布版本下载支持,而snapshots的enabled值为false,表示关闭JBoss仓库的快照版本的下载支持。根据该配置,Maven只会从JBoss仓库下载发布版的构件,而不会下载快照版的构件。
- layout:元素值default表示仓库的布局是Maven2及Maven3的默认布局,而不是Maven1的布局。基本不会用到Maven1的布局。
- 其他:对于releases和snapshots来说,除了enabled,它们还包含另外两个子元素updatePolicy和checksumPolicy。
1:元素updatePolicy用来配置Maven从远处仓库检查更新的频率,默认值是daily,表示Maven每天检查一次。其他可用的值包括:never-从不检查更新;always-每次构建都检查更新;interval:X-每隔X分钟检查一次更新(X为任意整数)。
2:元素checksumPolicy用来配置Maven检查校验和文件的策略。当构建被部署到Maven仓库中时,会同时部署对应的检验和文件。在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败,当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息,其他可用的值包括:fail-Maven遇到校验和错误就让构建失败;ignore-使Maven完全忽略校验和错误。远程仓库的认证
大部分的远程仓库不需要认证,但是如果是自己内部使用,为了安全起见,还是要配置认证信息的。 配置认证信息和配置远程仓库不同,远程仓库可以直接在pom.xml中配置,但是认证信息必须配置在settings.xml文件中。这是因为pom往往是被提交到代码仓库中供所有成员访问的,而settings.xml一般只存在于本机。因此,在settings.xml中配置认证信息更为安全。
1
2
3
4
5
6
7
8
9
10
11
12
13<settings>
2 ...
3 <!--配置远程仓库认证信息-->
4 <servers>
5 <server>
6 <id>releases</id>
7 <username>admin</username>
8 <password>admin123</password>
9 </server>
10 </servers>
11 ...
12 </settings>这里除了配置账号密码之外,值关键的就是id了,这个id要跟你在pom.xml里面配置的远程仓库repository的id一致,正是这个id将认证信息与仓库配置联系在了一起。
部署构件至远程仓库
我们自己搭建远程仓库的目的就是为了可以方便部署我们自己项目的构件以及一些无法从外部仓库直接获取的构件。这样才能在开发时,供其他对团队成员使用。 Maven除了能对项目进行编译、测试、打包之外,还能将项目生成的构件部署到远程仓库中。首先,需要编辑项目的pom.xml文件。配置distributionManagement元素,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13<distributionManagement>
<repository>
<id>releases</id>
<name>public</name>
<url>http://59.50.95.66:8081/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Snapshots</name>
<url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>看代码,从命名上就看的出来区别,repository表示表示发布版本(稳定版本)构件的仓库,snapshotRepository表示快照版本(开发测试版本)的仓库。这两个元素都需要配置id、name和url,id为远程仓库的唯一标识,name是为了方便人阅读,关键的url表示该仓库的地址。
配置好了就运行命令mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,则部署到快照版本的仓库地址,否则就部署到发布版本的仓库地址。 当前项目是快照还是发布版本是通过 true 这个来区分的。忘记的同学在看看上面的## 远程仓库的配置。
镜像
如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。用过Maven的都知道,国外的中央仓库用起来太慢了,所以选择一个国内的镜像就很有必要,我推荐国内的阿里云镜像。 阿里云镜像:配置很简单,修改conf文件夹下的settings.xml文件,添加如下镜像配置:
1
2
3
4
5
6
7
8
9<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>上例子中,的值为central,表示该配置为中央库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以用同样的方法配置其他仓库的镜像
这里介绍下``配置的各种选项
*:匹配所有远程仓库。external:*:匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。也就是说,匹配所有不在本机上的远程仓库。repo1,repo2:匹配仓库repo1h和repo2,使用逗号分隔多个远程仓库。*,!repo1:匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。
仓库服务搜索
这里介绍2个提供仓库服务搜索的地址:
- Sonatype Nexus:repository.sonatype.org/
- MVNrepository:mvnrepository.com/
第3章 目录结构
maven提供了一个标准
1、核心代码目录:src/main/java
2、核心配置目录:src/main/resources
3、测试代码目录:src/test/java
4、测试配置目录:src/test/resources
5、其他目录:根据模板不同,会有对应的目录
第4章 常用命令
maven有一套管理项目结构的命令,每一个命令都是一个插件
- mvn clean:表示运行清理操作(会默认把target文件夹中的数据清理)。
- mvn clean compile:表示先运行清理之后运行编译,会将代码编译到target文件夹中。
- mvn clean test:运行清理和测试。
- mvn clean package:运行清理和打包。
- mvn clean install:运行清理和安装,会将打好的包安装到本地仓库中,以便其他的项目可以调用。
- mvn clean deploy:运行清理和发布(发布到私服上面)。
mvn clean package 及之后的命令跳过test阶段
第5章 生命周期
maven有三套生命周期
1、“清理生命周期”:clean【项目运行之前需要清除项目之前编译的代码】
2、“默认生命周期”:编译compile、测试test、打包package、安装install、发布deploy【一个项目编译到发布的过程】
3、“站点生命周期”:【使用较少,暂不介绍】
第6章 依赖范围
1、依赖范围
依赖范围就是用来控制依赖和三种classpath(编译classpath,测试classpath、运行classpath)的关系,Maven有如下几种依赖范围:
- compile: 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。典型的例子是spring-code,在编译、测试和运行的时候都需要使用该依赖。
- test: 测试依赖范围。使用次依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此依赖。典型的例子是Jnuit,它只有在编译测试代码及运行测试的时候才需要。
- 如junit
- provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时候无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器以及提供,就不需要Maven重复地引入一遍。
- 如servlet-api
- **runtime:**运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
- JDBC驱动实现
- **system(一般不用):**系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致,但是,使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能构成构建的不可移植,因此应该谨慎使用。systemPath元素可以引用环境变量,如:
1 | |
- **import:**导入依赖范围。该依赖范围不会对三种classpath产生实际的影响。 上述除import以外的各种依赖范围与三种classpath的关系如下:
2、传递性依赖
比如一个account-email项目为例,account-email有一个compile范围的spring-code依赖,spring-code有一个compile范围的commons-logging依赖,那么commons-logging就会成为account-email的compile的范围依赖,commons-logging是account-email的一个传递性依赖
有了传递性依赖机制,在使用Spring Framework的时候就不用去考虑它依赖了什么,也不用担心引入多余的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。
3、依赖范围
假设A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖和第二直接依赖的范围决定了传递性依赖的范围,如下图所示,最左边一行表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间的交叉单元格则表示传递依赖范围。
从上图中,我们可以发现这样的规律:
- 当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
- 当第二直接依赖的范围是test的时候,依赖不会得以传递;
- 当第二直接依赖的范围是provided的时候,只传递第一直接依赖范围也为provided的依赖,切传递依赖的范围同样为provided;
- 当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile列外,此时传递性依赖范围为runtime.
4、依赖调解
有时候,当传递性依赖造成为题的时候,就需要清楚地知道该传递性依赖是从哪条依赖路径引入的。这就是依赖调解的作用,依赖调解有两大原则: 1. 路径最近者优先 比如项目有A有这样的依赖关系:A->B->C->X(1.0)、A->D->X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版本的X,所以根据第一原则,A->D->X(2.0)路径短,所以X(2.0)会被解析使用 2. 第一声明者优先 如果路径都一样长的话,第一原则就不行了,比如 A->B->Y(1.0)、A->C->Y(2.0),Y(1.0)和Y(2.0)的路径一样,所以这时候根据第二原则,2.先声明的被解析。
5、可选依赖
如图,项目中A依赖B,B依赖于X和Y,如果所有这三个的范围都是compile的话,那么X和Y就是A的compile范围的传递性依赖,但是如果我想X,Y不作为A的传递性依赖,不给他用的话。就需要下面提到的配置可选依赖。
1 | |
配置也简单,在依赖里面添加
1 | |
就表示可选依赖了,这样A如果想用X,Y就要直接显示的添加依赖了。
6、排除依赖
有时候你引入的依赖中包含你不想要的依赖包,你想引入自己想要的,这时候就要用到排除依赖了,比如下图中spring-boot-starter-web自带了logback这个日志包,我想引入log4j2的,所以我先排除掉logback的依赖包,再引入想要的包就行了
排除依赖代码结构:
1 | |
这里注意:声明exclustion的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖。
7、归类依赖
有时候我们引入的很多依赖包,他们都来自同一个项目的不同模块,所以他们的版本号都一样,这时候我们可以用属性来统一管理版本号
1 | |
如图所示,先通过
1 | |
来定义,然后在下面依赖使用${}来引入你的属性。
第7章 概念模型
主要体现了maven的两个核心功能:依赖管理和一键构建

第八章 操作与配置
1、maven安装




2、仓库配置 & setting.xml文件

3、IDEA配置


-DarchetypeCatalog=internal
4、使用骨架
java项目





web项目


5、不用骨架
开发中推荐不使用骨架创建maven项目

6、多模块管理:方式1
大型项目project需要分模块mudule管理。以下是maven多模块管理的测试案例一。
(1)创建空项目(project)

(2)创建parent模块(module)


(3)创建child模块(mudule)



(4)统一管理依赖
1、父类中的依赖子类会无条件继承
2、使用dependencyManagement标签强制管理依赖

(5)获取指定依赖
子模块声明需要继承的依赖,不用写version

(6)管理版本号
maven管理依赖最终的目的就是管理版本号,parent一改全部跟着改

📎pom.xml(parent的pom.xml文件)
(7)项目结构

7、多模块管理:方式2
(1)创建parent工程
创建好之后同样需要删除src目录,添加packing标签,标签值为pom

(2)创建child工程



其他操作,如管理依赖、管理版本号、继承指定版本号这些和方式1一致
8、调整java编译器版本
方式1:IDEA设置;当pom文件变化时,jdk版本还是会变成1.5

方式2:在pom文件配置jdk编译插件的版本,这样,当pom文件引入新的依赖,也不会改变jdk的版本
1 | |
方案3:和方案2一样的效果
1 | |
第九章 转载:Maven中的profile标签
原文连接:Maven根据pom文件中的Profile标签动态配置编译选项
概述
在实际项目开发中,我们需要根据不同的使用场景,构建不同的程序包。当使用Maven编译时,我们可以通过Maven的profile标签来配置编译选项,从而达到生成不同构建产物的目的。例如,在开发环境下,我们有一套适用于本机的调试配置;而在生产环境下,又需要关闭调试环境时的大量调试日志,或变更日志保存路径等。这些需求都可以通过Maven的Profile标签配置来解决。
profile可以让我们定义一系列的配置信息,然后指定其激活条件。由此,我们就可以定义多个profile,然后每个profile对应不同的激活条件和配置信息,从而达到不同环境使用不同配置信息的效果。比如说,我们可以通过profile定义在jdk1.5以上使用一套配置信息,在jdk1.5以下使用另外一套配置信息;或者有时候我们可以通过操作系统的不同来使用不同的配置信息,比如windows下是一套信息,linux下又是另外一套信息,等等。
1、profile属性的定义位置
我们有多个可选位置来定义profile。定义的地方不同,它的作用范围也不同。
- 针对于特定项目的profile配置我们可以定义在该项目的pom.xml中。
- 针对于特定用户的profile配置,我们可以在用户的settings.xml文件中定义profile。该文件在用户家目录下的“.m2”目录下。
- 全局的profile配置。全局的profile是定义在Maven安装目录下的“conf/settings.xml”文件中的。
2、profile中能定义的信息
profile中能够定义的配置信息跟profile所处的位置是相关的。以下就分两种情况来讨论,一种是定义在settings.xml中,另一种是定义在pom.xml中。
3、profile定义在settings.xml中
当profile定义在settings.xml中时意味着该profile是全局的,它会对所有项目或者某一用户的所有项目都产生作用。也正因为它是全局的,所以在settings.xml中只能定义一些相对而言范围宽泛一点的配置信息,比如远程仓库等。而一些比较细致一点的需要根据项目的不同来定义的就需要定义在项目的pom.xml中。具体而言,能够定义在settings.xml中的信息有:
- 定义在
里面的键值对可以在pom.xml中使用。
4、profile定义在pom.xml中
定义在pom.xml中的profile可以定义更多的信息。主要有以下这些:
还有build元素下面的子元素,主要包括:
5、profile标签配置的激活方式
Maven给我们提供了多种不同的profile激活方式。比如我们可以使用-P参数在编译时,显示的激活一个profile,也可以根据环境条件的设置让它自动激活等。
6、使用activeByDefault设置默认激活(定义在pom文件中)
1 | |
我们可以在profile下的activation标签中,通过activeByDefault标签配置激活状态,当没有在编译命令中配置任何激活条件时,activeByDefault标签在哪个profile下配置为true的时候,就表示该profile在编译时默认会被激活。
7、在settings.xml中使用activeProfiles指定处于激活状态的profile
我们可以在settings.xml中使用activeProfiles来指定需要激活的profile,这种方式激活的profile将所有情况下都处于激活状态。比如现在我们定义了如下两个profile:
1 | |
这里的profile可以是定义在settings.xml中的,也可以是定义在pom.xml中的。当这时需要指定dev为激活状态,那么我们就可以在settings.xml中定义activeProfiles,如下:
1 | |
考虑这样一种情况,我们在activeProfiles下同时定义了多个需要激活的profile。这里还拿上面的profile定义来举例,我们定义了同时激活dev和release。
1 | |
那么这个时候我在pom.xml中使用属性properties.active的时候,它是根据profile定义的先后顺序来进行覆盖取值的,即后面定义的会覆盖前面定义的(定义仓库的时候也是如此)。
8、使用-P参数显示的激活一个profile
我们在进行Maven操作时可以使用-P参数显示的指定当前激活的是哪一个profile。比如我们需要在对项目进行打包的时候使用id为dev的profile,我们就可以这样做:
1 | |
假如我们使用activeByDefault或settings.xml中定义了处于激活的profile,但是当我们在进行某些操作的时候又不想它处于激活状态,这个时候我们可以这样做:
1 | |
这里假设dev是在settings.xml中使用activeProfile标记的处于激活状态的profile,那么当我们使用“-P !dev”的时候就表示在当前操作中该profile将不处于激活状态。
9、根据编译环境来激活profile
profile一个非常重要的特性就是它可以根据不同的编译环境来激活,比如说根据操作系统的不同激活不同的profile,也可以根据jdk版本的不同激活不同的profile,等等。
1 | |
第十章 举例-基于Springboot下的log4j2实践配置步骤
我们以配置log4j2为例来说一说开发环境和生产环境的不同设置。
一、在src/main/resources/下新建config目录,并在其中创建dev和release文件夹
二、分别编写两个不同环境下的log4j2配置文件
这两个配置文件的主要区别在于,其中的日志保存路径是不同的。(此处只是为了演示区别,随意对路径进行了配置,可自己配置所需路径) 调试用的log4j2-spring.xml:
正式环境下的log4j2-spring.xml:
并分别将刚才的两个文件放置到对应的目录中。
三、配置POM文件
在项目的pom.xml文件中,在其根节点project下,增加profiles标签:
其中:
标签表明当前为一个profile描述体 标签表明当前profile的id,用来区分不同的profile 标签中,可以自定义K、V值,这里的标签名任意,在项目的properties或xml等配置文件中可以使用${profiles.active}可以取出”dev”或“release”这个值
在项目的pom.xml文件中,在其build节点下,增加resource标签:
其中:
表示编译所需的资源目录 标签表示排除掉资源目录下的某文件或文件夹 表示该资源标签下的资源打包编译后的保存路径,“.”表示当前路径 由此可见,我们将路径src/main/resources/config/${profiles.active}配置上了我们在profile中定义的Key值,这样,当我们通过-P参数来激活配置时,就可以引入对应的配置文件了。
四、编译
通过执行下面的命令进行编译:
1 | |
激活了dev编译条件。编译生成war或jar文件后,可以解压构建包,确认配置文件被打包到构建包的根目录下。