这篇文章主要介绍了springboot中getSpringFactoriesInstances源码的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
在springboot启动过程中,getSpringFactoriesInstances这个方法很重要,启动的时候使用该方法从classpath上所有jar包中找出对应的META-INF/spring.factorys属性文件,并将其中的初始化器和监听器加载并实例化,应用于更进一步的初始化工作。其工作流程图如下:
让我们跟着流程图和时序图一步步窥视其中的奥妙:
调用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();
}
获取类加载器和调用loadFactoryNames()方法及对返回结果进行初始化以及排序
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//2. 获取类加载器
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//3. 调用loadFactoryNames方法,并使用set对其返回结果进行去重处理
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//9. 实例化初始化器
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//9. 对实例化的结果进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//该方法主要是通过反射实例化初始化器
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> 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;
}
查询缓存和读取META-INFO/spring.factorys文件key-value值,并对value值进行处理
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 返回初始化器的value值
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = //查询缓存,如果有就返回,没有就加载
cache.get(classLoader);
if (result != null) {
return result;
}
try {
//通过类加载器加载所有jar包中包含META-INFO/spring.factorys的文件资源路径
Enumeration<URL> 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源码的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。