spring boot 源碼分析(二) 配置文件加載2

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的源碼,來與你們一塊兒分享

相關文章
相關標籤/搜索