您的位置:首页 > 博客中心 > 互联网 >

常用技术之SPI ServiceLoader

时间:2022-05-11 11:22

ServiceLoader是jdk对SPI(Service Provider Interface)机制的实现, 让具体业务实现与接口分离,让接口可以自由扩展,是非常常用的技术

常用场景如下:

1. java nio java.nio.channels.spi.SelectorProvider
2. java.nio.charset.spi.CharsetProvider
3. java.nio.file.spi.FileSystemProvider
4. com.fasterxml.jackson.databind.Module
5. java.sql.Driver

源码解析

    public static  ServiceLoader load(Class service) {
       //默认使用上下文类加载器加载
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }
    public static  ServiceLoader load(Class service,
                                            ClassLoader loader)
    {
        return new ServiceLoader<>(service, loader);
    }
    private ServiceLoader(Class 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();
        lookupIterator = new LazyIterator(service, loader);
    }
        //查找META-INF/services/+service 的文件,并解析
        private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    String fullName = preFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        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;
        }
        //返回上次解析的到类名,并把类名放进providers变量中缓存
        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
        }
java.util.ServiceLoader#iterator迭代器设计模式,如果查询缓存providers中有数据,直接返回,否则交给LazyIterator查找

    public Iterator iterator() {
        return new Iterator() {

            Iterator> 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();
            }

        };
    }

本类排行

今日推荐

热门手游