Maven:生命周期 vs. 阶段 vs. 插件 vs. 目标
回答晚只是为了澄清此线程中缺少的另一个粒度级别:执行(目标),这是 Maven 构建的最小单位。
因此,我们有 构建周期(基本上是针对特定总体目标的一组操作),它由 阶段(较低粒度,一个周期步骤)组成,其中可以调用某些插件提供的一组配置目标。也就是说,Maven(也)是一个插件执行器,每个插件都可以提供一个或多个目标。然后,您(也)决定哪个目标附加到哪个阶段,大多数时候在默认生命周期中(没有任何目标,即默认值)。但你实际上可以有另一个层次:执行(相同目标,来自相同插件,或不同目标来自不同插件)
一张我准备恢复的图片
事实上,这就是 Maven 通过其构建日志中的唯一字符串显示它(它的最小工作单元)的方式:
plugin-artifactId:plugin-version:plugin-goal (goal-execution-id) @ project-name
例如,我们会:
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ sample-project ---
这确实意味着(通过不同的粒度级别):
- 在
compile 阶段(不幸的是,仅在mvn -X ... 中提到用于调试,在REACTOR BUILD PLAN – Tasks: [...] 下)→
- 我正在调用 Maven 编译器插件(由
artifactId 和 version 指定)及其 compile 目标 →
- 由
execution 和id default-compile 定义。
这是独一无二的,因为您确实可以将相同的目标(同一个插件)绑定到不同的阶段或绑定到同一阶段但在不同的执行中(即使用不同的配置)。例如,maven-compiler-plugin 在test-compile phase(不同的阶段)期间也用于在不同的执行(default-testCompile)中编译测试代码(通过其testCompile 目标)。您还可以在不同阶段编译(使用相同的插件和目标)一些自动生成的代码,这些阶段由您在 POM 中指定的执行定义(并且可能是不同的配置)。
默认执行是通过Maven packaging bindings 开箱即用地提供的,也就是说,默认情况下(并且强制约定优于配置)Maven 已经在某些阶段调用了某些目标(标准插件的)。这些默认调用的执行id是根据certain conventions定义的。
这也解释了为什么如果你真的想覆盖一个 Maven 构建的默认行为(绑定),你需要在你的 POM 中为同一个插件指定(覆盖)完全相同的执行 ID。例如,您可以跳过编译,只需定义具有相同 default-compile id 但绑定到不存在的阶段(或空的阶段)的 maven-compiler-plugin 的执行。
简而言之:执行告诉 Maven 在哪个阶段使用哪个配置执行哪个目标。
默认提供了一些执行(默认绑定),这就解释了为什么只有 6 行的maven minimal pom 已经可以做很多事情(编译、测试、打包等):执行目标某些阶段的标准插件:约定优于配置。然后,通过pom.xml 配置,您可以将stuff(执行)添加到构建中或影响已配置插件的行为(在这种情况下没有executions 部分,但只有configuration 将是够了)。
是的,您可以跳过构建周期(及其阶段)并直接调用(插件的)目标。想象一下:
mvn compiler:compile
mvn compiler:testCompile
mvn surefire:test
mvn jar:jar
(注意:您也可以在一次调用中调用内联)
我们在这里编译应用代码、测试代码、执行测试和打包:想象一下这将是多么手动、容易出错、重复和耗时。约定优于配置有助于我们:Maven 引入了构建生命周期和阶段。默认生命周期(没有名称,即默认)提供了一系列基于最佳实践和约定的阶段(Maven 的口头禅)。
如果您想实现与上述相同的效果,只需运行:mvn package,它将自动编译、测试和打包您的项目。如何?调用插件。也就是说,阶段是有意义且可配置的插件(目标)执行集。为了使其更加标准,对于每个阶段,Maven 将首先调用任何先前的阶段,例如如果你想测试,你一定会先编译。
附言请注意,当为同一个 execution 指定多个目标时,您仍然会在构建日志中清楚地看到两个不同目标的两个不同执行(具有相同的 id)(因此,仍然是唯一的元组)。