生命周期
生命周期
Maven 对构建(build)的过程进行了抽象和定义,这个过程被称为构建的生命周期(lifecycle)。生命周期(lifecycle)由多个阶段(phase)组成,每个阶段(phase)会挂接一到多个 goal。goal 是 maven 里定义任务的最小单元,相当于 ant 里的 target。
Maven 的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。Maven 的生命周期是抽象的,即生命周期不做任何实际的工作,实际任务由插件完成,类似于设计模式中的模板方法。
核心概念
-
lifecycle:生命周期,这是 maven 最高级别的的控制单元,它是一系列的 phase 组成,也就是说,一个生命周期,就是一个大任务的总称,不管它里面分成多少个子任务,反正就是运行一个 lifecycle,就是交待了一个任务,运行完后,就得到了一个结果,中间的过程,是 phase 完成的,自己可以定义自己的 lifecycle,包含自己想要的 phase。
-
phase:可以理解为任务单元,lifecycle 是总任务,phase 就是总任务分出来的一个个子任务,但是这些子任务是被规格化的,它可以同时被多个 lifecycle 所包含,一个 lifecycle 可以包含任意个 phase,phase 的执行是按顺序的,一个 phase 可以绑定很多个 goal,至少为一个,没有 goal 的 phase 是没有意义的。
-
goal: 这是执行任务的最小单元,它可以绑定到任意个 phase 中,一个 phase 有一个或多个 goal,goal 也是按顺序执行的,一个 phase 被执行时,绑定到 phase 里的 goal 会按绑定的时间被顺序执行,不管 phase 己经绑定了多少个 goal,你自己定义的 goal 都可以继续绑到 phase 中。
-
mojo: lifecycle 与 phase 与 goal 都是概念上的东西,mojo 才是做具体事情的,可以简单理解 mojo 为 goal 的实现类,它继承于 AbstractMojo,有一个 execute 方法,goal 等的定义都是通过在 mojo 里定义一些注释的 anotation 来实现的,maven 会在打包时,自动根据这些 anotation 生成一些 xml 文件,放在 plugin 的 jar 包里。
抛开 mojo 不讲,lifecycle 与 phase 与 goal 就是级别的大小问题,引用必须是从高级引用下级(goal 绑定到 phase,也可理间为 phase 引用 goal,只是在具体绑定时,不会 phase 定义引用哪些 goal,但是执行是,却是 phase 调用绑定到它那的 goal),也不能跨级引用,如 lifecycle 可以引用任意的 phase,不同 lifecycle 可以同时引用相同的 phase,lifecycle 不能跨级引用 goal。goal 会绑定到任意的 phase 中,也就是说不同的 phase 可以同时引用相同的 goal,所以 goal 可以在一个 lifecycle 里被重复执行哦,goal 自然也不能说绑定到 lifecycle 中,它们三者的关系可以用公司里的 总领导,组领导,与职员的关系来解释。
lifecycle 的 phase 执行会指向之前所有的 phase,然后执行当前指定的 phase,一个 phase 会引用至少一个 goal。plugin 中的 goal 只是单单执行当前指定的 goal。执行 install:install 只会执行 installplugin 中的 goal:install,但是项目创建后还没有进行之前必要的步骤,比如 complie。这样直接执行 install:install 是肯定会出错的。
三套生命周期
Maven 有三套相互独立的生命周期,分别是 clean、default 和 site。每个生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。
- clean 生命周期:清理项目,包含三个 phase:
1)pre-clean:执行清理前需要完成的工作 2)clean:清理上一次构建生成的文件 3)post-clean:执行清理后需要完成的工作
- default 生命周期:构建项目,重要的 phase 如下:
1)validate:验证工程是否正确,所有需要的资源是否可用。 2)compile:编译项目的源代码。 3)test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。 4)package:把已编译的代码打包成可发布的格式,比如 jar。 5)integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。 6)verify:运行所有检查,验证包是否有效且达到质量标准。 7)install:把包安装到 maven 本地仓库,可以被其他工程作为依赖来使用。 8)deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的 repository,使得其他的开发者或者工程可以共享。
- site 生命周期:建立和发布项目站点,phase 如下:
1)pre-site:生成项目站点之前需要完成的工作 2)site:生成项目站点文档 3)post-site:生成项目站点之后需要完成的工作 4)site-deploy:将项目站点发布到服务器
各个生命周期相互独立,一个生命周期的阶段前后依赖。举例如下:
-
mvn clean:调用 clean 生命周期的 clean 阶段,实际执行 pre-clean 和 clean 阶段
-
mvn test:调用 default 生命周期的 test 阶段,实际执行 test 以及之前所有阶段
-
mvn clean install:调用 clean 生命周期的 clean 阶段和 default 的 install 阶段,实际执行 pre-clean 和 clean,install 以及之前所有阶段
Mojo
以 phase 为目标构建
以 phase 为目标进行构建是最常见的,如我们平时经常执行的 mvn compile,mvn test,mvn package… 等等,compile,test,package 都是 maven 生命周期(lifecycle)里的 phase,通过 mvn 命令,你可以指定一次构建执行到那一个阶段,在执行过程中,所有经历的执行阶段(phase)上绑定的 goal 都将得到执行。例如,对于一个 jar 包应用,当执行 mvn package 命令时,maven 从 validate 阶段一个阶段一个阶段的执行,在执行到 compile 阶段时,compiler 插件的 compile goal 会被执行,因为这个 goal 是绑定在 compile 阶段(phase)上的。这一点可从其对应的 mojo 类上得知:
再比如经常使用的打包插件 shade,它的 goal 是绑定到 package 阶段的,这样,使用 mvn package 进行打包时都会执行 shade 的。
以 goal 为目标构建
虽然以 phase 为目标的构建最常见,但是有时候我们会发现,一些插件的 goal 并不适合绑定到任何阶段(phase)上,或者是,这些 goal 往往是单独执行,不需要同某个阶段(phase)绑定在一起,比如 hibernate 插件的导入\导出 goal 多数情况下是根据需要要手动执行的(当然,也可以绑定到某个阶段上,比如进行单元测试时,可考虑将其绑定到 test 阶段上)。再比如 jetty(6.1.26)插件,它的 goal 都是将打包或未打包的工程部署到 jetty 里然后启动 jetty 容器的,多数情况下,人们都是独立运行这些 goal 的,比如:人们希望当键入 mvn jetty:run 后,工程就能完成编译后启动 jetty,而 jetty 插件也确实是这样做的,它的 run goal 的 mojo 是这样声明的:
其中@execute phase=“test-compile"指明 jetty:run 这一 goal 会促使 maven 先 build 到 test-compile 阶段,再执行这个 goal.同样,对于 jetty:run-war 这个 goal 则要求先 build 到 package 阶段再执行该 goal。
而另外一个例子是 exec 插件的 exec:java:
这个 goal 也声明了 execute 的 phase,但却是 validate,这样,如果代码没有编译,执行这个 goal 就会出错,所以多数情况下,人们总是使用下面的方式执行的:mvn clean compile exec:java
。