千家信息网

springboot中getSpringFactoriesInstances源码的示例分析

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,这篇文章主要介绍了springboot中getSpringFactoriesInstances源码的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带
千家信息网最后更新 2024年09月22日springboot中getSpringFactoriesInstances源码的示例分析

这篇文章主要介绍了springboot中getSpringFactoriesInstances源码的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

一、概述及流程图

在springboot启动过程中,getSpringFactoriesInstances这个方法很重要,启动的时候使用该方法从classpath上所有jar包中找出对应的META-INF/spring.factorys属性文件,并将其中的初始化器和监听器加载并实例化,应用于更进一步的初始化工作。其工作流程图如下:

image

二、源码解析

让我们跟着流程图和时序图一步步窥视其中的奥妙:

image
  1. 调用getSpringFactoriesInstances()方法
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 = WebApplicationType.deduceFromClasspath();
//1.加载初始化器并实例化,10.并赋值给initializers
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//同上,监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断应用主类
this.mainApplicationClass = deduceMainApplicationClass();
}
  1. 获取类加载器和调用loadFactoryNames()方法及对返回结果进行初始化以及排序
private  Collection getSpringFactoriesInstances(Class type) {
return getSpringFactoriesInstances(type, new Class[] {});
}

private Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
//2. 获取类加载器
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//3. 调用loadFactoryNames方法,并使用set对其返回结果进行去重处理
Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//9. 实例化初始化器
List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//9. 对实例化的结果进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

//该方法主要是通过反射实例化初始化器
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;
}
  1. 查询缓存和读取META-INFO/spring.factorys文件key-value值,并对value值进行处理
public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 返回初始化器的value值
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = //查询缓存,如果有就返回,没有就加载
cache.get(classLoader);
if (result != null) {
return result;
}

try {
//通过类加载器加载所有jar包中包含META-INFO/spring.factorys的文件资源路径
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);
//实例化properties对象,并加载路径中的spring.factorys文件内容
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry entry : properties.entrySet()) {
String factoryClassName = ((String)
//获取key值
entry.getKey()).trim();
//对value值进行都好拆分处理
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
//将key和value值存入result中 result.add(factoryClassName, factoryName.trim());
}
}
}
//将结果存入缓存
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

感谢你能够认真阅读完这篇文章,希望小编分享的"springboot中getSpringFactoriesInstances源码的示例分析"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

0