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的源码,来与你们一块儿分享

相关文章
相关标签/搜索