SpringBoot?spring.factories加載時機分析
spring.factories作用
這個類似于Java中的SPI功能,SpringBoot啟動的時候會讀取所有jar包下面的META-INF/spring.factories文件;
并且將文件中的 接口/抽象類 對應(yīng)的實現(xiàn)類都對應(yīng)起來,并在需要的時候可以實例化對應(yīng)的實現(xiàn)類
下面我們來分析一下源碼看看spring.factories的使用場景
源碼解析
啟動SpringApplication,看看構(gòu)造方法
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();
}
其中方法getSpringFactoriesInstances( ApplicationContextInitializer.class) 是用于獲取Spring中指定類實例用的;并且獲取的時候是根據(jù)讀取整個項目中文件路徑為META-INF/spring.factories 中的內(nèi)容實例化對應(yīng)的實例類的;
例如這里的ApplicationContextInitializer 是一個接口,那么應(yīng)該實例化哪些他的實現(xiàn)類呢?那就找META-INF/spring.factories文件 ; 那么我們在spring-boot:2.1.0jar包中找到了這個文件

讀取到需要實例化的實現(xiàn)類為
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
并且還在spring-boot-autoconfigure-2.1.0.RELEASE.jar中找到了這個文件

那么文件中的兩個實現(xiàn)類也會被實例化;加上上面4個總共有6個
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

可以看到不僅僅只是把org.springframework.context.ApplicationContextInitializer 的實例類解析了出來;而是所有的都解析了出來并且保存下來了.下次其他的類需要被實例化的時候就可以直接從內(nèi)存里面拿了;
上面過程拿到了實例類之后,接下來就是實例化的過程了
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
方法createSpringFactoriesInstances就是創(chuàng)建實例的過程;可以看到傳入了對應(yīng)的接口類org.springframework.context.ApplicationContextInitializer ;接下來就會實例化 上面找到了對應(yīng)的實現(xiàn)類;
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
實例化的過程如果,沒有什么特別需要講解的;
上面有個方法 AnnotationAwareOrderComparator.sort(instances);是用來排序所有實例的; 實現(xiàn)類需要實現(xiàn) 接口Ordered ; getOrder返回的值越小,優(yōu)先級更高
用法
知道spring.factories的用法之后, 那么我們就可以利用這個特性實現(xiàn)自己的目的;
例如我們也可以寫一個接口類ApplicationContextInitializer的實現(xiàn)類;
等等之類的;
以上就是SpringBoot spring.factories加載時機分析的詳細內(nèi)容,更多關(guān)于spring.factories加載時機的資料請關(guān)注腳本之家其它相關(guān)文章!
- Spring中的spring.factories文件用法(Spring如何加載第三方Bean)
- springboot自動配置原理以及spring.factories文件的作用詳解
- springboot 加載 META-INF/spring.factories方式
- SpringBoot借助spring.factories文件跨模塊實例化Bean
- 關(guān)于SpringBoot3.x中spring.factories功能被移除的解決方案
- springBoot?之spring.factories擴展機制示例解析
- SpringBoot 自動掃描第三方包及spring.factories失效的問題解決
- SpringBoot3.x中spring.factories?SPI?服務(wù)發(fā)現(xiàn)機制的改變問題小結(jié)
- SpringBoot之spring.factories的使用方式
- 在SpringBoot3中spring.factories配置不起作用的原因和解決方法
- 淺談spring.factories文件的作用
相關(guān)文章
詳解RabbitMQ中延遲隊列結(jié)合業(yè)務(wù)場景的使用
這篇文章主要介紹了詳解RabbitMQ中延遲隊列結(jié)合業(yè)務(wù)場景的使用,延遲隊列中的元素都是帶有時間屬性的,延遲隊列就是用來存放需要在指定時間被處理的元素的隊列,需要的朋友可以參考下2023-05-05
Springboot如何設(shè)置過濾器及重復(fù)讀取request里的body
這篇文章主要介紹了Springboot如何設(shè)置過濾器及重復(fù)讀取request里的body,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
Java動態(tài)線程池插件dynamic-tp集成zookeeper
ZooKeeper是一個分布式的,開放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù),是Google的Chubby一個開源的實現(xiàn),是Hadoop和Hbase的重要組件。它是一個為分布式應(yīng)用提供一致性的軟件,提供的功能包括:配置維護、域名服務(wù)、分布式同步、組服務(wù)等2023-03-03
Idea安裝bpmn插件actiBPM的詳細過程(解決高版本無法安裝actiBPM插件)
這篇文章主要介紹了Idea安裝bpmn插件actiBPM的詳細過程(解決高版本無法安裝actiBPM插件)的問題,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-01-01

