千家信息网

[SpringBoot]深入浅出剖析SpringBoot中Spring Factories机制

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,微信号:GitShare微信公众号:爱折腾的稻草如有问题或建议,请在公众号留言[1]前续为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全
千家信息网最后更新 2026年11月04日[SpringBoot]深入浅出剖析SpringBoot中Spring Factories机制

微信号:GitShare
微信公众号:爱折腾的稻草
如有问题或建议,请在公众号留言[1]

前续

为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理。

  • 1、[SpringBoot]利用SpringBoot快速构建并启动项目

  • 2、[SpringBoot]详解SpringBoot应用的启动过程

  • 3、[SpringBoot]深入浅出剖析SpringBoot的应用类型识别机制

Java SPI机制
  • Java SPI是什么?
    SPI的全名为Service Provider Interface.大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。
    我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。
    面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,
    如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。
    Java SPI就是提供这样的一个机制:为某个接口寻×××实现的机制。

  • Java SPI的约定
    当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。
    该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

    • 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。

    • jdk提供服务实现查找的一个工具类:java.util.ServiceLoader 。

SpringBoot中的SPI机制

在Spring中也有一种类似与Java SPI的加载机制。它在META-INF/spring.factories文件中配置接口的实现类名称,然后在程序中读取这些配置文件并实例化。
这种自定义的SPI机制是Spring Boot Starter实现的基础。

Spring Factories实现原理

spring-core包里定义了SpringFactoriesLoader类,这个类实现了检索META-INF/spring.factories文件,并获取指定接口的配置的功能。
在这个类中定义了两个对外的方法:

1、loadFactories

根据接口类获取其实现类的实例,这个方法返回的是对象列表,其源代码:

public static  List loadFactories(Class factoryClass, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
}
List result = new ArrayList<>(factoryNames.size());
for (String factoryName : factoryNames) {
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
  • 先获取ClassLoader

  • 调用loadFacotoryNames()方法,获取factoryNames,其源码如下:

public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
//获取到类名
String factoryClassName = factoryClass.getName();
//在当前ClassLoader下的所有META-INF/spring.factories文件的配置信息的Map中获取指定的factory的值,如果不存在,则返回空列表
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
  • 调用loadSpringFactories方法,获取当前ClassLoader下的所有META-INF/spring.factories文件的配置信息

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
//去缓存中获取对应的
MultiValueMap result = cache.get(classLoader);
if (result != null)
return result;
try {
//获取当前ClassLoader下的所有包含META-INF/spring.factories文件的URL路径
Enumeration urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
//初始返回对象
result = new LinkedMultiValueMap<>();
//遍历所有的包含META-INF/spring.factories文件URL集合
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//转换为Properties对象
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
//遍历META-INF/spring.factories文件中的所有属性
for (Map.Entry entry : properties.entrySet()) {
//如果一个接口希望配置多个实现类,可以使用','进行分割,将当前Key对应的值转换为List
List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
//添加到返回对象中
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
//添加到缓存中
cache.put(classLoader, result);
//返回结果
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

我们可以在自己的jar中配置spring.factories文件,不会影响到其它地方的配置,也不会被别人的配置覆盖。
这一点非常有利于后期我们进行自定义扩展。

  • 调用instantiateFactory,实例化获取到的对应的Factory对象,其源码:

private static  T instantiateFactory(String instanceClassName, Class factoryClass, ClassLoader classLoader) {
try {
//根据类名获取类的实例,这个源码在上一篇中已经剖析过了。
Class instanceClass = ClassUtils.forName(instanceClassName, classLoader);
//isAssignableFrom()是判断instanceClassName的对象是否是FactoryClass的子类或者相同的类,如果是返回true。
if (!factoryClass.isAssignableFrom(instanceClass)) {
//如果实例化的目标类不是Factory类的子类或者不是Factory类,则抛出异常
throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]");
}
//通过java反射机制,实例化目标类
return (T) ReflectionUtils.accessibleConstructor(instanceClass).newInstance();
}
catch (Throwable ex) {
throw new IllegalArgumentException("Unable to instantiate factory class: " + factoryClass.getName(), ex);
}
}

从这段代码中我们可以知道,它只支持没有参数的构造方法。

2、loadFactoryNames

根据接口获取其接口类的名称,这个方法返回的是类名的列表,其源代码已经在上面分析过了。

SpringBoot启动时的应用

在SpringBoot启动过程中,创建SpringApplication对象是,有如下两行代码:

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer

  • 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener

Spring Factories机制的应用

在日常工作中,我们可能需要实现一些SDK或者Spring Boot Starter给被人使用,这个使用我们就可以使用Factories机制。
Factories机制可以让SDK或者Starter的使用只需要很少或者不需要进行配置,只需要在服务中引入我们的jar包。

知识点
  • Class的isAssignableFrom()解析

public native boolean isAssignableFrom(Class cls);

由方法签名可见是一个本地方法,即C代码编写的。
其作用:
有两个Class类型的类象,一个是调用isAssignableFrom方法的类对象(后称对象a),以及方法中作为参数的这个类对象(称之为对象b),这两个对象如果满足以下条件则返回true,否则返回false:

  • a对象所对应类信息是b对象所对应的类信息的父类或者是父接口,简单理解即a是b的父类或接口

  • a对象所对应类信息与b对象所对应的类信息相同,简单理解即a和b为同一个类或同一个接口

后记

为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理。 敬请关注[爱折腾的稻草(GitShare)]公众号,为您提供更多更优质的技术教程。


图注:爱折腾的稻草


对象 接口 文件 机制 配置 方法 模块 服务 实例 代码 应用 类名 剖析 类信息 两个 公众 原理 方案 源码 程序 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 深圳市人人互联网科技有限公司 广州为想互联网科技有限公司 互联网科技工作委员会副主任毛军 科技互联网产品 互联网科技革命 融贸通互联网科技 广州紫鲸互联网科技 齐家互联网科技有限公司 互联网科技美容 互联网金融科技委员会 北京华百购互联网科技有限公司 阿大互联网科技有限公司 健康食品互联网创新科技园项目 科技大学互联网 广州千川互联网科技有限公司 黑云互联网科技有限公司 互联网科技职业技能培训学校 马化腾互联网科技教学 安徽九吞吴互联网科技有限公司 互联网科技快速发展优美句子 奇酷互联网科技公司 互联网保险科技创业 伊宁互联网科技做什么的 工业互联网展湾科技股份有限公司 兰石爱特工业互联网科技分公司 第三届互联网大会安防黑科技 互联网大会出现的黑科技 互联网高科技绘画 互联网科技创业有什么好项目 六子台科技互联网展会
0