您好,登錄后才能下訂單哦!
這篇文章主要介紹了springboot中getSpringFactoriesInstances源碼的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
在springboot啟動過程中,getSpringFactoriesInstances這個方法很重要,啟動的時候使用該方法從classpath上所有jar包中找出對應的META-INF/spring.factorys屬性文件,并將其中的初始化器和監聽器加載并實例化,應用于更進一步的初始化工作。其工作流程圖如下:
讓我們跟著流程圖和時序圖一步步窺視其中的奧妙:
調用getSpringFactoriesInstances()方法
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();
//1.加載初始化器并實例化,10.并賦值給initializers
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//同上,監聽器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推斷應用主類
this.mainApplicationClass = deduceMainApplicationClass();
}
獲取類加載器和調用loadFactoryNames()方法及對返回結果進行初始化以及排序
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//2. 獲取類加載器
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//3. 調用loadFactoryNames方法,并使用set對其返回結果進行去重處理
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//9. 實例化初始化器
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//9. 對實例化的結果進行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//該方法主要是通過反射實例化初始化器
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;
}
查詢緩存和讀取META-INFO/spring.factorys文件key-value值,并對value值進行處理
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 返回初始化器的value值
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = //查詢緩存,如果有就返回,沒有就加載
cache.get(classLoader);
if (result != null) {
return result;
}
try {
//通過類加載器加載所有jar包中包含META-INFO/spring.factorys的文件資源路徑
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//實例化properties對象,并加載路徑中的spring.factorys文件內容
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String)
//獲取key值
entry.getKey()).trim();
//對value值進行都好拆分處理
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
//將key和value值存入result中 result.add(factoryClassName, factoryName.trim());
}
}
}
//將結果存入緩存
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
感謝你能夠認真閱讀完這篇文章,希望小編分享的“springboot中getSpringFactoriesInstances源碼的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。