springfactoriesloader如何实现
时间: 2023-11-16 11:10:40 浏览: 25
SpringFactoriesLoader 是 Spring 框架中一个非常重要的工具类,它可以用于实现插件化架构。该工具类可以从类路径下的 `META-INF/spring.factories` 文件中加载指定的配置信息,然后将这些配置信息实例化为具体的对象并返回。
SpringFactoriesLoader 的实现原理主要分为两个步骤:
1. 获取 `META-INF/spring.factories` 配置文件中的所有配置信息,通过 `ClassLoader.getResources()` 方法获取到所有的 `spring.factories` 文件,然后解析文件内容,将其中的配置信息存储到一个 `Map<Class<?>, List<String>>` 中。
2. 根据配置信息创建对应的对象实例,遍历上述的 `Map`,对于每一个键值对,获取其对应的类和实现类列表,然后使用 `Class.forName(className)` 方法加载对应的实现类,并通过反射创建实例对象。最后将创建的实例对象添加到一个 List 中并返回。
下面是 SpringFactoriesLoader 的部分源码:
```java
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadFactories(factoryClass, classLoader).stream()
.map(className -> {
try {
Class<?> clazz = ClassUtils.forName(className, classLoader);
if (!factoryClass.isAssignableFrom(clazz)) {
throw new IllegalArgumentException(
"Class [" + className + "] is not assignable to [" + factoryClassName + "]");
}
return (T) BeanUtils.instantiateClass(clazz);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Unable to instantiate factory class [" + className + "] for factory type [" +
factoryClassName + "]", ex);
}
}).collect(Collectors.toList());
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
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);
}
}
```
通过上述代码可以看出,SpringFactoriesLoader 的实现主要依赖于 `ClassLoader.getResources()` 方法和 `PropertiesLoaderUtils.loadProperties()` 方法来加载 `spring.factories` 配置文件,并解析其中的配置信息。然后通过反射创建实现类的实例对象,最后返回实例对象列表。