在 SpringBoot中是通过getSpringFactoriesInstances(Class<T> type)方法获取所有classpath下面的META-INF/spring.factories文件,然后根据type值找到对应的 class 的全限定名称列表。下面我来分析一下getSpringFactoriesInstances(Class<T> type)方法是如何工作的
public class SpringApplication {
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
// 获取Spring工厂
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
// 获取ClassLoader
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
// 定义class数组,即返回值 names 是所有 classpath 下面的 META-INF/spring.factories 中定义的父节点(图2)
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 内部循环初始化 names的构造函数,获取实例实例对象(图2)
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
// 创建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());
// 循环处理names的值
for (String name : names) {
try { //( 图3)
//通过指定的classloader加载对应的类获取对应的Class对象
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;
}
}
getSpringFactoriesInstances方法通过SpringFactoriesLoader类的loadFactoryNames方法获取系统加载类去所有classpath下面的 META-INF/spring.factories文件中获取对应的 class 的全限定名称结合,在执行createSpringFactoriesInstances方法遍历该集合对进行循环创建实例。然后返回实例对象集合。
图1-1和图1-2标记出所有classpath下面的 META-INF/spring.factories文件中ApplicationContextInitializer.class对应的所有全限定名称
(图1-1)
(图1-2)
(图2)根据类名“applicationContextInitializer”获取 spring.factories文件中applicationContextInitializer相关的工厂类,并进行初始化)
( 图3) 根据类名进行初始化创建实例
public abstract class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();
// 加载工厂
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
// 获取类名称(图4)
String factoryClassName = factoryClass.getName();
// 根据类名称获取需要加载的工厂类名称
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
// 通过加载所有 classpath 下面的 META-INF/spring.factories文件,扫描加载类,(图8)
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 从cache获取实例的结果集 当是Null表示当前的cache是空的;cache 实现 new ConcurrentReferenceHashMap<>()
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 获取所有 classpath 下面的 META-INF/spring.factories 中的资源 urls(图5)
// 当classLoader为非空的时候调用getResouurces方法获取
// 当classLoader为空的时候调用ClassLoader.getSystemResouurces方法获取
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
// 循环处理 urls中的元素,获取元素
while (urls.hasMoreElements()) {
// 获取元素 url地址(图6)
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
// 解析文件 把文件变成配置属性(图6)
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
// 循环解析并把结果放入result
for (Map.Entry<?, ?> entry : properties.entrySet()) {
// 类名列表(图7)
List<String> 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);
}
}
}
(图4)获取class全称
(图5) 获取所有 classpath 下面的 META-INF/spring.factories文件的urls
(图6) 获取spring.factories文件的具体位置及文件中的内容)(图7) 获取spring.factories文件内容中的对应类列表
( 图8)
通过classLoader加载classpath下面的META-INF/spring.factories文件,获取文件信息解析成配置属性存入结果集中,在根据type的全限定名称,从结果集中获取type对应的结果集。循环便利该结果集根据“全限定名称”创建实例。对实例集合排序后返回
Original url: Access
Created at: 2019-10-31 11:28:58
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论