Maven某种程度上跟NPM类似,都是软件项目中包依赖解决方案。但是它比NPM更强大,因为它提供了更多地软件项目的编译、打包以及发布等操作。
本篇介绍最基础的步骤。
下载与配置
跟NPM需要安装node.js不同,Maven只需要下载和配置就能使用。
首先,去官方网站去下载。
以Windows系统为例,下载并解压缩到选定的文件夹(/install_dir/)。配置系统变量:
M2_HOME=/install_dir/
同时,更新系统变量Path
Path=$PATH:$M2_HOME/bin
确认下配置成功:
mvn -version
输出结果:
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: D:\Tools\apache-maven-3.6.3\bin\..
Java version: 15.0.1, vendor: Oracle Corporation, runtime: D:\Tools\jdk-15.0.1
Default locale: en_US, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
新建、运行第一个项目
下载和配置完成之后,动手创建和执行项目才是最关键的。详情参阅官方文档。
官方文档建议使用以下命令来创建新建一个项目:
mvn -B archetype:generate -DgroupId=com.alvachien.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4
然而,这里有个第一个坑,在Windows环境下,上述命令只会导致下列错误:
The goal you specified requires a project to execute but there is no POM in this directory (D:\xxx). Please verify you invoked Maven from the correct directory.
解决方法:参数输入需要以“”封装:
mvn -B archetype:generate "-DgroupId=com.alvachien.app" "-DartifactId=marvin-tutorial" "-DarchetypeArtifcatId=maven-archetype-quickstart"
当然,可以看看Visual Studio Code的New Maven Project的命令:
mvn org.apache.maven.plugins:maven-archetype-plugin:3.1.2:generate -DarchetypeArtifactId="maven-archetype-quickstart" -DarchetypeGroupId="org.apache.maven.archetypes" -DarchetypeVersion="1.4"
这时,就会成功创建项目。打开其中的App.java,就是一个简单的Hello World程序:
package com.alvachien.app;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
然后,编译项目:
mvn compile
接着,第二个坑出现了,因为刚刚创建的project编译通不过:
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< com.alvachien.app:marvin-tutorial >------------------
[INFO] Building marvin-tutorial 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ marvin-tutorial ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory D:\srccodes\git\learning-notes\marvin-tutorial\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ marvin-tutorial ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:\srccodes\git\learning-notes\marvin-tutorial\target\classes
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] Source option 5 is no longer supported. Use 7 or later.
[ERROR] Target option 5 is no longer supported. Use 7 or later.
[INFO] 2 errors
解决方法是,更新POM文件,指定使用Java Version 15:
<properties>
<maven.compiler.release>15</maven.compiler.release>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
然后,进行测试:
mvn test
测试结果顺利通过:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.alvachien.app.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.007 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.183 s
[INFO] Finished at: 2020-11-21T15:21:15+08:00
[INFO] ------------------------------------------------------------------------
如果需要运行程序,还需要将package为jar文件:
mvn package
这时,可以观察到target目录下就多了marvin-tutorial-1.0-SNAPSHOT.jar文件。
有了jar文件,可以运行程序了:
java -cp target/marvin-tutorial-1.0-SNAPSHOT.jar com.alvachien.app.App
运行结果:
>>
Hello World!
一个典型的Maven项目
一个典型的Maven项目结构,详情参与Standard Directory Layout:
my-app
├──── pom.xml
├──── README.txt
├──── LICENSE.txt
├──── src
│ ├──── main
│ │ ├──── java
│ │ │ └──── com
│ │ │ └──── mycompany
│ │ │ └──── app
│ │ │ └──── App.java
│ │ ├──── resources
│ │ └──── filters
│ ├──── test
│ │ ├──── java
│ │ │ └──── com
│ │ │ └──── mycompany
│ │ │ └──── app
│ │ │ └──── AppTest.java
│ │ ├──── resources
│ │ └──── filters
│ ├──── assembly
│ ├──── site
│ └──── it
└──── target
各文件和目录说明如下:
- 项目描述文件: pom.xml
- 项目说明文件: readme.txt
- 项目版权文件: license.txt
- 源码目录: src/main/java
- 项目资源目录: src/main/resources
- 项目资源filter目录: src/main/filters
- 测试代码目录: src/test/java
- 测试资源目录: src/test/resources
- 测试资源filter目录: src/test/filters
- 集成测试目录: src/it
- 编译、打包输出目录:target
- Assembly:Assembly
- Site: Site
项目描述文件
一个典型的项目描述文件:
<project ...>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>11</maven.compiler.release>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
项目包的逻辑key
与NPM中使用名称和Version作为唯一标识来确定dependence类似,Maven中依赖管理的逻辑key是:
- groupId,项目包开发组织的名称;
- artifactId,该jar包自身的名称;
- version,该jar包的版本。注意,以-SNAPSHOT结尾的版本会被Maven视为开发版本。
同样,在项目描述文件中,上述三个逻辑key也用作项目描述文件的关键信息。
依赖关系范围
Maven的依赖关系范围:
scope | 说明 |
---|---|
compile | (默认)编译范围,只在编译时用到该依赖 |
test | 编译test时需要用到该依赖。典型的runtime是JUnit |
runtime | 编译时不需要该依赖,运行时需要。典型runtime是JDBC驱动,如MySQL |
provided | 编译时用到该依赖,但运行时由JDK或某个服务器提供。典型的provided依赖是Servlet API |
Maven下载与国内镜像
当Maven进行编译或测试时候,Maven会自动下载依赖的包。基于国情,指定使用国内镜像还是很有必要的。Windows系统下,在用户主目录下创建.m2目录,创建一个settings.xml配置文件:
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<name>aliyun</name>
<mirrorOf>central</mirrorOf>
<!-- 阿里云的Maven镜像 -->
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>
</mirrors>
</settings>
编译Maven项目
在根目录下(即pom.xml所在目录),可以直接进行编译:
mvn clean package
这样,所有文件被编译,并输出到target目录。
Maven的生命周期 (lifecyle)
常见的Maven的生命周期有两个:default和clean。
而Maven的生命周期由一系列阶段(Phase)构成。而Phase则对应了一个或多个Goal。常见的Phase对应的Goal如下:
Phase | 对应的Goal |
---|---|
compile | compiler:compile |
test | compiler:testCompile;surefire:test |
实际上,每个Phase的执行,都是通过其对应的插件(plugin)来执行的。譬如,Maven本身其实并不知道如何执行compile,它只是负责找到对应的compiler插件,然后执行默认的compiler:compile这个goal来完成编译。
换言之,使用Maven,实际上就是配置好需要使用的插件,然后通过phase调用它们。
Plugin | 对应执行Phase |
---|---|
clean | clean |
compiler | compile |
surefire | test |
jar | package |
Maven提供了能满足需求的标准插件。如果标准插件无法满足需求,我们还可以使用自定义插件。 一些常用的插件:
- maven-shade-plugin:打包所有依赖包并生成可执行jar;
- cobertura-maven-plugin:生成单元测试覆盖率报告;
- findbugs-maven-plugin:对Java源码进行静态分析以找出潜在问题。
Maven的default生命周期
它包含了如下的阶段(Phase):
- validate: validate the project is correct and all necessary information is available;
- initialize
- generate-sources
- process-sources
- generate-resources
- process-resources
- compile: compile the source code of the project;
- process-classes
- generate-test-sources
- process-test-sources
- generate-test-resources
- process-test-resources
- test-compile
- process-test-classes
- test: test the compiled source code using a suitable unit test framework;
- prepare-package
- package
- pre-integration-test
- integration-test
- post-integration-test
- verify: run any checks to verify the package is valid and meets quality criteria;
- install: install the package into the local repository.
- deploy: done in an integration or release environment, copies the final package to the remote repository.
Maven的clean生命周期
它包含了如下的阶段:
- pre-clean
- clean
- post-clean
常见的Maven的命令
常见的Maven命令如下:
- mvn clean: 执行clean生命周期中的phase,主要用于清理所有生成的class和jar;
- mvn clean compile:先执行clean生命周期,再执行default生命周期到compile的phase;
- mvn clean test:先执行clean生命周期,再执行default生命周期到test的phase;
- mvn clean package:先执行clean生命周期,再执行default生命周期到package的phase;