1. Maven 基础
1.1 Maven 安装
Maven 的下载和安装过程这里就不在累述,下面是 Maven 安装完毕后需要配置的环境变量
配置环境变量
(1) 添加变量M2_HOME,其值为 Maven的安装目录,例如:D:\Program Files (x86)\Maven\maven-3.6.1
(2) 将M2_HOME添加到系统变量PATH,即在PATH中追加 %M2_HOME%/bin;
1.2 Maven 配置
(1) 配置本地仓库
修改 settings.xml 文件中的 localRepository
标签,用来指定本地仓库,如下所示:
<localRepository>D:\Program Files (x86)\Maven\maven-3.6.1\repository</localRepository>
(2) 配置镜像
有的时候 Maven 的中央仓库下载文件会很慢,我们可以配置国内的 Maven 仓库镜像,这样下载文件就非常迅速。下面是配置阿里云的镜像:
<mirrors>
<mirror>
<id>aliyunmvn</id>
<name>aliyunmvn</name>
<indexOf>public</indexOf>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
注意:
有的同学在配置阿里云的镜像时,将indexOf
标签的值设置为*
,*
表示匹配任意的远程仓库,这可能会导致用户在 pom.xml 文件中指定的远程仓库无效。为了避免这种情况,可以将indexOf
设置为具体的仓库名称。
阿里云的Maven仓库:
1.3 Maven 工程目录结构
使用 Maven 创建工程的时,默认的工程目录结构如下所示:
|---src
|---|---main
|---|---|---java
|---|---|---resources
|---|---test
|---|---|---java
|---|---|---resources
|---pom.xml
- src/main/java:存放主程序的类文件
- src/main/resources:存放主程序的资源文件,例如:配置文件、静态资源文件等
- src/test/java:存放测试程序的类文件
- src/test/resources:存放测试程序的资源文件,例如:配置文件,静态资源文件等
- pom.xml:pom文件
1.4 资源检索
当你在引入依赖但却不知道依赖的坐标时,你可以访问https://mvnrepository.com
,然后通过关键字可以查询所需要资源信息。
2. Maven的生命周期、命令、插件
2.1 生命周期
Maven 的生命周期本质上是对项目构建过程的抽象,Maven 定义了 3 套生命周期:clean
、default
、site
。每个生命周期又包含很多阶段,即phase
,例如:清理、编译、测试、打包、部署等等...,这些phase
都可以通过 Maven 相关的命令来完成,但是,实际上都是通过对应的 Maven 插件来实现的。
Tips:在项目开发过程中,我们最常用的生命周期就是default,这也是Maven最核心的生命周期。
2.2 Maven 基础命令
mvn clean:清理原先编译生成的目录,即 target
目录,但是已经 install 到本地仓库的依赖包不会被删除
mvn compile:编译主程序,会生成一个target
目录,编译后的字节码文件存放在 target /classes
目录
mvn test-compile:编译测试程序,会生成一个 target
目录,编译后的字节码文件存放在test-classes
目录
mvn test:进行测试,测试结果会放在target/surefire-reports
目录
mvn package:打包主程序,执行该命令会先编译再打包,打包的结果默认存放在target
目录
mvn install:安装主程序,执行该命令会先编译打包再 install,install 的目的是将打包的结果存放在本地仓库,可供其它项目使用
2.3 Maven 常用插件
Maven 是一个插件框架,Maven 生命周期的每一个阶段都是由不同的插件来完成的。例如,在编译阶段,需要maven-compiler-plugin
插件来指定编译时采用的 JDK 版本;在打包阶段,需要maven-jar-plugin
插件或者maven-war-plugin
插件来完成项目的打包工作,等等....
正因如此,我们需要对一些常用的 Maven 插件进行学习和总结,以便在今后的工作中能正确地使用 Maven,从而提开发效率。
(1) maven-compiler-plugin 插件
maven-complier-plugin
插件用来指定编译阶段采用的 JDK 版本以及编码格式。如果不显示地指定,则在编译阶段会使用maven-complier-plugin
插件默认的 JDK 进行编译,这可能会导致项目编译失败。例如,代码中使用了 Java 8 的新特性,但是在编译的时候使用 JDK 6,因此导致编译失败。
示例:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<!--设置源码JDK版本-->
<source>1.8</source>
<!--设置编译采用的JDK版本-->
<target>1.8</target>
<!--设置字符编码-->
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
(2) maven-jar-plugin 插件
maven-jar-plugin
是 Maven 默认的打包插件,这个插件会将可执行的 jar 包与依赖包分开。将打包后的 jar 包存放在target
目录中,将依赖包存放在target/lib
目录中,并且可执行的 jar 包与 lib 目录在同一级。
使用maven-jar-plugin
插件打包后,在得到的 jar 包内的MATE-INF
目录下会生成一个MANIFEST.MF
文件,这个文件主要是记录了当前 jar 包在执行时读取的 classpath,以及依赖包的位置等信息。
示例:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<!--归档-->
<archive>
<!--配置清单-->
<manifest>
<!--指定入口程序-->
<mainClass>com.example.Application</mainClass>
<!--是否将依赖包的classpath添加到当前jar的classpath中-->
<addClasspath>true</addClasspath>
<!--依赖包的存放目录-->
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<!--追加当前jar可读取的classpath-->
<manifestEntries>./</manifestEntries>
</archive>
<!--排除不需要一起打包的文件-->
<excludes>
<exclude>省略</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
(3) maven-resource-plugin 插件
maven-resource-plugin
插件在默认情况下只会读取src/main/resources
目录下的所有文件,并且在编译的时候会将 src/main/resources
目录下的所有文件拷贝到 target/classes
目录下。但是,如果你的资源文件在其它目录,那么就需要配置maven-resource-plugin
插件,让其读取指定的资源文件。
示例:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
</plugin>
</plugins>
<!-- 资源配置 -->
<resources>
<!-- 读取src/main/resources目录下所有以.properties、.xml、.yml、.yaml结尾的文件 -->
<resource>
<directory>src/main/resources/</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
<include>**/*.yaml</include>
</includes>
</resource>
<!-- 读取src/main/resources目录以.xml结尾的文件 -->
<resource>
<directory>src/main/java/</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
更多插件的学习可以参考官网 Maven Plugins 部分。
3. 依赖管理
3.1 依赖的范围
在 pom.xml 文件中引入依赖的时候,通过<scope>
标签来指定依赖的作用范围,依赖的作用范围用来控制依赖包在哪些phase
生效,<scope>
标签的可选值如下所示:
- compile:默认的依赖范围,如果使用 compile,依赖包在主程序和测试程序的编译与运行阶段都有效
- test:测试依赖范围,如果使用 test,依赖包在主程序的编译、运行阶段不会生效,而在测试程序的编译、运行阶段有效;例如:在引入 junit 依赖时,其依赖范围就是 test
- provided:provided依赖范围,如果使用 provided,依赖包在主程序和测试程序的编译阶段生效,而在运行阶段不会生效;例如:引入 javax.servlet-api 依赖时,其依赖范围就是 provided,因为在运行时 Tomcat 容器会提供 javax.servlet-api 依赖
- runtime:运行时依赖范围,如果使用runtime,依赖包在主程序和测试程序的编译阶段不会生效,而在运行阶段才会生效
- import:导入依赖范围,这个依赖范围只能在
<dependencyManagement>
标签下使用才能生效 - system:跟 provided 基本一致,不常用,可忽略
3.2 依赖的传递性
假设有 A、B、C 三个项目,A 依赖 B,B 依赖 C,则 A 依赖 C;Maven 依赖传递性描述如下:
A->B; B->C => A->C
依赖的传递性对依赖作用范围的影响:
compile | test | provided | runtime | |
---|---|---|---|---|
compile | compile | - | - | runtime |
test | test | - | - | test |
provided | provided | - | provided | provided |
runtime | runtime | - | - | runtime |
上述表格中,最左边一列的依赖范围为第一直接依赖的依赖范围,最上面一行的依赖范围为第二直接依赖的依赖范围,现总结规律如下:
- 如果第二直接依赖的依赖范围为
compile
,则传递的依赖的作用范围与第一直接依赖一致 - 如果第二直接依赖的依赖范围为
test
,则依赖不可传递 - 如果第二直接依赖的依赖范围为
provided
,则只有第一直接依赖的依赖范围也为provided
时,依赖才会传递 - 如果第二直接依赖的依赖范围为
runtime
,则传递的依赖的作用范围与第一直接依赖一致,除第一直接依赖的依赖范围为compile
外