這篇文章將為大家詳細講解有關如何理解springboot2.0.6中META-INF/spring.factories通過系統(tǒng)加載類獲取對應的class的全限定名稱,文章內(nèi)容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
專注于為中小企業(yè)提供網(wǎng)站設計、成都網(wǎng)站設計服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)灌云免費做網(wǎng)站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了近1000家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉變。
在 SpringBoot中是通過getSpringFactoriesInstances(Class
public class SpringApplication { privateCollection 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的構造函數(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加載對應的類獲取對應的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文件中獲取對應的 class 的全限定名稱結合,在執(zhí)行createSpringFactoriesInstances方法遍歷該集合對進行循環(huán)創(chuàng)建實例。然后返回實例對象集合。
names 為獲取所有 classpath 下面的 META-INF/spring.factories文件中applicationContextInitializer相關加載類的值
instances 為遍歷names創(chuàng)建的Spring工廠實例列表
圖1-1和圖1-2標記出所有classpath下面的 META-INF/spring.factories文件中ApplicationContextInitializer.class對應的所有全限定名稱
(圖1-1)
(圖1-2)
(圖2)根據(jù)類名“applicationContextInitializer”獲取 spring.factories文件中applicationContextInitializer相關的工廠類,并進行初始化)
( 圖3) 根據(jù)類名進行初始化創(chuàng)建實例
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獲取實例的結果集 當是Null表示當前的cache是空的;cache 實現(xiàn) new ConcurrentReferenceHashMap<>() MultiValueMap result = cache.get(classLoader); if (result != null) { return result; } try { // 獲取所有 classpath 下面的 META-INF/spring.factories 中的資源 urls(圖5) // 當classLoader為非空的時候調用getResouurces方法獲取 // 當classLoader為空的時候調用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)解析并把結果放入result for (Map.Entry, ?> entry : properties.entrySet()) { // 類名列表(圖7) List factoryClassNames = Arrays.asList( StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); result.addAll((String) entry.getKey(), factoryClassNames); } } // 緩存類加載器和文件解析器的結果集 cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } }
(圖4)獲取class全稱
(圖5) 獲取所有 classpath 下面的 META-INF/spring.factories文件的urls
(圖6) 獲取spring.factories文件的具體位置及文件中的內(nèi)容)(圖7) 獲取spring.factories文件內(nèi)容中的對應類列表
( 圖8)
通過classLoader加載classpath下面的META-INF/spring.factories文件,獲取文件信息解析成配置屬性存入結果集中,在根據(jù)type的全限定名稱,從結果集中獲取type對應的結果集。循環(huán)便利該結果集根據(jù)“全限定名稱”創(chuàng)建實例。對實例集合排序后返回
關于如何理解springboot2.0.6中META-INF/spring.factories通過系統(tǒng)加載類獲取對應的class的全限定名稱就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。