[置顶] 如何编写一个有效的缓存

摘要: 缓存作为计算机历史上最重要的发明之一,对计算机历史起到了举足轻重的作用,因为缓存可以协调两个速度不一致的组件之间的并行运作。内存作为CPU和非易失性存储介质之间的缓存,避免CPU每次读取指令,读取数据都去速度缓慢的硬盘读取。快速缓存作为内存和CPU之间的缓存进一步提高了CPU的效率,现在大部分CPU... 阅读全文

posted @ 2014-12-07 22:37 Leo-Yang 阅读(615) 评论(0) 推荐(1)

2015年12月15日

[深入Maven源代码]maven绑定命令行参数到具体插件

maven的插件

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

maven绑定插件(plugin)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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去找到具体的插件,找的方法是先从项目定义的插件里找,找不到的话再去仓库里找,这里把核心部分代码贴出来:

1
2
3
4
5
6
7
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具体要执行的插件到下一段代码再写入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
     * 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里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * 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内的优先级进行排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
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 );
       }

  

posted @ 2015-12-15 19:50 Leo-Yang 阅读(2548) 评论(0) 推荐(0)

2015年11月3日

java.util.ServiceLoader的用法

摘要: 在很多开源组件里经常会看到java.util.ServiceLoader的使用,这里给大家介绍下怎么通过ServiceLoader找到一个接口的所有实现类。我们新建一个接口Hellopublic interface Hello {String say();}然后创建一个实现类DefaultHello... 阅读全文

posted @ 2015-11-03 09:49 Leo-Yang 阅读(2243) 评论(0) 推荐(0)

非阻塞算法-栈

摘要: 上一节我们以计数器作为例子描述了非阻塞算法,这一节我们拿一个稍微复杂一点的数据结构栈来讲述非阻塞算法的实践应用。1.单线程栈public class SingleThreadStack implements Stack{ private Node head; public Node p... 阅读全文

posted @ 2015-11-03 09:48 Leo-Yang 阅读(638) 评论(0) 推荐(1)

非阻塞算法-简单的计数器

摘要: 1.为什么要用非阻塞算法?我们知道为了避免并发环境下操作共享变量的问题,可以采用同步(synchronize)和锁(Lock)的方式做到线程安全,但是JVM处理锁竞争时对于竞争失败的线程采用的是挂起稍后调度的策略,这样会带来额外的线程上下文切换成本。同时和CAS(Compare And Set)这种... 阅读全文

posted @ 2015-11-03 09:39 Leo-Yang 阅读(1193) 评论(0) 推荐(0)

2015年6月10日

Excelbatis-一个将excel文件读入成实体列表、将实体列表解析成excel文件的ORM框架,简洁易于配置、可扩展性好

摘要: 欢迎使用Excelbatis!github地址:https://github.com/log4leo/ExcelbatisExcelbatis的优点和spring天然结合,易于接入xsd支持,使得配置更加简洁,不需要按照bean冗长的语法进行配置遵循“约定大于配置”原则,如果不配置的话,自动推断字段... 阅读全文

posted @ 2015-06-10 10:27 Leo-Yang 阅读(718) 评论(0) 推荐(0)

2014年6月4日

教你如何迭代地遍历二叉树

摘要: 为何要迭代?二叉树遍历是一个非常常见的操作,无论是中序遍历、先序遍历还是后续遍历,都可以用递归的方法很好地完成,但是相对来说迭代的方法难度就高不少,而且除此之外,迭代地遍历树至少有两个现实意义的优点:1.比递归节省空间,递归是用栈实现的,因此如果树的高度h很大的话,递归很有可能会造成栈溢出2.迭代的... 阅读全文

posted @ 2014-06-04 15:45 Leo-Yang 阅读(3613) 评论(0) 推荐(0)

2014年3月1日

你真的理解编码吗?unicode,utf8,utf16详解

摘要: Java,编码,unicode 阅读全文

posted @ 2014-03-01 17:09 Leo-Yang 阅读(6988) 评论(2) 推荐(5)

2014年2月28日

[开源项目]Shell4Win,一个在Windows下执行shell命令的解释器

摘要: shell解释器 python Shell4Win 阅读全文

posted @ 2014-02-28 21:58 Leo-Yang 阅读(3211) 评论(0) 推荐(0)

2014年2月17日

[LeetCode]Single Number II

摘要: LeetCode java algorithm 阅读全文

posted @ 2014-02-17 19:32 Leo-Yang 阅读(426) 评论(0) 推荐(0)

< 2025年6月 >
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 1 2 3 4 5
6 7 8 9 10 11 12

导航

统计

转载请注明出处
点击右上角即可分享
微信分享提示