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加载的次要流程供参考: