maven的插件

我们知道Maven具体构建动作都是由插件执行的,maven本身只是提供一个框架,这样就提供了高度可定制化的功能,我们用maven命令执行比如mvn clean package这样的命令时maven会将package这个阶段(phase)绑定到相应的生命周期(lifecycle),再寻找项目(project)里配置的plugin,执行具体的plugin完成持续构建

maven绑定插件(plugin)

maven在读取命令行之后会根据命令行参数是系统默认的phase还是其他的自定义插件(goal)来解析成task参数,继而根据这些task参数来生成插件执行列表。

for ( Object task : tasks ) { if ( task instanceof GoalTask ) { String pluginGoal = ( (GoalTask) task ).pluginGoal;

                MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( pluginGoal, session, project );

                MojoExecution mojoExecution =
new MojoExecution( mojoDescriptor, "default-cli", MojoExecution.Source.CLI ); mojoExecutions.add( mojoExecution );
}
else if ( task instanceof LifecycleTask )
{
String lifecyclePhase = ( (LifecycleTask) task ).getLifecyclePhase(); Map<String, List<MojoExecution>> phaseToMojoMapping =
calculateLifecycleMappings( session, project, lifecyclePhase ); for ( List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values() )
{
mojoExecutions.addAll( mojoExecutionsFromLifecycle );
}
}
else
{
throw new IllegalStateException( "unexpected task " + task );
}
}

  

代码里先判断task的类型,如果是GoalTask就说明参数是clean:clean这一种带goal的格式,这种情况可能是maven内置插件也可能是开发者自己开发的插件,这种情况下maven就会先根据插件的goal去找到具体的插件,找的方法是先从项目定义的插件里找,找不到的话再去仓库里找,这里把核心部分代码贴出来:

   PluginDescriptor pluginDescriptor =
pluginManager.loadPlugin( plugin, request.getRepositories(), request.getRepositorySession() ); if ( request.getPrefix().equals( pluginDescriptor.getGoalPrefix() ) )
{
return new DefaultPluginPrefixResult( plugin );
}

这个这部分比较简单,就是遍历项目里的插件一个个加载,然后比较这个插件的goal前缀是否和命令行的请求相同,如果相同的话直接封装下该插件返回。其他用groupId:artifactId:version:goal格式的命令行解析也是差不多的方法,根据这些信息加载响应的plugin插件。接下来要重点说的是比较复杂的情况,即clean package这种比较内置的phase,下面代码一一解读: 先根据lifecyclephase来决定是哪个lifecycle,比如package这个phase就是在default生命周期里,maven内置定义了clean、default、site三个生命周期,maven采用plexus作为IOC容器,这个defaultLifeCycles的依赖是在maven-core的component.xml中定义的,与此同时定义了各个生命周期里的phase,这个读者感兴趣可以去看相应的代码,此处略去不表。回到这里的代码,maven根据phase去默认找生命周期,这里通过package找到了default生命周期。

/*
* Determine the lifecycle that corresponds to the given phase.
*/ Lifecycle lifecycle = defaultLifeCycles.get( lifecyclePhase ); if ( lifecycle == null )
{
throw new LifecyclePhaseNotFoundException(
"Unknown lifecycle phase \"" + lifecyclePhase + "\". You must specify a valid lifecycle phase" +
" or a goal in the format <plugin-prefix>:<goal> or" +
" <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: " +
defaultLifeCycles.getLifecyclePhaseList() + ".", lifecyclePhase );
}

接下来遍历default lifecycle下所有的phase直到package这个phase就退出遍历循环,这里体现了maven的一个特性,就是如果你指定了某个生命周期中某个phase,那这个phase之前的phase都会被执行,这里主要是初始化mappings包含哪些phase,每个phase的插件列表之所以是TreeMap是因为后面要根据优先级,也就是Key来排序遍历确定插件执行顺序,每个phase具体要执行的插件到下一段代码再写入。

    /*
* Initialize mapping from lifecycle phase to bound mojos. The key set of this map denotes the phases the caller
* is interested in, i.e. all phases up to and including the specified phase.
*/ Map<String, Map<Integer, List<MojoExecution>>> mappings =
new LinkedHashMap<String, Map<Integer, List<MojoExecution>>>(); for ( String phase : lifecycle.getPhases() )
{
Map<Integer, List<MojoExecution>> phaseBindings = new TreeMap<Integer, List<MojoExecution>>(); mappings.put( phase, phaseBindings ); if ( phase.equals( lifecyclePhase ) )
{
break;
}
}
接下来遍历本项目中所有插件,每个插件在遍历所有执行配置,如果execution配置里已经指定了phase,则将这个execution下所有goal对应的Mojo加到对应phase的执行map里,如果execution配置里没有指定phase的话,那就要去遍历这个execution下所有goal,依次获取该goal的Mojo描述信息,根据每个Mojo绑定的phase来将该Mojo加到对应phase的执行map里。
        /*
* Grab plugin executions that are bound to the selected lifecycle phases from project. The effective model of
* the project already contains the plugin executions induced by the project's packaging type. Remember, all
* phases of interest and only those are in the lifecyle mapping, if a phase has no value in the map, we are not
* interested in any of the executions bound to it.
*/ for ( Plugin plugin : project.getBuild().getPlugins() )
{
for ( PluginExecution execution : plugin.getExecutions() )
{
// if the phase is specified then I don't have to go fetch the plugin yet and pull it down
// to examine the phase it is associated to.
if ( execution.getPhase() != null )
{
Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( execution.getPhase() );
if ( phaseBindings != null )
{
for ( String goal : execution.getGoals() )
{
MojoExecution mojoExecution = new MojoExecution( plugin, goal, execution.getId() );
mojoExecution.setLifecyclePhase( execution.getPhase() );
addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
}
}
}
// if not then i need to grab the mojo descriptor and look at the phase that is specified
else
{
for ( String goal : execution.getGoals() )
{
MojoDescriptor mojoDescriptor =
pluginManager.getMojoDescriptor( plugin, goal, project.getRemotePluginRepositories(),
session.getRepositorySession() ); Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( mojoDescriptor.getPhase() );
if ( phaseBindings != null )
{
MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
mojoExecution.setLifecyclePhase( mojoDescriptor.getPhase() );
addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
}
}
}
}
}

  

经过前面几个步骤之后,已经拿到了所有phase对应的Mojo执行列表,接下来需要将所有phase的Mojo串起来到一个总的列表里,这里注意mappings是一个LinkedHashMap,所以遍历的时候是有顺序的,而每个phase的execution map是TreeMap,根据优先级排序,这样最后总体的顺序是先按照总体的phase顺序,再按照phase内的优先级进行排序。

 Map<String, List<MojoExecution>> lifecycleMappings = new LinkedHashMap<String, List<MojoExecution>>();

        for ( Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet() )
{
List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>(); for ( List<MojoExecution> executions : entry.getValue().values() )
{
mojoExecutions.addAll( executions );
} lifecycleMappings.put( entry.getKey(), mojoExecutions );
}

  

[深入Maven源代码]maven绑定命令行参数到具体插件的更多相关文章

  1. powershell脚本,命令行参数传值,并绑定变量的例子

    这是小技巧文章,所以文章不长.但原创唯一,非常重要.我搜了下,还真没有人发 powershell怎样 [命令行 参数 绑定],所以我决定写成博客. 搜索关键字如下: powershell 命令行 参数 ...

  2. java的-D命令行参数 mvn -D参数

    java的-D命令行参数 我们会用mvn启动一个应用,如下的命令行: MAVEN_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m" mvn ...

  3. .NET Core采用的全新配置系统[5]: 聊聊默认支持的各种配置源[内存变量,环境变量和命令行参数]

    较之传统通过App.config和Web.config这两个XML文件承载的配置系统,.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命令行参 ...

  4. 你可能不知道的Google Chrome命令行参数

    概述:              关于Google Chrome命令行参数(英文叫Google Chrome Command line switches),是Chrome为了实现实验性功能.方便调试. ...

  5. gflags命令行参数解析

    gflags库是google开源的命令行参数解析工具. 安装 官方没有提供二进制库,但是Debian/Ubuntu平台本身提供了二进制库,可以直接git clone https://github.co ...

  6. optparse模块解析命令行参数的说明及优化

    一.关于解析命令行参数的方法 关于“解析命令行参数”的方法我们一般都会用到sys.argv跟optparse模块.关于sys.argv,网上有一篇非常优秀的博客已经介绍的很详细了,大家可以去这里参考: ...

  7. go语言之行--文件操作、命令行参数、序列化与反序列化详解

    一.简介 文件操作对于我们来说也是非常常用的,在python中使用open函数来对文件进行操作,而在go语言中我们使用os.File对文件进行操作. 二.终端读写 操作终端句柄常量 os.Stdin: ...

  8. [Go] 命令行参数解析包(flag 包)使用详解

    Go 的 flag 包可以解析命令行的参数. 一.命令行语法 命令行语法主要有以下几种形式: cmd -flag       // 只支持bool类型 cmd -flag=xxx cmd -flag ...

  9. Go Flag包-命令行参数解析

    Flag包用法 package main import ( "flag" "fmt" ) func main() { var num int var mode ...

随机推荐

  1. 基于canvas+ajax+zui.js的蓄电池监控系统

    今天抽空做的,仪表盘用canvas做的,数据采用ajax刷新,左边菜单用zui.js做的

  2. noip第33课作业

    1.    排座椅 [问题描述] 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同 ...

  3. SRM477

    250pt: 题意:给定一块蜂巢状的N*M矩阵,每块六边形和周围6个六边形相邻,现在告诉你哪些是陆地,哪些是水,问水陆交界处的长度. 思路:直接模拟 code: #line 7 "Islan ...

  4. poj 2155 区间更新 单点查询

    Matrix Time Limit: 3000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u Java class ...

  5. Delphi FastReport报表常用方法

    Delphi FastReport报表常用方法   作者及来源: EasyPass - 博客园    收藏到→_→:   摘要: Delphi FastReport报表常用方法       点击这里! ...

  6. 分形之二叉树(Binary Tree)

    上一篇文章讲的是分形之树(Tree),这一篇中将其简化一下,来展示二叉分形树的生长过程. 核心代码: static void FractalBinaryTree(const Vector3& ...

  7. 实验5 IIC通讯与AD/接DA接口

    1.利用单片机控制PCF8591的AD转换,控制AD0和AD1电位器,在数码光上显示DA转换的值. 2.利用单片机控制PCF8591的DA转换,让发光二极管D1由暗到亮变化,整个过程时间差不多2s左右 ...

  8. Asp.Net Core探索 之 appsettings.json

    appsettings.json是什么? 相信大家在.Net Framework的项目都会用的web.config,app.config这些文件,appsettings.json文件就是Asp.Net ...

  9. WPF App.xaml.cs常用模板,包括:异常捕获,App只能启动一次

    App.xaml.cs中的代码每次都差不多,故特地将其整理出来直接复用: using System; using System.Configuration; using System.Diagnost ...

  10. spring cloud学习(六) 配置中心-自动更新

    上一篇学习了spring cloud config的基本使用,但发现有个问题,就是每次更改配置后,都需要重启服务才能更新配置,这样肯定是不行的.在上网查资料了解后,spring cloud支持通过AM ...