创建一个新的Maven项目,在命令上使用Maven Archetype插件。
3.0.5版本之后create命名被舍弃,需要使用generate命令创建项目
$ mvn archetype:generate
[WARNING]
[WARNING] Some problems were encountered while building the effective settings
[WARNING] Unrecognised tag: 'mirrors' (position: START_TAG seen ...\n -->\n\t\n ... @161:11) @ /opt/apache-maven-3.5.2/conf/settings.xml, line 161, column 11
[WARNING] Unrecognised tag: 'mirrors' (position: START_TAG seen ...\n -->\n\t\n ... @161:11) @ /home/ageeklet/.m2/settings.xml, line 161, column 11
[WARNING]
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.0.1:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.0.1:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.0.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Interactive mode
......
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1191:
Choose org.apache.maven.archetypes:maven-archetype-quickstart version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
Choose a number: 7:
Define value for property 'groupId': com.m
Define value for property 'artifactId': maven_02
Define value for property 'version' 1.0-SNAPSHOT: : 2
Define value for property 'package' com.m: : com.ageeklet
Confirm properties configuration:
groupId: com.m
artifactId: maven_02
version: 2
package: com.ageeklet
Y: :
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.3
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.m
[INFO] Parameter: artifactId, Value: maven_02
[INFO] Parameter: version, Value: 2
[INFO] Parameter: package, Value: com.ageeklet
[INFO] Parameter: packageInPathFormat, Value: com/ageeklet
[INFO] Parameter: package, Value: com.ageeklet
[INFO] Parameter: version, Value: 2
[INFO] Parameter: groupId, Value: com.m
[INFO] Parameter: artifactId, Value: maven_02
[INFO] Project created from Archetype in dir: /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_02
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 04:02 min
[INFO] Finished at: 2018-05-21T20:09:31+08:00
[INFO] Final Memory: 18M/203M
[INFO] ------------------------------------------------------------------------
生成的项目目录结构如下:
maven_02/
├── pom.xml
└── src
├── main
│ └── java
│ └── com
│ └── ageeklet
│ └── App.java
└── test
└── java
└── com
└── ageeklet
└── AppTest.java
生成的目录遵循Maven标准目录布局:
- Maven Archetype插件创建了一个与artifactId匹配的目录–maven_02,这是一个项目的基础目录。
- 每个目录在文件pom.xml里有它的项目对象模型(POM)。这个文件描述了一个项目,配置了插件,声明了依赖。
- 项目源码的资源文件放在src/main目录下面。再简单的Java项目中,该目录下包含了一些Java类和一些配置文件。在其他项目中,它可能是web应用的文档根目录,或者还放一些应用服务器的配置文件。在一个Java项目中,Java类放在src/main/java下面,而classpath资源文件放在src/main/resources下面。
- 将项目的测试用例放在src/test下。在该目录下,src/test/java存放像使用Junit或者TestNG这样的测试类,src/test/resources下存放测试classpath资源文件。
使用Maven Archetype插件创建了一个项目,想要构建打包这个应用,在包含pom.xml目录下运行mvn install.
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven_01 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ maven_01 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ maven_01 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ maven_01 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ maven_01 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.20.1:test (default-test) @ maven_01 ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.ageeklet.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 s - in com.ageeklet.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ maven_01 ---
[INFO] Building jar: /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/target/maven_01-1.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ maven_01 ---
[INFO] Installing /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/target/maven_01-1.jar to /home/ageeklet/.m2/repository/com/ageeklet/maven_01/1/maven_01-1.jar
[INFO] Installing /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/pom.xml to /home/ageeklet/.m2/repository/com/ageeklet/maven_01/1/maven_01-1.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.781 s
[INFO] Finished at: 2018-05-21T20:45:11+08:00
[INFO] Final Memory: 19M/201M
[INFO] ------------------------------------------------------------------------
创建,编译,测试,打包,并且安装了(installed)最简单的Maven项目,在命令行运行:
java -cp target/maven_01-1.jar com.ageeklet.App
Hello World!
当Maven运行的时候它向项目对象模型(POM)查看关于这个项目的信息。
pom.xml是Maven项目中最基础的POM:定义多个依赖,自定义插件行为;
groupId,artifactId,packaging,version–是Maven的坐标(coordinates),他们唯一标识了一个项目。name和url是POM提供的描述性元素,给我们提供了可阅读的名字,将一个项目关联到了项目的web站点。最后dependencies元素定义了一个单独的,测试范围(test-scoped)依赖,依赖于称为JUnit的单元测试框架。pom.xml是一个让Maven跑起来的文件
mvn help:effective-pom
在项目根目录下运行会打印出Maven的默认设置。
生命周期是包含在一个项目构建中的一系列有序的阶段。Maven可以支持许多不同的生命周期,最常用的生命周期是默认的生命周期,该生命周期一开始的阶段是验证项目的基本完整性,最后一个阶段是把一个项目发布成产品。生命周期的阶段被特地留得含糊,单独的定义为验证(validation),测试(test),或者发布(deployment),而他们对不同的项目来说意味着不同的事情。
插件目标可以附着生命周期阶段上,随着Maven沿着生命周期的阶段移动,它会执行附着在特定阶段上的目标。每个阶段可能绑定了零个或者多个目标。
Maven执行一个阶段的时候,它首先会有序的执行前面的所有阶段,到命令行指定的那个阶段为止。每个阶段对应了零个或者多个目标。我们没有进行任何插件配置或者定制,所以这个例子绑定了一组标准插件的目标到默认的生命周期。
当Maven经过以package为结尾的默认生命周期的时候,下面的目标按顺序呢被执行:
- resources:resources resources插件的resources目标绑定到了resources阶段。这个目标复制到src/main/resources下的所有资源和其他任何配置的资源目录,输出到目录;
- complier:complie Complier插件的compile目标绑定到了compile阶段。这个目标编译到src/main/java下所有源代码和其他任何配置的资源目录,到输出目录。
- resources:testResources Resources插件的testResources目标绑定到了test-resources阶段。这个目录复制src/test/resources下所有资源和其他任何的配置的测试资源目录,到测试输出目录。
- surefire:test Surefire插件的test目标绑定到了test阶段。这个目标运行所有的测试并且创建那些捕捉详细测试结果的输出文件。默认情况下,如果有测试失败,这个目标会终止。
- jar:jar jar插件的jar目标绑定到了package阶段。这个目标把输出目录打包成jar文件。
总的来说,当我们运行mvn package,Maven运行到打包为止的所有阶段,在Maven沿着生命周期向前的过程中,他运行绑定在每个阶段上的所有目标。也可以像下面这样显式的指定一系列插件目标,已得到同样的结果:
mvn resources:resources \
compiler:compile \
resources:testResources \
compiler:testCompile \
surefire:test \
jar:jar
运行package阶段能够很好的跟踪一个特定的构建中包含的所有目标,他也允许每个项目使用Maven来遵循一组定义明确的标准。而这个生命周期能让开发人员从一个Maven项目跳到另一个Maven项目,不用知道太多每个项目构建的细节。
Archetype插件通过名字为pom.xml的文件创建了一个项目,这就是项目对象模型(POM),一个项目的声明描述。当Maven运行一个目标的时候,每个目标都会访问定义在POM里的信息。当jar:jar目标创建一个jar文件的时候,他通过观察POM来找出这个jar文件的名字。当compiler:complier任务编译Java源代码为字节的时候,他通过观察POM来看是否有编译目标的参数。目标在POM的上下文运行。目标是我们希望针对项目运行的动作,而项目是通过POM定义的。POM为项目命名,提供了项目的一组唯一标识符(坐标),并且通过依赖(dependencies),父(parents)和先决条件(prerequisite)来定义和其他项目的关系。POM也可以是自定义插件行为,提供项目相关的社区和开发人员的信息。
Maven坐标定义了一组标识,它们可以用来唯一标识一个项目,一个依赖,或者MavenPOM里的一个插件。
<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.0modelVersion>
<groupId>com.ageekletgroupId>
<artifactId>maven_01artifactId>
<version>1version>
<packaging>jarpackaging>
<name>maven_01name>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.7maven.compiler.source>
<maven.compiler.target>1.7maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
<scope>testscope>
dependency>
dependencies>
project>
groupId,artifactId,version,packaging这些标识符拼成了一个项目的坐标,一个Maven坐标是一个地址,既“空间”的某个点:从一般到特殊。当一个项目通过依赖,插件或者父项目引用和另外一个项目关联的时候,Maven通过坐标来精确定位一个项目。
- groupId 团队,公司,小组,组织,或者其他团队。团队标识的约定是,他以创建这个项目的组织名称的(reverse domain name)开头。
- artifactId 在groupId下的表示一个单独项目的唯一标识符。
- version 一个项目的特定版本。发布的项目有一个固定版本标识来指向该项目的某一个特定的版本。而正在开发中的项目可以用一个特殊的标识,这个标志给版本加上一个“SNAPSHOT”的标记。
- packaging 项目的类型,默认是jar,描述了项目打包后的输出。类型为jar的项目产生了一个jar文件,类型为war的项目产生了一个web应用。
当你第一次运行Maven的时候,Maven会从一个远程的Maven仓库下载了许多文件。如果这个简单的项目是你第一次运行Maven,那么当触发resources:resources目标的时候,它首先会做的事情是去下载最新版本的Resources插件。在Maven中,构件和插件是在它们被需要的时候从远程的仓库取来的。初始的Maven下载包的大小相当的小(1.8兆),其中一个原因是事实上这个初始Maven不包括很多插件。它只包含了几近赤裸的最少值,而在需要的时候再从远程仓库去取。Maven自带了一个用来下载Maven核心插件和依赖的远程仓库地址。
Maven仓库是通过结构来定义的,一个Maven仓库是项目构件的一个集合,这些构件存储在一个目录结构下面,它们的格式能很容易的被Maven所理解。在一个Maven仓库中,所有的东西存储在一个与Maven项目坐标十分匹配的目录结构中。
Maven从远程仓库下载构件和插件到你本机上,存储在你的本地Maven仓库里。一旦Maven已经从远程仓库下载了一个构件,它将永远不需要再下载一次,因为maven会首先在本地仓库查找插件,然后才是其它地方。在Windows上,你的本地仓库很可能在C:\Documents and Settings\USERNAME.m2\repository,在Windows Vista上,会是C:\Users\USERNAME.m2\repository。在类Unix系统上,你的本地仓库在~/.m2/repository。当你创建像前一节创建的简单项目时,install阶段执行一个目标,把你项目的构件安装到你的本地仓库。
运行 mvn install,Maven会把项目的构件安装到本地仓库。
ageeklet ~/D/0/0/maven_01 λ mvn install
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven_01 1
[INFO] ------------------------------------------------------------------------
[INFO] Installing /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/target/maven_01-1.jar to /home/ageeklet/.m2/repository/com/ageeklet/maven_01/1/maven_01-1.jar
[INFO] Installing /home/ageeklet/Documents/08_学习笔记_markdown/02_maven/maven_01/pom.xml to /home/ageeklet/.m2/repository/com/ageeklet/maven_01/1/maven_01-1.pom
[INFO] ------------------------------------------------------------------------
......
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 43.118 s
[INFO] Finished at: 2018-05-29T11:24:22+08:00
[INFO] Final Memory: 12M/120M
[INFO] ------------------------------------------------------------------------
一个复杂的项目将会包含很多依赖,也有可能包含依赖于其他构件的依赖。这是Maven最强大的特征之一,它支持了传递依赖(transitive Dependencies)。假如你的项目依赖于一个库,而这个又依赖于五十或者十个其他的库(就像Spring或者Hibernate)。不必找出所有的依赖然后把它们写在你的pom.xml,只需加上直接需要依赖的库,Maven会隐式的把这些库间接依赖的库也加入到你的项目中。Maven会处理这些依赖中的冲突。同时能让你的自定义默认行为,或者排除一些特定的传递性依赖。
当你把项目的构件安装到本地仓库时,你会发现在和JAR文件同一目录下,Maven发布了一个稍微修改过的pom.xml的版本。存储POM文件在仓库里提供给其它项目了该项目的信息,其中最重要的就是它有哪些依赖。如果项目B依赖于项目A,那么它也依赖于项目A的依赖。当Maven通过一组Maven坐标来处理依赖构件的时候,它也会获取POM,通依赖的POM来寻找传递性依赖。那些传递性依赖就会被添加到当前项目的依赖列表中。
在Maven中一个依赖不仅仅是一个JAR。它是一个POM文件,这个POM可能也声明了对其它构件的依赖。这些依赖的依赖叫做传递性依赖,Maven仓库不仅仅存贮二进制文件,也存储了这些构建的元数据(metadata),才使传递性依赖成为可能。
当为项目创建JAR文件的时候,它的依赖不会被捆绑在生成的构件中,他们只是用来编译。当用Maven来创建WAR或者EAR,你可以配置Maven让它在生成的构件中捆绑依赖,你也可以配置Maven,使用provided范围,让它排除WAR文件中特定的依赖。provided范围告诉Maven一个依赖在编译的时候需要,但是它不应该被捆绑在构建的输出中。当你开发web应用的时候provided范围变得十分有用,你需要通过Servlet API来编译你的代码,但是你不希望Servlet API的JAR文件包含在你web应用的WEB-INF/lib目录中。
Maven能够生成文档和报告,在项目的根目录下运行
mvn site
这将会运行site生命周期阶段。它不像默认生命周期那样,管理代码生成,操作资源,编译,打包等等。Site生命周期只关心处理在src/site目录下的site内容,还有生成报告。在这个命令运行过之后,你将会在target/site目录下看到一个项目web站点。载入target/site/index.html你会看到项目站点的基本外貌。它包含了一些报告,它们在左手边的导航目录的“项目报告”下面。它也包含了项目相关的信息,依赖和相关开发人员信息,在“项目信息”下面。Simple项目的web站点大部分是空的,因为POM只包含了比较少的信息,只有项目坐标,名称,URL和一个test依赖。
在这个站点上,你会注意到一些默认的报告已经可以访问了,有一个报告详细描述了测试的结果。这个单元测试报告描述了项目中所有单元测试的成功和失败信息。另外一个报告生成了项目API的JavaDoc。Maven提供了很完整的可配置的报告,像Clover报告检查单元测试覆盖率,JXR报告生成HTML源代码相互间引用,这在代码审查的时候非常有用,PMD报告针对各种编码问题来分析源代码,JDepend报告分析源代码中各个包之间的依赖。通过在pom.xml中配置那些报告被包含在构建中,站点报告就可以被定制了。