简单了解SPI机制
1. Java SPI机制
- SPI只是一个简写,全名为Service Provider Interface,可以理解成服务接口提供者,一般用于针对厂商或者插件的场景下,在java.util.ServiceLoader的文档里有比较详细的介绍。
- 简单的总结java SPI机制的思想,系统里抽象的各个某块往往会有不同的实现方案或者有不同的服务厂商来提供实现,比如常见的日志模块,XML解析模块,JSON解析处理模块,数据库JDBC模块等,Java是面向对象设计的,一般推荐模块之间基于接口进行编程,这也是基于可插拔原则的一种设计理念
- Java SPI 就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。
- Java SPI 的具体约定为: 当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
- 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader
JDBC SPI使用例子: MySQL VS Oracle
自定义 SPI使用例子
/* @Description: 使用Java SPI机制--定义接口 */ public interface SpiService { void doWork(); } /* @Description: 使用Java SPI机制--接口实现 */ public class StuSpiService implements SpiService{ @Override public void doWork() { System.out.println("我是一名学生,正在写作业完成功课"); } } public class TeaSpiService implements SpiService{ @Override public void doWork() { System.out.println("我是一名老师,我正在备课"); } }
定义SPI提供服务文件 resources/META-INF/services/com.java.interview.spi.SpiService com.java.interview.spi.StuSpiService com.java.interview.spi.TeaSpiService
/* @Description: 使用Java SPI机制--具体使用 */ public class SpiApp { public static void main(String[] args) { // 使用ServiceLoader加载SpiService指定实现类 ServiceLoader<SpiService> load = ServiceLoader.load(SpiService.class); Iterator<SpiService> iterator = load.iterator(); while (iterator.hasNext()) { SpiService next = iterator.next(); next.doWork(); } } }
执行结果:
我是一名学生,正在写作业完成功课
我是一名老师,我正在备课
java SPI源码追踪解析
public static void main(String[] args) { // 使用ServiceLoader加载SpiService指定实现类 ServiceLoader<SpiService> load = ServiceLoader.load(SpiService.class); Iterator<SpiService> iterator = load.iterator(); while (iterator.hasNext()) { SpiService next = iterator.next(); next.doWork(); } }
ServiceLoader.load方法追踪
public static <S> ServiceLoader<S> load(Class<S> service) {
// 获取当前线程的类加载器 ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); } public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader){ return new ServiceLoader<>(service, loader); } 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(); } public void reload() { providers.clear(); // LazyIterator是内部Iterator接口的一个实现 lookupIterator = new LazyIterator(service, loader); }
ServiceLoader.iterator方法追踪: 获取迭代器返回自定义实现的LazyIterator
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; return lookupIterator.hasNext(); } public S next() { if (knownProviders.hasNext()) return knownProviders.next().getValue(); return lookupIterator.next(); } public void remove() { throw new UnsupportedOperationException(); } } }
LazyIterator迭代方法追踪
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); } }
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); } throw new Error(); // Th
java SPI存在的不足
- 通过对Java SPI 源码追踪分析,发现Java SPI 在查找扩展实现类的时候遍历 SPI 的配置文件并且将实现类全部实例化,假设一个实现类初始化过程比较消耗资源且耗时,但是你的代码里面又用不上它,这就产生了资源的浪费,所以说 Java SPI 无法按需加载实现类
2. Dubbo SPI机制
- Dubbo或者SpringFactoriesLoader并没有使用JDK内置的SPI机制,只是利用了SPI的思想根据实际情况做了一些优化和调整
-
Dubbo SPI相关逻辑被封装在ExtensionLoader类中,通过这个类我们可以加载指定的实现类Dubbo SPI扩展有两个规则
- Dubbo SPI扩展有两个规则
- 跟JDK内置的SPI一样,需要在resources目录下创建任一目录结构
META-INF/dubbo META-INF/dubbo/internal META-INF/services 在对应的目录下创建以接口全路径全名称命名的文件,Dubbo会去这三个目录下加载相应的扩展点
- 文件内容和JDK内置的SPI不一样,内容是一种Key和Value形式的数据
Key是一个字符串,Value是一个对应扩展点的实现, 这样的方式可以按照需要加载指定的实现类
- Dubbo SPI 简单使用样例
- 定义一个Dubbo的扩展点
/** * @description: Dubbo的一个扩展点 * @author: dyg * @date: 2022/1/25 23:53 */ @SPI public interface DubboDriver { String connect(); }
- 实现该扩展点
/** * @description: * @author: dyg * @date: 2022/1/25 23:54 */ public class DubboMySqlDriver implements DubboDriver { @Override public String connect() { return "Dubbo扩展点--连接MySQL数据库"; } }
- 配置文件
dubboMySqlDriver=com.dubbo.spi.dubbo.DubboMySqlDriver
- 使用Dubbo SPI机制
public class DubboSpiApp { public static void main(String[] args) { ExtensionLoader<DubboDriver> extensionLoader = ExtensionLoader.getExtensionLoader(DubboDriver.class); System.out.println(extensionLoader.getExtension("dubboMySqlDriver").connect()); } }
- 定义一个Dubbo的扩展点
-
ExtensionLoader源码追踪
首先通过 ExtensionLoader.getExtensionLoader来获取一个 ExtensionLoader实例,之后通过代码getExtension()方法或的指定名称的扩展点,因此就分以下两步骤追踪
-
ExtensionLoader.getExtensionLoader(DubboDriver.class)
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { if (type == null) { // 扩展点类型不能为空 throw new IllegalArgumentException("Extension type == null"); } else if (!type.isInterface()) { // 扩展点类型必须为接口 throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!"); } else if (!withExtensionAnnotation(type)) { // 扩展点接口必须使用@SPI注解标记 throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!"); } else { // 先尝试从缓存中获取,如果缓存中没有的话新建一个放入缓存中 ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type); if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type)); loader = (ExtensionLoader)EXTENSION_LOADERS.get(type); } return loader; } } private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap(64); private static <T> boolean withExtensionAnnotation(Class<T> type) { return type.isAnnotationPresent(SPI.class); }
// ExtensionLoader构造方法中,初始化一个objectFactory
private ExtensionLoader(Class<?> type) {
this.type = type;
this.objectFactory = type == ExtensionFactory.class ? null : (ExtensionFactory)getExtensionLoader(ExtensionFactory.class)
.getAdaptiveExtension();
} -
extensionLoader.getExtension("dubboMySqlDriver")
public T getExtension(String name) { return this.getExtension(name, true); } public T getExtension(String name, boolean wrap) { if (StringUtils.isEmpty(name)) { // SPI扩展点的名称不能为空,也就是配置文件中的Key throw new IllegalArgumentException("Extension name == null"); } else if ("true".equals(name)) { // 如果name=true则返回一个默认的扩展实现 return this.getDefaultExtension(); } else { // 创建或者返回一个Holder对象,用户缓存该扩展点的实例 Holder<Object> holder = this.getOrCreateHolder(name); Object instance = holder.get(); if (instance == null) { synchronized(holder) { instance = holder.get(); if (instance == null) { instance = this.createExtension(name, wrap); holder.set(instance); } } } return instance; } }
// 获取默认的扩展点实现 public T getOrDefaultExtension(String name) { return this.containsExtension(name) ? this.getExtension(name) : this.getDefaultExtension(); } public T getDefaultExtension() { this.getExtensionClasses(); return !StringUtils.isBlank(this.cachedDefaultName) && !"true".equals(this.cachedDefaultName) ?
this.getExtension(this.cachedDefaultName) : null; }
// 创建缓存器 private Holder<Object> getOrCreateHolder(String name) { Holder<Object> holder = (Holder)this.cachedInstances.get(name); if (holder == null) { this.cachedInstances.putIfAbsent(name, new Holder()); holder = (Holder)this.cachedInstances.get(name); } return holder; } private T createExtension(String name, boolean wrap) { // 根据name返回扩展类 Class<?> clazz = (Class)this.getExtensionClasses().get(name); if (clazz == null) { throw this.findException(name); } else { try { // 从缓存中查找该类是否已经被初始化 T instance = EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = EXTENSION_INSTANCES.get(clazz); } // 依赖注入操作(IOC|DI) this.injectExtension(instance); // 通过wrapper进行包装(AOP切面通过包装类的方式处理) if (wrap) { List<Class<?>> wrapperClassesList = new ArrayList(); if (this.cachedWrapperClasses != null) { wrapperClassesList.addAll(this.cachedWrapperClasses); wrapperClassesList.sort(WrapperComparator.COMPARATOR); Collections.reverse(wrapperClassesList); } if (CollectionUtils.isNotEmpty(wrapperClassesList)) { Iterator var6 = wrapperClassesList.iterator(); while(true) { Class wrapperClass; Wrapper wrapper; do { if (!var6.hasNext()) { break; } wrapperClass = (Class)var6.next(); wrapper = (Wrapper)wrapperClass.getAnnotation(Wrapper.class); } while(wrapper != null && (!ArrayUtils.contains(wrapper.matches(), name) || ArrayUtils.contains(wrapper.mismatches(), name))); instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance)); } } } // 初始化扩展点 this.initExtension(instance); return instance; } catch (Throwable var9) { throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var9.getMessage(), var9); } } } private boolean containsExtension(String name) { return this.getExtensionClasses().containsKey(name); } // Dubbo中代码实现套路基本都差不多,先访问缓存,缓存未命中再通过loadExtensionClasses加载扩展类 private Map<String, Class<?>> getExtensionClasses() { Map<String, Class<?>> classes = (Map)this.cachedClasses.get(); if (classes == null) { Holder var2 = this.cachedClasses; synchronized(this.cachedClasses) { classes = (Map)this.cachedClasses.get(); if (classes == null) {
// 缓存中没有时加载扩展类 classes = this.loadExtensionClasses(); this.cachedClasses.set(classes); } } } return classes; } // 进行依赖注入 private T injectExtension(T instance) { if (this.objectFactory == null) { return instance; } else { try { Method[] var2 = instance.getClass().getMethods(); int var3 = var2.length; for(int var4 = 0; var4 < var3; ++var4) { Method method = var2[var4];
// 获取对应的setter方法注入依赖参数 if (this.isSetter(method) && method.getAnnotation(DisableInject.class) == null) { Class<?> pt = method.getParameterTypes()[0]; if (!ReflectUtils.isPrimitives(pt)) { try {
// 获取方法对应的属性名称 String property = this.getSetterProperty(method);
// 根据class以及name,使用自适应扩展点加载并通过set方法进行赋值 Object object = this.objectFactory.getExtension(pt, property); if (object != null) { method.invoke(instance, object); } } catch (Exception var9) { logger.error("Failed to inject via method " + method.getName() + " of interface " + this.type.getName() + ": " + var9.getMessage(), var9); } } } } } catch (Exception var10) { logger.error(var10.getMessage(), var10); } return instance; } }// 初始化扩展类 private void initExtension(T instance) { if (instance instanceof Lifecycle) { Lifecycle lifecycle = (Lifecycle)instance; lifecycle.initialize(); } } // 加载扩展类 private Map<String, Class<?>> loadExtensionClasses() { // 获取当前type接口默认的扩展类 this.cacheDefaultExtensionName(); Map<String, Class<?>> extensionClasses = new HashMap(); LoadingStrategy[] var2 = strategies; int var3 = var2.length; for(int var4 = 0; var4 < var3; ++var4) { LoadingStrategy strategy = var2[var4]; // 解析指定路径下的文件 this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); this.loadDirectory(extensionClasses, strategy.directory(), this.type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); } return extensionClasses; } private void cacheDefaultExtensionName() { // 获取type类声明的注解@SPI SPI defaultAnnotation = (SPI)this.type.getAnnotation(SPI.class); if (defaultAnnotation != null) { // 得到注解中定义的value值 String value = defaultAnnotation.value(); if ((value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1) { throw new IllegalStateException("More than 1 default extension name on extension " + this.type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1) {this.cachedDefaultName = names[0];} } } } // 从指定的目录下,根据传入的type全路径名查找对应得文件,解析内容后保存到extensionClass集合中 private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) { this.loadDirectory(extensionClasses, dir, type, false, false); } private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) { String fileName = dir + type; try { Enumeration<java.net.URL> urls = null; ClassLoader classLoader = findClassLoader(); if (extensionLoaderClassLoaderFirst) { ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader(); if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) { urls = extensionLoaderClassLoader.getResources(fileName); } } if (urls == null || !urls.hasMoreElements()) { if (classLoader != null) { urls = classLoader.getResources(fileName); } else { urls = ClassLoader.getSystemResources(fileName); } } if (urls != null) { while(urls.hasMoreElements()) { java.net.URL resourceURL = (java.net.URL)urls.nextElement(); this.loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages); } } } catch (Throwable var11) { logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", var11); } } private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL, boolean overridden, String... excludedPackages) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8)); Throwable var7 = null; try { String line; try { while((line = reader.readLine()) != null) { int ci = line.indexOf(35); if (ci >= 0) { line = line.substring(0, ci); } line = line.trim(); if (line.length() > 0) { try { String name = null; int i = line.indexOf(61); if (i > 0) { name = line.substring(0, i).trim(); line = line.substring(i + 1).trim(); } if (line.length() > 0 && !this.isExcluded(line, excludedPackages)) { this.loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name, overridden); } } catch (Throwable var21) { IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + this.type + ", class line: " + line + ") in " + resourceURL + ", cause: " + var21.getMessage(), var21); this.exceptions.put(line, e); } } } } catch (Throwable var22) { var7 = var22; throw var22; } } finally { if (reader != null) { if (var7 != null) { try { reader.close(); } catch (Throwable var20) { var7.addSuppressed(var20); } } else { reader.close(); } } } } catch (Throwable var24) { logger.error("Exception occurred when loading extension class (interface: " + this.type + ", class file: " + resourceURL + ") in " + resourceURL, var24); } } private boolean isExcluded(String className, String... excludedPackages) { if (excludedPackages != null) { String[] var3 = excludedPackages; int var4 = excludedPackages.length; for(int var5 = 0; var5 < var4; ++var5) { String excludePackage = var3[var5]; if (className.startsWith(excludePackage + ".")) { return true; } } } return false; } // 真正加载扩展点的方法 private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name, boolean overridden) throws NoSuchMethodException { if (!this.type.isAssignableFrom(clazz)) { throw new IllegalStateException("Error occurred when loading extension class (interface: " + this.type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + " is not subtype of interface."); } else {
// 处理Adaptive自适应扩展点 if (clazz.isAnnotationPresent(Adaptive.class)) { this.cacheAdaptiveClass(clazz, overridden); } else if (this.isWrapperClass(clazz)) { // isWrapperClass是判断方法,如果为true表示当前clazz是一个装饰器类,这个判断逻辑很简单就是判断clazz类中是否存在一个带有扩展类的构造函数 this.cacheWrapperClass(clazz); } else { clazz.getConstructor(); if (StringUtils.isEmpty(name)) { name = this.findAnnotationName(clazz); if (name.length() == 0) { throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL); } } String[] names = NAME_SEPARATOR.split(name); if (ArrayUtils.isNotEmpty(names)) { this.cacheActivateClass(clazz, names[0]); String[] var7 = names; int var8 = names.length; for(int var9 = 0; var9 < var8; ++var9) { String n = var7[var9]; this.cacheName(clazz, n); this.saveInExtensionClass(extensionClasses, clazz, n, overridden); } } } } } private void cacheName(Class<?> clazz, String name) { if (!this.cachedNames.containsKey(clazz)) { this.cachedNames.put(clazz, name); } } private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) { Class<?> c = (Class)extensionClasses.get(name); if (c != null && !overridden) { if (c != clazz) { String duplicateMsg = "Duplicate extension " + this.type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName(); logger.error(duplicateMsg); throw new IllegalStateException(duplicateMsg); } } else { extensionClasses.put(name, clazz); } }// 装饰器类示例 public class ProtocolListenerWrapper implements Protocol{
// 继承自一个接口,同时在属性中包含当前接口实例,并且通过构造方法注入接口实例 private final Protocol protocol; public ProtocolListenerWrapper(Protocol protocol){ if(null == protocol){ throw new IllegalArgumentException("protocol==null"); } this.protocol = protocol; } }
-
- 自适应扩展点Adaptive
自适应(Adaptive)扩展点可以理解为适配器扩展点,简单来说就是能够根据上下文动态匹配一个扩展类,它的使用方式如下 ExtensionLoader.getExtensionLoader(class).getAdaptiveExtension()
- 自适应扩展点通过@Adaptive注解来声明,有两种使用方式
- @Adaptive 注解定义在类上面,表示当前类是自适应类
- @Adaptive 注解定义在方法层面,会通过动态代理的方式生成一个动态字节码,进行自适应匹配
@Adaptive public class AdaptiveCompiler { public String getName(String name){ return String.format("%s _ %s","AdaptiveCompiler",name); } } @SPI("dubbo") public interface AdaptiveProtocol { int getDefaultport(); @Adaptive <T> Exporter<T> export(Invoker<T> invoker) throws RpcException; @Adaptive <T> Invoker<T> refer(Class<T> type,URL url) throws RpcException; }
- 自适应扩展点源码
public T getAdaptiveExtension() { // 从缓存中获取自适应扩展点实例 Object instance = this.cachedAdaptiveInstance.get(); if (instance == null) { if (this.createAdaptiveInstanceError != null) { throw new IllegalStateException("Failed to create adaptive instance: " + this.createAdaptiveInstanceError.toString(), this.createAdaptiveInstanceError); } Holder var2 = this.cachedAdaptiveInstance; // 创建自适应扩展点实例,并放置到缓存中 synchronized(this.cachedAdaptiveInstance) { instance = this.cachedAdaptiveInstance.get(); if (instance == null) { try { instance = this.createAdaptiveExtension(); this.cachedAdaptiveInstance.set(instance); } catch (Throwable var5) { this.createAdaptiveInstanceError = var5; throw new IllegalStateException("Failed to create adaptive instance: " + var5.toString(), var5); } } } } return instance; } private T createAdaptiveExtension() { try { return this.injectExtension(this.getAdaptiveExtensionClass().newInstance()); } catch (Exception var2) { throw new IllegalStateException("Can't create adaptive extension " + this.type + ", cause: " + var2.getMessage(), var2); } } private Class<?> getAdaptiveExtensionClass() { this.getExtensionClasses(); return this.cachedAdaptiveClass != null ? this.cachedAdaptiveClass : (this.cachedAdaptiveClass = this.createAdaptiveExtensionClass()); } private Class<?> createAdaptiveExtensionClass() { String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate(); ClassLoader classLoader = findClassLoader(); Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
- 自适应扩展点通过@Adaptive注解来声明,有两种使用方式
3. SpringBoot SPI机制
- 在springboot的自动装配过程中,最终会加载META-INF/spring.factories文件,而加载的过程是由SpringFactoriesLoader加载的。从CLASSPATH下的每个Jar包中搜寻所有META-INF/spring.factories配置文件,然后将解析properties文件,找到指定名称的配置后返回。需要注意的是,其实这里不仅仅是会去ClassPath路径下查找,会扫描所有路径下的Jar包,只不过这个文件只会在Classpath下的jar包中。
public abstract class SpringFactoriesLoader { /** * The location to look for factories.<p>Can be present in multiple JAR files. * -- 工厂设定的配置文件存放位置 可以在Jar包中包含 */ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
// 用来存储不同的classLoader类加载器加载的数据 private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>(); /** * Load and instantiate the factory implementations of the given type from * {@value #FACTORIES_RESOURCE_LOCATION}, using the given class loader. * <p>The returned factories are sorted through {@link AnnotationAwareOrderComparator}. * <p>If a custom instantiation strategy is required, use {@link #loadFactoryNames} */ public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) { Assert.notNull(factoryClass, "'factoryClass' must not be null"); ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse); if (logger.isTraceEnabled()) { logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames); } List<T> result = new ArrayList<>(factoryNames.size()); for (String factoryName : factoryNames) { result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse)); } AnnotationAwareOrderComparator.sort(result); return result; } /** * Load the fully qualified class names of factory implementations of the * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given * class loader.*/ public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result;} try { Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex); } } @SuppressWarnings("unchecked") private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) { try { Class<?> instanceClass = ClassUtils.forName(instanceClassName, classLoader); if (!factoryClass.isAssignableFrom(instanceClass)) { throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]"); } return (T) ReflectionUtils.accessibleConstructor(instanceClass).newInstance(); }catch (Throwable ex) { throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), ex); } } }
- META-INF/spring.factories 如果采用SpringBoot默认的配置,该文件处于spring-boot-autoconfigure 子模块下 resource/META-INF/spring.factories文件,数据以key-value键值对呈现
- 关键Key对应类详情
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
// 该配置决定了SpringBoot中是否启用Enable机制 String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude */ Class<?>[] exclude() default {}; /** * Exclude specific auto-configuration class names such that they will never be * applied. * @return the class names to exclude * @since 1.3.0 */ String[] excludeName() default {}; }public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { void initialize(C var1); }
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E var1); }
@FunctionalInterface public interface AutoConfigurationImportListener extends EventListener { /** * Handle an auto-configuration import event. * @param event the event to respond to */ void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event); }
@FunctionalInterface public interface AutoConfigurationImportFilter { /** * Apply the filter to the given auto-configuration class candidates. * @param autoConfigurationClasses the auto-configuration classes being considered. * Implementations should not change the values in this array. * @param autoConfigurationMetadata access to the meta-data generated by the * auto-configure annotation processor * @return a boolean array indicating which of the auto-configuration classes should * be imported. The returned array must be the same size as the incoming * {@code autoConfigurationClasses} parameter. Entries containing {@code false} will * not be imported. */ boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata); }
@FunctionalInterface public interface TemplateAvailabilityProvider { /** * Returns {@code true} if a template is available for the given {@code view}. * @param view the view name * @param environment the environment * @param classLoader the class loader * @param resourceLoader the resource loader * @return if the template is available */ boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,ResourceLoader resourceLoader); }
@FunctionalInterface public interface FailureAnalyzer { /** * Returns an analysis of the given {@code failure}, or {@code null} if no analysis * was possible. * @param failure the failure * @return the analysis or {@code null} */ FailureAnalysis analyze(Throwable failure); }
SpringBoot自动化机制 https://www.cnblogs.com/dduo/p/14964349.html