SPI

2019-08-17  本文已影响0人  Audience0

SPI,全程为Service Provider Interface,是一种服务发现机制.它通过在ClassPath下META-INF/services文件夹查找文件,自动加载文件中所定义的类.

在这个过程中,可以通过ServiceLoader.load以及ServiceLoader.iterator来获取文件中定义的实现类
其中,文件名为接口的全限定名,文件中的定义的类是该接口的实现类的全限定名


ServiceLoader部分源码如下:
ServiceLoader.load() 主要是初始化对象


public final class ServiceLoader<S>
        implements Iterable<S>
{
    //定义查询文件的目录
    private static final String PREFIX = "META-INF/services/";

    //要加载的接口
    private final Class<S> service;
    //类加载器
    private final ClassLoader loader;

    private final AccessControlContext acc;
    //缓存已加载的实现类
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
    //ServiceLoader 的内部类,由它实现加载
    private LazyIterator lookupIterator;

    public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader)
    {   //初始化ServiceLoader
        return new ServiceLoader<>(service, loader);
    }

    //load 方法,主要做ServiceLoad 及其内部类 LazyIterator 初始化(service,loader),
    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

    public void reload() {
        providers.clear();
        //初始化内部类LazyIterator
        lookupIterator = new LazyIterator(service, loader);
    }
    //校验service是否为空,初始化ServiceLoader
    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();
    }
    
        private class LazyIterator
            implements Iterator<S>
    {

        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;
        //初始化LazyIterator
        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }
  }
}

ServiceLoader.iterator();获取迭代器,但其实都是在调用其内部类LazyIterator的迭代器

public final class ServiceLoader<S>  implements Iterable<S>{
      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;
               //实际是ServiceLoader内部类LazyIterator的hasNext
                return lookupIterator.hasNext();
            }
            
            public S next() {
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
              //实际是ServiceLoader内部类LazyIterator的next
                return lookupIterator.next();
            }

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

LazyIterator的实现

private class LazyIterator implements Iterator<S> {
      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;
        }

        private S nextService() {
             //调用hasNextService判断是否还有元素
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
               //根据实现类权限定名获取Class
                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();
        }
}

开源框架中的实际应用:


image.png

其中foreach相当于调用iterator,以及hasNext,next

上一篇下一篇

猜你喜欢

热点阅读