maven的理想:像一种什么设计模式?—模板方法模式

  • 自动走完标准的构建流程:清理 --> 编译 --> 測试 --> 报告 --> 打包 --> 部署
  • 统一入口,所有配置在一个pom里搞定

1.maven生命周期、阶段

maven有三个完全独立的生命周期(LifeCycle):Clean,Build,Site。每个生命周期都由一系列阶段(Phase)组成,执行其中某个阶段时,必须将当前周期的所有阶段执行完。LifeCycle和Phase具体的对应关系如下图:

maven 插件执行脚本 maven插件执行顺序_生命周期

各个生命周期的阶段(phase)定义如下:

阶段

处理

描述

验证 validate

验证项目

验证项目是否正确且所有必须信息是可用的

编译 compile

执行编译

源代码编译在此阶段完成

测试 Test

测试

使用适当的单元测试框架(例如JUnit)运行测试。

包装 package

打包

创建JAR/WAR包如在 pom.xml 中定义提及的包

检查 verify

检查

对集成测试的结果进行检查,以保证质量达标

安装 install

安装

安装打包的项目到本地仓库,以供其他项目使用

部署 deploy

部署

拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程

运行任何一个阶段,都会从其所在生命周期的第一个阶段开始,顺序执行到指定的阶段。比如,mvn package — 本义:执行default周期的package阶段,maven会自动从process-resources阶段开始运行到package阶段结束

maven的构建生命周期,只是一个抽象规范流程。周期内的每个阶段的执行,是交由plugin插件来完成

2.maven插件

插件plugin是绑定到生命周期,承担实际功能的组件。mvn运行时,自动关联插件来运行。下表是maven默认的各阶段对应的插件列表:

生命周期

生命周期阶段

插件目标

执行任务

clean

pre-clean

clean

maven-clean-plugin:clean

删除项目的输出目录

post-clean

site

pre-site

site

maven-site-plugin:site

post-site

site-deploy

maven-site-plugin:deploy

default

process-resources

maven-resources-plugin:resources

复制主资源文件至主输出目录

compile

maven-compiler-plugin:compile

编译主代码至主输出目录

process-test-resources

maven-resources-plugin:testResources

复制测试资源文件至测试输出目

test-compile

maven-compiler-plugin:testCompile

编译测试代码至测试输出目录

test

maven-surefire-plugin:test

执行测试用例

package

maven-jar-plugin:jar(ejb:ejb jar:jar rar:rar war:war)

创建项目jar包

install

maven-install-plugin:install

将项目输出构件安装到本地仓库

deploy

maven-deploy-plugin:deploy

将项目输出构件部署到远程仓库

另外,maven还可以自定义插件,来扩展maven的功能。

问题一:这些插件在哪里设置?

关于插件的配置一般是在pom文件的<plgin>标签中,具体关系是:<bulid>:<pluginManagement>:<plugins>:<plugin>。下图是关于maven默认插件和自定义插件的配置示例:

maven 插件执行脚本 maven插件执行顺序_maven 插件执行脚本_02


可以看到,默认插件是maven开头,没有execution这一项,不需要再手动绑定声明周期阶段。

问题二:如何执行maven中的这些插件?

Maven 只是定义了抽象的生命周期,生命周期阶段具体执行的操作是由其绑定的插件目标实现的。

PS:LifeCycle、Phase、Plugin、Goal关系?

  • 一个 LifeCycle 包含多个 Phase
  • 一个 Plugin 可以提供一个/多个 goal

=> 一个 Phase 由一个/多个 goal 实现

也就是说插件目标有一下两种方式被执行:

1)通过绑定到生命周期阶段,而在生命周期阶段执行时被自动调用

命令格式:mvn phase。比如下面这些常用命令:

  • mvn clean:清理旧的jar包
  • mvn compile:编译主程序
  • mvn package:打包当前项目
  • mvn install:安装jar到本地库,等于package+放到本地仓库

PS:一个生命周期阶段绑定多个插件目标的情况,其执行顺序是按照POM文件中插件目标定义的顺序。

2)通过直接调用的方式(也就是“plugin:goal”的方式)在生命周期阶段外执行

命令格式:mvn plugin:goal。比如:

  • mvn jetty:run
  • mvn com.xupt.yzh:my_maven_plugin:1.0-SNAPSHOT:log(下面的自定义插件示例)

另外,在执行命令时还可以传入参数,mvn com.xupt.yzh:my_maven_plugin:1.0-SNAPSHOT:log -D log.name=Lisi

PS:直接执行 goal 与执行 phase 的区别是,执行 phase 必须把当前 lifecycle 内之前 phase 也执行,而执行 goal 的话可以只执行当前 goal。

idea 和 eclipse 生成项目最终也是依赖 maven 插件生成的,它们一般自带了默认插件,在 idea 右侧的 maven#plugin 可以看见。一般情况下,我们通过 maven#LifeCycle 直接运行即可。

问题三:如何自定义插件?

插件的开发步骤如下:

1.引入maven api的依赖,设置打包方式为maven-plugin

maven 插件执行脚本 maven插件执行顺序_自定义插件_03


2. 编写简单Mojo类—继承AbstractMojo,并指定goal,然后打包插件。

maven 插件执行脚本 maven插件执行顺序_生命周期_04

注:这里其实也可以直接在 @Mojo 中通过 defaultPhase 指定当前 goal 所属的 phase,比如 defaultPhase = LifecyclePhase.PACKAGE

  1. 通过命令执行插件 mvn [plugin-name] [goal-name],在这里是`

maven 插件执行脚本 maven插件执行顺序_maven_05

这里再提一点,一个插件可以绑定多个周期。

问题四:自定义插件可以传入参数吗?

可以的,可以通过@Parameter定义参数,并指定默认值

maven 插件执行脚本 maven插件执行顺序_生命周期_06


执行结果如下:

maven 插件执行脚本 maven插件执行顺序_maven_07


现在我在执行命令时通过 -D 传入参数。mvn com.xupt.yzh:my_maven_plugin:1.0-SNAPSHOT:log -D log.name=Lisi,执行结果如下:

maven 插件执行脚本 maven插件执行顺序_maven_08


虽然我们可以自定义插件,但在实际开发中,使用默认插件就完全够用了,自定义插件很少用到。