JavaSPI详解( 三 )

跟踪load()方法发现其本质是创建了一个ServiceLoader对象,其共有两个参数,分别是代加载的类父类(接口)Class类对象和类加载器 。在构造方法中完成了两件事,一个是变量赋值,一个是调用reload()方法 。reload()方法则根据接口类型(父类)和类加载器初始化LazyIterator
当执行ServiceLoader#iterator()时,会创建java.util.Iterator匿名内部类实现:
    public Iterator<S> iterator() {        return new Iterator<S>() {            Iterator<Map.Entry<String,S>> knownProviders                = providers.entrySet().iterator();            public boolean hasNext() {                if (knownProviders.hasNext())                    return true;                return lookupIterator.hasNext();            }            public S next() {                if (knownProviders.hasNext())                    return knownProviders.next().getValue();                return lookupIterator.next();            }            public void remove() {                throw new UnsupportedOperationException();            }        };    }当执行hasNext() 方法时,会先去providers 查找已经加载的缓存实现,如果不存在,则会继续调用LazyIterator#hasNext()用于发现尚未加载的实现,最后的实现在LazyIterator#hasNextService()
LazyIterator的关键属性
// 缓存所有需要查找jar包(文件)路径,Enumeration<URL> configs = null;// 缓存所有被查找到的实现类全限定名Iterator<String> pending = null;// 迭代器使用,下一个需要被加载的类全限定名String nextName = null;hasNextService()实现核心如下:
// 获取所由需要扫描的包路径configs = loader.getResources(fullName);// 循环扫描configs中所有的包路径,解析META-INF/services中的指定文件(上例中的cn.bmilk.chat.spi.Registry文件)//while ((pending == null) || !pending.hasNext()) {    if (!configs.hasMoreElements()) {        return false;    }    // pending缓存了所有查找到的类全限定名    pending = parse(service, configs.nextElement());}在知道是否存在接口的实现后,就是通过next()方法获取实现,核心功能由nextService()

经验总结扩展阅读