1、前言html
上篇講到了spring boot 經過SpringFactoriesLoader.loadFactoryNames進行加載工廠實例名稱列表。本篇是接着上篇繼續從源碼講解spring boot加載配置文件的流程,java
2、代碼解讀web
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates //使用name來保證惟一,防止重複 Set<String> names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
既然他加載完工廠實例名稱列表了,那麼他如何初始化呢。咱們繼續往下看,他有個spring
createSpringFactoriesInstances()app
//用來建立spring工廠實例 private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size());//建立實例list,用來裝建立好的實例 for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader);//建立沒有被連接的類,此處底層用到了 ClassLoader.loadClass 關於它和 Class.forName的區別 能夠參考https://www.cnblogs.com/suibianle/p/6676215.html Assert.isAssignable(type, instanceClass);//判斷instanceClass是不是type類型 Constructor<?> constructor = instanceClass .getDeclaredConstructor(parameterTypes);//獲取instanceClass構造 T instance = (T) BeanUtils.instantiateClass(constructor, args);//實例化 instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException( "Cannot instantiate " + type + " : " + name, ex); } } return instances; }
通過此方法後,關於type類型的工廠實例就初始化完成了。ui
那麼咱們上篇文章講到,spring boot 在建立完工廠實例後,他又進行了註冊監聽器,他註冊監聽幹什麼事情了呢?咱們看一下,研究研究。this
package org.springframework.boot; public class 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 = deduceWebApplicationType(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } }
咱們看一下setListeners();code
他內部也進行了建立工廠實例。這裏咱們就再也不進行贅述了。上述文章已經針對建立工廠實例進行詳細的描述了。htm
咱們看setListeners內部是如何實現的,他拿這些工廠實例作什麼了?blog
//Sets the ApplicationListeners that will be applied to the SpringApplication and registered with the ApplicationContext. //解釋一下,他大體意思就是說設置這些集合主要是應用於SpringApplication而且註冊到ApplicationContext public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<>(); this.listeners.addAll(listeners); }
咱們能夠看到,他內部其實就是將這些工廠實例加入到了一個大的listeners集合中,並無作其餘操做。可能之後他會用到這個listeners集合。
ok,本章關於初始化配置就講到這裏,下一篇會繼續解讀Spring Boot的源碼,來與你們一塊兒分享