Java的SPI机制

78 阅读1分钟

1.案例代码

public class SPIDemo {
    public static void main(String[] args) {
        ServiceLoader<RunInterface> load = ServiceLoader.load(RunInterface.class);

        Iterator<RunInterface> iterator = load.iterator();

        while (iterator.hasNext()) {
            RunInterface runInterface = iterator.next();
            runInterface.run();
        }
        
    }
}

接口

public interface RunInterface {
    void run();
}

实现类

public class Car implements RunInterface {
    @Override
    public void run() {
        System.out.println("小汽车四个轮跑");
    }
}
public class Human implements RunInterface {
    @Override
    public void run() {
        System.out.println("人类两条腿跑");
    }
}

resource目录下新建META-INF/META-INF/services文件夹

文件夹下新建文件,文件名为需要调用的接口名的全限定类名

2.源码跟进

2.1 实例化ServiceLoader与LazyIterator

ServiceLoader.load(Class service);

获取应用类加载器ApplicationClassLoad,用于加载用户自定义的类

创建一个ServiceLoader

同时创建一个LazyIterator对象 

LazyIterator 为ServiceLoader的内部类

2.2 加载资源与实例化服务

获取迭代器

加载资源

当调用 iterator.hasNext() javaspi将完成资源的加载与实例化

此处的lookupIterator 即为 ServiceLoader 的内部类LazyIterator

java.util.ServiceLoader.LazyIterator#hasNext

java.util.ServiceLoader.LazyIterator#hasNextService

加载资源

拿到接口的名字与 META-INF/services/ 拼接,通过类加载器去加载资源

解析资源

一次解析一行,存入LIst集合name中

拿到了需要调用的服务的全限定类名

然后就是实例化

java.util.ServiceLoader.LazyIterator#next

java.util.ServiceLoader.LazyIterator#nextService

最终通过Class.forName实例化