Java--SPI(Service Provider Interface)

1.什么是SPI

    SPI全称Service Provide Interface,是JDK内置的一种服务提供发现机制(如:JDBC)。是一种动态替换发现机制。例如:有个接口想在运行时才发现具体的实现类,那么你只需要在程序运行前添加一个实现即可,并把新加的实现描述给JDK即可。实现类系统类加载器AppClassLoader来加载(注:这里是违反了类加载器双亲委派模式)。

2.SPI规范

3.SPI使用

     1.定义接口

  2.设置实现类

3.设置类加载配置文件

4.使用

添加依赖

类加载

5.SPI缺点

我们使用SPI查找具体的实现的时候,需要遍历所有的实现,并实例化,然后我们在循环中才能找到我们需要实现。这应该也是最大的缺点,需要把所有的实现都实例化了,即便我们不需要,也都给实例化了。

结果

5.ServiceLoader源码简单分析

1.获取上下文类加载器(App ClassLoader)

/**
*
*获取上下文类加载器
*/
public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

2.初始化服务提供者查找的迭代器

    public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

3.服务提供者查找的迭代器

private class LazyIterator
        implements Iterator<S>
    {

        //服务提供者接口 例如:Hello
        Class<S> service;
        //类加载器
        ClassLoader loader;
        //保存实现类的url
        Enumeration<URL> configs = null;
        //保存实现类的名称
        Iterator<String> pending = null;
        //下一个实现类的名称
        String nextName = null;

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

4.实现迭代器的方法 在迭代的时候才会去获取具体实现接口的实例

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

猜你喜欢

转载自blog.csdn.net/qq_34724270/article/details/85112017
今日推荐