Spring Boot 工廠加載機制 SpringFactoriesLoader


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);
	}

  

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM