• Java ServiceLoader(SPI)学习


    1. 几个不错的关于ServiceLoader的文章,大家可以先参考一下

    1) http://www.myexception.cn/program/1355384.html 这篇的后面的问题分析不错

    2.实例代码

    直接上代码吧
    1) 接口
    package com.ctrip.lzyan.test.element.serviceloader.sample1;
    
    public interface Command {
        
        public void execute(); 
        
    }

    2) 实现类

    package com.ctrip.lzyan.test.element.serviceloader.sample1;
    
    public class StartCommand implements Command {
    
        public void execute() {  
            System.out.println("start....");  
        }
        
    }
    package com.ctrip.lzyan.test.element.serviceloader.sample1;
    
    public class ShutdownCommand implements Command {
    
        @Override
        public void execute() {
            System.out.println("shutdown....");
        }
    
    }

    3) 配置文件

    由于是使用maven构建的项目,所以就在resources下面新建目录META-INF/services,在该目录下新建文件com.ctrip.lzyan.test.element.serviceloader.sample1.Command, 即完整的接口名
    文件内容如下:
    com.ctrip.lzyan.test.element.serviceloader.sample1.StartCommand
    com.ctrip.lzyan.test.element.serviceloader.sample1.ShutdownCommand

    4) 测试类

    package com.ctrip.lzyan.test.element.serviceloader.sample1;
    
    import java.util.ServiceLoader;
    
    public class CommandTester {
        
        public static void main(String[] args) {
            ServiceLoader<Command> serviceLoader = ServiceLoader.load(Command.class);  
            for(Command command:serviceLoader){  
                command.execute();
            }
        }
        
    }

    5) 编译执行

    mvn clean install -Dmaven.test.skip=true  
    mvn exec:java -Dexec.mainClass=com.ctrip.lzyan.test.element.serviceloader.sample1.CommandTester

    3.activemq中的使用实例

    第一次接触到ServiceLoader就是在activemq的启动过程中,所以学习了一下
    activemq broker启动时,调用的是org.apache.activemq.console.command.ShellCommand 类,ShellCommand.main调用runTask,runTask会调用getCommands方法,下面看一下getCommands的代 码:
        ArrayList<Command> getCommands() {  
            ServiceLoader<Command> loader = ServiceLoader.load(Command.class);  
            Iterator<Command> iterator = loader.iterator();  
            ArrayList<Command> rc = new ArrayList<Command>();  
            boolean done = false;  
            while (!done) {  
                try {  
                    if( iterator.hasNext() ) {  
                        rc.add(iterator.next());  
                    } else {  
                        done = true;  
                    }  
                } catch (ServiceConfigurationError e) {  
                    // it's ok, some commands may not load if their dependencies  
                    // are not available.  
                }  
            }  
            return rc;  
        }  

    ServiceLoader会读取META-INF/services/org.apache.activemq.console.command.Command 配置的类并在迭代时将其实例化。

    回头看一下runTask方法:
        protected void runTask(List<String> tokens) throws Exception {  
          
            // Process task token  
            if (tokens.size() > 0) {  
                Command command=null;  
                String taskToken = (String)tokens.remove(0);  
          
          
                for( Command c: getCommands() ) {  
                    if( taskToken.equals(c.getName()) ) {  
                        command = c;  
                        break;  
                    }  
                }  
                if( command == null ) {  
                    if (taskToken.equals("help")) {  
                        printHelp();  
                    } else {  
                        printHelp();  
                    }  
                }  
          
                if( command!=null ) {  
                    command.setCommandContext(context);  
                    command.execute(tokens);  
                }  
            } else {  
                printHelp();  
            }  
          
        }  

    该方法根据类名选择Command,并执行。


    问题:

    1.配置文件为什么要放在META-INF/services下面?
    ServiceLoader.PREFIX定义如下:
    private static final String PREFIX = "META-INF/services/";
    但是如果ServiceLoader在load时提供Classloader,则可以从其他的目录读取。
    ServiceLoader.LazyIterator.nextService中实例化,即load的结果迭代时才会被实例化。


    转自:

    http://blog.csdn.net/unei66/article/details/47051017

  • 相关阅读:
    Delphi StrUtils-字符串函数RightStr、MidStr、LeftStr
    Delphi 错误:Could not convert variant to type(Null) into type (String)
    Delphi Variants-VarIsEmpty、VarIsNull 判断Variant变量是否为空、是否包含Null值
    Python使用openpyxl读写excel文件
    CentOS7设置为局域网固定ip
    Linux下ps aux命令中STAT的参数含义(转)
    Python生成8位随机字符串的方法分析
    php源码加密方法详解
    普通程序员 与 大牛 的区别 ???
    开始记录前端学习过程中的点点滴滴
  • 原文地址:https://www.cnblogs.com/ylz8401/p/7359061.html
Copyright © 2020-2023  润新知