上一篇我们介绍了初始化器的使用方法
这次我们一起来看看初始化器的实现原理
因为初始化器的使用方式有三种,有表面上看的话,初始化器的加载原理也是略有不同的,本篇主要讲解的是使用spring.factories配置初始化器的原理,其他两种下篇继续讲解
我们首先要创建一个springboot的工程,然后启动进行源码追踪
package com.jun.lee;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
我们进入到SpringApplication的run方法中,这里做了两个事情,一个就是实例化了SpringApplication类,并且调用了它的run方法
/**
* Static helper that can be used to run a {@link SpringApplication} from the
* specified sources using default settings and user supplied arguments.
* @param primarySources the primary sources to load
* @param args the application arguments (usually passed from a Java main method)
* @return the running {@link ApplicationContext}
*/
public static ConfigurableApplicationContext run(Class>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
我们进入到SpringApplication的构造方法中,可以看到一个 setInitializers的方法,其中调用了getSpringFactoriesInstances的方法并传入了ApplicationContextInitializer的class类对象,这个类就是我们需要重点关注的
@SuppressWarnings({ "unchecked", "rawtypes" })
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();
}
我们进入getSpringFactoriesInstances方法,是一个重载方法,我们继续深入
private Collection getSpringFactoriesInstances(Class type) {
return getSpringFactoriesInstances(type, new Class>[] {});
}
在下面方法中就是初始化器做实现的重点方法
private Collection getSpringFactoriesInstances(Class type,
Class>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set names = new LinkedHashSet<>(
//加载初始化器
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//实例化初始化器
List instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//对初始化器进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
我们深入SpringFactoriesLoader.loadFactoryNames(type, classLoader))方法,看看详细的加载过程
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
//查询缓存
MultiValueMap result = cache.get(classLoader);
if (result != null)
return result;
try {
//获取jar包下spring.factories文件的路径
Enumeration urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
//遍历路径
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//解析每个spring.factories文件,封装为properties
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
//遍历properties的kv结构
for (Map.Entry, ?> entry : properties.entrySet()) {
//将多个value封装为集合结构
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);
}
}
接下来我们看看createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);方法
private List createSpringFactoriesInstances(Class type,
Class>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set names) {
List instances = new ArrayList<>(names.size());
//遍历类名
for (String name : names) {
try {
Class> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
//实例化对象
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
最后执行AnnotationAwareOrderComparator.sort(instances);方法进行排序
public static void sort(List> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
到此初始化器加载完成