spring的SpringFactoriesLoader是spring框架外部工具类,在 Spring boot 利用启动的过程中,这个类的工作很重要, 启动逻辑应用该类从classpath上所有jar包中找出各自的 META-INF/spring.factories 属性文件,并剖析出其中定义的工厂类。这些工厂类进而被启动逻辑应用,利用于进一步初始化工作。其应用的形式和java的spi根本相似,咱们能够先学习java的spi而且进一步学习SpringFactoriesLoader。

一、java spi

1、什么是Spi

SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩大的接口,它能够用来启用框架扩大和替换组件。 SPI的作用就是为这些被扩大的API寻找服务实现。

2、Spi的利用场景

SPI (Service Provider Interface)调用方来制订接口标准,提供给内部来实现,调用方在调用时则抉择本人须要的内部实现。  从应用人员上来说,SPI 被框架扩大人员应用。

3、Spi的简略demo

(1)、定义一个接口

public interface Upload {    void upload();}

(2)、接口实现类

package cn..antispam.soa.service;public class BduUploadImpl implements Upload {    @Override public void upload(){        System.out.println("上传到百度云"); }}
public class AliUploadImpl implements Upload {    @Override public void upload() {        System.out.println("上传到阿里oss"); }}

(3)、测试类

public class spidemo {   public static void main(String[] args) {       ServiceLoader<Upload> uploads = ServiceLoader.load(Upload.class);for (Upload upload :uploads){           upload.upload();}   }}

(4)输入

上传到阿里oss上传到百度云Process finished with exit code 0

4、Spi源码剖析

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<>();    // 懒加载迭代器    private java.util.ServiceLoader.LazyIterator lookupIterator;    // 公有外部类,提供对所有的service的类的加载与实例化    private class LazyIterator implements Iterator<S> {        Class<S> service;        ClassLoader loader;        Enumeration<URL> configs = null;        String nextName = null;           public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader){       return new ServiceLoader<>(service, loader);    }   public static <S> ServiceLoader<S> load(Class<S> service) {        ClassLoader cl = Thread.currentThread().getContextClassLoader();        return ServiceLoader.load(service, cl);    }          private ServiceLoader(Class<S> svc, ClassLoader cl) {        //....        reload();    }   public void reload() {       // 清空providers        providers.clear();        lookupIterator = new LazyIterator(service, loader);    }         private LazyIterator(Class<S> service, ClassLoader loader) {            this.service = service;            this.loader = loader;   }        //...        private boolean hasNextService() {            if (configs == null) {                try {                    //获取目录下所有的类                    //"META-INF/services/"+service的全限定类名                    String fullName = PREFIX + service.getName();                    if (loader == null)                        //加载 META-INF/services/"+service里的所有全限定类名                        configs = ClassLoader.getSystemResources(fullName);                    else                        configs = loader.getResources(fullName);                } catch (IOException x) {                    //...                }                //....            }        }        private S nextService() {            String cn = nextName;            nextName = null;            Class<?> c = null;            try {                //反射加载类                c = Class.forName(cn, false, loader);            } catch (ClassNotFoundException x) {            }            try {                //实例化                S p = service.cast(c.newInstance());                //放进缓存                providers.put(cn, p);                return p;            } catch (Throwable x) {                //..            }            //..        }    }}

下面的代码只贴出了局部要害的实现,上面贴出比拟直观的spi加载的次要流程供参考: