SpringFactoriesLoader 介绍

框架内部使用的通用工厂加载机制

从classpath下多个jar包特定的位置读取文件并初始化类

文件内容必须是kv形式,即properties类型

key是全限定名(抽象类|接口)、value是实现,多个用逗号分隔

 

SpringFactoriesLoader作用

SpringBoot框架中从类路径jar包中读取特定文件实现扩展类的载入

将所有Jar中的spring.factories(A.jar(spring.factories),

   B.jar(spring.factories),

    C.jar(spring.factories)

   ......

)载入 Spring Boot框架

 

SpringFactoriesLoader在什么时候加载系统初始化器呢?

   Spring Boot 工厂加载机制 SpringFactoriesLoader_jar

 

 

查看源码

从启动类开始



SpringApplication.run(Sb2Application.class, args);


  

1、进入run方法



public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}


public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}


  

2、进入SpringApplication构造函数



public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}


  

 

3、然后进入setInitializers方法

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));


 

4、进入getSpringFactoriesInstances方法

Spring Boot 工厂加载机制 SpringFactoriesLoader_初始化_02

 

 

5、然后进入loadFactoryNames方法

Spring Boot 工厂加载机制 SpringFactoriesLoader_实例化_03

 

 

6、然后进入loadFactoryNames方法

Spring Boot 工厂加载机制 SpringFactoriesLoader_jar_04

 上面代码对应loadFactories的流程图

 

 Spring Boot 工厂加载机制 SpringFactoriesLoader_jar_05

 

 可以发现FACTORIES_RESOURCE_LOCATION的值为"META-INF/spring.factories"。 这就是为什么我们前面要在META-INF文件夹下创建spring.factories 文件的原因。

获得所有Jar包下的META-INF/spring.factories文件

classLoader.getResources(FACTORIES_RESOURCE_LOCATION)

通过以下过程,将初始化器注入到容器当中

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());
}
}
如下图,Debug显示的所有系统初始化器


Spring Boot 工厂加载机制 SpringFactoriesLoader_jar包_06

 names返回7个初始化器

 

Spring Boot 工厂加载机制 SpringFactoriesLoader_jar_07

 

 7、然后实例化这7个初始化器

Spring Boot 工厂加载机制 SpringFactoriesLoader_初始化_08

 

 通过反射进行实例化

Spring Boot 工厂加载机制 SpringFactoriesLoader_jar_09

 

 

 8、通过setInitializers将初始化器实例注入到spring容器中



public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>();
this.initializers.addAll(initializers);
}