JAVA SPI ServiceLoader源码分析

第一节 参考
第二节 架构
第三节 源码细节
一.ServiceLoader初始化

ServiceLoader.load(),代码只有一行,new 一个ServiceLoader对象,

private ServiceLoader(Class<S> svc, ClassLoader cl) {
	//赋值三个成员变量
	//赋值要加载的接口
    service = Objects.requireNonNull(svc, "Service interface cannot be null");
    //默认进来是AppClassLoader
    loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
    //默认为空
    acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
    //清除缓存,初始化接口的迭代器ServiceLoader.LazyIterator对象
    //后面遍历主要是调用LazyIterator的方法.
    reload();
}

二.遍历接口的实现类
(一).创建迭代器
ServiceLoader.iterator()方法,创建java.util.Iterator对象.Iterator成员变量knownProviders指向ServiceLoader.providers.每次迭代器遍历时遍历两个成员变量,先遍历ServiceLoader.providers,再遍历ServiceLoader.lookupIterator.lookupIterator是ServiceLoader.LazyIterator类型.
(二).第一次hasNext.
ServiceLoader.providers为空Map.进入ServiceLoader.LazyIterator#hasNext()方法.进入LazyIterator.hasNextService().
 

private boolean hasNextService() {
	//第一次进来nextName为null
	//第一次后就指向下一行实现类,后面调用LazyIterator#nextService()时使用这个nextName,创建实例.
    if (nextName != null) {
        return true;
    }
    //第一遍历进来configs为null
    if (configs == null) {
        try {
        	//PREFIX为"META-INF/services/"路径 这里拼接完整的META-INF下interface文件的路径
            String fullName = PREFIX + service.getName();
            //loader指向AppClassLoader,进入else部分
            if (loader == null)
                configs = ClassLoader.getSystemResources(fullName);
            else
            	//configs是URL类型的Enumeration,加载到这里面
                configs = loader.getResources(fullName);
        } catch (IOException x) {
            fail(service, "Error locating configuration files", x);
        }
    }
    while ((pending == null) || !pending.hasNext()) {
    	//遍历到最后一行实现类之后,这里return false,结束遍历
        if (!configs.hasMoreElements()) {
            return false;
        }
        //读取spi文件,代码在后面
        pending = parse(service, configs.nextElement());
    }
    nextName = pending.next();
    return true;
}

读取spi的文件

private Iterator<String> parse(Class<?> service, URL u)
        throws ServiceConfigurationError
{
    InputStream in = null;
    BufferedReader r = null;
    ArrayList<String> names = new ArrayList<>();
    try {
    	//打开spi文件
        in = u.openStream();
        r = new BufferedReader(new InputStreamReader(in, "utf-8"));
        int lc = 1;
        //解析一行实现类,解析到names列表里面
        while ((lc = parseLine(service, u, r, lc, names)) >= 0);
    } catch (IOException x) {
        fail(service, "Error reading configuration file", x);
    } finally {
        try {
            if (r != null) r.close();
            if (in != null) in.close();
        } catch (IOException y) {
            fail(service, "Error closing configuration file", y);
        }
    }
    return names.iterator();
}

(三).第一次Iterator#next().

private S nextService() {
    if (!hasNextService())
        throw new NoSuchElementException();
    String cn = nextName;
    nextName = null;
    Class<?> c = null;
    try {
    	//创建遍历出来的一行实现类的Class对象,默认使用AppClassLoader
        c = Class.forName(cn, false, loader);
    } catch (ClassNotFoundException x) {
        fail(service,
             "Provider " + cn + " not found");
    }
    //判断实现类是不是该接口的对象
    if (!service.isAssignableFrom(c)) {
        fail(service,
             "Provider " + cn  + " not a subtype");
    }
    try {
    	//实例化一行实现类的对象
        S p = service.cast(c.newInstance());
        //放入到缓存里面,key是实现类的全路径名,value是实例对象
        providers.put(cn, p);
        return p;
    } catch (Throwable x) {
        fail(service,
             "Provider " + cn + " could not be instantiated",
             x);
    }
    throw new Error();          // This cannot happen
}
发布了82 篇原创文章 · 获赞 8 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/feivirus/article/details/104231395