ServiceLoader 机制原理和源码分析

一:工作原理:

serviceloader 是一个server 提供者加载设施,目前 应用了到了SPI( jdbc 驱动),它提供了延迟加载功能。

当调用 ServiceLoader.load(Class clz) 方法时,会到jar中中的目录 "META-INF/services/" + clz.getName 进行文件读取,

然后当在调用LazyIterator.hasNext() 时,在文件中读取到实际的服务实现类并把它们通过调用 Class.forName(String name, boolean initialize,ClassLoader loader)

进行类加载。

二:源码分析:

ServiceLoader 里面提供两个静态的loader 方法和一个内部类 LazyIterator(延迟加载的迭代器)

2.1 loader 方法分析:

 // 此方法是通过外部传递过来需要加载的服务接口的class 对象,最终会通过class.getName 当作jar包资源文件名    "META-INF/services/" + clz.getName  
 public static <S> ServiceLoader<S> load(Class<S> service) {
        //获取当前线程类加载器
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
 }
 
 public static <S> ServiceLoader<S> load(Class<S> service,ClassLoader loader){
        return new ServiceLoader<>(service, loader);
 }
//安全认证之后,调用reload()方法
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();
}
// 主要是创建当前serviceLoader 对象中的属性LazyIterator lookupIterator 对象,用于当有程序需要访问SPI 实现类时,它再进行加载
public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
}
// 一旦外部有调用iterator 方法时,先从 providers 中获取具体服务提供者,如果没有,则从 lookupIterator 中获取到服务配置文件中需要加载的类
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();
        }

    };
}

// Cached providers, in instantiation order
// 存放缓存的服务提供者
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

// The current lazy-lookup iterator
private LazyIterator lookupIterator;

 

2.2 内部实现lazy 加载的内部类迭代器:

private class LazyIterator implements Iterator<S>
    {
        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }

        private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    // 组装配置文件路径
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        //获取文件中的URL,如果类加载器为null,会委托系统类加载器进行加载(ClassLoader 中实现的)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                         //获取文件中的URL
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                // 从配置的文件中读取组装 服务提供者实现类的类名
                pending = parse(service, configs.nextElement());
            }
            nextName = pending.next();
            return true;
        }

        private S nextService() {
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                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());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                fail(service,
                     "Provider " + cn + " could not be instantiated",
                     x);
            }
            throw new Error();          // This cannot happen
        }

        public boolean hasNext() {
            if (acc == null) {
                return hasNextService();
            } else {
                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
                    public Boolean run() { return hasNextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public S next() {
            if (acc == null) {
                return nextService();
            } else {
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
                    public S run() { return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }

    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值