JavaSPI详解( 二 )

从运行结果中可以看到EurekaRegistryZookeeperRegistry都被实例化并且生成相应的对象 。但是我们全程并没有显示的加载和生成EurekaRegistryZookeeperRegistry类对象,那么是怎么来的呢?
SPI机制的实现SPI机制的核心就是ServiceLoader类 。其主要的属性如下:
    // 指出接口配置文件的位置,也就是为什么要在META-INF/services/下创建接口的全限定名文件的原因    private static final String PREFIX = "META-INF/services/";    // 正在被加载的类(接口)的class对象    private final Class<S> service;    // 加载使用的类加载器    private final ClassLoader loader;    // 创建 ServiceLoader 时采用的访问控制上下文    private final AccessControlContext acc;    // 缓存已经加载的实现, 按实例化顺序缓存    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();    // The current lazy-lookup iterator    private LazyIterator lookupIterator;load()方法的实现如下:
    public static <S> ServiceLoader<S> load(Class<S> service) {        ClassLoader cl = Thread.currentThread().getContextClassLoader();        // 使用当前线程的ClassLoader进行加载待加载的实现类        return ServiceLoader.load(service, cl);    }    public static <S> ServiceLoader<S> load(Class<S> service,                                            ClassLoader loader)    {        // load 方法本质是创建一个ServiceLoader对象        return new ServiceLoader<>(service, loader);    }    // new ServiceLoader<>(service, loader)的实现    private ServiceLoader(Class<S> svc, ClassLoader cl) {        service = Objects.requireNonNull(svc, "Service interface cannot be null");        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;        reload();    }    public void reload() {        providers.clear();        // 根据接口类型(父类)和类加载器初始化LazyIterator        lookupIterator = new LazyIterator(service, loader);    }    private LazyIterator(Class<S> service, ClassLoader loader) {            this.service = service;            this.loader = loader;        }跟踪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();            }        };    }

推荐阅读