新聞中心
這篇文章將為大家詳細(xì)講解有關(guān)如何理解springboot2.0.6中META-INF/spring.factories通過系統(tǒng)加載類獲取對應(yīng)的class的全限定名稱,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
專注于為中小企業(yè)提供網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)灌云免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了近1000家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
在 SpringBoot中是通過getSpringFactoriesInstances(Class
源碼解析
getSpringFactoriesInstances()方法
public class SpringApplication {
private Collection getSpringFactoriesInstances(Class type) {
return getSpringFactoriesInstances(type, new Class>[] {});
}
// 獲取Spring工廠
private Collection getSpringFactoriesInstances(Class type,
Class>[] parameterTypes, Object... args) {
// 獲取ClassLoader
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
// 定義class數(shù)組,即返回值 names 是所有 classpath 下面的 META-INF/spring.factories 中定義的父節(jié)點(圖2)
Set names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 內(nèi)部循環(huán)初始化 names的構(gòu)造函數(shù),獲取實例實例對象(圖2)
List instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 創(chuàng)建Spring工廠實例
private List createSpringFactoriesInstances(Class type,
Class>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set names) {
List instances = new ArrayList<>(names.size());
// 循環(huán)處理names的值
for (String name : names) {
try { //( 圖3)
//通過指定的classloader加載對應(yīng)的類獲取對應(yīng)的Class對象
Class> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
//創(chuàng)建一個實例
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
} getSpringFactoriesInstances方法通過SpringFactoriesLoader類的loadFactoryNames方法獲取系統(tǒng)加載類去所有classpath下面的 META-INF/spring.factories文件中獲取對應(yīng)的 class 的全限定名稱結(jié)合,在執(zhí)行createSpringFactoriesInstances方法遍歷該集合對進(jìn)行循環(huán)創(chuàng)建實例。然后返回實例對象集合。
names 為獲取所有 classpath 下面的 META-INF/spring.factories文件中applicationContextInitializer相關(guān)加載類的值
instances 為遍歷names創(chuàng)建的Spring工廠實例列表
以getSpringFactoriesInstances(ApplicationContextInitializer.class)為例進(jìn)行debug分析
圖1-1和圖1-2標(biāo)記出所有classpath下面的 META-INF/spring.factories文件中ApplicationContextInitializer.class對應(yīng)的所有全限定名稱
(圖1-1)

(圖1-2)

(圖2)根據(jù)類名“applicationContextInitializer”獲取 spring.factories文件中applicationContextInitializer相關(guān)的工廠類,并進(jìn)行初始化)
( 圖3) 根據(jù)類名進(jìn)行初始化創(chuàng)建實例

在SpringApplication類的getSpringFactoriesInstances方法中進(jìn)入SpringFactoresLoader類的loadFactoryNames方法
public abstract class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Map> cache = new ConcurrentReferenceHashMap<>();
// 加載工廠
public static List loadFactoryNames(Class> factoryClass, @Nullable ClassLoader classLoader) {
// 獲取類名稱(圖4)
String factoryClassName = factoryClass.getName();
// 根據(jù)類名稱獲取需要加載的工廠類名稱
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 通過加載所有 classpath 下面的 META-INF/spring.factories文件,掃描加載類,(圖8)
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 從cache獲取實例的結(jié)果集 當(dāng)是Null表示當(dāng)前的cache是空的;cache 實現(xiàn) new ConcurrentReferenceHashMap<>()
MultiValueMap result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 獲取所有 classpath 下面的 META-INF/spring.factories 中的資源 urls(圖5)
// 當(dāng)classLoader為非空的時候調(diào)用getResouurces方法獲取
// 當(dāng)classLoader為空的時候調(diào)用ClassLoader.getSystemResouurces方法獲取
Enumeration urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 循環(huán)處理 urls中的元素,獲取元素
while (urls.hasMoreElements()) {
// 獲取元素 url地址(圖6)
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 解析文件 把文件變成配置屬性(圖6)
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
// 循環(huán)解析并把結(jié)果放入result
for (Map.Entry, ?> entry : properties.entrySet()) {
// 類名列表(圖7)
List factoryClassNames = Arrays.asList(
StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
result.addAll((String) entry.getKey(), factoryClassNames);
}
}
// 緩存類加載器和文件解析器的結(jié)果集
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
} 以loadFactoryNames(ApplicationContextInitializer.class,classLoader)為例進(jìn)行debug分析
(圖4)獲取class全稱

(圖5) 獲取所有 classpath 下面的 META-INF/spring.factories文件的urls

(圖6) 獲取spring.factories文件的具體位置及文件中的內(nèi)容)
(圖7) 獲取spring.factories文件內(nèi)容中的對應(yīng)類列表
( 圖8)
總結(jié)
通過classLoader加載classpath下面的META-INF/spring.factories文件,獲取文件信息解析成配置屬性存入結(jié)果集中,在根據(jù)type的全限定名稱,從結(jié)果集中獲取type對應(yīng)的結(jié)果集。循環(huán)便利該結(jié)果集根據(jù)“全限定名稱”創(chuàng)建實例。對實例集合排序后返回
關(guān)于如何理解springboot2.0.6中META-INF/spring.factories通過系統(tǒng)加載類獲取對應(yīng)的class的全限定名稱就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
當(dāng)前題目:如何理解springboot2.0.6中META-INF/spring.factories通過系統(tǒng)加載類獲取對應(yīng)的class的全限定名稱
網(wǎng)站URL:http://www.dlmjj.cn/article/ihcioe.html


咨詢
建站咨詢
