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在什么時候加載系統初始化器呢?
查看源碼
從啟動類開始
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方法
5、然后進入loadFactoryNames方法
6、然后進入loadFactoryNames方法
上面代碼對應loadFactories的流程圖
可以發現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顯示的所有系統初始化器
names返回7個初始化器
7、然后實例化這7個初始化器
通過反射進行實例化
8、通過setInitializers將初始化器實例注入到spring容器中
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<>(); this.initializers.addAll(initializers); }