简介

项目里一直用的 maven,几乎天天和这个“熟知”的工具打交道,但是,最近我发觉自己对 maven 了解的还不够,例如,什么是 goal?什么是 phase?等等。趁着最近有时间,把官网文档大致看了一遍,并且做做笔记,也就形成了这篇博客。

本文主要讲解以下内容:

  1. 什么是 maven?maven有什么用?
  2. 安装和使用 maven
  3. maven 的构建生命周期
  4. 配置 maven
  5. 常见问题(持续更新)

什么是maven?maven 有什么用?

这两个问题,很多文章都有说到,但是,大部分都是翻译了官网的这句笼统的话,看了和没看一样。

Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.

以下是我的个人总结,可能稍微好理解一点。

首先,maven 是一个工具,用来帮助我们简化标准化项目的构建,主要分成四点:

  1. 如何描述一个项目。我们可以简单地用一个坐标(groupId、artifactId、version)来描述一个项目。
  2. 将项目的构建分为哪些阶段。maven 将项目的构建过程标准化,划分为多个有序的阶段,例如,默认生命周期大致包括:编译、测试、打包、安装、部署等。
  3. 如何发布和共享项目。maven 项目的发布和共享基于仓库坐标两个基础,我们可将项目发布到仓库,其他人可以通过项目的坐标从仓库中获取这个项目。
  4. 如何处理项目间的关系。我们可以在 pom.xml 配置对应的坐标来依赖其他的项目,而不需要手动地将众多的 jar 包添加到 classpath 中。

下载、安装

项目环境

maven:3.6.3

操作系统:win10

JDK:8u231

下载、安装

进入官网下载地址,根据自己的操作系统和 JDK 选择合适的 maven 版本,这里我们也可以选择下载二进制安装包或者源码包。这里我选择版本 3.6.3 的二进制安装包。

将下载的 .zip 文件解压,可以看到以下的目录结构:

进行到这一步可以说 maven 已经安装好了,只是我们还需要进行简单的配置。

环境配置

首先,因为 maven 是由 Java 编写,需要 JDK 才能运行,所以,我们必须保证配置好了 JAVA_HOME 的环境变量。这个我就不展开了。

然后,将解压文件中的 bin 目录添加到 Path 的环境变量中(我的电脑(右键属性)->高级系统设置->环境变量),如下所示:

测试

在任一位置打开命令行,输入:mvn -vmvn --version,显示以下内容,说明安装完成。

简单使用maven

安装完成后,下面通过一个简单的例子来模拟构建 maven 项目的过程。

生成maven项目

cmd 进入到你想要存放项目的文件夹,输入以下命令:

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

在这个命令中,archetype:generate为一个goal(后面展开分析),而后面那些都是执行这个goal所需的参数。

如果是你的 maven 是刚安装的,这个命令可以会执行比较久,因为 maven 需要将所需的软件包或其他文件下载到你的本地仓库(默认在 ${user.home}/.m2/repository 目录下)。如果出现连接超时等情况,可以尝试多执行几次(可以将settings.xml的仓库镜像配置为其他地址来提高下载速度)。

执行完这个命令,可以看到指定文件夹下生成了一个 maven 项目,cd my-app,它的文件结构如下:

my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java

其中,

src/main/java目录用来放项目的代码,这些代码将会被编译并打包。

src/test/java目录用来放项目的测试代码,这些代码仅进行编译运行,不打包。

如果我们想要添加一些资源文件,可以在src/main目录下创建一个resource目录,这些资源最终也会被打包到项目根目录下。

my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- META-INF
| `-- application.properties
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java

pom.xml则包含了构建这个项目的配置信息,后面我们将重点介绍这个文件。

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version> <name>my-app</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

上面生成的项目中包含了两个类,其中,App.java 有一个打印 Hello World! 的 main 方法。接下来我们尝试将项目打包并运行。

构建项目

maven 将构建和部署项目的过程定义成了很多个有序的phase(可以理解为步骤),我们可以执行以下命令来打包项目。

mvn package

这个命令将执行package之前的phase,如validatecompiletest等,以及执行package本身。严格上来讲,实际上执行的不是phase,而是绑定在这些phase上的goal,后面会展开讲解。

执行成功后,项目根目录生成了一个 target 文件夹,里面就有打包好的 my-app-1.0-SNAPSHOT.jar。

my-app\target
│ my-app-1.0-SNAPSHOT.jar

├─classes
│ └─com
│ └─mycompany
│ └─app
│ App.class

├─generated-sources
│ └─annotations
├─generated-test-sources
│ └─test-annotations
├─maven-archiver
│ pom.properties

├─maven-status
│ └─maven-compiler-plugin
│ ├─compile
│ │ └─default-compile
│ │ createdFiles.lst
│ │ inputFiles.lst
│ │
│ └─testCompile
│ └─default-testCompile
│ createdFiles.lst
│ inputFiles.lst

├─surefire-reports
│ com.mycompany.app.AppTest.txt
│ TEST-com.mycompany.app.AppTest.xml

└─test-classes
└─com
└─mycompany
└─app
AppTest.class

运行项目

接下来就是运行 jar 包了,在命令行输入

java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App

执行完成,可以看到打印:

Hello World!

maven 的构建生命周期

构建生命周期( build lifecycle )是 maven 的核心理论基础之一,它将项目的构建过程标准化。

maven 有三个独立的生命周期:

  1. 默认生命周期。用来定义项目构建的过程。
  2. 清理生命周期。用来定义项目清理的过程。
  3. 站点生命周期。用来定义项目站点发布的过程。

phases

一个生命周期包括了许多具体的phase(可以理解为步骤),如下:

默认生命周期

一般我们接触比较多的是默认生命周期,它主要包括以下过程:

  • validate - 校验项目是一个正确的 maven 项目
  • compile - 编译代码
  • test - 测试src/test/java中的方法,src/test/java的内容仅作为测试使用,不会进行打包或部署
  • package - 将项目打包为可执行的 jar、war 等二进制软件包。
  • install - 将软件包安装到本地仓库
  • deploy - 将软件包部署到远程仓库

除了这几个常用的phase,还有initializegenerate-sourcesprocess-sources等等,需要注意一点,当我们执行某个阶段的命令时,类似 pre-*, post-*, or process-* 的阶段一般只是产生中间结果,并不会对最终构建结果产生影响。

清理生命周期

pre-clean - 在清理项目前执行一些东西

clean- 清理项目,例如删除 target 包

post-clean- 在清理项目后执行一些东西

站点生命周期

pre-site - 在生成站点文档前执行一些东西

site - 生成站点文档

post-site - 在生成站点文档后、部署站点文档前执行一些东西

site-deploy - 部署站点文档

goals

在下面这个 maven 命令中,archetype:generate称之为一个goal,后面那些都是执行这个goal所需的参数。

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

至于goal,对应的是某个插件的某个方法,执行这个命令,我们可以在界面中看到执行的是maven-archetype-plugin插件的generate方法

bindings

和上面这个命令不同,下面的这个命令我们并没有传入goal,传入的是phase

mvn clean

执行这个命令,可以看到,这个命令也是执行了插件的方法,换句话来讲,就是执行了goal

这里就涉及到一个很重要的概念:当我们在命令中指定了phase,执行的并不是phase本身,而是绑定在phase上面的goal,绑定的goal数量可以是一个也可以是多个

下面是官方给的部分bindingphasegoal的绑定关系主要和项目的packaging配置有关。

Phase plugin:goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package ejb:ejb or ejb3:ejb3 or jar:jar or par:par or rar:rar or war:war
install install:install
deploy deploy:deploy

这些绑定关系,在${MAVEN_HOME}\lib\maven-core-3.6.3\META-INF\plexus\ default-bindings.xml中定义。

mvn [phase]命令的运行

当我们执行phase命令时,在执行指定phase之前,会先有序地执行指定phase之前的phase以及它本身。例如,我执行mvn package,会出现下面的信息:

package之前的phase,包括compiletest等都会被执行,而且是有序的。

settings.xml

pom.xml不同,settings.xml用于全局地配置 maven,而不是配置具体的项目。我们可以在${maven.home}/conf/目录下找到这个文件。

settings.xml文件主要包含以下节点:

    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>

这个文件的配置可以参考Settings Reference。这里我补充下serversmirrorsprofiles这三个节点的内容。

servers--配置仓库认证授权信息

servers用于配置仓库(包括下载项目和部署项目的仓库)的认证授权信息,例如,用户密码等。

在具体项目中,我们可以在pom.xml中的repositoriespluginRepositoriesdistributionManagement节点配置用于下载项目和部署项目的仓库,但是我们不能把认证授权的信息放在pom.xml文件中,于是servers就发挥了作用。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<servers>
<server>
<id>server001</id>
<username>my_login</username>
<password>my_password</password>
<privateKey>${user.home}/.ssh/id_dsa</privateKey>
<passphrase>some_passphrase</passphrase>
<filePermissions>664</filePermissions>
<directoryPermissions>775</directoryPermissions>
<configuration></configuration>
</server>
</servers>
...
</settings>

Mirrors--配置仓库的镜像

Mirrors用于配置下载项目的仓库镜像。前面说过,国内使用 maven 的中央仓库下载项目比较慢,甚至会出现超时失败的情况,这时,我们就可以通过配置镜像来提高传输速度。在此之前,我们需要区分镜像和仓库两个概念,以下这篇文章作出了很好的解释。Maven:mirror和repository 区别

在下面这个例子中,我们使用阿里云的镜像来请求 maven 的中央仓库,注意,mirrormirrorOf节点必须指定仓库的 id,当然,这里还支持多种形式。例如,<mirrorOf>*</mirrorOf>表示匹配所有远程仓库;<mirrorOf>repo1,repo2</mirrorOf>表示匹配仓库 repo1 和 repo2,使用逗号分隔多个远程仓库;<mirrorOf>*,!repo1</miiroOf> 匹配所有远程仓库,repo1 除外,使用感叹号将仓库从匹配中排除。

<!-- settings.xml的配置 -->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors
...
</settings> <!-- pom.xml的配置 -->
<project>
...
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
...
</project>

补充下,mirror节点对repositoriespluginRepositoriesdistributionManagement均生效。

profiles

profiles:提供了一组可选的配置,我们可以根据不同的环境选择激活哪一套配置,它包括:activationrepositoriespluginRepositoriesproperties四个节点。其中,activation节点用于配置该profile在什么环境下才能激活。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<profiles>
<profile>
<id>test</id>
<activation>
<activeByDefault>false</activeByDefault>
<jdk>1.5</jdk>
<os>
<name>Windows XP</name>
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
</os>
<property>
<name>mavenVersion</name>
<value>2.0.3</value>
</property>
<file>
<exists>${basedir}/file2.properties</exists>
<missing>${basedir}/file1.properties</missing>
</file>
</activation> <properties>
<user.install>${user.home}/our-project</user.install>
</properties> <repositories>
<repository>
<id>codehausSnapshots</id>
<name>Codehaus Snapshots</name>
<releases>
<enabled>false</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
<url>http://snapshots.maven.codehaus.org/maven2</url>
<layout>default</layout>
</repository>
</repositories> <pluginRepositories>
...
</pluginRepositories> </profile>
...
</profiles>
...
</settings>

注意,如果settings.xml的某个profile被激活,那么,它的配置将覆盖pom.xml中相同 id 的仓库以及相同名称的 property

pom.xml

pom.xml几乎包含了对 maven 项目的所有描述信息,包括项目的坐标、依赖关系、构建配置等等。这个文件非常重要,官网有这么一句话,在 maven 的世界里,一个完整的项目可以不包含任何的代码,而只需要一个pom.xml

pom.xml的节点如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <!-- The Basics -->
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<packaging>...</packaging>
<dependencies>...</dependencies>
<parent>...</parent>
<dependencyManagement>...</dependencyManagement>
<modules>...</modules>
<properties>...</properties> <!-- Build Settings -->
<build>...</build>
<reporting>...</reporting> <!-- More Project Information -->
<name>...</name>
<description>...</description>
<url>...</url>
<inceptionYear>...</inceptionYear>
<licenses>...</licenses>
<organization>...</organization>
<developers>...</developers>
<contributors>...</contributors> <!-- Environment Settings -->
<issueManagement>...</issueManagement>
<ciManagement>...</ciManagement>
<mailingLists>...</mailingLists>
<scm>...</scm>
<prerequisites>...</prerequisites>
<repositories>...</repositories>
<pluginRepositories>...</pluginRepositories>
<distributionManagement>...</distributionManagement>
<profiles>...</profiles>
</project>

关于pom.xml文件的内容,就不详细展开了,可参考POM Reference。这里介绍下两个比较重要的概念。

scope

scopedependency的子节点,用于设置以下两个内容:

  1. 依赖是否在(测试)编译、(测试)运行等时机加入 classpath。
  2. 限制依赖的传递性。(假设当前项目为 A,它依赖了 B,如果 C 依赖了 A,则 C 也会依赖 B。可以看出,A 将自己对 B 的依赖传递给了 C)

maven 提供了五种scope给我们选择,如下。

scope 编译期 运行期 测试编译期 测试运行期 依赖传递
compile
provided ×
runtime × ×
test × × ×
system

通过dependency的子节点 optional可以改变传递性。system对应的依赖不会从仓库获取,而是从systemPath指定的路径中获取

super pom

pom 文件可以通过<parent>节点来继承其他项目的配置信息,而且,和 Java 的对象默认继承 Object 一样,pom 文件默认会去继承 super pom,该 pom 文件的内容见: Super POM for Maven 3.6.3

常见问题

中央仓库没有的依赖,怎么获取

当我们的项目需要依赖某个在中央仓库中不存在的依赖,例如,oracle的驱动包,我们可以采用三种解决方案:

  1. 将依赖的项目安装到本地仓库。命令如下:
mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
  1. 将依赖的项目安装到私服。命令如下:
deploy:deploy-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
  1. 使用system作用域指定包的路径。
<dependency>
<groupId>some.group</groupId>
<artifactId>non-maven-proj</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/non-maven-proj.jar</systemPath>
</dependency>

参考资料

Apache Maven官网

Maven:mirror和repository 区别

相关源码请移步:https://github.com/ZhangZiSheng001/maven-demo

本文为原创文章,转载请附上原文出处链接:https://www.cnblogs.com/ZhangZiSheng001/p/13360234.html

关于maven的一份小笔记的更多相关文章

  1. Maven的第一个小程序

    这里是介绍关于maven的第一个小程序 关于maven的安装 : Install Maven in your computer 先看看目录结构: 这是本来的项目目录结构,由于maven有自己的目录结构 ...

  2. 转:【iOS开发每日小笔记(十一)】iOS8更新留下的“坑” NSAttributedString设置下划线 NSUnderlineStyleAttributeName 属性必须为NSNumber

    http://www.bubuko.com/infodetail-382485.html 标签:des   class   style   代码   html   使用   问题   文件   数据 ...

  3. 小笔记:Timer定时间隔时间操作

    小笔记:Timer定时间隔时间操作,后面有时间再补充和完善: public class TimingSvc { /// <summary> /// 定时器,执行定时任务 /// </ ...

  4. 关于 linux中TCP数据包(SKB)序列号的小笔记

    关于  SKB序列号的小笔记 为了修改TCP协议,现在遇到了要改动tcp分组的序列号,但是只是在tcp_sendmsg函数中找到了SKB的end_seq  一直没有找到seq 不清楚在那里初始化了,就 ...

  5. Linux下postgres9.4 版本的单机版安装小笔记

    1.添加RPMyum install https://download.postgresql.org/pub/repos/yum/9.4/redhat/rhel-7-x86_64/pgdg-redha ...

  6. Maven 依赖管理问题小计

    刚学Maven,遇到点小问题,记录一下.https://maven.apache.org/ 问题的起因是项目中使用了 Hibernate Validator ,但是运行起来后总是不能按照设置的注解校验 ...

  7. 深入剖析Nginx一点小笔记

    前几天在图书馆看书,恰好看到这本<深入剖析nginx>,花了快一周的时间看完了这本书,写点笔记心得便于以后复习. 以前对nginx的认识就只是停留在一个反向代理服务器上.百度了一下ngin ...

  8. 同事不太懂负载均衡,我直接把阿里架构师的这份Nginx笔记甩给他

    Nginx功能强大,架构复杂,学习.维护和开发的门槛较高. 本份笔记深入最新的Nginx源码,详细剖析了模块体系.动态插件.功能框架.进程模型.事件驱动.线程池.TCP/UDP/HTTP 处理等Ngi ...

  9. Git-rebase 小笔记

    转自: https://blog.yorkxin.org/posts/2011/07/29/git-rebase/ 最近刚好有个机会整理很乱的Git commit tree,终于搞懂了rebase 的 ...

随机推荐

  1. 深入理解React:事件机制原理

    目录 序言 DOM事件流 事件捕获阶段.处于目标阶段.事件冒泡阶段 addEventListener 方法 React 事件概述 事件注册 document 上注册 回调函数存储 事件分发 小结 参考 ...

  2. Nginx深入学习(一篇搞定)

     我们的口号是:人生不设限!  一.nginx简介 1.什么是nginx Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,特点是占有内存少,并发能力强,事实上nginx的并发 ...

  3. SpringSceurity(5)---短信验证码登陆功能

    SpringSceurity(5)---短信验证码登陆功能 有关SpringSceurity系列之前有写文章 1.SpringSecurity(1)---认证+授权代码实现 2.SpringSecur ...

  4. 微信开发_Exception_02_"errcode":40164,"errmsg":"invalid ip 61.172.68.219, not in whitelist hint

    ip查询网址: http://www.ip.cn/ 一.异常现象 今天开始做微信开发,在办公室时能正常获取access_token,晚上回家之后获取access_token时却报出下列错误信息: {& ...

  5. js进度条

    第一步//====================.wrap,.circle,.percent{                  position: absolute;                ...

  6. tkinter的控件

    包含如下控件: Button  按钮控件 Canvas 画布控件,显示图形元素如线程或文本 Checkbutton 多选框控件,用于在程序中提供多项选择框 Entry 单行输入控件,用于显示简单的文本 ...

  7. 分析并封装排序算法(js,java)

    前言 本次来分享一下排序的api底层的逻辑,这次用js模拟,java的逻辑也是差不多. 先看封装好的api例子: js的sort排序 java的compareTo排序 自己模拟的代码(JS) func ...

  8. 记一次解密wireshark抓取的冰蝎通信流量

    一.关于冰蝎 1.1 简单介绍 冰蝎是一款基于Java开发的动态加密通信流量的新型Webshell客户端.老牌 Webshell 管理神器——中国菜刀的攻击流量特征明显,容易被各类安全设备检测,实际场 ...

  9. CSS中的一些细节

    一.塌陷 1.当position设置为:absolute或者fixed时,元素的display会转换为block.(设置float也会产生这样的效应)2.正常情况下,div会被内容撑开,但是如果设置了 ...

  10. 免费馅饼——移动dp

    免费馅饼 题目描述 SERKOI最新推出了一种叫做"免费馅饼"的游戏: 游戏在一个舞台上进行.舞台的宽度为 \(W\) 格,天幕的高度为 \(H\) 格,游戏者占一格. 开始时游戏 ...