zoukankan      html  css  js  c++  java
  • [深入Maven源代码]maven绑定命令行参数到具体插件

    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 );
            }
    

      

  • 相关阅读:
    Android 下压缩图片—微弱失真
    android中ViewHolder通用简洁写法
    Android裁剪固定大小头像的功能
    Android进度加载的Loading效果
    GitHub开源项目总结
    Android 实现emoji表情的demo
    vim 高级使用技巧第二篇
    android apk 防止反编译技术第一篇-加壳技术
    Android Metro风格的Launcher开发系列第二篇
    FFMPEG高级编程第一篇:环境搭建及编译
  • 原文地址:https://www.cnblogs.com/developerY/p/maven_bind_command_line_plugin.html
Copyright © 2011-2022 走看看